UNPKG

n8n-nodes-awx

Version:

n8n node to interact with Ansible AWX/Tower with improved type safety

390 lines 20.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.handleJobOperations = handleJobOperations; exports.handleJobStatusOperations = handleJobStatusOperations; exports.generateStatusSummary = generateStatusSummary; const n8n_workflow_1 = require("n8n-workflow"); const SharedHelpers_1 = require("../utils/SharedHelpers"); const resourceHelpers_1 = require("../utils/resourceHelpers"); async function handleJobOperations(action) { if (action === 'list') { const filter = this.getNodeParameter('filter', 0, ''); const dateFilterInput = this.getNodeParameter('dateFilter', 0, ''); const returnAll = this.getNodeParameter('returnAll', 0, false); const sortDescending = this.getNodeParameter('sortDescending', 0, true); const responseFormat = this.getNodeParameter('responseFormat', 0, 'friendly'); const queryParams = {}; if (filter) { queryParams.search = filter; } queryParams.order_by = sortDescending ? '-created' : 'created'; console.log(`[AWX Node DEBUG] Setting sort order: ${queryParams.order_by}`); if (dateFilterInput) { const dateFilterPairs = dateFilterInput.split(','); console.log(`[AWX Node DEBUG] dateFilterPairs after split by comma:`, dateFilterPairs); dateFilterPairs.forEach(pairString => { console.log(`[AWX Node DEBUG] Processing pairString: '${pairString}'`); const firstEqualIndex = pairString.indexOf('='); if (firstEqualIndex > 0) { const key = pairString.substring(0, firstEqualIndex).trim(); const value = pairString.substring(firstEqualIndex + 1).trim(); if (key && value) { queryParams[key] = value; console.log(`[AWX Node DEBUG] Added to queryParams: ${key} = ${value}`); } else { console.log(`[AWX Node DEBUG] Skipped adding to queryParams for pairString '${pairString}' because key or value was empty after parsing.`); } } else { console.log(`[AWX Node DEBUG] Skipped processing pairString '${pairString}' because no '=' was found or it was at the beginning.`); } }); } const fetchMode = returnAll ? 'allPages' : 'firstPage'; const response = await SharedHelpers_1.getAwxResources.call(this, '/jobs/', fetchMode, queryParams); if (Array.isArray(response) && response.length > 0) { const jobsArray = response; const formattedJobs = jobsArray.map(job => resourceHelpers_1.formatResourceResponse.call(this, job, responseFormat, 'job')); const finalResponse = { count: formattedJobs.length, jobs: formattedJobs, }; return [[{ json: finalResponse }]]; } return [this.helpers.returnJsonArray(response)]; } else if (action === 'get') { console.log('[AWX Node DEBUG] Getting job ID parameter for get action'); const { id: resolvedJobId } = resourceHelpers_1.resolveResourceParameters.call(this, ['jobId', 'Job_ID', 'id'], [], 'job', 0); if (!resolvedJobId) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Job ID could not be determined for get action. Please ensure the Job ID parameter is set correctly.'); } const jobIdToUse = String(resolvedJobId); console.log(`[AWX Node DEBUG] Using job ID: ${jobIdToUse}`); const includeOutput = this.getNodeParameter('includeOutput', 0, false); const responseFormat = this.getNodeParameter('responseFormat', 0, 'friendly'); console.log(`[AWX Node DEBUG] Fetching job with ID: ${jobIdToUse}`); const job = await SharedHelpers_1.getAwxResource.call(this, 'jobs', { id: jobIdToUse }); console.log(`[AWX Node DEBUG] Retrieved job data:`, job); let job_output = null; if (responseFormat === 'friendly' || includeOutput) { try { console.log(`[AWX Node DEBUG] Getting job output using getAwxResource for job ID: ${jobIdToUse}`); const stdoutResource = await SharedHelpers_1.getAwxResource.call(this, 'jobs', { id: `${jobIdToUse}/stdout` }); let determinedOutput = null; let rawOutputText; if (typeof stdoutResource === 'string') { rawOutputText = stdoutResource; } else if (stdoutResource && typeof stdoutResource === 'object' && stdoutResource !== null) { const content = stdoutResource.content; const text = stdoutResource.text; if (typeof content === 'string') { rawOutputText = content; } else if (typeof text === 'string') { rawOutputText = text; } } if (rawOutputText !== undefined) { determinedOutput = rawOutputText.trim(); } job_output = determinedOutput !== null ? determinedOutput : (typeof stdoutResource === 'object' && stdoutResource !== null) ? JSON.stringify(stdoutResource) : 'No job output content available or in unexpected format'; } catch (error) { console.log(`[AWX Node DEBUG] Error getting job output: ${error.message}`); job_output = `Error retrieving job output: ${error.message}`; } console.log(`[AWX Node DEBUG] job_output:`, job_output); } if (job_output !== null && job_output !== undefined) { job.job_output = job_output; } const formattedJob = resourceHelpers_1.formatResourceResponse.call(this, job, responseFormat, 'job'); if (responseFormat === 'standard' && includeOutput && job_output) { return [[{ json: { job_output } }]]; } return [[{ json: formattedJob }]]; } else if (action === 'cancel') { let resolvedCancelJobId = null; const cancelIdKeysToTry = ['Job_ID', 'jobId', 'id']; for (const key of cancelIdKeysToTry) { const val = this.getNodeParameter(key, 0, undefined); if (val !== undefined && val !== null && val !== '') { resolvedCancelJobId = val; break; } } if (!resolvedCancelJobId) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Job ID must be provided for cancel (checked: ${cancelIdKeysToTry.join(', ')}).`); } const jobIdToCancel = String(resolvedCancelJobId); const response = await SharedHelpers_1.createAwxResource.call(this, `/jobs/${jobIdToCancel}/cancel/`, {}, 0); return [this.helpers.returnJsonArray([response])]; } throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The action "${action}" is not supported for jobs`); } async function handleJobStatusOperations(operation) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m; const returnData = []; try { if (operation === 'list') { const filter = this.getNodeParameter('filter', 0, ''); const returnAll = this.getNodeParameter('returnAll', 0, false); const responseFormat = this.getNodeParameter('responseFormat', 0, 'friendly'); const queryParams = {}; if (filter) { queryParams.search = filter; } const dateFilterInput = this.getNodeParameter('dateFilter', 0, ''); console.log(`[AWX Node DEBUG] Raw dateFilterInput: '${dateFilterInput}'`); if (dateFilterInput) { const dateFilterPairs = dateFilterInput.split(','); console.log(`[AWX Node DEBUG] dateFilterPairs after split by comma:`, dateFilterPairs); dateFilterPairs.forEach(pairString => { console.log(`[AWX Node DEBUG] Processing pairString: '${pairString}'`); const firstEqualIndex = pairString.indexOf('='); if (firstEqualIndex > 0) { const key = pairString.substring(0, firstEqualIndex).trim(); const value = pairString.substring(firstEqualIndex + 1).trim(); if (key && value) { queryParams[key] = value; console.log(`[AWX Node DEBUG] Added to queryParams: ${key} = ${value}`); } else { console.log(`[AWX Node DEBUG] Skipped adding to queryParams for pairString '${pairString}' because key or value was empty after parsing.`); } } else { console.log(`[AWX Node DEBUG] Skipped processing pairString '${pairString}' because no '=' was found or it was at the beginning.`); } }); } const fetchMode = returnAll ? 'allPages' : 'firstPage'; const jobs = await SharedHelpers_1.getAwxResources.call(this, '/jobs/', fetchMode, queryParams); const statusSummary = generateStatusSummary(jobs); if (responseFormat === 'friendly' || responseFormat === 'minimal') { const formattedResponse = { success: true, count: jobs.length, message: `Found ${jobs.length} jobs`, status_summary: statusSummary, jobs: jobs.map(job => { var _a, _b, _c, _d, _e, _f; return ({ id: job.id, name: job.name, status: job.status, started: job.started, finished: job.finished, elapsed: job.elapsed, job_template_name: ((_b = (_a = job.summary_fields) === null || _a === void 0 ? void 0 : _a.job_template) === null || _b === void 0 ? void 0 : _b.name) || null, inventory_name: ((_d = (_c = job.summary_fields) === null || _c === void 0 ? void 0 : _c.inventory) === null || _d === void 0 ? void 0 : _d.name) || null, launched_by: ((_f = (_e = job.summary_fields) === null || _e === void 0 ? void 0 : _e.created_by) === null || _f === void 0 ? void 0 : _f.username) || null, ui_url: job.url ? `${job.url.replace('/api/v2/jobs/', '/jobs/output/')}` : null, }); }) }; returnData.push({ json: formattedResponse, }); } else { const fullResponse = { jobs, status_summary: statusSummary, }; returnData.push({ json: fullResponse, }); } } else if (operation === 'get') { let resolvedStatusJobId = null; const statusIdKeysToTry = ['Job_ID', 'jobId', 'id']; for (const key of statusIdKeysToTry) { const val = this.getNodeParameter(key, 0, undefined); if (val !== undefined && val !== null && val !== '') { resolvedStatusJobId = val; break; } } if (!resolvedStatusJobId) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Job ID must be provided for status (checked: ${statusIdKeysToTry.join(', ')}).`); } const jobIdForStatus = String(resolvedStatusJobId); const includeOutput = this.getNodeParameter('includeOutput', 0, false); const responseFormat = this.getNodeParameter('responseFormat', 0, 'friendly'); const job = await SharedHelpers_1.getAwxResource.call(this, 'jobs', { id: jobIdForStatus }); let output = null; if (includeOutput) { try { const stdoutResourceForStatus = await SharedHelpers_1.getAwxResource.call(this, 'jobs', { id: `${jobIdForStatus}/stdout` }); let determinedStatusOutput = null; let rawStatusOutputText; if (typeof stdoutResourceForStatus === 'string') { rawStatusOutputText = stdoutResourceForStatus; } else if (stdoutResourceForStatus && typeof stdoutResourceForStatus === 'object' && stdoutResourceForStatus !== null) { const content = stdoutResourceForStatus.content; const text = stdoutResourceForStatus.text; if (typeof content === 'string') { rawStatusOutputText = content; } else if (typeof text === 'string') { rawStatusOutputText = text; } } if (rawStatusOutputText !== undefined) { determinedStatusOutput = rawStatusOutputText.trim(); } output = determinedStatusOutput !== null ? determinedStatusOutput : (typeof stdoutResourceForStatus === 'object' && stdoutResourceForStatus !== null) ? JSON.stringify(stdoutResourceForStatus) : 'No job output content available or in unexpected format'; } catch (error) { output = `Error retrieving job output: ${error.message}`; } } if (responseFormat === 'friendly' || responseFormat === 'minimal') { const formattedJob = { id: job.id, name: job.name, status: job.status, started: job.started, finished: job.finished, elapsed: job.elapsed, job_template_name: ((_b = (_a = job.summary_fields) === null || _a === void 0 ? void 0 : _a.job_template) === null || _b === void 0 ? void 0 : _b.name) || null, inventory_name: ((_d = (_c = job.summary_fields) === null || _c === void 0 ? void 0 : _c.inventory) === null || _d === void 0 ? void 0 : _d.name) || null, launched_by: ((_f = (_e = job.summary_fields) === null || _e === void 0 ? void 0 : _e.created_by) === null || _f === void 0 ? void 0 : _f.username) || null, ui_url: job.url ? `${job.url.replace('/api/v2/jobs/', '/jobs/output/')}` : null, output: includeOutput ? output : null, }; returnData.push({ json: formattedJob, }); } else { const fullJobData = { ...job }; if (includeOutput) { fullJobData.output = output; } returnData.push({ json: fullJobData, }); } } else if (operation === 'getWorkflowJob') { let resolvedWorkflowJobId = null; const wfJobIdKeysToTry = ['Workflow_Job_ID', 'Job_ID', 'workflowJobId', 'jobId', 'id']; for (const key of wfJobIdKeysToTry) { const val = this.getNodeParameter(key, 0, undefined); if (val !== undefined && val !== null && val !== '') { resolvedWorkflowJobId = val; break; } } if (!resolvedWorkflowJobId) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Workflow Job ID must be provided (checked: ${wfJobIdKeysToTry.join(', ')}).`); } const workflowJobId = String(resolvedWorkflowJobId); const includeOutput = this.getNodeParameter('includeOutput', 0, false); const responseFormat = this.getNodeParameter('responseFormat', 0, 'friendly'); const workflowJob = (await SharedHelpers_1.getAwxResources.call(this, `/workflow_jobs/${workflowJobId}/`)); const workflowNodes = await SharedHelpers_1.getAwxResources.call(this, `/workflow_jobs/${workflowJobId}/workflow_nodes/`, 'allPages'); let output = null; if (includeOutput) { try { output = await SharedHelpers_1.getAwxResource.call(this, `/workflow_jobs/${workflowJobId}/stdout/`, {}, 0); } catch (error) { output = `Error retrieving workflow job output: ${error.message}`; } } if (responseFormat === 'friendly' || responseFormat === 'minimal') { const formattedWorkflowJob = { id: workflowJob.id, name: workflowJob.name, status: workflowJob.status, started: workflowJob.started, finished: workflowJob.finished, elapsed: workflowJob.elapsed, workflow_job_template_name: ((_h = (_g = workflowJob.summary_fields) === null || _g === void 0 ? void 0 : _g.workflow_job_template) === null || _h === void 0 ? void 0 : _h.name) || null, inventory_name: ((_k = (_j = workflowJob.summary_fields) === null || _j === void 0 ? void 0 : _j.inventory) === null || _k === void 0 ? void 0 : _k.name) || null, launched_by: ((_m = (_l = workflowJob.summary_fields) === null || _l === void 0 ? void 0 : _l.created_by) === null || _m === void 0 ? void 0 : _m.username) || null, nodes: workflowNodes.map(node => { var _a, _b, _c, _d, _e, _f; return ({ id: node.id, job_id: node.job, job_name: ((_b = (_a = node.summary_fields) === null || _a === void 0 ? void 0 : _a.job) === null || _b === void 0 ? void 0 : _b.name) || null, job_status: ((_d = (_c = node.summary_fields) === null || _c === void 0 ? void 0 : _c.job) === null || _d === void 0 ? void 0 : _d.status) || null, job_type: ((_f = (_e = node.summary_fields) === null || _e === void 0 ? void 0 : _e.job) === null || _f === void 0 ? void 0 : _f.type) || null, }); }), output: includeOutput ? output : null, }; returnData.push({ json: formattedWorkflowJob, }); } else { const fullWorkflowJobData = { ...workflowJob }; fullWorkflowJobData.workflow_nodes = workflowNodes; if (includeOutput) { fullWorkflowJobData.output = output; } returnData.push({ json: fullWorkflowJobData, }); } } else { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The operation "${operation}" is not supported!`); } } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Error in job status operation: ${error.message}`); } return [returnData]; } function generateStatusSummary(jobs) { const statusCounts = { pending: 0, running: 0, successful: 0, failed: 0, canceled: 0, error: 0, waiting: 0, other: 0, }; for (const job of jobs) { const status = (job.status || '').toLowerCase(); if (status === 'pending' || status === 'waiting') { statusCounts.pending = statusCounts.pending + 1; } else if (status === 'running') { statusCounts.running = statusCounts.running + 1; } else if (status === 'successful') { statusCounts.successful = statusCounts.successful + 1; } else if (status === 'failed') { statusCounts.failed = statusCounts.failed + 1; } else if (status === 'canceled') { statusCounts.canceled = statusCounts.canceled + 1; } else if (status === 'error') { statusCounts.error = statusCounts.error + 1; } else { statusCounts.other = statusCounts.other + 1; } } return statusCounts; } //# sourceMappingURL=JobResources.js.map