host($run); $client = $this->pve->forHost($host); $nodes = $client->listNodes(); $node = $nodes[0]['node'] ?? 'pve'; $status = $client->nodeStatus($node); $storage = $client->nodeStorage($node); $cores = (int) ($status['cpuinfo']['cpus'] ?? 0); $ramMb = (int) round((int) ($status['memory']['total'] ?? 0) / 1048576); // Proxmox lists overlapping pools (e.g. local + local-lvm on one disk). // Take the largest VM-capable datastore instead of summing, so shared // backing storage is never double-counted and placement can't overcommit. $allocatable = array_filter($storage, function ($s) { $content = (string) ($s['content'] ?? ''); return str_contains($content, 'images') || str_contains($content, 'rootdir'); }); $pool = $allocatable ?: $storage; $totalBytes = $pool === [] ? 0 : max(array_map(fn ($s) => (int) ($s['total'] ?? 0), $pool)); $totalGb = (int) round($totalBytes / 1073741824); $host->update([ 'cpu_cores' => $cores, 'cpu_weight' => $cores, 'total_ram_mb' => $ramMb, 'total_gb' => $totalGb, 'pve_version' => $status['pveversion'] ?? null, 'last_seen_at' => now(), ]); return StepResult::advance(); } }