where('vmware_id', $this->productId) ->where('customer_id', $this->userId) ->firstOrFail(); $osFamily = (string) ($product->os->osGroup->name ?? ''); $isWindows = stripos($osFamily, 'windows') !== false; if (!$isWindows) { throw new \RuntimeException('Only Windows is supported by this reset job.'); } $vmName = $product->ipAddress->vm_name ?? $product->name ?? $product->hostname ?? null; if (!$vmName && preg_match('/^vm-\d+$/i', (string) $product->vmware_id)) { $rawName = trim($serviceVCenter->runPsCommand("(Get-VM -Id '" . addslashes($product->vmware_id) . "').Name")); if (($p = strpos($rawName, '[STDERR]')) !== false) { $rawName = trim(substr($rawName, 0, $p)); } $vmName = trim(preg_replace('/\s+/', ' ', $rawName)); } if (!$vmName) { throw new \RuntimeException('Cannot resolve VM Name on vCenter.'); } $guestUser = 'Administrator'; $result = $serviceVCenter->changeRDPPortWindows( vmName: $vmName, guestUser: 'Administrator', guestPassword: $this->password, newPort: $this->newPort, ); if ($result === 'Login_Fail' || $result === false || $result === null) { throw new \RuntimeException('SSH runner login failed.'); } if (is_string($result)) { // Script trả non-JSON → bắn lỗi kèm raw để debug throw new \RuntimeException('Script returned non-JSON output: ' . $result); } /** * Chuẩn hoá $row: * - Script 1-VM: trả 1 object: ['vm'=>.., 'status'=>.., 'message'=>.., 'newPort'=>..] * - (Phòng hờ) Nếu lỡ trả array nhiều item, chọn item có 'vm' trùng $vmName, không thì lấy phần tử đầu. */ $row = null; if (is_array($result)) { // case: object đơn if (isset($result['vm']) && isset($result['status'])) { $row = $result; } else { // case: mảng các object // Tìm theo vmName foreach ($result as $it) { if (is_array($it) && (($it['vm'] ?? null) === $vmName)) { $row = $it; break; } } // fallback: phần tử đầu tiên nếu chưa có if ($row === null && isset($result[0]) && is_array($result[0])) { $row = $result[0]; } } } if (!is_array($row) || empty($row)) { Log::error('ChangeRemotePortJob: invalid script response shape', ['vm' => $vmName, 'raw' => $result]); throw new \RuntimeException('Invalid script response.'); } // Đọc trường returned $status = strtolower((string) ($row['status'] ?? '')); $message = (string) ($row['message'] ?? ''); $newPort = (string) ($row['newPort'] ?? $this->newPort); // Xét thành công: status === 'ok' $ok = ($status === 'ok'); Log::info('ChangeRemotePortJob: script result', [ 'vm' => $vmName, 'status' => $status, 'message' => $message, 'newPort' => $newPort, 'raw' => $row, ]); if (!$ok) { // Nếu muốn cho phép 'warning' pass, có thể đổi điều kiện ở trên hoặc thêm nhánh dưới: // if ($status === 'warning' && str_contains(strtolower($message), 'rdp port is now')) { $ok = true; } throw new \RuntimeException($message !== '' ? $message : ('Change RDP port failed with status: ' . $status)); } // Gửi mail thông báo Mail::to($this->email)->send( new ChangePortRemote(vmName: $vmName, newPort: (string) $newPort) ); Log::info('ChangeRemotePortJob: success', ['vm' => $vmName, 'newPort' => $newPort]); } }