newVmId === null) { throw new RuntimeException('Rebuild addons: newVmId is null'); } $vcenter = VCenterModel::find($ctx->vcenterId); if (!$vcenter || !$this->vCenter->loginServer($vcenter)) { throw new RuntimeException( "Rebuild addons: cannot login to vCenter #{$ctx->vcenterId}" ); } // Resolve the totals we want the rebuilt VM to end up with. // Base spec ensures CPU/RAM/Disk parity even if there are no addons. $targetCpu = max($ctx->baseCpu, (int) ($ctx->addonTotals['cpu'] ?? 0)); $targetRam = max($ctx->baseRam, (int) ($ctx->addonTotals['ram'] ?? 0)); $targetDisk = max($ctx->baseDisk, (int) ($ctx->addonTotals['disk'] ?? 0)); Log::info('VmRebuildAddonService: applying specs', [ 'module_vmware_id' => $ctx->moduleVmwareId, 'new_vm_id' => $ctx->newVmId, 'cpu' => $targetCpu, 'ram' => $targetRam, 'disk' => $targetDisk, ]); if ($targetCpu > $ctx->baseCpu) { $res = $this->vCenter->UpgradeCPUVirtualMachine($ctx->newVmId, $targetCpu); $this->ensureOk($res, 'UpgradeCPU'); } if ($targetRam > $ctx->baseRam) { $res = $this->vCenter->UpgradeMemoryVirtualMachine($ctx->newVmId, $targetRam); $this->ensureOk($res, 'UpgradeMemory'); } if ($targetDisk > $ctx->baseDisk) { // UpgradeDiskVirtualMachine expects a "product" with vmware_id — // build a transient ModuleVmware-like object pointing at the new VM. $shim = new ModuleVmware(); $shim->vmware_id = $ctx->newVmId; $res = $this->vCenter->UpgradeDiskVirtualMachine($shim, $targetDisk); $this->ensureOk($res, 'UpgradeDisk'); } Log::info('VmRebuildAddonService: addons reinstalled', [ 'module_vmware_id' => $ctx->moduleVmwareId, 'new_vm_id' => $ctx->newVmId, ]); } private function ensureOk(array|string $result, string $op): void { if (is_string($result)) { throw new RuntimeException("Rebuild addons: {$op} returned '{$result}'"); } if (($result['error'] ?? false)) { throw new RuntimeException( "Rebuild addons: {$op} failed — " . json_encode($result), ); } } }