volid = $volid; $this->confirmRestore = false; $this->showRestore = true; } public function mount(Server $server): void { parent::mount($server); $settings = $this->server->service->product->settings()->where('key', 'backups')->first(); if ($settings?->value <= 0) { $this->redirect(route('proxmox.server.overview', $this->server->id), true); return; } // Check if backup_location is configured if (empty($this->server->node->backup_location)) { $this->backups = []; return; } $this->loadBackups(); } #[\Livewire\Attributes\On('backup-started')] public function handleBackupStarted(): void { $this->loadBackups(); } public function loadBackups(): void { if (empty($this->server->node->backup_location)) { $this->backups = []; return; } try { $proxmox = new Proxmox; $response = $proxmox->request('/nodes/' . $this->server->node->name . '/storage/' . $this->server->node->backup_location . '/content', data: [ 'content' => 'backup', 'vmid' => $this->server->vm_id, ]); $this->backups = $response->json()['data'] ?? []; } catch (\Exception $e) { $this->backups = []; // Log the error for debugging \Illuminate\Support\Facades\Log::error('Failed to fetch backups: ' . $e->getMessage()); } } public function restoreBackup() { $this->validate([ 'volid' => 'required', ]); if (!$this->confirmRestore) { $this->notify('Please confirm the restore action', 'error'); return; } // Check if backup exists $backup = collect($this->backups)->firstWhere('volid', $this->volid); if (!$backup) { $this->notify('Backup not found', 'error'); return; } $proxmox = new Proxmox; // Stop the VM before restoring — Proxmox requires it try { $stopStatus = $proxmox->requestAndWait('/nodes/' . $this->server->node->name . '/' . $this->server->node->vmType() . '/' . $this->server->vm_id . '/status/stop', 'post', [ 'vmid' => $this->server->vm_id, ], $this->server->node->name); if ($stopStatus !== 'stopped' && $stopStatus !== 'OK') { $this->notify('Failed to stop VM before restore. Please try again.', 'error'); return; } } catch (\Exception $e) { $msg = strtolower($e->getMessage()); // If VM is already stopped, continue with restore; otherwise abort if (!str_contains($msg, 'not running') && !str_contains($msg, 'already stopped') && !str_contains($msg, 'is not running')) { report($e); $this->notify('Failed to stop VM before restore. Please try again.', 'error'); return; } } try { $restoreStatus = $proxmox->requestAndWait('/nodes/' . $this->server->node->name . '/' . $this->server->node->vmType(), 'post', data: [ 'vmid' => $this->server->vm_id, 'force' => true, 'archive' => $this->volid, ], node: $this->server->node->name); if ($restoreStatus !== 'stopped' && $restoreStatus !== 'OK') { $this->notify('Backup restore task failed to complete successfully.', 'error'); return; } } catch (\Throwable $e) { report($e); $this->notify('Backup restore failed. Please try again in a moment.', 'error'); return; } $this->notify('Backup restoration in progress', 'success'); $this->showRestore = false; // Redirect to the server overview page $this->redirect(route('proxmox.server.overview', $this->server->id), true); } public function promptDelete(string $volid): void { $this->volid = $volid; $this->confirmDelete = false; $this->showDelete = true; } public function deleteBackup(?string $volid = null) { $volid = $volid ?? $this->volid; if (!$volid) { $this->notify('Select a backup to delete.', 'error'); return; } if (!$this->confirmDelete) { $this->notify('Please confirm the delete action', 'error'); return; } // Check if backup exists $backup = collect($this->backups)->firstWhere('volid', $volid); if (!$backup) { $this->notify('Backup not found', 'error'); return; } $proxmox = new Proxmox; try { $response = $proxmox->request('/nodes/' . $this->server->node->name . '/storage/' . $this->server->node->backup_location . '/content/' . $volid, 'delete'); $this->notify('Backup deleted successfully', 'success'); $this->loadBackups(); $this->showDelete = false; $this->confirmDelete = false; $this->volid = null; } catch (\Illuminate\Http\Client\RequestException $e) { $errors = $e->response?->json()['errors'] ?? null; $message = is_array($errors) ? implode(', ', array_values($errors)) : 'Unknown error'; $this->notify('Failed to delete backup: ' . $message, 'error'); } } public function render() { return view('proxmox::backups')->layoutData([ 'sidebar' => true, ]); } }