127 lines
4.1 KiB
TypeScript
127 lines
4.1 KiB
TypeScript
import { execSync } from 'child_process';
|
|
|
|
const SSH_CONFIG: Record<string, { host: string; user: string }> = {
|
|
'proxmox': { host: '192.168.178.32', user: 'root' },
|
|
'n8n': { host: '192.168.178.129', user: 'basti' },
|
|
'webserver': { host: '192.168.178.130', user: 'basti' }
|
|
};
|
|
|
|
const SSH_KEY_PATH = '/home/basti/.ssh/id_ed25519';
|
|
|
|
function executeSSHCommand(host: string, command: string): string {
|
|
try {
|
|
const config = SSH_CONFIG[host];
|
|
const sshHost = config ? `${config.user}@${config.host}` : host;
|
|
|
|
const fullCommand = `ssh -o StrictHostKeyChecking=no -i ${SSH_KEY_PATH} ${sshHost} "${command.replace(/"/g, '\\"')}"`;
|
|
const stdout = execSync(fullCommand, {
|
|
encoding: 'utf-8',
|
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
timeout: 10000,
|
|
env: { ...process.env, HOME: '/home/basti' }
|
|
});
|
|
return stdout.trim();
|
|
} catch (error: any) {
|
|
console.error('SSH Command Error:', error.message);
|
|
throw new Error(`SSH command failed: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
export async function getVMList() {
|
|
const output = executeSSHCommand('proxmox', 'qm list');
|
|
const lines = output.split('\n').slice(1); // Skip header
|
|
|
|
return lines
|
|
.map(line => {
|
|
const parts = line.trim().split(/\s+/);
|
|
if (!parts[0] || parts[0] === '') return null;
|
|
|
|
return {
|
|
vmid: parts[0],
|
|
name: parts[1] || 'unknown',
|
|
status: parts[2] || 'unknown',
|
|
mem: parts[3] || '0',
|
|
bootdisk: parts[4] || '0',
|
|
pid: parts[5] || null
|
|
};
|
|
})
|
|
.filter((vm): vm is NonNullable<typeof vm> => vm !== null);
|
|
}
|
|
|
|
export async function getVMConfig(vmid: string) {
|
|
const output = executeSSHCommand('proxmox', `qm config ${vmid}`);
|
|
const config: Record<string, string> = {};
|
|
|
|
output.split('\n').forEach(line => {
|
|
const [key, ...valueParts] = line.split(':');
|
|
if (key && valueParts.length) {
|
|
config[key.trim()] = valueParts.join(':').trim();
|
|
}
|
|
});
|
|
|
|
return config;
|
|
}
|
|
|
|
export async function getVMStatus(vmid: string) {
|
|
const output = executeSSHCommand('proxmox', `qm status ${vmid}`);
|
|
const match = output.match(/status:\s*(\w+)/);
|
|
return match ? match[1] : 'unknown';
|
|
}
|
|
|
|
export async function controlVM(vmid: string, action: 'start' | 'stop' | 'restart') {
|
|
return executeSSHCommand('proxmox', `qm ${action} ${vmid}`);
|
|
}
|
|
|
|
// Get VM stats via SSH
|
|
export async function getVMStats(vmid: string, vmName: string) {
|
|
try {
|
|
// Use the webserver directly since we're running on VM 200
|
|
if (vmName === 'webserver') {
|
|
const cpuCmd = execSync("top -bn1 | grep 'Cpu(s)' | awk '{print 100 - $8}'", { encoding: 'utf-8' });
|
|
const memCmd = execSync("free -m | awk 'NR==2{printf \"%d/%d\", $3, $2}'", { encoding: 'utf-8' });
|
|
const diskCmd = execSync("df -h / | awk 'NR==2{print $5}'", { encoding: 'utf-8' });
|
|
|
|
const [memUsed, memTotal] = memCmd.trim().split('/').map(Number);
|
|
|
|
return {
|
|
cpu: Math.round(parseFloat(cpuCmd.trim()) || 0),
|
|
mem: {
|
|
used: memUsed,
|
|
total: memTotal,
|
|
percent: Math.round((memUsed / memTotal) * 100)
|
|
},
|
|
disk: {
|
|
percent: parseInt(diskCmd.replace('%', '').trim()) || 0
|
|
}
|
|
};
|
|
}
|
|
|
|
// For other VMs, use SSH
|
|
const cpuCmd = executeSSHCommand(vmName, "top -bn1 | grep 'Cpu(s)' | awk '{print 100 - \\$8}'");
|
|
const memCmd = executeSSHCommand(vmName, "free -m | awk 'NR==2{printf \"%d/%d\", \\$3, \\$2}'");
|
|
const diskCmd = executeSSHCommand(vmName, "df -h / | awk 'NR==2{print \\$5}'");
|
|
|
|
const [memUsed, memTotal] = memCmd.split('/').map(Number);
|
|
|
|
return {
|
|
cpu: Math.round(parseFloat(cpuCmd) || 0),
|
|
mem: {
|
|
used: memUsed,
|
|
total: memTotal,
|
|
percent: Math.round((memUsed / memTotal) * 100)
|
|
},
|
|
disk: {
|
|
percent: parseInt(diskCmd.replace('%', '')) || 0
|
|
}
|
|
};
|
|
} catch (error) {
|
|
console.error('Error fetching VM stats:', error);
|
|
// If VM is not running or SSH fails, return zeros
|
|
return {
|
|
cpu: 0,
|
|
mem: { used: 0, total: 0, percent: 0 },
|
|
disk: { percent: 0 }
|
|
};
|
|
}
|
|
}
|