client = new Client([ 'base_uri' => "https://{$hypervisor->host}:{$hypervisor->port}/api2/json/", 'timeout' => 30, RequestOptions::VERIFY => $hypervisor->ssl_verify, ]); } private function authenticate(): void { if ($this->ticket) return; $response = $this->client->post('access/ticket', [ 'form_params' => [ 'username' => $this->hypervisor->username, 'password' => $this->hypervisor->password, ], ]); $data = json_decode($response->getBody()->getContents(), true)['data']; $this->ticket = $data['ticket']; $this->csrfToken = $data['CSRFPreventionToken']; } private function authHeaders(): array { return [ 'Cookie' => "PVEAuthCookie={$this->ticket}", 'CSRFPreventionToken' => $this->csrfToken, ]; } public function testConnection(): array { $this->authenticate(); $response = $this->client->get('version', ['headers' => $this->authHeaders()]); return json_decode($response->getBody()->getContents(), true)['data'] ?? []; } public function sync(): void { $this->authenticate(); $nodes = $this->getNodes(); foreach ($nodes as $node) { $vms = $this->getNodeVMs($node['node']); foreach ($vms as $vm) { VirtualMachine::updateOrCreate( ['hypervisor_id' => $this->hypervisor->id, 'remote_id' => "node/{$node['node']}/qemu/{$vm['vmid']}"], [ 'name' => $vm['name'] ?? "VM-{$vm['vmid']}", 'status' => $vm['status'], 'cpu_count' => $vm['cpus'] ?? 0, 'memory_mb' => isset($vm['mem']) ? intval($vm['mem'] / 1048576) : 0, 'cpu_usage' => ($vm['cpu'] ?? 0) * 100, 'memory_usage' => isset($vm['mem'], $vm['maxmem']) && $vm['maxmem'] > 0 ? ($vm['mem'] / $vm['maxmem']) * 100 : 0, 'host_node' => $node['node'], 'metadata' => $vm, ] ); } } $this->hypervisor->update(['status' => 'online', 'last_sync_at' => now(), 'last_error' => null]); } private function getNodes(): array { $response = $this->client->get('nodes', ['headers' => $this->authHeaders()]); return json_decode($response->getBody()->getContents(), true)['data'] ?? []; } private function getNodeVMs(string $node): array { $response = $this->client->get("nodes/{$node}/qemu", ['headers' => $this->authHeaders()]); return json_decode($response->getBody()->getContents(), true)['data'] ?? []; } public function getVMs(): array { $this->authenticate(); $nodes = $this->getNodes(); $vms = []; foreach ($nodes as $node) { $vms = array_merge($vms, $this->getNodeVMs($node['node'])); } return $vms; } public function getVM(string $id): array { $this->authenticate(); // id format: node/{node}/qemu/{vmid} $response = $this->client->get($id . '/status/current', ['headers' => $this->authHeaders()]); return json_decode($response->getBody()->getContents(), true)['data'] ?? []; } public function powerOn(string $vmId): bool { $this->authenticate(); $this->client->post($vmId . '/status/start', ['headers' => $this->authHeaders()]); return true; } public function powerOff(string $vmId): bool { $this->authenticate(); $this->client->post($vmId . '/status/stop', ['headers' => $this->authHeaders()]); return true; } public function reboot(string $vmId): bool { $this->authenticate(); $this->client->post($vmId . '/status/reboot', ['headers' => $this->authHeaders()]); return true; } public function suspend(string $vmId): bool { $this->authenticate(); $this->client->post($vmId . '/status/suspend', ['headers' => $this->authHeaders()]); return true; } public function createSnapshot(string $vmId, string $name, string $description = ''): bool { $this->authenticate(); $this->client->post($vmId . '/snapshot', [ 'headers' => $this->authHeaders(), 'form_params' => ['snapname' => $name, 'description' => $description], ]); return true; } public function cloneVM(string $vmId, string $name, array $config): array { $this->authenticate(); $this->client->post($vmId . '/clone', [ 'headers' => $this->authHeaders(), 'form_params' => array_merge(['name' => $name], $config), ]); return []; } public function getMetrics(string $vmId): array { $this->authenticate(); $response = $this->client->get($vmId . '/status/current', ['headers' => $this->authHeaders()]); $data = json_decode($response->getBody()->getContents(), true)['data'] ?? []; return [ 'cpu_usage' => ($data['cpu'] ?? 0) * 100, 'memory_usage' => isset($data['mem'], $data['maxmem']) && $data['maxmem'] > 0 ? ($data['mem'] / $data['maxmem']) * 100 : 0, ]; } public function deployTemplate(array $templateConfig, array $deployConfig): array { return $this->cloneVM($templateConfig['remote_id'], $deployConfig['name'], $deployConfig); } }