invoiceRepository->findWithRelationships($invoice_ordernum, [ 'order', 'invoiceItem.addons', 'invoiceItem.os.osGroup', 'customer' ]); if (!$invoice) { return redirect()->route('service.index')->with('error', 'Không tìm thấy dịch vụ.'); } // Kiểm tra quyền truy cập - chỉ cho phép customer sở hữu if ($invoice->customer_id !== customer()->id) { return redirect()->route('service.index')->with('error', 'Bạn không có quyền truy cập dịch vụ này.'); } // Lấy thông tin VM nếu có - WITH CACHING AND BACKGROUND UPDATE $vmInfo = null; if ($invoice->vm_id) { $vmInfo = $this->getVMInfoFromVCenter($invoice, $vCenterService); // Dispatch background job to update VM info if cache is stale $this->dispatchVMInfoUpdateJob($invoice); } $title = "Chi tiết dịch vụ #" . $invoice->id; return view('frontend.service.show', [ 'title' => $title, 'invoice' => $invoice, 'vmInfo' => $vmInfo, 'breadcrumbs' => $this->crums->add(__('Dashboard'))->add('Dịch vụ #' . $invoice->id), ]); } catch (\Exception $e) { Log::error('Error in ServiceController@show: ' . $e->getMessage()); return redirect()->route('service.index')->with('error', 'Có lỗi xảy ra khi tải thông tin dịch vụ.'); } } /** * Lấy thông tin VM từ vCenter API - OPTIMIZED WITH CACHING */ private function getVMInfoFromVCenter($invoice, $vCenterService) { // Cache key for this VM info $cacheKey = "vm_info_{$invoice->vm_id}"; $cacheDuration = 300; // 5 minutes // Try to get from cache first if (Cache::has($cacheKey)) { return Cache::get($cacheKey); } try { $orderItem = $invoice->invoiceItem->first(); if (!$orderItem) { Log::warning('Không tìm thấy order item cho invoice', ['invoice_id' => $invoice->id]); $defaultInfo = $this->getDefaultVMInfo($invoice); Cache::put($cacheKey, $defaultInfo, $cacheDuration); return $defaultInfo; } $product = $orderItem->getProductAttribute(); if (!$product) { Log::warning('Không tìm thấy product cho order item', ['order_item_id' => $orderItem->id]); $defaultInfo = $this->getDefaultVMInfo($invoice); Cache::put($cacheKey, $defaultInfo, $cacheDuration); return $defaultInfo; } $host = $product->host; $datacenter = $host?->datacenter; $vcenter = $datacenter?->vcenter; if (!$vcenter) { $defaultInfo = $this->getDefaultVMInfo($invoice); Cache::put($cacheKey, $defaultInfo, $cacheDuration); return $defaultInfo; } // Login vào vCenter - with timeout $loginSuccess = false; try { $loginSuccess = $vCenterService->loginServer($vcenter); } catch (\Exception $e) { Log::warning('vCenter login failed', ['vm_id' => $invoice->vm_id, 'error' => $e->getMessage()]); } if (!$loginSuccess) { $defaultInfo = $this->getDefaultVMInfo($invoice); Cache::put($cacheKey, $defaultInfo, $cacheDuration); return $defaultInfo; } // Lấy thông tin VM từ vCenter API - with timeout handling $vmDetail = null; $ipInfo = null; try { // Set timeout for API calls $vmDetail = $vCenterService->GetDetailVirtualMachine($invoice->vm_id); $ipInfo = $vCenterService->GetIPAddressVirtualMachine($invoice->vm_id); } catch (\Exception $e) { Log::warning('vCenter API calls failed', ['vm_id' => $invoice->vm_id, 'error' => $e->getMessage()]); $defaultInfo = $this->getDefaultVMInfo($invoice); Cache::put($cacheKey, $defaultInfo, $cacheDuration); return $defaultInfo; } if ($vmDetail['error'] === false) { $vmData = $vmDetail['data']; // Lấy thông tin IP $ipAddress = 'N/A'; if ($ipInfo['error'] === false && !empty($ipInfo['data']['ip_addresses'])) { $ipAddress = $ipInfo['data']['ip_addresses'][0] ?? 'N/A'; } // Tính toán thông tin phần cứng $cpuCount = $vmData['cpu']['count'] ?? 1; $memoryMB = $vmData['memory']['size_MiB'] ?? 1024; $memoryGB = round($memoryMB / 1024, 1); $diskSizeGB = 0; if (isset($vmData['disks']) && is_array($vmData['disks'])) { foreach ($vmData['disks'] as $disk) { $diskSizeGB += round(($disk['value']['capacity'] ?? 0) / (1024 * 1024 * 1024), 1); } } $vmInfo = [ 'vm_id' => $invoice->vm_id, 'status' => $vmData['power_state'], 'ip_address' => $ipAddress, 'hostname' => $orderItem->server_name ?? 'Unknown', 'os' => $orderItem->os->osGroup->name ?? 'Unknown', 'cpu' => $cpuCount . ' cores', 'ram' => $memoryGB . ' GB', 'disk' => $diskSizeGB . ' GB', 'uptime' => 'N/A', // Có thể lấy từ guest info nếu cần 'last_updated' => now()->format('Y-m-d H:i:s'), 'vm_name' => $vmData['name'] ?? 'Unknown', 'vm_folder' => $vmData['folder'] ?? 'Unknown', 'vm_resource_pool' => $vmData['resource_pool'] ?? 'Unknown', 'vm_datastore' => $vmData['datastore'] ?? 'Unknown', 'vm_network' => $vmData['nics'][0]['backing']['network'] ?? 'Unknown', 'vm_mac' => $vmData['nics'][0]['mac_address'] ?? 'N/A', 'vm_guest_id' => $vmData['guest_ID'] ?? 'Unknown', 'vm_version' => $vmData['version'] ?? 'Unknown', 'vm_hardware_version' => $vmData['hardware']['version'] ?? 'Unknown', ]; // Cache the successful result Cache::put($cacheKey, $vmInfo, $cacheDuration); return $vmInfo; } else { $defaultInfo = $this->getDefaultVMInfo($invoice); Cache::put($cacheKey, $defaultInfo, $cacheDuration); return $defaultInfo; } } catch (\Exception $e) { Log::error('Error in getVMInfoFromVCenter', ['vm_id' => $invoice->vm_id, 'error' => $e->getMessage()]); $defaultInfo = $this->getDefaultVMInfo($invoice); Cache::put($cacheKey, $defaultInfo, $cacheDuration); return $defaultInfo; } } /** * Lấy thông tin VM mặc định khi không thể kết nối vCenter */ private function getDefaultVMInfo($invoice) { $orderItem = $invoice->invoiceItem->first(); return [ 'vm_id' => $invoice->vm_id, 'status' => 'unknown', 'ip_address' => 'N/A', 'hostname' => $orderItem->server_name ?? 'Unknown', 'os' => $orderItem->os->osGroup->name ?? 'Unknown', 'cpu' => 'N/A', 'ram' => 'N/A', 'disk' => 'N/A', 'uptime' => 'N/A', 'last_updated' => now()->format('Y-m-d H:i:s'), 'vm_name' => 'Unknown', 'vm_folder' => 'Unknown', 'vm_resource_pool' => 'Unknown', 'vm_datastore' => 'Unknown', 'vm_network' => 'Unknown', 'vm_mac' => 'N/A', 'vm_guest_id' => 'Unknown', 'vm_version' => 'Unknown', 'vm_hardware_version' => 'Unknown', ]; } /** * Action để bật/tắt VM (placeholder - chưa implement) */ public function toggleVM(Request $request, $invoice_ordernum) { try { $invoice = Invoice::where('order_num', $invoice_ordernum)->first(); // Kiểm tra quyền truy cập if ($invoice->customer_id !== customer()->id) { return response()->json(['error' => true, 'message' => 'Bạn không có quyền thực hiện thao tác này.']); } $action = $request->input('action'); $response = [ 'success' => true, 'message' => "Đã thực hiện thao tác: {$action}", 'vm_id' => $invoice->vm_id, 'action' => $action ]; // Clear cache when VM state changes if ($invoice->vm_id) { Cache::forget("vm_info_{$invoice->vm_id}"); } return response()->json($response); } catch (\Exception $e) { // Log::error('Error in ServiceController@toggleVM: ' . $e->getMessage()); return response()->json(['error' => true, 'message' => 'Có lỗi xảy ra khi thực hiện thao tác. ' . $e->getMessage()]); } } /** * Lấy thông tin VM từ vCenter (placeholder - chưa implement) */ public function getVMInfo($invoice_id) { try { $invoice = Invoice::findOrFail($invoice_id); // Kiểm tra quyền truy cập if ($invoice->customer_id !== customer()->id) { return response()->json(['error' => true, 'message' => 'Bạn không có quyền truy cập thông tin này.']); } if (!$invoice->vm_id) { return response()->json(['error' => true, 'message' => 'Dịch vụ này chưa có VM ID.']); } // TODO: Implement vCenter API calls here // Hiện tại chỉ trả về data mẫu $vmInfo = [ 'vm_id' => $invoice->vm_id, 'status' => 'running', 'ip_address' => '192.168.1.100', 'hostname' => $invoice->invoiceItem->first()->server_name ?? 'Unknown', 'os' => $invoice->invoiceItem->first()->os->osGroup->name ?? 'Unknown', 'cpu' => '2 cores', 'ram' => '4 GB', 'disk' => '50 GB', 'uptime' => '2 days, 5 hours', 'last_updated' => now()->format('Y-m-d H:i:s') ]; return redirect()->back()->with('success', 'Lấy thông tin VM thành công'); } catch (\Exception $e) { // Log::error('Error in ServiceController@getVMInfo: ' . $e->getMessage()); return response()->json(['error' => true, 'message' => 'Có lỗi xảy ra khi lấy thông tin VM.']); } } /** * Dispatch background job to update VM info */ private function dispatchVMInfoUpdateJob($invoice): void { try { // Check if cache is stale (older than 2 minutes) $cacheKey = "vm_info_{$invoice->vm_id}"; $cachedData = Cache::get($cacheKey); if ( !$cachedData || (isset($cachedData['last_updated']) && now()->diffInMinutes($cachedData['last_updated']) > 2) ) { // Dispatch background job to update VM info \App\Jobs\VirtualMachine\Sync\UpdateVMInfoJob::dispatch($invoice->id, $invoice->vm_id) ->delay(now()->addSeconds(5)) ->onQueue('vm-updates'); } } catch (\Exception $e) { Log::warning('Failed to dispatch VM info update job', [ 'vm_id' => $invoice->vm_id, 'error' => $e->getMessage() ]); } } public function vmConsole(Request $request, $invoice_ordernum) { $cacheKey = 'vm_console_invoice_' . $invoice_ordernum; $data = cache()->remember($cacheKey, 300, function () use ($invoice_ordernum) { $invoice = Invoice::where('order_num', $invoice_ordernum)->first(); if (!$invoice) return null; $order = Order::find($invoice->order_id); if (!$order) return null; $product = ModuleVmware::where('order_id', $order->id)->first(); if (!$product) return null; $title = "VM Console - " . $product->name; return compact('product', 'title', 'invoice'); }); if (!$data) { abort(404, 'Không tìm thấy thông tin VM Console'); } return view('frontend.service.console', $data); } public function createSnapshots(SnapShotRequest $request, vCenter $serviceVCenter) { try { $user = customer(); if (!$user) { return redirect()->back()->with('error', 'Chưa đăng nhập. Vui lòng đăng nhập để sử dụng tính năng này.'); } $validator = $request->validated(); $productId = $validator['product_id']; $userId = $user->id; $product = ModuleVmware::with('ipAddress.host.datacenter.vCenter') ->where('vmware_id', $productId) ->where('customer_id', $userId) ->first(); if (!$product) { return redirect()->back()->with('error', "Không tìm thấy VPS #{$productId} hoặc bạn không có quyền truy cập"); } if (!$product->ipAddress) { return redirect()->back()->with('error', "VPS #{$productId} không có thông tin IP được cấu hình"); } if (!$product->ipAddress->host) { return redirect()->back()->with('error', "VPS #{$productId} không có thông tin Host được cấu hình"); } if (!$product->ipAddress->host->datacenter) { return redirect()->back()->with('error', "VPS #{$productId} không có thông tin Datacenter được cấu hình"); } if (!$product->ipAddress->host->datacenter->vCenter) { return redirect()->back()->with('error', "VPS #{$productId} không có thông tin vCenter được cấu hình"); } if ($product->status != 1) { return redirect()->back()->with('error', 'Chỉ có thể tạo snapshot cho máy ảo đang hoạt động'); } // Kiểm tra giới hạn snapshot $snapshotLimit = \App\Models\ModuleSnapshotLimit::where('customer_id', $user->id)->first(); if ($snapshotLimit) { $currentCount = ModuleSnapshot::where('customer_id', $user->id) ->where('module_vmware_id', $product->id) ->count(); if ($currentCount >= $snapshotLimit->limit) { return redirect()->back()->with('error', "Đã đạt giới hạn snapshot ({$snapshotLimit->limit}). Vui lòng xóa snapshot cũ."); } } // Dispatch job để tạo snapshot trong background \App\Jobs\VirtualMachine\Snapshot\CreateSnapshot::dispatch($product->id) ->delay(now()->addSeconds(5)) ->onQueue('snapshots'); return redirect()->back()->with('success', 'Đã gửi yêu cầu tạo snapshot. Quá trình sẽ mất 3-5 phút, vui lòng chờ đợi.'); } catch (\Exception $e) { Log::error('❌ Lỗi khi tạo snapshot', [ 'product_id' => $request->product_id ?? 'not_provided', 'user_id' => $user->id ?? 'guest', 'error' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine() ]); return redirect()->back()->with('error', 'Lỗi hệ thống khi tạo snapshot: ' . $e->getMessage()); } } /** * Secure get snapshots using session authentication - NO BEARER TOKEN */ /** * Lấy danh sách snapshot với bảo mật và tối ưu hóa */ public function getSnapshots(Request $request, vCenter $serviceVCenter) { try { // Kiểm tra authentication $user = customer(); if (!$user) { return response()->json([ 'error' => true, 'message' => __('Chưa đăng nhập. Vui lòng đăng nhập để sử dụng tính năng này.') ], 401); } // Validation với sanitization $validator = Validator::make($request->all(), [ 'product_id' => 'required|string|max:255', ]); if ($validator->fails()) { return response()->json([ 'error' => true, 'message' => __('Dữ liệu không hợp lệ'), 'errors' => $validator->errors() ], 422); } $productId = $this->sanitizeInput($request->product_id); $userId = $user->id; // Cache key cho snapshot data $cacheKey = "snapshots_{$userId}_{$productId}"; $cacheDuration = 300; // 5 phút // Thử lấy từ cache trước if (Cache::has($cacheKey)) { $cachedData = Cache::get($cacheKey); if ($cachedData && !$this->isCacheExpired($cachedData)) { return response()->json([ 'error' => false, 'message' => __('Lấy danh sách snapshot thành công'), 'data' => $cachedData, 'cached' => true ]); } } // Tìm VPS với eager loading tối ưu $product = $this->findVmwareProduct($productId, $userId); if (!$product) { return response()->json([ 'error' => true, 'message' => __('Không tìm thấy VPS hoặc bạn không có quyền truy cập') ], 404); } // Kiểm tra cấu hình vCenter $vcenter = $this->validateVcenterConfiguration($product); if (!$vcenter) { return response()->json([ 'error' => true, 'message' => __('Cấu hình vCenter không hợp lệ') ], 400); } // Lấy snapshot từ vCenter $snapshots = $this->fetchSnapshotsFromVCenter($serviceVCenter, $product, $vcenter); if ($snapshots === false) { return response()->json([ 'error' => true, 'message' => __('Không thể kết nối đến vCenter') ], 500); } // Lấy thông tin bổ sung từ database $dbSnapshots = $this->getDatabaseSnapshots($userId, $product->id); // Merge và sanitize data $processedSnapshots = $this->processSnapshotsData($snapshots, $dbSnapshots); // Chuẩn bị response data $responseData = [ 'snapshots' => $processedSnapshots, 'total_count' => count($processedSnapshots), 'vm_name' => $this->sanitizeOutput($product->name), 'vm_id' => $product->vmware_id, 'last_updated' => now()->format('Y-m-d H:i:s') ]; // Cache kết quả Cache::put($cacheKey, $responseData, $cacheDuration); return response()->json([ 'error' => false, 'message' => __('Lấy danh sách snapshot thành công'), 'data' => $responseData, 'cached' => false ]); } catch (\Exception $e) { Log::error('Lỗi khi lấy danh sách snapshot', [ 'user_id' => $user->id ?? 'guest', 'product_id' => $request->product_id ?? 'not_provided', 'error' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine() ]); return response()->json([ 'error' => true, 'message' => __('Có lỗi xảy ra khi lấy danh sách snapshot') ], 500); } } /** * Secure remove snapshot using session authentication - NO BEARER TOKEN */ public function removeSnapshot(Request $request) { try { $user = customer(); if (!$user) { return response()->json([ 'error' => true, 'message' => 'Chưa đăng nhập. Vui lòng đăng nhập để sử dụng tính năng này.' ], 401); } $validator = Validator::make($request->all(), [ 'product_id' => 'required|string', 'snapshot_name' => 'required|string', ]); if ($validator->fails()) { return response()->json([ 'error' => true, 'message' => 'Dữ liệu không hợp lệ', 'errors' => $validator->errors() ], 422); } $productId = $request->product_id; $snapshotName = $request->snapshot_name; $userId = $user->id; // Tìm VPS $product = ModuleVmware::with('ipAddress.host.datacenter.vCenter') ->where('vmware_id', $productId) ->where('customer_id', $userId) ->first(); if (!$product) { return response()->json([ 'error' => true, 'message' => "Không tìm thấy VPS #{$productId} hoặc bạn không có quyền truy cập" ], 404); } // Tìm snapshot trong database $snapshot = ModuleSnapshot::where('customer_id', $userId) ->where('module_vmware_id', $product->id) ->where('name', $snapshotName) ->first(); if (!$snapshot) { return response()->json([ 'error' => true, 'message' => "Không tìm thấy snapshot '{$snapshotName}' hoặc bạn không có quyền truy cập" ], 404); } // Kiểm tra trạng thái VPS if ($product->status != 1) { return response()->json([ 'error' => true, 'message' => 'Chỉ có thể xóa snapshot cho máy ảo đang hoạt động' ], 400); } // Dispatch job để xóa snapshot trong background \App\Jobs\VirtualMachine\Snapshot\RemoveSnapshot::dispatch($product->id, $snapshot->id) ->delay(now()->addSeconds(5)) ->onQueue('snapshots'); return response()->json([ 'error' => false, 'message' => 'Đã gửi yêu cầu xóa snapshot. Quá trình sẽ mất 1-2 phút, vui lòng chờ đợi.' ]); } catch (\Exception $e) { Log::error('❌ Lỗi khi xóa snapshot', [ 'product_id' => $request->product_id ?? 'not_provided', 'snapshot_name' => $request->snapshot_name ?? 'not_provided', 'user_id' => $user->id ?? 'guest', 'error' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine() ]); return response()->json([ 'error' => true, 'message' => 'Lỗi hệ thống khi xóa snapshot: ' . $e->getMessage() ], 500); } } /** * Secure revert snapshot using session authentication - NO BEARER TOKEN */ public function revertSnapshot(Request $request) { try { $user = customer(); if (!$user) { return response()->json([ 'error' => true, 'message' => 'Chưa đăng nhập. Vui lòng đăng nhập để sử dụng tính năng này.' ], 401); } $validator = Validator::make($request->all(), [ 'product_id' => 'required|string', 'snapshot_name' => 'required|string', ]); if ($validator->fails()) { return response()->json([ 'error' => true, 'message' => 'Dữ liệu không hợp lệ', 'errors' => $validator->errors() ], 422); } $productId = $request->product_id; $snapshotName = $request->snapshot_name; $userId = $user->id; // Tìm VPS $product = ModuleVmware::with('ipAddress.host.datacenter.vCenter') ->where('vmware_id', $productId) ->where('customer_id', $userId) ->first(); if (!$product) { return response()->json([ 'error' => true, 'message' => "Không tìm thấy VPS #{$productId} hoặc bạn không có quyền truy cập" ], 404); } // Tìm snapshot trong database $snapshot = ModuleSnapshot::where('customer_id', $userId) ->where('module_vmware_id', $product->id) ->where('name', $snapshotName) ->first(); if (!$snapshot) { return response()->json([ 'error' => true, 'message' => "Không tìm thấy snapshot '{$snapshotName}' hoặc bạn không có quyền truy cập" ], 404); } // Kiểm tra trạng thái VPS if ($product->status != 1) { return response()->json([ 'error' => true, 'message' => 'Chỉ có thể khôi phục snapshot cho máy ảo đang hoạt động' ], 400); } // Dispatch job để khôi phục snapshot trong background \App\Jobs\VirtualMachine\Snapshot\RevertSnapshot::dispatch($product->id, $snapshot->id) ->delay(now()->addSeconds(5)) ->onQueue('snapshots'); return response()->json([ 'error' => false, 'message' => 'Đã gửi yêu cầu khôi phục snapshot. Quá trình sẽ mất 2-3 phút, vui lòng chờ đợi.' ]); } catch (\Exception $e) { Log::error('❌ Lỗi khi khôi phục snapshot', [ 'product_id' => $request->product_id ?? 'not_provided', 'snapshot_name' => $request->snapshot_name ?? 'not_provided', 'user_id' => $user->id ?? 'guest', 'error' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine() ]); return response()->json([ 'error' => true, 'message' => 'Lỗi hệ thống khi khôi phục snapshot: ' . $e->getMessage() ], 500); } } /** * Secure start VM using session authentication - NO BEARER TOKEN */ public function startVM(Request $request, vCenter $vCenterService) { try { $user = customer(); if (!$user) { return response()->json([ 'error' => true, 'message' => __('Chưa đăng nhập. Vui lòng đăng nhập để sử dụng tính năng này.') ], 401); } $validator = \Validator::make($request->all(), [ 'product_id' => 'required|string|max:255', ]); if ($validator->fails()) { return response()->json([ 'error' => true, 'message' => __('Dữ liệu không hợp lệ'), 'errors' => $validator->errors() ], 422); } $productId = htmlspecialchars(strip_tags(trim($request->product_id)), ENT_QUOTES, 'UTF-8'); $userId = $user->id; $product = ModuleVmware::where('vmware_id', $productId) ->where('customer_id', $userId) ->first(); if (!$product) { return response()->json([ 'error' => true, 'message' => __('Không tìm thấy VPS hoặc bạn không có quyền truy cập') ], 404); } $result = $vCenterService->StartVirtualMachine($product, $product->vmware_id); if (is_array($result) && isset($result['error']) && $result['error'] === false) { // Clear VM info cache after starting VM \Cache::forget('vm_info_' . $product->vmware_id); return response()->json([ 'error' => false, 'message' => __('Yêu cầu khởi động máy ảo đã được gửi thành công.') ]); } else { $msg = is_array($result) && isset($result['data']) ? $result['data'] : __('Không thể khởi động máy ảo'); return response()->json([ 'error' => true, 'message' => $msg ], 500); } } catch (\Exception $e) { \Log::error('Lỗi khi khởi động máy ảo', [ 'user_id' => $user->id ?? 'guest', 'product_id' => $request->product_id ?? 'not_provided', 'error' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine() ]); return response()->json([ 'error' => true, 'message' => __('Có lỗi xảy ra khi khởi động máy ảo') ], 500); } } /** * Secure stop VM using session authentication - NO BEARER TOKEN */ public function stopVM(Request $request, vCenter $vCenterService) { try { $user = customer(); if (!$user) { return response()->json([ 'error' => true, 'message' => __('Chưa đăng nhập. Vui lòng đăng nhập để sử dụng tính năng này.') ], 401); } $validator = \Validator::make($request->all(), [ 'product_id' => 'required|string|max:255', ]); if ($validator->fails()) { return response()->json([ 'error' => true, 'message' => __('Dữ liệu không hợp lệ'), 'errors' => $validator->errors() ], 422); } $productId = htmlspecialchars(strip_tags(trim($request->product_id)), ENT_QUOTES, 'UTF-8'); $userId = $user->id; $product = ModuleVmware::where('vmware_id', $productId) ->where('customer_id', $userId) ->first(); if (!$product) { return response()->json([ 'error' => true, 'message' => __('Không tìm thấy VPS hoặc bạn không có quyền truy cập') ], 404); } $result = $vCenterService->ShutdownGuestVirtualMachine($product, $product->vmware_id); if (is_array($result) && isset($result['error']) && $result['error'] === false) { // Clear VM info cache after stopping VM \Cache::forget('vm_info_' . $product->vmware_id); return response()->json([ 'error' => false, 'message' => __('Yêu cầu tắt máy ảo đã được gửi thành công.') ]); } else { $msg = is_array($result) && isset($result['data']) ? $result['data'] : __('Không thể tắt máy ảo'); return response()->json([ 'error' => true, 'message' => $msg ], 500); } } catch (\Exception $e) { \Log::error('Lỗi khi tắt máy ảo', [ 'user_id' => $user->id ?? 'guest', 'product_id' => $request->product_id ?? 'not_provided', 'error' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine() ]); return response()->json([ 'error' => true, 'message' => __('Có lỗi xảy ra khi tắt máy ảo') ], 500); } } /** * Secure reboot VM using session authentication - NO BEARER TOKEN */ public function rebootVM(Request $request, vCenter $vCenterService) { try { $user = customer(); if (!$user) { return response()->json([ 'error' => true, 'message' => __('Chưa đăng nhập. Vui lòng đăng nhập để sử dụng tính năng này.') ], 401); } $validator = \Validator::make($request->all(), [ 'product_id' => 'required|string|max:255', ]); if ($validator->fails()) { return response()->json([ 'error' => true, 'message' => __('Dữ liệu không hợp lệ'), 'errors' => $validator->errors() ], 422); } $productId = htmlspecialchars(strip_tags(trim($request->product_id)), ENT_QUOTES, 'UTF-8'); $userId = $user->id; $product = ModuleVmware::where('vmware_id', $productId) ->where('customer_id', $userId) ->first(); if (!$product) { return response()->json([ 'error' => true, 'message' => __('Không tìm thấy VPS hoặc bạn không có quyền truy cập') ], 404); } $result = $vCenterService->RebootVirtualMachine($product, $product->vmware_id); if (is_array($result) && isset($result['error']) && $result['error'] === false) { return response()->json([ 'error' => false, 'message' => __('Yêu cầu khởi động lại máy ảo đã được gửi thành công.') ]); } else { $msg = is_array($result) && isset($result['data']) ? $result['data'] : __('Không thể khởi động lại máy ảo'); return response()->json([ 'error' => true, 'message' => $msg ], 500); } } catch (\Exception $e) { \Log::error('Lỗi khi reboot VM', [ 'user_id' => $user->id ?? 'guest', 'product_id' => $request->product_id ?? 'not_provided', 'error' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine() ]); return response()->json([ 'error' => true, 'message' => __('Có lỗi xảy ra khi khởi động lại máy ảo') ], 500); } } /** * Sanitize input data */ private function sanitizeInput($input): string { return htmlspecialchars(strip_tags(trim($input)), ENT_QUOTES, 'UTF-8'); } /** * Sanitize output data */ private function sanitizeOutput($output): string { return htmlspecialchars($output, ENT_QUOTES, 'UTF-8'); } /** * Kiểm tra cache có hết hạn chưa */ private function isCacheExpired($cachedData): bool { if (!isset($cachedData['last_updated'])) { return true; } $lastUpdated = \Carbon\Carbon::parse($cachedData['last_updated']); return now()->diffInMinutes($lastUpdated) > 2; // Cache 2 phút } /** * Tìm VPS với eager loading */ private function findVmwareProduct($productId, $userId) { return ModuleVmware::with(['ipAddress.host.datacenter.vCenter']) ->where('vmware_id', $productId) ->where('customer_id', $userId) ->first(); } /** * Validate vCenter configuration */ private function validateVcenterConfiguration($product) { if (!$product->ipAddress?->host?->datacenter?->vCenter) { return null; } return $product->ipAddress->host->datacenter->vCenter; } /** * Lấy snapshot từ vCenter */ private function fetchSnapshotsFromVCenter($serviceVCenter, $product, $vcenter) { try { // Login to vCenter if (!$serviceVCenter->loginServer($vcenter)) { return false; } // Kiểm tra method tồn tại if (!method_exists($serviceVCenter, 'getSnapShot')) { Log::error('getSnapShot method không tồn tại trong ServiceVCenter'); return false; } $result = $serviceVCenter->getSnapShot($product); // Retry logic if ($result === "Login_Again") { if ($serviceVCenter->loginServer($vcenter)) { $result = $serviceVCenter->getSnapShot($product); } else { return false; } } // Validate result if (is_string($result) || (isset($result['error']) && $result['error'])) { return false; } return $result['data'] ?? []; } catch (\Exception $e) { Log::error('Lỗi khi lấy snapshot từ vCenter', [ 'product_id' => $product->id, 'error' => $e->getMessage() ]); return false; } } /** * Lấy snapshot từ database */ private function getDatabaseSnapshots($userId, $productId) { return ModuleSnapshot::where('customer_id', $userId) ->where('module_vmware_id', $productId) ->get() ->keyBy('name'); } /** * Xử lý và sanitize snapshot data */ private function processSnapshotsData($snapshots, $dbSnapshots): array { $processed = []; if (!is_array($snapshots)) { return $processed; } foreach ($snapshots as $snapshot) { $snapshotName = $this->sanitizeOutput($snapshot['name'] ?? $snapshot['Name'] ?? 'Unknown'); $dbSnapshot = $dbSnapshots->get($snapshotName); $processed[] = [ 'name' => $snapshotName, 'description' => $this->sanitizeOutput($snapshot['description'] ?? $snapshot['Description'] ?? ''), 'created' => $this->sanitizeOutput($snapshot['created'] ?? $snapshot['Created'] ?? ''), 'power_state' => $this->sanitizeOutput($snapshot['power_state'] ?? $snapshot['PowerState'] ?? ''), 'size_mb' => (int) ($snapshot['size_mb'] ?? $snapshot['SizeMB'] ?? 0), 'size_gb' => (float) ($snapshot['size_gb'] ?? $snapshot['SizeGB'] ?? 0), 'is_current' => (bool) ($snapshot['is_current'] ?? $snapshot['IsCurrent'] ?? false), 'is_replay_supported' => (bool) ($snapshot['is_replay_supported'] ?? $snapshot['IsReplaySupported'] ?? false), 'in_database' => $dbSnapshot ? true : false, 'db_created_at' => $dbSnapshot ? $dbSnapshot->created_at->format('d/m/Y H:i:s') : null ]; } return $processed; } }