find($item->os_id); if (!$os) { throw new RuntimeException( "Không tìm thấy OS id={$item->os_id} trong OrderItem #{$item->id}. os_id không hợp lệ." ); } // Priority 1: host attached directly to OS $host = $os->host; $datacenter = $host?->datacenter; $vcenter = $datacenter?->vCenter; // Priority 2: host from OS group fallback if (!$host || !$datacenter || !$vcenter) { $groupHost = $os->osGroup?->host; $host = $host ?? $groupHost; $datacenter = $datacenter ?? $groupHost?->datacenter; $vcenter = $vcenter ?? $groupHost?->datacenter?->vCenter; if ($groupHost) { $this->logger->step('Infrastructure fallback: osGroup host', [ 'os_id' => $os->id, 'os_group_id' => $os->os_group_id, 'host_id' => $groupHost->id, ]); } } // Priority 3: host from product (Provisioning tab) if ((!$host || !$datacenter || !$vcenter) && $product && $product->module_host_id) { $productHost = ModuleHost::with('datacenter.vCenter')->find($product->module_host_id); if ($productHost) { $host = $host ?? $productHost; $datacenter = $datacenter ?? $productHost->datacenter; $vcenter = $vcenter ?? $productHost->datacenter?->vCenter; $this->logger->step('Infrastructure fallback: product host', [ 'product_id' => $product->id, 'host_id' => $productHost->id, 'datacenter_id' => $productHost->datacenter?->id, ]); } } if (!$vcenter || !$host || !$datacenter) { throw new RuntimeException( "Thiếu thông tin host/datacenter/vcenter từ sản phẩm ID #" . ($product->id ?? 'unknown') . ". " . "Vui lòng cấu hình vCenter trong tab Provisioning của sản phẩm, " . "hoặc gán host cho OS group của OS được chọn." ); } $osGroupName = $os->osGroup?->name ?? ''; $isWindows = str_contains(strtolower($osGroupName), 'windows'); return new VmInfrastructureContext( os: $os, host: $host, datacenter: $datacenter, vcenter: $vcenter, template: $os->template_id, isWindows: $isWindows, vmUser: $isWindows ? 'administrator' : 'root', vmPort: $isWindows ? 3389 : 22, ); } }