mirror of
https://github.com/myronblair/jarvis
synced 2026-06-30 17:50:23 -05:00
Proxmox VMs: full resources from cluster API (both nodes), CPU/RAM/disk/uptime/network per VM
This commit is contained in:
@@ -39,39 +39,70 @@ if (PROXMOX_HOST !== '10.48.200.X' && PROXMOX_TOKEN_VAL !== 'YOUR_TOKEN_VALUE_HE
|
||||
$pveBase = 'https://orbisne.fortiddns.com:' . PROXMOX_PORT . '/api2/json';
|
||||
$pveAuth = ['Authorization: PVEAPIToken=' . PROXMOX_USER . '!' . PROXMOX_TOKEN_ID . '=' . PROXMOX_TOKEN_VAL];
|
||||
|
||||
// Cluster resources API — returns all VMs/CTs from ALL nodes (pve + pve2)
|
||||
$clusterRaw = curlGet("$pveBase/cluster/resources?type=vm", $pveAuth);
|
||||
$nodeStatusRaw = curlGet("$pveBase/nodes/" . PROXMOX_NODE . "/status", $pveAuth);
|
||||
$vmsRaw = curlGet("$pveBase/nodes/" . PROXMOX_NODE . "/qemu", $pveAuth);
|
||||
$lxcRaw = curlGet("$pveBase/nodes/" . PROXMOX_NODE . "/lxc", $pveAuth);
|
||||
$nodeStatus = $nodeStatusRaw ? (json_decode($nodeStatusRaw, true)['data'] ?? null) : null;
|
||||
|
||||
$nodeStatus = $nodeStatusRaw ? (json_decode($nodeStatusRaw, true)['data'] ?? null) : null;
|
||||
$vms = $vmsRaw ? (json_decode($vmsRaw, true)['data'] ?? []) : [];
|
||||
$lxcs = $lxcRaw ? (json_decode($lxcRaw, true)['data'] ?? []) : [];
|
||||
$allResources = $clusterRaw ? (json_decode($clusterRaw, true)['data'] ?? []) : [];
|
||||
|
||||
$vmDetails = [];
|
||||
foreach ($vms as $vm) {
|
||||
$vmDetails[] = [
|
||||
'vmid' => $vm['vmid'],
|
||||
'name' => $vm['name'] ?? 'VM-' . $vm['vmid'],
|
||||
'status' => $vm['status'] ?? 'unknown',
|
||||
'cpu' => round(($vm['cpu'] ?? 0) * 100, 1),
|
||||
'mem_mb' => round(($vm['mem'] ?? 0) / 1048576),
|
||||
'maxmem_mb' => round(($vm['maxmem'] ?? 0) / 1048576),
|
||||
'disk_gb' => round(($vm['disk'] ?? 0) / 1073741824, 1),
|
||||
'uptime' => $vm['uptime'] ?? 0,
|
||||
'netin' => $vm['netin'] ?? 0,
|
||||
'netout' => $vm['netout'] ?? 0,
|
||||
];
|
||||
function fmtUptime(int $sec): string {
|
||||
$d = intdiv($sec, 86400); $h = intdiv($sec % 86400, 3600); $m = intdiv($sec % 3600, 60);
|
||||
return ($d > 0 ? "{$d}d " : '') . "{$h}h {$m}m";
|
||||
}
|
||||
$lxcDetails = [];
|
||||
foreach ($lxcs as $lxc) {
|
||||
$lxcDetails[] = [
|
||||
'vmid' => $lxc['vmid'],
|
||||
'name' => $lxc['name'] ?? 'CT-' . $lxc['vmid'],
|
||||
'status' => $lxc['status'] ?? 'unknown',
|
||||
'cpu' => round(($lxc['cpu'] ?? 0) * 100, 1),
|
||||
'mem_mb' => round(($lxc['mem'] ?? 0) / 1048576),
|
||||
'maxmem_mb' => round(($lxc['maxmem'] ?? 0) / 1048576),
|
||||
'type' => 'lxc',
|
||||
|
||||
function fmtBytes(int $b): string {
|
||||
if ($b >= 1073741824) return round($b/1073741824, 1) . ' GB';
|
||||
if ($b >= 1048576) return round($b/1048576, 1) . ' MB';
|
||||
return $b . ' B';
|
||||
}
|
||||
|
||||
$vmDetails = []; $lxcDetails = [];
|
||||
foreach ($allResources as $r) {
|
||||
$memPct = ($r['maxmem'] ?? 0) > 0 ? round($r['mem'] / $r['maxmem'] * 100, 1) : 0;
|
||||
$diskGb = round(($r['maxdisk'] ?? 0) / 1073741824, 1);
|
||||
$cpuPct = round(($r['cpu'] ?? 0) * 100, 1);
|
||||
$upSec = (int)($r['uptime'] ?? 0);
|
||||
$entry = [
|
||||
'vmid' => $r['vmid'],
|
||||
'name' => $r['name'] ?? ($r['type'] === 'lxc' ? 'CT-' : 'VM-') . $r['vmid'],
|
||||
'node' => $r['node'] ?? 'pve',
|
||||
'type' => $r['type'] ?? 'qemu',
|
||||
'status' => $r['status'] ?? 'unknown',
|
||||
'cpu_pct' => $cpuPct,
|
||||
'cpus' => $r['maxcpu'] ?? 1,
|
||||
'mem_pct' => $memPct,
|
||||
'mem_used_mb' => round(($r['mem'] ?? 0) / 1048576),
|
||||
'mem_total_mb' => round(($r['maxmem'] ?? 0) / 1048576),
|
||||
'disk_gb' => $diskGb,
|
||||
'uptime_s' => $upSec,
|
||||
'uptime_human' => $upSec > 0 ? fmtUptime($upSec) : '—',
|
||||
'netin' => $r['netin'] ?? 0,
|
||||
'netout' => $r['netout'] ?? 0,
|
||||
'netin_fmt' => fmtBytes((int)($r['netin'] ?? 0)),
|
||||
'netout_fmt' => fmtBytes((int)($r['netout'] ?? 0)),
|
||||
];
|
||||
if ($r['type'] === 'lxc') $lxcDetails[] = $entry;
|
||||
else $vmDetails[] = $entry;
|
||||
}
|
||||
|
||||
// Sort by node then vmid
|
||||
usort($vmDetails, fn($a,$b) => $a['node'] <=> $b['node'] ?: $a['vmid'] <=> $b['vmid']);
|
||||
usort($lxcDetails, fn($a,$b) => $a['node'] <=> $b['node'] ?: $a['vmid'] <=> $b['vmid']);
|
||||
|
||||
// Node summary for both nodes
|
||||
$nodeInfo = [];
|
||||
if ($nodeStatus) {
|
||||
$ns = $nodeStatus;
|
||||
$nodeInfo['pve'] = [
|
||||
'cpu_pct' => round(($ns['cpu'] ?? 0) * 100, 1),
|
||||
'mem_pct' => ($ns['memory']['total'] ?? 0) > 0
|
||||
? round($ns['memory']['used'] / $ns['memory']['total'] * 100, 1) : 0,
|
||||
'mem_used_gb' => round(($ns['memory']['used'] ?? 0) / 1073741824, 1),
|
||||
'mem_total_gb' => round(($ns['memory']['total'] ?? 0) / 1073741824, 1),
|
||||
'uptime' => fmtUptime((int)($ns['uptime'] ?? 0)),
|
||||
'disk_used_gb' => round(($ns['rootfs']['used'] ?? 0) / 1073741824, 1),
|
||||
'disk_total_gb'=> round(($ns['rootfs']['total'] ?? 0) / 1073741824, 1),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -79,13 +110,14 @@ if (PROXMOX_HOST !== '10.48.200.X' && PROXMOX_TOKEN_VAL !== 'YOUR_TOKEN_VALUE_HE
|
||||
'configured' => true,
|
||||
'node' => PROXMOX_NODE,
|
||||
'node_status' => $nodeStatus,
|
||||
'node_info' => $nodeInfo,
|
||||
'vms' => $vmDetails,
|
||||
'containers' => $lxcDetails,
|
||||
'vm_count' => count($vmDetails),
|
||||
'ct_count' => count($lxcDetails),
|
||||
'cached_at' => date('c'),
|
||||
]);
|
||||
echo '[cache] Proxmox: ' . count($vmDetails) . ' VMs, ' . count($lxcDetails) . " CTs cached\n";
|
||||
echo '[cache] Proxmox: ' . count($vmDetails) . ' VMs, ' . count($lxcDetails) . " CTs cached (both nodes)\n";
|
||||
}
|
||||
|
||||
// ── Home Assistant ────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user