Files
moxytool/ts/moxytool.classes.scriptrunner.ts

171 lines
5.3 KiB
TypeScript
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import * as plugins from './moxytool.plugins.ts';
import { logger } from './moxytool.logging.ts';
import type { IScriptMetadata } from './moxytool.classes.scriptindex.ts';
/**
* ScriptRunner class handles the execution of Proxmox community scripts
* - Executes scripts via bash with curl
* - Ensures proper stdin/stdout/stderr passthrough for interactive prompts
* - Handles script exit codes
*/
export class ScriptRunner {
private static readonly SCRIPT_BASE_URL =
'https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main';
/**
* Execute a community script
* @param script The script metadata
* @returns The exit code of the script
*/
public async execute(script: IScriptMetadata): Promise<number> {
try {
// Get the script URL from install_methods
if (!script.install_methods || script.install_methods.length === 0) {
logger.log('error', 'Script has no install methods defined');
return 1;
}
const installMethod = script.install_methods[0];
const scriptPath = installMethod.script;
if (!scriptPath) {
logger.log('error', 'Script path is not defined');
return 1;
}
// Construct the full script URL
const scriptUrl = `${ScriptRunner.SCRIPT_BASE_URL}${scriptPath}`;
logger.log('info', `Executing script: ${script.name}`);
logger.log('info', `URL: ${scriptUrl}`);
logger.log('info', '');
// Show script details
if (script.description) {
logger.log('info', `Description: ${script.description}`);
}
if (script.notes && script.notes.length > 0) {
logger.log('info', '');
logger.log('info', 'Important Notes:');
for (const note of script.notes) {
const prefix = note.type === 'warning' ? '⚠️ ' : ' ';
logger.log('warn', `${prefix}${note.content}`);
}
}
if (installMethod.resources) {
logger.log('info', '');
logger.log('info', 'Resource Requirements:');
if (installMethod.resources.cpu) {
logger.log('info', ` CPU: ${installMethod.resources.cpu} cores`);
}
if (installMethod.resources.ram) {
logger.log('info', ` RAM: ${installMethod.resources.ram} MB`);
}
if (installMethod.resources.hdd) {
logger.log('info', ` Disk: ${installMethod.resources.hdd} GB`);
}
if (installMethod.resources.os) {
logger.log(
'info',
` OS: ${installMethod.resources.os} ${installMethod.resources.version || ''}`,
);
}
}
logger.log('info', '');
logger.log('info', 'Starting installation...');
logger.log('info', '═'.repeat(60));
logger.log('info', '');
// Execute the script using smartshell
// The command structure: bash -c "$(curl -fsSL <url>)"
const smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash',
});
// Construct the command that will be executed
const command = `bash -c "$(curl -fsSL ${scriptUrl})"`;
// Execute with inherited stdio for full interactivity
const result = await smartshellInstance.exec(command);
logger.log('info', '');
logger.log('info', '═'.repeat(60));
if (result.exitCode === 0) {
logger.log('success', `✓ Script completed successfully`);
if (script.interface_port) {
logger.log('info', '');
logger.log('info', `Access the service at: http://<your-ip>:${script.interface_port}`);
}
if (script.default_credentials) {
logger.log('info', '');
logger.log('info', 'Default Credentials:');
if (script.default_credentials.username) {
logger.log('info', ` Username: ${script.default_credentials.username}`);
}
if (script.default_credentials.password) {
logger.log('info', ` Password: ${script.default_credentials.password}`);
}
}
if (script.documentation) {
logger.log('info', '');
logger.log('info', `Documentation: ${script.documentation}`);
}
} else {
logger.log('error', `✗ Script failed with exit code: ${result.exitCode}`);
if (result.stderr) {
logger.log('error', `Error output: ${result.stderr}`);
}
}
return result.exitCode;
} catch (error) {
logger.log('error', `Failed to execute script: ${error}`);
return 1;
}
}
/**
* Validate that we're running on a Proxmox host
*/
public async validateProxmoxHost(): Promise<boolean> {
try {
const smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash',
});
const result = await smartshellInstance.exec('which pveversion');
return result.exitCode === 0;
} catch {
return false;
}
}
/**
* Get Proxmox version information
*/
public async getProxmoxVersion(): Promise<string | null> {
try {
const smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash',
});
const result = await smartshellInstance.exec('pveversion');
if (result.exitCode === 0 && result.stdout) {
return result.stdout.trim();
}
return null;
} catch {
return null;
}
}
}