n8n-nodes-proxmox
Version:
n8n community node for Proxmox Virtual Environment (VE) API integration with VM, container, storage, and cluster management capabilities
252 lines (221 loc) • 6.84 kB
text/typescript
import {
IExecuteFunctions,
INodeExecutionData,
INodeType,
INodeTypeDescription,
NodeOperationError,
} from 'n8n-workflow';
import { clusterOperations, clusterFields } from './descriptions/cluster.descriptions';
import { vmOperations, vmFields } from './descriptions/vm.descriptions';
import { containerOperations, containerFields } from './descriptions/container.descriptions';
import { storageOperations, storageFields } from './descriptions/storage.descriptions';
import { backupOperations, backupFields } from './descriptions/backup.descriptions';
import { executeClusterOperation } from './methods/cluster.methods';
import { executeVmOperation } from './methods/vm.methods';
import { executeContainerOperation } from './methods/container.methods';
import { executeStorageOperation } from './methods/storage.methods';
import { executeBackupOperation } from './methods/backup.methods';
import { logger } from './helpers/logger';
export class ProxMox implements INodeType {
description: INodeTypeDescription = {
displayName: 'ProxMox VE',
name: 'proxMox',
icon: 'file:ProxMox.svg',
group: ['transform'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description:
'Interact with ProxMox Virtual Environment API for managing VMs, containers, storage, and cluster operations',
defaults: {
name: 'ProxMox VE',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'proxMoxApi',
required: true,
},
],
requestDefaults: {
baseURL: '={{$credentials.host}}:{{$credentials.port}}/api2/json',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
},
usableAsTool: true,
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Cluster',
value: 'cluster',
description: 'Manage cluster operations',
},
{
name: 'Virtual Machine',
value: 'vm',
description: 'Manage virtual machines (QEMU/KVM)',
},
{
name: 'Container',
value: 'container',
description: 'Manage LXC containers',
},
{
name: 'Storage',
value: 'storage',
description: 'Manage storage and file operations',
},
{
name: 'Backup',
value: 'backup',
description: 'Manage backups and restore operations',
},
],
default: 'vm',
required: true,
},
// Cluster operations
clusterOperations,
...clusterFields,
// VM operations
vmOperations,
...vmFields,
// Container operations
containerOperations,
...containerFields,
// Storage operations
storageOperations,
...storageFields,
// Backup operations
backupOperations,
...backupFields,
// Continue on Fail
{
displayName: 'Continue on Fail',
name: 'continueOnFail',
type: 'boolean',
default: false,
description: 'Whether to continue the workflow if this node fails',
},
],
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
console.log('\n\n========== PROXMOX NODE EXECUTION STARTED ==========');
try {
const items = this.getInputData();
console.log('Input data retrieved:', { itemCount: items.length });
const returnData: INodeExecutionData[] = [];
const length = items.length;
console.log('Attempting to get resource parameter...');
const resource = this.getNodeParameter('resource', 0) as string;
console.log('Resource parameter retrieved:', resource);
console.log('Attempting to get operation parameter...');
const operation = this.getNodeParameter('operation', 0) as string;
console.log('Operation parameter retrieved:', operation);
logger.info('node', `ProxMox node execution started`, {
resource,
operation,
itemCount: length,
});
for (let i = 0; i < length; i++) {
console.log(`Processing item ${i + 1}/${length}`);
try {
let responseData;
console.log(`Executing ${resource} - ${operation} operation`);
switch (resource) {
case 'cluster':
console.log('Calling executeClusterOperation...');
responseData = await executeClusterOperation.call(this, operation, i);
break;
case 'vm':
console.log('Calling executeVmOperation...');
responseData = await executeVmOperation.call(this, operation, i);
break;
case 'container':
console.log('Calling executeContainerOperation...');
responseData = await executeContainerOperation.call(this, operation, i);
break;
case 'storage':
console.log('Calling executeStorageOperation...');
responseData = await executeStorageOperation.call(this, operation, i);
break;
case 'backup':
console.log('Calling executeBackupOperation...');
responseData = await executeBackupOperation.call(this, operation, i);
break;
default:
throw new NodeOperationError(
this.getNode(),
`The resource "${resource}" is not known!`,
{ itemIndex: i },
);
}
console.log('Operation completed successfully, processing response...');
// Handle array responses
if (Array.isArray(responseData)) {
responseData.forEach((item) => {
returnData.push({
json: item,
pairedItem: { item: i },
});
});
} else {
returnData.push({
json: responseData,
pairedItem: { item: i },
});
}
} catch (error) {
console.log('=== ERROR CAUGHT IN ITEM PROCESSING ===');
console.log('Error object:', error);
console.log('Error message:', error.message);
console.log('Error stack:', error.stack);
console.log('Error type:', typeof error);
console.log('Error constructor:', error.constructor.name);
logger.error('node', `ProxMox node execution failed`, {
resource,
operation,
itemIndex: i,
error: error.message,
});
if (this.continueOnFail()) {
returnData.push({
json: {
error: error.message,
itemIndex: i,
resource,
operation,
},
pairedItem: { item: i },
});
continue;
}
throw error;
}
}
logger.info('node', `ProxMox node execution completed`, {
resource,
operation,
itemCount: length,
resultCount: returnData.length,
});
console.log('========== PROXMOX NODE EXECUTION COMPLETED ==========\n\n');
return [returnData];
} catch (globalError) {
console.log('ERROR in node execution:');
console.log(globalError);
if (this.continueOnFail()) {
console.log('Continue on fail is enabled, returning error as output');
return [[{ json: { error: globalError.message } }]];
}
throw globalError;
}
}
}