invoiceRepository->findWithRelationships($invoice_id, [ '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_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 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.']); } } /** * 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_id) { $cacheKey = 'vm_console_invoice_' . $invoice_id; $data = cache()->remember($cacheKey, 300, function () use ($invoice_id) { $invoice = \App\Models\Invoice::where('id', $invoice_id)->first(); if (!$invoice) return null; $order = \App\Models\Order::find($invoice->order_id); if (!$order) return null; $product = \App\Models\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 */ public function getSnapshots(Request $request, vCenter $serviceVCenter) { 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.', 'debug' => 'User not authenticated via session' ], 401); } $validator = Validator::make($request->all(), [ 'product_id' => '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; $userId = $user->id; Log::info('🔍 Debug - Tìm kiếm VPS để lấy snapshot', [ 'product_id' => $productId, 'user_id' => $userId ]); $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", 'debug' => 'product not found or unauthorized' ], 404); } if (!$product->ipAddress) { return response()->json([ 'error' => true, 'message' => "VPS #{$productId} không có thông tin IP được cấu hình", 'debug' => 'product->ipAddress is null' ], 400); } if (!$product->ipAddress->host) { return response()->json([ 'error' => true, 'message' => "VPS #{$productId} không có thông tin Host được cấu hình", 'debug' => 'product->ipAddress->host is null' ], 400); } if (!$product->ipAddress->host->datacenter) { return response()->json([ 'error' => true, 'message' => "VPS #{$productId} không có thông tin Datacenter được cấu hình", 'debug' => 'product->ipAddress->host->datacenter is null' ], 400); } if (!$product->ipAddress->host->datacenter->vCenter) { return response()->json([ 'error' => true, 'message' => "VPS #{$productId} không có thông tin vCenter được cấu hình", 'debug' => 'product->ipAddress->host->datacenter->vCenter is null' ], 400); } // Get vCenter configuration $vcenter = $product->ipAddress->host->datacenter->vCenter; // Login to vCenter if (!$serviceVCenter->loginServer($vcenter)) { return response()->json([ 'error' => true, 'message' => 'Không thể đăng nhập vào vCenter' ], 500); } Log::info('�� Bắt đầu lấy danh sách snapshot', [ 'product_id' => $productId, 'product_name' => $product->name, 'vmware_id' => $product->vmware_id, 'vcenter_host' => $product->ipAddress->host->datacenter->vCenter->host ?? 'null', 'vcenter_user' => $product->ipAddress->host->datacenter->vCenter->user ?? 'null' ]); // Check if getSnapShot method exists if (!method_exists($serviceVCenter, 'getSnapShot')) { Log::error('❌ getSnapShot method không tồn tại trong ServiceVCenter'); return response()->json([ 'error' => true, 'message' => 'getSnapShot method không tồn tại' ], 500); } $result = $serviceVCenter->getSnapShot($product); Log::info('✅ getSnapShot function đã được gọi'); Log::info('📸 Kết quả getSnapShot', [ 'result' => $result, 'product_id' => $productId ]); if ($result === "Login_Again") { if ($serviceVCenter->loginServer($vcenter)) { $result = $serviceVCenter->getSnapShot($product); } else { return response()->json([ 'error' => true, 'message' => 'Không thể đăng nhập lại vào vCenter' ], 500); } } if (is_string($result)) { return response()->json([ 'error' => true, 'message' => "Lỗi lấy snapshot: $result" ], 500); } if (isset($result['error']) && $result['error']) { return response()->json([ 'error' => true, 'message' => "Lấy snapshot thất bại: " . ($result['message'] ?? 'Unknown error') ], 500); } // Get snapshots from database for additional info $dbSnapshots = ModuleSnapshot::where('customer_id', $user->id) ->where('module_vmware_id', $product->id) ->get() ->keyBy('name'); // Merge vCenter data with database data $snapshots = []; if (isset($result['data']) && is_array($result['data'])) { foreach ($result['data'] as $snapshot) { $snapshotName = $snapshot['name'] ?? $snapshot['Name'] ?? 'Unknown'; $dbSnapshot = $dbSnapshots->get($snapshotName); $snapshots[] = [ 'name' => $snapshotName, 'description' => $snapshot['description'] ?? $snapshot['Description'] ?? '', 'created' => $snapshot['created'] ?? $snapshot['Created'] ?? '', 'power_state' => $snapshot['power_state'] ?? $snapshot['PowerState'] ?? '', 'size_mb' => $snapshot['size_mb'] ?? $snapshot['SizeMB'] ?? 0, 'size_gb' => $snapshot['size_gb'] ?? $snapshot['SizeGB'] ?? 0, 'vm_name' => $snapshot['vm_name'] ?? $snapshot['VM'] ?? '', 'vm_id' => $snapshot['vm_id'] ?? $snapshot['VMId'] ?? '', 'parent' => $snapshot['parent'] ?? $snapshot['Parent'] ?? '', 'parent_snapshot_id' => $snapshot['parent_snapshot_id'] ?? $snapshot['ParentSnapshotId'] ?? '', 'parent_snapshot' => $snapshot['parent_snapshot'] ?? $snapshot['ParentSnapshot'] ?? '', 'children' => $snapshot['children'] ?? $snapshot['Children'] ?? '', 'is_current' => $snapshot['is_current'] ?? $snapshot['IsCurrent'] ?? false, 'is_replay_supported' => $snapshot['is_replay_supported'] ?? $snapshot['IsReplaySupported'] ?? false, 'snapshot_id' => $snapshot['id'] ?? $snapshot['Id'] ?? '', 'uid' => $snapshot['uid'] ?? $snapshot['Uid'] ?? '', 'in_database' => $dbSnapshot ? true : false, 'db_created_at' => $dbSnapshot ? $dbSnapshot->created_at->format('d/m/Y H:i:s') : null, 'raw_data' => $snapshot ]; } } return response()->json([ 'error' => false, 'message' => 'Lấy danh sách snapshot thành công', 'data' => [ 'snapshots' => $snapshots, 'total_count' => count($snapshots), 'vm_name' => $product->name, 'vm_id' => $product->vmware_id, 'cache_info' => [ 'cached' => false, 'cache_key' => "snapshots_{$product->id}_{$product->name}" ] ] ]); } catch (\Exception $e) { Log::error('❌ Lỗi khi lấy danh sách snapshot', [ 'product_id' => $request->product_id ?? '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 lấy danh sách snapshot: ' . $e->getMessage() ], 500); } } /** * Secure start VM using session authentication - NO BEARER TOKEN */ public function startVM(Request $request, vCenter $vCenterService) { try { // Use session authentication - NO Bearer token required $user = customer(); // This uses session 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); } // Implement start VM logic here return response()->json([ 'error' => false, 'message' => 'Chức năng start VM sẽ được thêm vào' ]); } catch (\Exception $e) { Log::error('❌ Lỗi trong secure startVM', [ 'user_id' => $user->id ?? 'guest', 'error' => $e->getMessage() ]); return response()->json([ 'error' => true, 'message' => 'Lỗi hệ thống: ' . $e->getMessage() ], 500); } } /** * Secure stop VM using session authentication - NO BEARER TOKEN */ public function stopVM(Request $request, vCenter $vCenterService) { try { // Use session authentication - NO Bearer token required $user = customer(); // This uses session 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); } // Implement stop VM logic here return response()->json([ 'error' => false, 'message' => 'Chức năng stop VM sẽ được thêm vào' ]); } catch (\Exception $e) { Log::error('❌ Lỗi trong secure stopVM', [ 'user_id' => $user->id ?? 'guest', 'error' => $e->getMessage() ]); return response()->json([ 'error' => true, 'message' => 'Lỗi hệ thống: ' . $e->getMessage() ], 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); } } }