UNPKG

n8n-nodes-proxmox

Version:

n8n community node for Proxmox Virtual Environment (VE) API integration with VM, container, storage, and cluster management capabilities

359 lines (358 loc) 17.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.executeVmOperation = executeVmOperation; const apiRequest_1 = require("../helpers/apiRequest"); const errorHandler_1 = require("../helpers/errorHandler"); const logger_1 = require("../helpers/logger"); async function executeVmOperation(operation, i) { try { console.log(`=== VM Operation Debug: ${operation} ===`); logger_1.logger.operation('vm', operation, 'start', { operation }); let response; switch (operation) { case 'create': response = await createVm.call(this, i); break; case 'delete': response = await deleteVm.call(this, i); break; case 'get': response = await getVm.call(this, i); break; case 'getAll': response = await getAllVms.call(this, i); break; case 'start': response = await startVm.call(this, i); break; case 'stop': response = await stopVm.call(this, i); break; case 'shutdown': response = await shutdownVm.call(this, i); break; case 'reboot': response = await rebootVm.call(this, i); break; case 'suspend': response = await suspendVm.call(this, i); break; case 'resume': response = await resumeVm.call(this, i); break; case 'clone': response = await cloneVm.call(this, i); break; case 'migrate': response = await migrateVm.call(this, i); break; case 'snapshot': response = await snapshotVm.call(this, i); break; case 'getStatus': response = await getVmStatus.call(this, i); break; default: throw new Error(`Unknown VM operation: ${operation}`); } logger_1.logger.operation('vm', operation, 'success', { operation }); return response; } catch (error) { logger_1.logger.operation('vm', operation, 'error', { operation, error: error.message }); return errorHandler_1.handleProxMoxError.call(this, error, operation, 'VM'); } } async function waitForTask(nodeName, taskId, timeout = 300) { const startTime = Date.now(); const timeoutMs = timeout * 1000; logger_1.logger.debug('task', `Waiting for task ${taskId} on node ${nodeName}`, { taskId, timeout }); while (Date.now() - startTime < timeoutMs) { try { const taskStatus = await apiRequest_1.apiRequest.call(this, 'GET', `/nodes/${nodeName}/tasks/${taskId}/status`); if (taskStatus.status === 'stopped') { if (taskStatus.exitstatus === 'OK') { logger_1.logger.debug('task', `Task ${taskId} completed successfully`); return taskStatus; } else { throw new Error(`Task failed: ${taskStatus.exitstatus}`); } } // Wait 2 seconds before checking again await new Promise((resolve) => setTimeout(resolve, 2000)); } catch (error) { logger_1.logger.error('task', `Error checking task status: ${error.message}`); throw error; } } throw new Error(`Task ${taskId} timed out after ${timeout} seconds`); } async function createVm(i) { const nodeName = this.getNodeParameter('nodeName', i); const newVmId = this.getNodeParameter('newVmId', i); const vmName = this.getNodeParameter('vmName', i); const waitForTask = this.getNodeParameter('waitForTask', i, true); const taskTimeout = this.getNodeParameter('taskTimeout', i, 300); const additionalOptions = this.getNodeParameter('additionalOptions', i, {}); errorHandler_1.validateParameters.call(this, { nodeName, newVmId, vmName }, ['nodeName', 'newVmId', 'vmName'], 'create VM'); const body = { vmid: newVmId, name: vmName, ...additionalOptions, }; // Set defaults for VM creation if (!body.memory) body.memory = 1024; if (!body.cores) body.cores = 1; if (!body.sockets) body.sockets = 1; if (!body.storage) body.storage = 'local-lvm'; if (!body.bridge) body.bridge = 'vmbr0'; logger_1.logger.debug('vm', 'Creating VM', { nodeName, vmId: newVmId, vmName }); const response = await apiRequest_1.apiRequest.call(this, 'POST', `/nodes/${nodeName}/qemu`, body); if (waitForTask && response.data) { const taskResult = await waitForTask.call(this, nodeName, response.data, taskTimeout); // Start VM if requested if (additionalOptions.startAfterCreate) { logger_1.logger.debug('vm', 'Starting VM after creation'); await apiRequest_1.apiRequest.call(this, 'POST', `/nodes/${nodeName}/qemu/${newVmId}/status/start`); } return { ...response, taskResult }; } return response; } async function deleteVm(i) { const nodeName = this.getNodeParameter('nodeName', i); const vmId = this.getNodeParameter('vmId', i); const waitForTask = this.getNodeParameter('waitForTask', i, true); const taskTimeout = this.getNodeParameter('taskTimeout', i, 300); errorHandler_1.validateParameters.call(this, { nodeName, vmId }, ['nodeName', 'vmId'], 'delete VM'); logger_1.logger.debug('vm', 'Deleting VM', { nodeName, vmId }); const response = await apiRequest_1.apiRequest.call(this, 'DELETE', `/nodes/${nodeName}/qemu/${vmId}`); if (waitForTask && response.data) { const taskResult = await waitForTask.call(this, nodeName, response.data, taskTimeout); return { ...response, taskResult }; } return response; } async function getVm(i) { const nodeName = this.getNodeParameter('nodeName', i); const vmId = this.getNodeParameter('vmId', i); errorHandler_1.validateParameters.call(this, { nodeName, vmId }, ['nodeName', 'vmId'], 'get VM'); logger_1.logger.debug('vm', 'Getting VM details', { nodeName, vmId }); return await apiRequest_1.apiRequest.call(this, 'GET', `/nodes/${nodeName}/qemu/${vmId}/config`); } async function getAllVms(i) { console.log('=== getAllVms function start ==='); console.log('Attempting to get returnAll parameter...'); try { const returnAll = this.getNodeParameter('returnAll', i); console.log('returnAll parameter retrieved:', returnAll); logger_1.logger.debug('vm', 'Getting all VMs'); if (returnAll) { console.log('returnAll is true, making API request for all items...'); return await apiRequest_1.apiRequestAllItems.call(this, 'GET', '/cluster/resources', {}, { type: 'vm' }); } else { console.log('returnAll is false, getting limit parameter...'); const limit = this.getNodeParameter('limit', i); console.log('limit parameter retrieved:', limit); console.log('Making limited API request...'); // ProxMox API doesn't support limit parameter, we'll slice the results client-side const response = await apiRequest_1.apiRequest.call(this, 'GET', '/cluster/resources', {}, { type: 'vm' }); return Array.isArray(response) ? response.slice(0, limit) : [response]; } } catch (error) { console.log('=== ERROR in getAllVms ==='); console.log('Error:', error); console.log('Error message:', error.message); console.log('Error stack:', error.stack); throw error; } } async function startVm(i) { const nodeName = this.getNodeParameter('nodeName', i); const vmId = this.getNodeParameter('vmId', i); const waitForTask = this.getNodeParameter('waitForTask', i, true); const taskTimeout = this.getNodeParameter('taskTimeout', i, 300); errorHandler_1.validateParameters.call(this, { nodeName, vmId }, ['nodeName', 'vmId'], 'start VM'); logger_1.logger.debug('vm', 'Starting VM', { nodeName, vmId }); const response = await apiRequest_1.apiRequest.call(this, 'POST', `/nodes/${nodeName}/qemu/${vmId}/status/start`); if (waitForTask && response.data) { const taskResult = await waitForTask.call(this, nodeName, response.data, taskTimeout); return { ...response, taskResult }; } return response; } async function stopVm(i) { const nodeName = this.getNodeParameter('nodeName', i); const vmId = this.getNodeParameter('vmId', i); const waitForTask = this.getNodeParameter('waitForTask', i, true); const taskTimeout = this.getNodeParameter('taskTimeout', i, 300); const additionalOptions = this.getNodeParameter('additionalOptions', i, {}); errorHandler_1.validateParameters.call(this, { nodeName, vmId }, ['nodeName', 'vmId'], 'stop VM'); const body = {}; if (additionalOptions.force) body.force = 1; if (additionalOptions.skipLock) body.skiplock = 1; logger_1.logger.debug('vm', 'Stopping VM', { nodeName, vmId, options: additionalOptions }); const response = await apiRequest_1.apiRequest.call(this, 'POST', `/nodes/${nodeName}/qemu/${vmId}/status/stop`, body); if (waitForTask && response.data) { const taskResult = await waitForTask.call(this, nodeName, response.data, taskTimeout); return { ...response, taskResult }; } return response; } async function shutdownVm(i) { const nodeName = this.getNodeParameter('nodeName', i); const vmId = this.getNodeParameter('vmId', i); const waitForTask = this.getNodeParameter('waitForTask', i, true); const taskTimeout = this.getNodeParameter('taskTimeout', i, 300); const additionalOptions = this.getNodeParameter('additionalOptions', i, {}); errorHandler_1.validateParameters.call(this, { nodeName, vmId }, ['nodeName', 'vmId'], 'shutdown VM'); const body = {}; if (additionalOptions.force) body.forceStop = 1; if (additionalOptions.skipLock) body.skiplock = 1; logger_1.logger.debug('vm', 'Shutting down VM', { nodeName, vmId, options: additionalOptions }); const response = await apiRequest_1.apiRequest.call(this, 'POST', `/nodes/${nodeName}/qemu/${vmId}/status/shutdown`, body); if (waitForTask && response.data) { const taskResult = await waitForTask.call(this, nodeName, response.data, taskTimeout); return { ...response, taskResult }; } return response; } async function rebootVm(i) { const nodeName = this.getNodeParameter('nodeName', i); const vmId = this.getNodeParameter('vmId', i); const waitForTask = this.getNodeParameter('waitForTask', i, true); const taskTimeout = this.getNodeParameter('taskTimeout', i, 300); errorHandler_1.validateParameters.call(this, { nodeName, vmId }, ['nodeName', 'vmId'], 'reboot VM'); logger_1.logger.debug('vm', 'Rebooting VM', { nodeName, vmId }); const response = await apiRequest_1.apiRequest.call(this, 'POST', `/nodes/${nodeName}/qemu/${vmId}/status/reboot`); if (waitForTask && response.data) { const taskResult = await waitForTask.call(this, nodeName, response.data, taskTimeout); return { ...response, taskResult }; } return response; } async function suspendVm(i) { const nodeName = this.getNodeParameter('nodeName', i); const vmId = this.getNodeParameter('vmId', i); const waitForTask = this.getNodeParameter('waitForTask', i, true); const taskTimeout = this.getNodeParameter('taskTimeout', i, 300); errorHandler_1.validateParameters.call(this, { nodeName, vmId }, ['nodeName', 'vmId'], 'suspend VM'); logger_1.logger.debug('vm', 'Suspending VM', { nodeName, vmId }); const response = await apiRequest_1.apiRequest.call(this, 'POST', `/nodes/${nodeName}/qemu/${vmId}/status/suspend`); if (waitForTask && response.data) { const taskResult = await waitForTask.call(this, nodeName, response.data, taskTimeout); return { ...response, taskResult }; } return response; } async function resumeVm(i) { const nodeName = this.getNodeParameter('nodeName', i); const vmId = this.getNodeParameter('vmId', i); const waitForTask = this.getNodeParameter('waitForTask', i, true); const taskTimeout = this.getNodeParameter('taskTimeout', i, 300); errorHandler_1.validateParameters.call(this, { nodeName, vmId }, ['nodeName', 'vmId'], 'resume VM'); logger_1.logger.debug('vm', 'Resuming VM', { nodeName, vmId }); const response = await apiRequest_1.apiRequest.call(this, 'POST', `/nodes/${nodeName}/qemu/${vmId}/status/resume`); if (waitForTask && response.data) { const taskResult = await waitForTask.call(this, nodeName, response.data, taskTimeout); return { ...response, taskResult }; } return response; } async function cloneVm(i) { const nodeName = this.getNodeParameter('nodeName', i); const vmId = this.getNodeParameter('vmId', i); const newVmId = this.getNodeParameter('newVmId', i); const cloneName = this.getNodeParameter('cloneName', i, ''); const waitForTask = this.getNodeParameter('waitForTask', i, true); const taskTimeout = this.getNodeParameter('taskTimeout', i, 300); const additionalOptions = this.getNodeParameter('additionalOptions', i, {}); errorHandler_1.validateParameters.call(this, { nodeName, vmId, newVmId }, ['nodeName', 'vmId', 'newVmId'], 'clone VM'); const body = { newid: newVmId, ...additionalOptions, }; if (cloneName) { body.name = cloneName; } logger_1.logger.debug('vm', 'Cloning VM', { nodeName, vmId, newVmId, cloneName }); const response = await apiRequest_1.apiRequest.call(this, 'POST', `/nodes/${nodeName}/qemu/${vmId}/clone`, body); if (waitForTask && response.data) { const taskResult = await waitForTask.call(this, nodeName, response.data, taskTimeout); return { ...response, taskResult }; } return response; } async function migrateVm(i) { const nodeName = this.getNodeParameter('nodeName', i); const vmId = this.getNodeParameter('vmId', i); const targetNode = this.getNodeParameter('targetNode', i); const waitForTask = this.getNodeParameter('waitForTask', i, true); const taskTimeout = this.getNodeParameter('taskTimeout', i, 300); const additionalOptions = this.getNodeParameter('additionalOptions', i, {}); errorHandler_1.validateParameters.call(this, { nodeName, vmId, targetNode }, ['nodeName', 'vmId', 'targetNode'], 'migrate VM'); const body = { target: targetNode, ...additionalOptions, }; // Set default migration options if (additionalOptions.online !== false) { body.online = 1; } logger_1.logger.debug('vm', 'Migrating VM', { nodeName, vmId, targetNode, options: additionalOptions }); const response = await apiRequest_1.apiRequest.call(this, 'POST', `/nodes/${nodeName}/qemu/${vmId}/migrate`, body); if (waitForTask && response.data) { const taskResult = await waitForTask.call(this, nodeName, response.data, taskTimeout); return { ...response, taskResult }; } return response; } async function snapshotVm(i) { const nodeName = this.getNodeParameter('nodeName', i); const vmId = this.getNodeParameter('vmId', i); const snapshotName = this.getNodeParameter('snapshotName', i); const waitForTask = this.getNodeParameter('waitForTask', i, true); const taskTimeout = this.getNodeParameter('taskTimeout', i, 300); const additionalOptions = this.getNodeParameter('additionalOptions', i, {}); errorHandler_1.validateParameters.call(this, { nodeName, vmId, snapshotName }, ['nodeName', 'vmId', 'snapshotName'], 'snapshot VM'); const body = { snapname: snapshotName, ...additionalOptions, }; // Set default snapshot options if (additionalOptions.includeRam !== false) { body.vmstate = 1; } logger_1.logger.debug('vm', 'Creating VM snapshot', { nodeName, vmId, snapshotName, options: additionalOptions, }); const response = await apiRequest_1.apiRequest.call(this, 'POST', `/nodes/${nodeName}/qemu/${vmId}/snapshot`, body); if (waitForTask && response.data) { const taskResult = await waitForTask.call(this, nodeName, response.data, taskTimeout); return { ...response, taskResult }; } return response; } async function getVmStatus(i) { const nodeName = this.getNodeParameter('nodeName', i); const vmId = this.getNodeParameter('vmId', i); errorHandler_1.validateParameters.call(this, { nodeName, vmId }, ['nodeName', 'vmId'], 'get VM status'); logger_1.logger.debug('vm', 'Getting VM status', { nodeName, vmId }); return await apiRequest_1.apiRequest.call(this, 'GET', `/nodes/${nodeName}/qemu/${vmId}/status/current`); }