Files
moxytool/ts/moxytool.cli.ts

351 lines
12 KiB
TypeScript
Raw 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 * as paths from './moxytool.paths.ts';
import { logger } from './moxytool.logging.ts';
import { ScriptIndex } from './moxytool.classes.scriptindex.ts';
import { ScriptRunner } from './moxytool.classes.scriptrunner.ts';
export const runCli = async () => {
const smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash',
});
const smartcliInstance = new plugins.smartcli.Smartcli();
// Initialize script index and check if refresh is needed
const scriptIndex = new ScriptIndex();
// Silently check and refresh index in the background if needed
(async () => {
try {
await scriptIndex.loadCache();
if (await scriptIndex.needsRefresh()) {
// Don't block CLI startup, refresh in background
scriptIndex.fetchIndex().catch(() => {
// Silently fail, will use cached data
});
}
} catch {
// Silently fail on index errors
}
})();
// Standard command (no arguments)
smartcliInstance.standardCommand().subscribe(async () => {
logger.log('info', 'MOXYTOOL - Proxmox Administration Tool');
logger.log('info', '');
logger.log('info', 'Available commands:');
logger.log('info', '* vgpu-setup - Install and configure Proxmox vGPU support');
logger.log('info', '* scripts - Manage Proxmox community scripts');
logger.log('info', '');
logger.log('info', 'Usage: moxytool <command> [options]');
});
// vGPU setup command
smartcliInstance.addCommand('vgpu-setup').subscribe(async (argvArg) => {
logger.log('ok', 'Starting Proxmox vGPU setup process');
logger.log('info', 'This will install vGPU support for NVIDIA GPUs on Proxmox');
logger.log('info', '');
// Check for arguments
const step = argvArg.step;
const url = argvArg.url;
const file = argvArg.file;
const debug = argvArg.debug;
// Check if running on Proxmox
try {
const result = await smartshellInstance.exec('which pveversion');
if (result.exitCode !== 0) {
logger.log('error', 'This system does not appear to be running Proxmox');
logger.log('error', 'Please run this command on a Proxmox host');
Deno.exit(1);
}
} catch (e) {
logger.log('error', 'Failed to verify Proxmox installation');
logger.log('error', 'Please ensure you are running this on a Proxmox host');
Deno.exit(1);
}
// Create temporary directory
const tmpDir = '/tmp/moxytool-vgpu-setup';
await smartshellInstance.exec(`mkdir -p ${tmpDir}`);
try {
// Step 1: Clone and run the installer script
logger.log('info', 'Step 1: Downloading Proxmox vGPU installer (supports v9)...');
const cloneResult = await smartshellInstance.exec(
`cd ${tmpDir} && git clone https://github.com/anomixer/proxmox-vgpu-installer.git`,
);
if (cloneResult.exitCode !== 0) {
logger.log('error', 'Failed to clone the installer repository');
logger.log('error', cloneResult.stderr || 'Unknown error');
Deno.exit(1);
}
logger.log('ok', 'Installer downloaded successfully');
logger.log('info', '');
// Build command with arguments
let command = 'bash proxmox-installer.sh';
if (step) {
command += ` --step ${step}`;
}
if (url) {
command += ` --url ${url}`;
}
if (file) {
command += ` --file ${file}`;
}
if (debug) {
command += ' --debug';
}
logger.log('info', 'Running installer script...');
logger.log('info', 'Please follow the interactive prompts');
logger.log('info', '');
// Run the installer script interactively
const installResult = await smartshellInstance.exec(
`cd ${tmpDir}/proxmox-vgpu-installer && ${command}`,
);
if (installResult.exitCode !== 0) {
logger.log('error', 'Installer script failed');
logger.log('error', installResult.stderr || 'Unknown error');
Deno.exit(1);
}
logger.log('ok', 'vGPU setup process completed');
logger.log('info', '');
logger.log('info', 'Next steps:');
logger.log('info', '1. If prompted, reboot your system');
logger.log('info', '2. After reboot, run this command again to continue setup');
logger.log('info', '3. Verify installation with: mdevctl types');
logger.log('info', '4. Configure your VMs with vGPU in the Proxmox web UI');
} catch (error) {
logger.log('error', `Setup failed: ${error instanceof Error ? error.message : String(error)}`);
Deno.exit(1);
}
});
// Scripts management commands
smartcliInstance.addCommand('scripts').subscribe(async (argvArg) => {
const subcommand = argvArg._[0];
if (!subcommand) {
logger.log('info', 'MOXYTOOL Scripts - Proxmox Community Scripts Management');
logger.log('info', '');
logger.log('info', 'Available subcommands:');
logger.log('info', '* list - List all available scripts');
logger.log('info', '* search <query> - Search for scripts by name or description');
logger.log('info', '* info <slug> - Show detailed information about a script');
logger.log('info', '* run <slug> - Execute a script');
logger.log('info', '* refresh - Force refresh the script index');
logger.log('info', '');
logger.log('info', 'Usage: moxytool scripts <subcommand> [options]');
return;
}
// Ensure index is loaded
await scriptIndex.loadCache();
switch (subcommand) {
case 'list': {
const scripts = scriptIndex.getAll();
if (scripts.length === 0) {
logger.log('warn', 'No scripts found. Run "moxytool scripts refresh" to fetch the index.');
return;
}
const stats = scriptIndex.getStats();
logger.log('info', `Available Scripts (${stats.count} total, indexed ${stats.age})`);
logger.log('info', '');
// Group by type
const containers = scripts.filter(s => s.type === 'ct');
const vms = scripts.filter(s => s.type === 'vm');
if (containers.length > 0) {
logger.log('info', 'Containers (LXC):');
containers.forEach(script => {
logger.log('info', `${script.slug.padEnd(25)} - ${script.name}`);
});
logger.log('info', '');
}
if (vms.length > 0) {
logger.log('info', 'Virtual Machines:');
vms.forEach(script => {
logger.log('info', `${script.slug.padEnd(25)} - ${script.name}`);
});
}
logger.log('info', '');
logger.log('info', 'Use "moxytool scripts info <slug>" for more details');
logger.log('info', 'Use "moxytool scripts run <slug>" to install');
break;
}
case 'search': {
const query = argvArg._[1];
if (!query) {
logger.log('error', 'Please provide a search query');
logger.log('info', 'Usage: moxytool scripts search <query>');
return;
}
const results = scriptIndex.search(query as string);
if (results.length === 0) {
logger.log('warn', `No scripts found matching "${query}"`);
return;
}
logger.log('info', `Found ${results.length} script(s) matching "${query}":`);
logger.log('info', '');
results.forEach(script => {
logger.log('info', `${script.slug} (${script.type})`);
logger.log('info', ` ${script.name}`);
logger.log('info', ` ${script.description.substring(0, 80)}...`);
logger.log('info', '');
});
logger.log('info', 'Use "moxytool scripts info <slug>" for more details');
break;
}
case 'info': {
const slug = argvArg._[1];
if (!slug) {
logger.log('error', 'Please provide a script slug');
logger.log('info', 'Usage: moxytool scripts info <slug>');
return;
}
const script = scriptIndex.getBySlug(slug as string);
if (!script) {
logger.log('error', `Script "${slug}" not found`);
logger.log('info', 'Use "moxytool scripts search <query>" to find scripts');
return;
}
logger.log('info', '═'.repeat(60));
logger.log('info', `${script.name}`);
logger.log('info', '═'.repeat(60));
logger.log('info', '');
logger.log('info', `Slug: ${script.slug}`);
logger.log('info', `Type: ${script.type === 'ct' ? 'Container (LXC)' : 'Virtual Machine'}`);
logger.log('info', '');
logger.log('info', 'Description:');
logger.log('info', script.description);
logger.log('info', '');
if (script.install_methods && script.install_methods[0]?.resources) {
const res = script.install_methods[0].resources;
logger.log('info', 'Resource Requirements:');
if (res.cpu) logger.log('info', ` CPU: ${res.cpu} cores`);
if (res.ram) logger.log('info', ` RAM: ${res.ram} MB`);
if (res.hdd) logger.log('info', ` Disk: ${res.hdd} GB`);
if (res.os) logger.log('info', ` OS: ${res.os} ${res.version || ''}`);
logger.log('info', '');
}
if (script.interface_port) {
logger.log('info', `Web Interface: http://<your-ip>:${script.interface_port}`);
logger.log('info', '');
}
if (script.default_credentials) {
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}`);
}
logger.log('info', '');
}
if (script.notes && script.notes.length > 0) {
logger.log('info', 'Important Notes:');
script.notes.forEach(note => {
const prefix = note.type === 'warning' ? '⚠️ ' : ' ';
logger.log('warn', `${prefix}${note.content}`);
});
logger.log('info', '');
}
if (script.documentation) {
logger.log('info', `Documentation: ${script.documentation}`);
}
if (script.website) {
logger.log('info', `Website: ${script.website}`);
}
logger.log('info', '');
logger.log('info', `To install: sudo moxytool scripts run ${script.slug}`);
logger.log('info', '═'.repeat(60));
break;
}
case 'run': {
const slug = argvArg._[1];
if (!slug) {
logger.log('error', 'Please provide a script slug');
logger.log('info', 'Usage: sudo moxytool scripts run <slug>');
return;
}
const script = scriptIndex.getBySlug(slug as string);
if (!script) {
logger.log('error', `Script "${slug}" not found`);
logger.log('info', 'Use "moxytool scripts search <query>" to find scripts');
return;
}
// Validate Proxmox host
const runner = new ScriptRunner();
const isProxmox = await runner.validateProxmoxHost();
if (!isProxmox) {
logger.log('error', 'This system does not appear to be running Proxmox');
logger.log('error', 'Community scripts can only be run on Proxmox hosts');
Deno.exit(1);
}
// Execute the script
const exitCode = await runner.execute(script);
Deno.exit(exitCode);
}
case 'refresh': {
logger.log('info', 'Refreshing script index...');
try {
await scriptIndex.fetchIndex();
const stats = scriptIndex.getStats();
logger.log('success', `Index refreshed: ${stats.count} scripts cached`);
} catch (error) {
logger.log('error', `Failed to refresh index: ${error}`);
Deno.exit(1);
}
break;
}
default:
logger.log('error', `Unknown subcommand: ${subcommand}`);
logger.log('info', 'Run "moxytool scripts" to see available subcommands');
}
});
smartcliInstance.startParse();
};