item = $item; $this->isRetry = $isRetry; } /** * Execute the job. */ public function handle(vCenter $vCenter, Discord $discord, VMDataService $vmDataService) { try { $product = $this->item->getProductAttribute(); // dùng helper trong OrderItem if (!$product) { $errorMessage = "Không tìm thấy sản phẩm từ OrderItem #{$this->item->id}"; Log::warning($errorMessage); $discord->SendErrorMessage($errorMessage, 'CreateVirtualMachineJob - Missing Product'); if (!$this->isRetry) { $this->sendFailureNotification($errorMessage); } return false; } $host = $product->host; // từ module_host_id $datacenter = $host?->datacenter; $vcenter = $datacenter?->vcenter; $osModel = Os::find($this->item->os_id); $template = $osModel?->template_id; if (!$vcenter || !$host || !$datacenter) { $errorMessage = "Thiếu thông tin host/datacenter/vcenter từ sản phẩm ID #{$product->id}"; Log::error($errorMessage); $discord->SendErrorMessage([ 'error' => $errorMessage, 'product_id' => $product->id, 'order_item_id' => $this->item->id, 'host_id' => $host?->id, 'datacenter_id' => $datacenter?->id, 'vcenter_id' => $vcenter?->id ], 'CreateVirtualMachineJob - Missing Infrastructure'); if (!$this->isRetry) { $this->sendFailureNotification($errorMessage); } return; } // Login to vCenter if (!$vCenter->loginServer($vcenter)) { $errorMessage = "Login vào vCenter thất bại với host: {$vcenter->host}"; Log::error($errorMessage); $discord->SendErrorMessage([ 'error' => $errorMessage, 'vcenter_host' => $vcenter->host, 'vcenter_user' => $vcenter->user, 'product_id' => $product->id, 'order_item_id' => $this->item->id ], 'CreateVirtualMachineJob - vCenter Login Failed'); if (!$this->isRetry) { $this->sendFailureNotification($errorMessage); } return false; } // Lấy thông tin addon (CPU, RAM) $addonData = [ 'cpu' => 0, 'ram' => 0, 'disk' => 0 ]; // Lấy addon từ order item if ($this->item->addons) { Log::info("🔍 Tìm thấy addons cho order item", [ 'order_item_id' => $this->item->id, 'addons_count' => $this->item->addons->count(), 'addons' => $this->item->addons->map(function($addon) { return [ 'id' => $addon->id, 'addon_id' => $addon->addon_id, 'qty' => $addon->qty, 'price' => $addon->price, 'addon_name' => $addon->addonItems?->name ?? 'Unknown' ]; }) ]); foreach ($this->item->addons as $orderAddon) { $addon = $orderAddon->addonItems; if (!$addon) { Log::warning("⚠️ Addon không tìm thấy addonItems", [ 'order_addon_id' => $orderAddon->id, 'addon_id' => $orderAddon->addon_id ]); continue; } $addonName = strtolower(trim($addon->name)); $quantity = (int) $orderAddon->qty; Log::info("🔍 Xử lý addon", [ 'addon_name' => $addon->name, 'addon_name_lower' => $addonName, 'quantity' => $quantity, 'addon_id' => $addon->id ]); switch ($addonName) { case 'cpu': $addonData['cpu'] += $quantity; Log::info("✅ Thêm CPU addon: +{$quantity}"); break; case 'ram': $addonData['ram'] += $quantity; Log::info("✅ Thêm RAM addon: +{$quantity}GB"); break; case 'disk': case 'ssd': $addonData['disk'] += $quantity; Log::info("✅ Thêm Disk addon: +{$quantity}GB"); break; default: Log::warning("⚠️ Addon không được nhận diện: {$addonName}"); break; } } } else { Log::info("ℹ️ Không có addons cho order item {$this->item->id}"); } Log::info('📊 Thông tin addon được xử lý', [ 'order_item_id' => $this->item->id, 'addon_data' => $addonData, 'addons_count' => $this->item->addons?->count() ?? 0, 'has_addons' => !empty($addonData) && array_sum($addonData) > 0 ]); $result = $vCenter->CreateVirtualMachine([ 'item' => $this->item, 'host' => $host, 'datacenter' => $datacenter, 'vcenter' => $vcenter, 'template' => $template, 'addon' => $addonData, ]); Log::info('Thông tin vCenter khi tạo máy ảo', [ 'product' => $product, 'item' => $this->item, 'host_id' => $host?->id, 'host_name' => $host?->name, 'host_vcenter_id' => $host?->vcenter_id, 'datacenter_id' => $datacenter?->id, 'datacenter_name' => $datacenter?->name, 'datacenter_vcenter_id' => $datacenter?->vcenter_id, 'vcenter' => $vcenter, 'vcenter_id' => $vcenter?->id, 'vcenter_host' => $vcenter?->host, 'vcenter_user' => $vcenter?->user, 'vcenter_password' => SignRSA::DecryptFunc($vcenter?->password) ]); if (is_array($result) && ($result['error'] ?? false)) { $errorMessage = 'Tạo máy ảo thất bại: ' . json_encode($result); Log::warning($errorMessage); $discord->SendErrorMessage([ 'error' => $result['error'] ?? 'Unknown error', 'result' => $result, 'product_id' => $product->id, 'order_item_id' => $this->item->id, 'host_name' => $host?->name, 'datacenter_name' => $datacenter?->name, 'vcenter_host' => $vcenter?->host ], 'CreateVirtualMachineJob - VM Creation Failed'); if (!$this->isRetry) { $this->sendFailureNotification($errorMessage); } return false; } elseif ($result === 'Login_Again') { $errorMessage = 'Tạo máy ảo thất bại: cần đăng nhập lại.'; Log::error($errorMessage); $discord->SendErrorMessage([ 'error' => $errorMessage, 'product_id' => $product->id, 'order_item_id' => $this->item->id, 'vcenter_host' => $vcenter?->host ], 'CreateVirtualMachineJob - vCenter Re-login Required'); if (!$this->isRetry) { $this->sendFailureNotification($errorMessage); } return false; } else { Log::info('Tạo máy ảo thành công: ' . json_encode($result)); // Lấy vm_id từ kết quả $vmId = is_array($result) ? ($result['data'] ?? 'unknown') : $result; if ($vmId !== 'unknown' && $vmId !== 'UNKNOWN') { try { // Lưu vm_id vào bảng invoice $invoice = \App\Models\Invoice::where('order_id', $this->item->order->id)->first(); if ($invoice) { $invoice->update(['vm_id' => $vmId]); Log::info('✅ Đã lưu vm_id vào bảng invoice', [ 'vm_id' => $vmId, 'invoice_id' => $invoice->id, 'order_id' => $this->item->order->id ]); } else { Log::warning('⚠️ Không tìm thấy invoice cho order', [ 'order_id' => $this->item->order->id, 'vm_id' => $vmId ]); } // Start VM ngay sau khi tạo thành công Log::info('🚀 Bắt đầu khởi động VM sau khi tạo thành công', [ 'vm_id' => $vmId, 'order_item_id' => $this->item->id ]); $startResult = $vCenter->StartVirtualMachine($vmId); if ($startResult === 'Login_Again') { // Thử đăng nhập lại và start VM Log::info('🔄 Thử đăng nhập lại vCenter để start VM', [ 'vm_id' => $vmId, 'vcenter_host' => $vcenter->host ]); if ($vCenter->loginServer($vcenter)) { $startResult = $vCenter->StartVirtualMachine($vmId); Log::info('✅ Đăng nhập lại thành công, thử start VM lần nữa', [ 'vm_id' => $vmId, 'start_result' => $startResult ]); } else { Log::error('❌ Không thể đăng nhập lại vCenter để start VM', [ 'vm_id' => $vmId, 'vcenter_host' => $vcenter->host ]); } } if (is_array($startResult) && $startResult['error'] === false) { Log::info('✅ Khởi động VM thành công', [ 'vm_id' => $vmId, 'order_item_id' => $this->item->id, 'result' => $startResult['data'] ]); // Dispatch ConfigCLICommand để cấu hình VM và lấy password $configJob = new ConfigCLICommand($vmId, $this->item, $vCenter); dispatch($configJob)->delay(now()->addMinutes(2)); // Chờ 2 phút để VM boot hoàn toàn Log::info('✅ Đã dispatch ConfigCLICommand job', [ 'vm_id' => $vmId, 'order_item_id' => $this->item->id ]); } else { Log::warning('⚠️ Khởi động VM thất bại', [ 'vm_id' => $vmId, 'order_item_id' => $this->item->id, 'error' => $startResult['data'] ]); } // Lưu dữ liệu VM và IP address vào database $ipAddresses = []; if (is_array($result)) { $ipAddresses = $result['ip_addresses'] ?? []; } $saveResult = $vmDataService->saveVMData($this->item, $vmId, $ipAddresses); if ($saveResult['success']) { Log::info('✅ Lưu dữ liệu VM và IP address thành công', [ 'vm_id' => $saveResult['vm']->id, 'vmware_id' => $vmId, 'ip_address_id' => $saveResult['ip_address']->id, 'order_item_id' => $this->item->id ]); } else { Log::error('❌ Lỗi khi lưu dữ liệu VM và IP address', [ 'vmware_id' => $vmId, 'error' => $saveResult['message'], 'order_item_id' => $this->item->id ]); } } catch (\Exception $e) { Log::error('❌ Lỗi khi lưu dữ liệu VM hoặc start VM: ' . $e->getMessage(), [ 'vm_id' => $vmId, 'order_id' => $this->item->order->id, 'trace' => $e->getTraceAsString() ]); } } // Log thông tin addon đã được áp dụng if (!empty($addonData) && array_sum($addonData) > 0) { Log::info('Addon đã được áp dụng thành công', [ 'vm_id' => $vmId, 'addon_data' => $addonData, 'order_item_id' => $this->item->id ]); } // Gửi thông báo thành công $discord->SendJobRunInfo( 'CreateVirtualMachineJob', 'success', [ 'product_id' => $product->id, 'order_item_id' => $this->item->id, 'result' => $result, 'addon_applied' => !empty($addonData) && array_sum($addonData) > 0, 'vm_id_saved' => $vmId !== 'unknown' && $vmId !== 'UNKNOWN', 'vm_started' => isset($startResult) && is_array($startResult) && $startResult['error'] === false ] ); return true; } } catch (\Throwable $e) { $errorMessage = 'Lỗi khi tạo máy ảo (Job): ' . $e->getMessage(); Log::error($errorMessage, [ 'exception' => $e, 'order_item_id' => $this->item->id, 'trace' => $e->getTraceAsString() ]); $discord->SendErrorMessage([ 'error' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), 'order_item_id' => $this->item->id, 'trace' => substr($e->getTraceAsString(), 0, 500) // Giới hạn độ dài trace ], 'CreateVirtualMachineJob - Exception'); if (!$this->isRetry) { $this->sendFailureNotification($errorMessage); } return false; } } /** * Send failure notification to customer */ private function sendFailureNotification(string $errorMessage): void { try { $customer = $this->item->order->customer; $product = $this->item->getProductAttribute(); VMCreationFailedJob::dispatch([ 'customer_email' => $customer->email, 'customer_name' => trim($customer->firstname . ' ' . $customer->lastname), 'product_name' => $product?->name ?? 'Unknown Product', 'order_id' => $this->item->order->id, 'order_num' => $this->item->order->order_num, 'error_message' => $errorMessage, 'order_item_id' => $this->item->id ]); } catch (\Throwable $e) { Log::error('Không thể gửi email thông báo lỗi VM: ' . $e->getMessage()); } } }