From af2b6bbef46c4f158960ce06b6dc112c50d8917e Mon Sep 17 00:00:00 2001 From: lucaskenda Date: Thu, 12 Mar 2020 15:57:57 -0300 Subject: [PATCH 1/3] New node for Rundeck API --- .../credentials/Rundeck.credentials.ts | 30 +++ packages/nodes-base/nodes/Rundeck/Api.ts | 44 +++++ .../nodes-base/nodes/Rundeck/Rundeck.node.ts | 171 ++++++++++++++++++ .../nodes-base/nodes/Rundeck/RundeckApi.ts | 63 +++++++ packages/nodes-base/nodes/Rundeck/rundeck.png | Bin 0 -> 825 bytes packages/nodes-base/package.json | 2 + 6 files changed, 310 insertions(+) create mode 100644 packages/nodes-base/credentials/Rundeck.credentials.ts create mode 100644 packages/nodes-base/nodes/Rundeck/Api.ts create mode 100644 packages/nodes-base/nodes/Rundeck/Rundeck.node.ts create mode 100644 packages/nodes-base/nodes/Rundeck/RundeckApi.ts create mode 100644 packages/nodes-base/nodes/Rundeck/rundeck.png diff --git a/packages/nodes-base/credentials/Rundeck.credentials.ts b/packages/nodes-base/credentials/Rundeck.credentials.ts new file mode 100644 index 0000000000..5285e59c5a --- /dev/null +++ b/packages/nodes-base/credentials/Rundeck.credentials.ts @@ -0,0 +1,30 @@ +import { + ICredentialType, + NodePropertyTypes, +} from 'n8n-workflow'; + + +export class Rundeck implements ICredentialType { + name = 'rundeck'; + displayName = 'Rundeck'; + properties = [ + { + displayName: 'Url', + name: 'url', + type: 'string' as NodePropertyTypes, + default: '', + }, + { + displayName: 'Api Version', + name: 'apiVersion', + type: 'number' as NodePropertyTypes, + default: '', + }, + { + displayName: 'Token', + name: 'token', + type: 'string' as NodePropertyTypes, + default: '', + }, + ]; +} diff --git a/packages/nodes-base/nodes/Rundeck/Api.ts b/packages/nodes-base/nodes/Rundeck/Api.ts new file mode 100644 index 0000000000..28f64c9d34 --- /dev/null +++ b/packages/nodes-base/nodes/Rundeck/Api.ts @@ -0,0 +1,44 @@ +import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios"; + +export class Api { + private api: AxiosInstance; + + constructor (config: AxiosRequestConfig) { + this.api = axios.create(config); + this.api.interceptors.request.use((param: AxiosRequestConfig) => ({ + ...param + })); + } + + protected getUri (config?: AxiosRequestConfig): string { + return this.api.getUri(config); + } + + protected request> (config: AxiosRequestConfig): Promise { + return this.api.request(config); + } + + protected get> (url: string, config?: AxiosRequestConfig): Promise { + return this.api.get(url, config); + } + + protected delete> (url: string, config?: AxiosRequestConfig): Promise { + return this.api.delete(url, config); + } + + protected head> (url: string, config?: AxiosRequestConfig): Promise { + return this.api.head(url, config); + } + + protected post> (url: string, data?: string, config?: AxiosRequestConfig): Promise { + return this.api.post(url, data, config); + } + + protected put> (url: string, data?: string, config?: AxiosRequestConfig): Promise { + return this.api.put(url, data, config); + } + + protected patch> (url: string, data?: string, config?: AxiosRequestConfig): Promise { + return this.api.patch(url, data, config); + } +} \ No newline at end of file diff --git a/packages/nodes-base/nodes/Rundeck/Rundeck.node.ts b/packages/nodes-base/nodes/Rundeck/Rundeck.node.ts new file mode 100644 index 0000000000..d9cb059cea --- /dev/null +++ b/packages/nodes-base/nodes/Rundeck/Rundeck.node.ts @@ -0,0 +1,171 @@ +import { IExecuteFunctions } from 'n8n-core'; +import { + IDataObject, + INodeExecutionData, + INodeType, + INodeTypeDescription, +} from 'n8n-workflow'; +import { Parser } from 'xml2js'; +import { RundeckApi, RundeckCredentials } from "./RundeckApi"; + +export class Rundeck implements INodeType { + description: INodeTypeDescription = { + displayName: 'Rundeck', + name: 'rundeck', + icon: 'file:rundeck.png', + group: ['transform'], + version: 1, + description: 'Manage Rundeck API', + defaults: { + name: 'Rundeck', + color: '#F73F39', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'rundeck', + required: true, + } + ], + properties: [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + options: [ + { + name: 'Execute Job', + value: 'executeJob', + description: 'Executes Job.', + }, + ], + default: 'executeJob', + description: 'The operation to perform.', + }, + + // ---------------------------------- + // JobId + // ---------------------------------- + { + displayName: 'Job Id', + name: 'jobid', + type: 'string', + displayOptions: { + show: { + operation: [ + 'executeJob' + ], + }, + }, + default: '', + placeholder: 'Rundeck Job Id', + required: true, + description: 'The job Id to execute.', + }, + + // ---------------------------------- + // Arguments + // ---------------------------------- + { + displayName: 'Arguments', + name: 'arguments', + placeholder: 'Arguments', + type: 'fixedCollection', + typeOptions: { + multipleValues: true, + }, + displayOptions: { + show: { + operation: [ + 'executeJob' + ], + }, + }, + default: {}, + options: [ + { + name: 'arguments', + displayName: 'Add argument', + values: [ + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + }, + { + displayName: 'Value', + name: 'value', + type: 'string', + default: '', + }, + ] + }, + ], + }, + ] + }; + + + async execute(this: IExecuteFunctions): Promise { + + // Input data + const items = this.getInputData(); + const returnData: IDataObject[] = []; + const length = items.length as unknown as number; + + const credentials = this.getCredentials('rundeck'); + + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + + const rundeckCredentials: RundeckCredentials = { + url: credentials.url as string, + apiVersion: credentials.apiVersion as number, + token: credentials.token as string + }; + + const operation = this.getNodeParameter('operation', 0) as string; + + for (let i = 0; i < length; i++) { + if (operation === 'executeJob') { + // ---------------------------------- + // executeJob + // ---------------------------------- + const rundeckApi = new RundeckApi(rundeckCredentials); + const jobid = this.getNodeParameter('jobid', i) as string; + const rundeckArguments = (this.getNodeParameter('arguments', i) as IDataObject).arguments as IDataObject[]; + let response; + + try { + + response = await rundeckApi.executeJob(jobid, rundeckArguments); + + const parser = new Parser({ + mergeAttrs: true, + explicitArray: false, + }); + + // @ts-ignore + const json = await parser.parseStringPromise(response); + returnData.push({ json }); + + } catch(error) { + if(error.response && error.response.data && error.response.status) { + throw Error(`status: ${error.response.status}, response: ${(error.response.data).replace('\n', '')}`); + } else { + throw error; + } + } + + } else { + throw new Error(`The operation "${operation}" is not supported!`); + } + } + + return [this.helpers.returnJsonArray(returnData)]; + + } +} diff --git a/packages/nodes-base/nodes/Rundeck/RundeckApi.ts b/packages/nodes-base/nodes/Rundeck/RundeckApi.ts new file mode 100644 index 0000000000..137ed2bd57 --- /dev/null +++ b/packages/nodes-base/nodes/Rundeck/RundeckApi.ts @@ -0,0 +1,63 @@ +import { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios"; +import { Api } from "./Api"; +import * as https from 'https'; +import { Xml } from "../Xml.node"; +import { IDataObject } from "n8n-workflow"; + +export interface RundeckCredentials { + url: string; + apiVersion: number; + token: string; +} + +function acceptVersion(credentialsApiVersion: number, apiVersion: number) { + if(apiVersion > credentialsApiVersion) { + throw Error('This endpoint is not supported for this version!'); + } +} + +export class RundeckApi extends Api { + + private credentials: RundeckCredentials; + + constructor (credentials: RundeckCredentials) { + + const config: AxiosRequestConfig = { + httpsAgent: new https.Agent({ + rejectUnauthorized: false + }), + headers: { + 'Accept': 'application/xml', + 'user-agent': 'n8n', + 'X-Rundeck-Auth-Token': credentials.token, + } + }; + + super(config); + this.credentials = credentials; + + } + + executeJob(jobId: string, args: IDataObject[]): Promise { + + acceptVersion(this.credentials.apiVersion, 12); + + let params = ''; + + if(args) { + for(const arg of args) { + params += "-" + arg.name + " " + arg.value + " "; + } + } + + return this.post(this.credentials.url + '/api/12/job/' + jobId + '/run?argString=' + params) + .then((response: AxiosResponse) => { + const { data } = response; + return data; + }) + .catch((error: AxiosError) => { + throw error; + }); + } + +} \ No newline at end of file diff --git a/packages/nodes-base/nodes/Rundeck/rundeck.png b/packages/nodes-base/nodes/Rundeck/rundeck.png new file mode 100644 index 0000000000000000000000000000000000000000..b55f1973ae376416c5677d12deac75652678368b GIT binary patch literal 825 zcmV-91IGM`P)(*1 zK~!ko?V4LlR8bVi|9kJz3A|v9CYp&EmX%0?FgU3XlL&!E7%DOLP)~iF-uwU!2wouZ zpfQw{cu6x1BQhirD=jSwQ?eQM-aYizlV>{1Gvr#&=VAX?|8+mYT5EBLOyZCk12ZrK zGcW@)a0XdmzaQGAWtiFLfYziB5~oi=HiUufEPsJf6oOrQ57Qebg%(Zq5XHq1)m8pV zT7-^4b#_41*N}SHPA@`+Y9^ZEqVJWqRl>gcxM-S*nyp1pzW8d z$|0|{d3IMyFNTvT=&2c)L5CJrDX5-K$cwe!D#o>xH@9H=hJdvV+CI6p5wh(HkelNp za54qsjM2}z zlwFU9c4--A`WgLt)*Rb*mCLF-s00000NkvXXu0mjf Dxjb Date: Fri, 13 Mar 2020 13:02:54 -0300 Subject: [PATCH 2/3] Change spaces for tabs --- packages/nodes-base/nodes/Rundeck/Api.ts | 66 +++++++-------- .../nodes-base/nodes/Rundeck/RundeckApi.ts | 80 +++++++++---------- 2 files changed, 73 insertions(+), 73 deletions(-) diff --git a/packages/nodes-base/nodes/Rundeck/Api.ts b/packages/nodes-base/nodes/Rundeck/Api.ts index 28f64c9d34..deac944ec1 100644 --- a/packages/nodes-base/nodes/Rundeck/Api.ts +++ b/packages/nodes-base/nodes/Rundeck/Api.ts @@ -1,44 +1,44 @@ import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios"; export class Api { - private api: AxiosInstance; + private api: AxiosInstance; - constructor (config: AxiosRequestConfig) { - this.api = axios.create(config); - this.api.interceptors.request.use((param: AxiosRequestConfig) => ({ - ...param - })); - } + constructor (config: AxiosRequestConfig) { + this.api = axios.create(config); + this.api.interceptors.request.use((param: AxiosRequestConfig) => ({ + ...param + })); + } + + protected getUri (config?: AxiosRequestConfig): string { + return this.api.getUri(config); + } + + protected request> (config: AxiosRequestConfig): Promise { + return this.api.request(config); + } - protected getUri (config?: AxiosRequestConfig): string { - return this.api.getUri(config); - } + protected get> (url: string, config?: AxiosRequestConfig): Promise { + return this.api.get(url, config); + } - protected request> (config: AxiosRequestConfig): Promise { - return this.api.request(config); - } + protected delete> (url: string, config?: AxiosRequestConfig): Promise { + return this.api.delete(url, config); + } - protected get> (url: string, config?: AxiosRequestConfig): Promise { - return this.api.get(url, config); - } + protected head> (url: string, config?: AxiosRequestConfig): Promise { + return this.api.head(url, config); + } - protected delete> (url: string, config?: AxiosRequestConfig): Promise { - return this.api.delete(url, config); - } + protected post> (url: string, data?: string, config?: AxiosRequestConfig): Promise { + return this.api.post(url, data, config); + } - protected head> (url: string, config?: AxiosRequestConfig): Promise { - return this.api.head(url, config); - } + protected put> (url: string, data?: string, config?: AxiosRequestConfig): Promise { + return this.api.put(url, data, config); + } - protected post> (url: string, data?: string, config?: AxiosRequestConfig): Promise { - return this.api.post(url, data, config); - } - - protected put> (url: string, data?: string, config?: AxiosRequestConfig): Promise { - return this.api.put(url, data, config); - } - - protected patch> (url: string, data?: string, config?: AxiosRequestConfig): Promise { - return this.api.patch(url, data, config); - } + protected patch> (url: string, data?: string, config?: AxiosRequestConfig): Promise { + return this.api.patch(url, data, config); + } } \ No newline at end of file diff --git a/packages/nodes-base/nodes/Rundeck/RundeckApi.ts b/packages/nodes-base/nodes/Rundeck/RundeckApi.ts index 137ed2bd57..23edf71f7e 100644 --- a/packages/nodes-base/nodes/Rundeck/RundeckApi.ts +++ b/packages/nodes-base/nodes/Rundeck/RundeckApi.ts @@ -5,59 +5,59 @@ import { Xml } from "../Xml.node"; import { IDataObject } from "n8n-workflow"; export interface RundeckCredentials { - url: string; - apiVersion: number; - token: string; + url: string; + apiVersion: number; + token: string; } function acceptVersion(credentialsApiVersion: number, apiVersion: number) { - if(apiVersion > credentialsApiVersion) { - throw Error('This endpoint is not supported for this version!'); - } + if(apiVersion > credentialsApiVersion) { + throw Error('This endpoint is not supported for this version!'); + } } export class RundeckApi extends Api { + + private credentials: RundeckCredentials; - private credentials: RundeckCredentials; + constructor (credentials: RundeckCredentials) { - constructor (credentials: RundeckCredentials) { + const config: AxiosRequestConfig = { + httpsAgent: new https.Agent({ + rejectUnauthorized: false + }), + headers: { + 'Accept': 'application/xml', + 'user-agent': 'n8n', + 'X-Rundeck-Auth-Token': credentials.token, + } + }; - const config: AxiosRequestConfig = { - httpsAgent: new https.Agent({ - rejectUnauthorized: false - }), - headers: { - 'Accept': 'application/xml', - 'user-agent': 'n8n', - 'X-Rundeck-Auth-Token': credentials.token, - } - }; - - super(config); - this.credentials = credentials; + super(config); + this.credentials = credentials; - } + } - executeJob(jobId: string, args: IDataObject[]): Promise { + executeJob(jobId: string, args: IDataObject[]): Promise { - acceptVersion(this.credentials.apiVersion, 12); + acceptVersion(this.credentials.apiVersion, 12); - let params = ''; + let params = ''; - if(args) { - for(const arg of args) { - params += "-" + arg.name + " " + arg.value + " "; - } - } - - return this.post(this.credentials.url + '/api/12/job/' + jobId + '/run?argString=' + params) - .then((response: AxiosResponse) => { - const { data } = response; - return data; - }) - .catch((error: AxiosError) => { - throw error; - }); - } + if(args) { + for(const arg of args) { + params += "-" + arg.name + " " + arg.value + " "; + } + } + + return this.post(this.credentials.url + '/api/12/job/' + jobId + '/run?argString=' + params) + .then((response: AxiosResponse) => { + const { data } = response; + return data; + }) + .catch((error: AxiosError) => { + throw error; + }); + } } \ No newline at end of file From 1d43cbf3e70fba74bdc8eacaef59ab0abb3011dd Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Sun, 15 Mar 2020 19:20:41 +0100 Subject: [PATCH 3/3] :zap: Improved Rundeck-Node --- ...edentials.ts => RundeckApi.credentials.ts} | 13 +- packages/nodes-base/nodes/Rundeck/Api.ts | 44 ------ .../nodes-base/nodes/Rundeck/Rundeck.node.ts | 149 +++++++++++------- .../nodes-base/nodes/Rundeck/RundeckApi.ts | 86 +++++----- packages/nodes-base/nodes/Rundeck/rundeck.png | Bin 825 -> 319 bytes packages/nodes-base/package.json | 2 +- 6 files changed, 143 insertions(+), 151 deletions(-) rename packages/nodes-base/credentials/{Rundeck.credentials.ts => RundeckApi.credentials.ts} (58%) delete mode 100644 packages/nodes-base/nodes/Rundeck/Api.ts diff --git a/packages/nodes-base/credentials/Rundeck.credentials.ts b/packages/nodes-base/credentials/RundeckApi.credentials.ts similarity index 58% rename from packages/nodes-base/credentials/Rundeck.credentials.ts rename to packages/nodes-base/credentials/RundeckApi.credentials.ts index 5285e59c5a..5f6c7422f7 100644 --- a/packages/nodes-base/credentials/Rundeck.credentials.ts +++ b/packages/nodes-base/credentials/RundeckApi.credentials.ts @@ -4,21 +4,16 @@ import { } from 'n8n-workflow'; -export class Rundeck implements ICredentialType { - name = 'rundeck'; - displayName = 'Rundeck'; +export class RundeckApi implements ICredentialType { + name = 'rundeckApi'; + displayName = 'Rundeck API'; properties = [ { displayName: 'Url', name: 'url', type: 'string' as NodePropertyTypes, default: '', - }, - { - displayName: 'Api Version', - name: 'apiVersion', - type: 'number' as NodePropertyTypes, - default: '', + placeholder: 'http://127.0.0.1:4440', }, { displayName: 'Token', diff --git a/packages/nodes-base/nodes/Rundeck/Api.ts b/packages/nodes-base/nodes/Rundeck/Api.ts deleted file mode 100644 index deac944ec1..0000000000 --- a/packages/nodes-base/nodes/Rundeck/Api.ts +++ /dev/null @@ -1,44 +0,0 @@ -import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios"; - -export class Api { - private api: AxiosInstance; - - constructor (config: AxiosRequestConfig) { - this.api = axios.create(config); - this.api.interceptors.request.use((param: AxiosRequestConfig) => ({ - ...param - })); - } - - protected getUri (config?: AxiosRequestConfig): string { - return this.api.getUri(config); - } - - protected request> (config: AxiosRequestConfig): Promise { - return this.api.request(config); - } - - protected get> (url: string, config?: AxiosRequestConfig): Promise { - return this.api.get(url, config); - } - - protected delete> (url: string, config?: AxiosRequestConfig): Promise { - return this.api.delete(url, config); - } - - protected head> (url: string, config?: AxiosRequestConfig): Promise { - return this.api.head(url, config); - } - - protected post> (url: string, data?: string, config?: AxiosRequestConfig): Promise { - return this.api.post(url, data, config); - } - - protected put> (url: string, data?: string, config?: AxiosRequestConfig): Promise { - return this.api.put(url, data, config); - } - - protected patch> (url: string, data?: string, config?: AxiosRequestConfig): Promise { - return this.api.patch(url, data, config); - } -} \ No newline at end of file diff --git a/packages/nodes-base/nodes/Rundeck/Rundeck.node.ts b/packages/nodes-base/nodes/Rundeck/Rundeck.node.ts index d9cb059cea..bae6b9a07f 100644 --- a/packages/nodes-base/nodes/Rundeck/Rundeck.node.ts +++ b/packages/nodes-base/nodes/Rundeck/Rundeck.node.ts @@ -5,8 +5,7 @@ import { INodeType, INodeTypeDescription, } from 'n8n-workflow'; -import { Parser } from 'xml2js'; -import { RundeckApi, RundeckCredentials } from "./RundeckApi"; +import { RundeckApi } from './RundeckApi'; export class Rundeck implements INodeType { description: INodeTypeDescription = { @@ -15,6 +14,7 @@ export class Rundeck implements INodeType { icon: 'file:rundeck.png', group: ['transform'], version: 1, + subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Manage Rundeck API', defaults: { name: 'Rundeck', @@ -24,28 +24,46 @@ export class Rundeck implements INodeType { outputs: ['main'], credentials: [ { - name: 'rundeck', + name: 'rundeckApi', required: true, } ], properties: [ + { + displayName: 'Resource', + name: 'resource', + type: 'options', + options: [ + { + name: 'Job', + value: 'job', + }, + ], + default: 'job', + description: 'The resource to operate on.', + }, { displayName: 'Operation', name: 'operation', type: 'options', options: [ { - name: 'Execute Job', - value: 'executeJob', - description: 'Executes Job.', + name: 'Execute', + value: 'execute', + description: 'Executes job', + }, + { + name: 'Get Metadata', + value: 'getMetadata', + description: 'Get metadata of a job', }, ], - default: 'executeJob', + default: 'execute', description: 'The operation to perform.', }, // ---------------------------------- - // JobId + // job:execute // ---------------------------------- { displayName: 'Job Id', @@ -54,7 +72,10 @@ export class Rundeck implements INodeType { displayOptions: { show: { operation: [ - 'executeJob' + 'execute', + ], + resource: [ + 'job', ], }, }, @@ -63,14 +84,10 @@ export class Rundeck implements INodeType { required: true, description: 'The job Id to execute.', }, - - // ---------------------------------- - // Arguments - // ---------------------------------- { displayName: 'Arguments', name: 'arguments', - placeholder: 'Arguments', + placeholder: 'Add Argument', type: 'fixedCollection', typeOptions: { multipleValues: true, @@ -78,7 +95,10 @@ export class Rundeck implements INodeType { displayOptions: { show: { operation: [ - 'executeJob' + 'execute', + ], + resource: [ + 'job', ], }, }, @@ -86,7 +106,7 @@ export class Rundeck implements INodeType { options: [ { name: 'arguments', - displayName: 'Add argument', + displayName: 'Arguments', values: [ { displayName: 'Name', @@ -104,7 +124,32 @@ export class Rundeck implements INodeType { }, ], }, - ] + + + // ---------------------------------- + // job:getMetadata + // ---------------------------------- + { + displayName: 'Job Id', + name: 'jobid', + type: 'string', + displayOptions: { + show: { + operation: [ + 'getMetadata', + ], + resource: [ + 'job', + ], + }, + }, + default: '', + placeholder: 'Rundeck Job Id', + required: true, + description: 'The job Id to get metadata off.', + }, + ], + }; @@ -114,58 +159,40 @@ export class Rundeck implements INodeType { const items = this.getInputData(); const returnData: IDataObject[] = []; const length = items.length as unknown as number; - - const credentials = this.getCredentials('rundeck'); - - if (credentials === undefined) { - throw new Error('No credentials got returned!'); - } - - const rundeckCredentials: RundeckCredentials = { - url: credentials.url as string, - apiVersion: credentials.apiVersion as number, - token: credentials.token as string - }; const operation = this.getNodeParameter('operation', 0) as string; + const resource = this.getNodeParameter('resource', 0) as string; for (let i = 0; i < length; i++) { - if (operation === 'executeJob') { - // ---------------------------------- - // executeJob - // ---------------------------------- - const rundeckApi = new RundeckApi(rundeckCredentials); - const jobid = this.getNodeParameter('jobid', i) as string; - const rundeckArguments = (this.getNodeParameter('arguments', i) as IDataObject).arguments as IDataObject[]; - let response; - - try { - - response = await rundeckApi.executeJob(jobid, rundeckArguments); - - const parser = new Parser({ - mergeAttrs: true, - explicitArray: false, - }); - - // @ts-ignore - const json = await parser.parseStringPromise(response); - returnData.push({ json }); - - } catch(error) { - if(error.response && error.response.data && error.response.status) { - throw Error(`status: ${error.response.status}, response: ${(error.response.data).replace('\n', '')}`); - } else { - throw error; - } + const rundeckApi = new RundeckApi(this); + + if (resource === 'job') { + if (operation === 'execute') { + // ---------------------------------- + // job: execute + // ---------------------------------- + const jobid = this.getNodeParameter('jobid', i) as string; + const rundeckArguments = (this.getNodeParameter('arguments', i) as IDataObject).arguments as IDataObject[]; + const response = await rundeckApi.executeJob(jobid, rundeckArguments); + + returnData.push(response); + } else if (operation === 'getMetadata') { + // ---------------------------------- + // job: getMetadata + // ---------------------------------- + const jobid = this.getNodeParameter('jobid', i) as string; + const response = await rundeckApi.getJobMetadata(jobid); + + returnData.push(response); + } else { + throw new Error(`The operation "${operation}" is not supported!`); } - } else { - throw new Error(`The operation "${operation}" is not supported!`); + throw new Error(`The resource "${resource}" is not supported!`); } } - + return [this.helpers.returnJsonArray(returnData)]; - + } } diff --git a/packages/nodes-base/nodes/Rundeck/RundeckApi.ts b/packages/nodes-base/nodes/Rundeck/RundeckApi.ts index 23edf71f7e..6b5fdfb202 100644 --- a/packages/nodes-base/nodes/Rundeck/RundeckApi.ts +++ b/packages/nodes-base/nodes/Rundeck/RundeckApi.ts @@ -1,46 +1,59 @@ -import { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios"; -import { Api } from "./Api"; -import * as https from 'https'; -import { Xml } from "../Xml.node"; -import { IDataObject } from "n8n-workflow"; +import { OptionsWithUri } from 'request'; +import { IExecuteFunctions } from 'n8n-core'; +import { IDataObject } from 'n8n-workflow'; export interface RundeckCredentials { url: string; - apiVersion: number; token: string; } -function acceptVersion(credentialsApiVersion: number, apiVersion: number) { - if(apiVersion > credentialsApiVersion) { - throw Error('This endpoint is not supported for this version!'); - } -} - -export class RundeckApi extends Api { - +export class RundeckApi { private credentials: RundeckCredentials; + private executeFunctions: IExecuteFunctions; - constructor (credentials: RundeckCredentials) { - const config: AxiosRequestConfig = { - httpsAgent: new https.Agent({ - rejectUnauthorized: false - }), + constructor(executeFunctions: IExecuteFunctions) { + + const credentials = executeFunctions.getCredentials('rundeckApi'); + + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + + this.credentials = credentials as unknown as RundeckCredentials; + this.executeFunctions = executeFunctions; + } + + + protected async request(method: string, endpoint: string, body: IDataObject, query: object) { + + const options: OptionsWithUri = { headers: { - 'Accept': 'application/xml', 'user-agent': 'n8n', - 'X-Rundeck-Auth-Token': credentials.token, - } + 'X-Rundeck-Auth-Token': this.credentials.token, + }, + rejectUnauthorized: false, + method, + qs: query, + uri: this.credentials.url + endpoint, + body, + json: true }; - super(config); - this.credentials = credentials; + try { + return await this.executeFunctions.helpers.request!(options); + } catch (error) { + let errorMessage = error.message; + if (error.response && error.response.body && error.response.body.message) { + errorMessage = error.response.body.message.replace('\n', ''); + } + throw Error(`Rundeck Error [${error.statusCode}]: ${errorMessage}`); + } } - executeJob(jobId: string, args: IDataObject[]): Promise { - acceptVersion(this.credentials.apiVersion, 12); + executeJob(jobId: string, args: IDataObject[]): Promise { let params = ''; @@ -49,15 +62,16 @@ export class RundeckApi extends Api { params += "-" + arg.name + " " + arg.value + " "; } } - - return this.post(this.credentials.url + '/api/12/job/' + jobId + '/run?argString=' + params) - .then((response: AxiosResponse) => { - const { data } = response; - return data; - }) - .catch((error: AxiosError) => { - throw error; - }); + + const body = { + argString: params + }; + + return this.request('POST', `/api/14/job/${jobId}/run`, body, {}); } -} \ No newline at end of file + getJobMetadata(jobId: string): Promise { + return this.request('GET', `/api/18/job/${jobId}/info`, {}, {}); + } + +} diff --git a/packages/nodes-base/nodes/Rundeck/rundeck.png b/packages/nodes-base/nodes/Rundeck/rundeck.png index b55f1973ae376416c5677d12deac75652678368b..45084aea60c5938aa7e58f10978b3b1164545e9b 100644 GIT binary patch delta 303 zcmV+~0nq-r2EPK38Gi!+000dlDL?=K07y_wR7L;)|M?av{^RBRsjmE;qWLB^`d?`J zQ(gc0`v2_h{@2?5!o~SFME~>j{?5_+b9(%^yZo1&{ECqJO<4Pai2HVa`etwXKuqs> zSknLi0J2F$K~zY`?bcfkg&+(?Q62&7~d$#r{By>$#ep|};NV?_7S+7 z5xHoAh2^?b5C<<0&X)y_te6|b;9RT6Zjb(j&3gi3GZJzTnc)MdcqEH)P66ooF7=C! z)~a8zF6x&%Z76W)RsZ9%=d8bxr2OU*H%{@O^#i`n3N2!GwX*;K002ovPDHLkV1kpG Bl|29e delta 813 zcmV+|1JeAz0=Wi|8Gi-<0027t*>V5?00v@9M??Vs0RI60puMM)00009a7bBm001r{ z001r{0eGc9b^rhX2XskIMF->q3JfA3{Mz;m0008UNkl01XIUAn~9vlz)|YNiz&1G9(czEiDRD zvKjW?J@nR-XFAI>jzX=&Al@01V8)49vg`{9h~pk|~(EdD!(& z^j@j0@$6olHn3e;g}&Ph`|2%u`zWH#K6`j)7k_%#ft_BU?U$>{A+NQ0c2`O-hLb7i zsTr6-hZa^TsGd&9i?!Y=#&%+GNzzod549vg`d|>t)*Rb*mCLF-s00000NkvXXu0mjf4Xkqr diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 62a6a3b4db..f60f638497 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -83,7 +83,7 @@ "dist/credentials/Postgres.credentials.js", "dist/credentials/Redis.credentials.js", "dist/credentials/RocketchatApi.credentials.js", - "dist/credentials/Rundeck.credentials.js", + "dist/credentials/RundeckApi.credentials.js", "dist/credentials/ShopifyApi.credentials.js", "dist/credentials/SlackApi.credentials.js", "dist/credentials/Smtp.credentials.js",