n8n-nodes-awx
Version:
n8n node to interact with Ansible AWX/Tower with improved type safety
390 lines • 20.9 kB
JavaScript
;
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