/** * `celilo proxmox node list` — live per-node capacity from the Proxmox cluster * (ISS-0060, Phase 1 of openspec/changes/proxmox-capacity-lifecycle/proposal.md). * * Reads reality from the Proxmox API via `ProxmoxClient`, never a cached DB * value — the foundation for capacity-aware placement (ISS-0061) and * reconcile-on-read (the rest of ISS-0060 / ISS-0090). */ import { ProxmoxClient, type ProxmoxCredentials } from '../../api-clients/proxmox'; import { getServiceCredentials, listContainerServices } from '../../services/container-service'; import { celiloIntro } from '../prompts'; import type { CommandResult } from '../types'; import { resolveProxmoxService } from './proxmox-service'; function formatUptime(sec: number): string { if (sec <= 0) return '—'; const days = Math.floor(sec / 86400); const hours = Math.floor((sec % 86400) / 3600); return days > 0 ? `${days}d${hours}h` : `${hours}h`; } export async function handleProxmoxNodeList( args: string[], _flags: Record = {}, ): Promise { celiloIntro('Proxmox nodes'); const resolved = resolveProxmoxService(await listContainerServices(), args[0]); if ('error' in resolved) { console.log(`✗ ${resolved.error}`); return { success: false, error: resolved.error }; } const { service } = resolved; const creds = (await getServiceCredentials(service.id)) as ProxmoxCredentials; const result = await new ProxmoxClient(creds).nodeCapacities(); if (!result.success) { console.log(`✗ Could not reach Proxmox (${service.serviceId}): ${result.message}`); return { success: false, error: result.message }; } if (result.data.length === 0) { console.log('No nodes reported by the cluster.'); return { success: true, message: 'No nodes' }; } console.log(`Service: ${service.serviceId} (${service.name})\n`); console.log( 'NODE STATUS RAM free/total CPU DISK free/total UPTIME', ); console.log( '─────────────────────────────────────────────────────────────────────────────────────', ); for (const n of result.data) { const status = n.online ? 'online' : 'OFFLINE'; const ram = `${(n.memFreeMb / 1024).toFixed(1)}/${(n.memTotalMb / 1024).toFixed(1)} GB`; const cpu = `${n.cpuCores} cores ${n.cpuUsedPct}%`; const disk = `${n.diskFreeGb}/${n.diskTotalGb} GB`; console.log( `${n.node.padEnd(11)} ${status.padEnd(9)} ${ram.padEnd(19)} ${cpu.padEnd(15)} ${disk.padEnd(19)} ${formatUptime( n.uptimeSec, )}`, ); } console.log(''); return { success: true, message: `${result.data.length} node(s)` }; }