feat: Update Proxmox extension with various improvements and bug fixes
- Change listStates method to accept nullable integer for limit parameter. - Modify TechnitiumDns class to return structured error messages on failure. - Enhance VNC and xterm popup routes with user authorization checks. - Update backups view to improve loading states and add unique keys for dynamic elements. - Refactor cloud-init view to ensure proper data binding and improve user experience. - Add wire:key attributes to various elements in views for better Livewire performance. - Improve error handling and user feedback in the firewall view. - Update server overview and statistics views to handle potential null values gracefully. - Add new migration files to extend database schema with user-set icons and notes for Proxmox nodes.
This commit is contained in:
@@ -143,7 +143,7 @@ class Proxmox extends ClassServer
|
||||
|
||||
$resourcePool = $this->request('/pools');
|
||||
$poolList = [];
|
||||
foreach ($resourcePool->json()['data'] as $pool) {
|
||||
foreach ($resourcePool->json()['data'] ?? [] as $pool) {
|
||||
$poolList[] = [
|
||||
'label' => $pool['poolid'],
|
||||
'value' => $pool['poolid'],
|
||||
@@ -326,7 +326,7 @@ class Proxmox extends ClassServer
|
||||
],
|
||||
[
|
||||
'label' => 'Write Back',
|
||||
'value' => 'write back',
|
||||
'value' => 'writeback',
|
||||
],
|
||||
[
|
||||
'label' => 'Write Back (unsafe)',
|
||||
@@ -411,19 +411,29 @@ class Proxmox extends ClassServer
|
||||
$response = $this->request($url, $method, $data);
|
||||
|
||||
// Check if the task is running
|
||||
$task = $response->json()['data'];
|
||||
$task = $response->json()['data'] ?? null;
|
||||
sleep(1); // Give Proxmox some time to start the task
|
||||
|
||||
if (!$task) {
|
||||
return 'error';
|
||||
}
|
||||
|
||||
return $this->waitForTask($task, $node);
|
||||
}
|
||||
|
||||
public function waitForTask($task, $node)
|
||||
{
|
||||
// Check if the task is running
|
||||
$status = $this->request('/nodes/' . $node . '/tasks/' . $task . '/status')->json()['data']['status'];
|
||||
while ($status == 'running') {
|
||||
// Check if the task is running (with max 300 iterations / 5 minute timeout)
|
||||
$status = $this->request('/nodes/' . $node . '/tasks/' . $task . '/status')->json()['data']['status'] ?? null;
|
||||
$iterations = 0;
|
||||
while ($status == 'running' && $iterations < 300) {
|
||||
sleep(1);
|
||||
$status = $this->request('/nodes/' . $node . '/tasks/' . $task . '/status')->json()['data']['status'];
|
||||
$status = $this->request('/nodes/' . $node . '/tasks/' . $task . '/status')->json()['data']['status'] ?? null;
|
||||
$iterations++;
|
||||
}
|
||||
|
||||
if ($iterations >= 300) {
|
||||
\Log::warning('Proxmox task timed out after 300 seconds', ['task' => $task, 'node' => $node]);
|
||||
}
|
||||
|
||||
return $status;
|
||||
@@ -456,7 +466,7 @@ class Proxmox extends ClassServer
|
||||
$server->save();
|
||||
|
||||
// Create the VM
|
||||
$this->requestAndWait('/nodes/' . $server->node->name . '/qemu/' . $server->os->vm_id . '/clone', 'post', [
|
||||
$cloneResult = $this->requestAndWait('/nodes/' . $server->node->name . '/qemu/' . $server->os->vm_id . '/clone', 'post', [
|
||||
'newid' => $server->vm_id,
|
||||
'name' => $server->hostname,
|
||||
'target' => $server->node->name,
|
||||
@@ -465,6 +475,18 @@ class Proxmox extends ClassServer
|
||||
'pool' => $settings['pool'],
|
||||
], $server->node->name);
|
||||
|
||||
if ($cloneResult !== 'stopped' && $cloneResult !== 'OK') {
|
||||
\Log::error('Proxmox VM clone failed for server ' . $server->id, [
|
||||
'result' => $cloneResult,
|
||||
'vm_id' => $server->vm_id,
|
||||
'node' => $server->node->name,
|
||||
]);
|
||||
$server->status = 'error';
|
||||
$server->save();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->syncServerSettings($server, $settings, $password);
|
||||
|
||||
// Start the server
|
||||
@@ -492,7 +514,7 @@ class Proxmox extends ClassServer
|
||||
$this->request('/nodes/' . $server->node->name . '/qemu/' . $server->vm_id . '/config', 'put', $data);
|
||||
|
||||
// Get current disk type
|
||||
$disk = $this->request('/nodes/' . $server->node->name . '/qemu/' . $server->vm_id . '/config')->json()['data'];
|
||||
$disk = $this->request('/nodes/' . $server->node->name . '/qemu/' . $server->vm_id . '/config')->json()['data'] ?? [];
|
||||
// As the disk type can be different, we need to check if it is scsi or virtio or sata or ide
|
||||
$diskType = 'scsi0';
|
||||
if (isset($disk['virtio0'])) {
|
||||
@@ -518,7 +540,9 @@ class Proxmox extends ClassServer
|
||||
$network .= ',rate=' . $settings['ratelimit'];
|
||||
}
|
||||
$config['net0'] = $network;
|
||||
$config['ipconfig0'] = 'ip=' . $ipv4->ip . '/24' . ',gw=' . $ipv4->gateway . ',ip6=' . $ipv6->ip . '/64' . ',gw6=' . $ipv6->gateway;
|
||||
$ipv4Cidr = $ipv4->netmask ?: '24';
|
||||
$ipv6Cidr = $ipv6->netmask ?: '64';
|
||||
$config['ipconfig0'] = 'ip=' . $ipv4->ip . '/' . $ipv4Cidr . ',gw=' . $ipv4->gateway . ',ip6=' . $ipv6->ip . '/' . $ipv6Cidr . ',gw6=' . $ipv6->gateway;
|
||||
} else {
|
||||
if ($ipv4) {
|
||||
$network = $settings['model'] . '=' . ($ipv4->mac_address ? $ipv4->mac_address : $this->generateMacAddress()) . ',bridge=' . $ipv4->ipPool->network_interface;
|
||||
@@ -527,7 +551,8 @@ class Proxmox extends ClassServer
|
||||
$network .= ',rate=' . $settings['ratelimit'];
|
||||
}
|
||||
$config['net0'] = $network;
|
||||
$config['ipconfig0'] = 'ip=' . $ipv4->ip . '/24' . ',gw=' . $ipv4->gateway;
|
||||
$ipv4Cidr = $ipv4->netmask ?: '24';
|
||||
$config['ipconfig0'] = 'ip=' . $ipv4->ip . '/' . $ipv4Cidr . ',gw=' . $ipv4->gateway;
|
||||
}
|
||||
if ($ipv6) {
|
||||
$network = $settings['model'] . '=' . ($ipv6->mac_address ? $ipv6->mac_address : $this->generateMacAddress()) . ',bridge=' . $ipv6->ipPool->network_interface;
|
||||
@@ -536,7 +561,8 @@ class Proxmox extends ClassServer
|
||||
$network .= ',rate=' . $settings['ratelimit'];
|
||||
}
|
||||
$config['net1'] = $network;
|
||||
$config['ipconfig1'] = 'ip6=' . $ipv6->ip . '/64' . ',gw6=' . $ipv6->gateway;
|
||||
$ipv6Cidr = $ipv6->netmask ?: '64';
|
||||
$config['ipconfig1'] = 'ip6=' . $ipv6->ip . '/' . $ipv6Cidr . ',gw6=' . $ipv6->gateway;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -724,7 +750,11 @@ class Proxmox extends ClassServer
|
||||
])->post(rtrim($this->config('host'), '/') . '/api2/json/access/ticket', [
|
||||
'username' => 'PAYMENTER_VNC_' . $server->id . '@pve',
|
||||
'password' => $password,
|
||||
])->throw()->json()['data'];
|
||||
])->throw()->json()['data'] ?? [];
|
||||
|
||||
if (empty($response['ticket']) || empty($response['CSRFPreventionToken'])) {
|
||||
throw new \RuntimeException('Failed to obtain Proxmox authentication ticket.');
|
||||
}
|
||||
|
||||
$domain = rtrim($this->config('host'), '/');
|
||||
// Remove port and http
|
||||
@@ -739,7 +769,7 @@ class Proxmox extends ClassServer
|
||||
'verify' => $this->config('verify_ssl') ? true : false,
|
||||
])->post(rtrim($this->config('host'), '/') . '/api2/json/nodes/' . $server->node->name . '/qemu/' . $server->vm_id . '/vncproxy', [
|
||||
'websocket' => 1,
|
||||
])->json()['data'];
|
||||
])->json()['data'] ?? [];
|
||||
|
||||
// Current
|
||||
$paymenterDomain = rtrim(config('settings.app_url'), '/');
|
||||
@@ -750,7 +780,7 @@ class Proxmox extends ClassServer
|
||||
if (count($parts) >= 2) {
|
||||
$paymenterDomain = $parts[count($parts) - 2] . '.' . $parts[count($parts) - 1];
|
||||
}
|
||||
setcookie('PVEAuthCookie', $response['ticket'], 0, '/', $paymenterDomain, false, true);
|
||||
setcookie('PVEAuthCookie', $response['ticket'], 0, '/', $paymenterDomain, true, true);
|
||||
|
||||
return rtrim($this->config('host'), '/') .
|
||||
'/?console=kvm' .
|
||||
@@ -770,7 +800,11 @@ class Proxmox extends ClassServer
|
||||
])->post(rtrim($this->config('host'), '/') . '/api2/json/access/ticket', [
|
||||
'username' => 'PAYMENTER_VNC_' . $server->id . '@pve',
|
||||
'password' => $password,
|
||||
])->throw()->json()['data'];
|
||||
])->throw()->json()['data'] ?? [];
|
||||
|
||||
if (empty($response['ticket'])) {
|
||||
throw new \RuntimeException('Failed to obtain Proxmox authentication ticket.');
|
||||
}
|
||||
|
||||
$domain = rtrim($this->config('host'), '/');
|
||||
// Remove port and http
|
||||
@@ -786,7 +820,7 @@ class Proxmox extends ClassServer
|
||||
if (count($parts) >= 2) {
|
||||
$paymenterDomain = $parts[count($parts) - 2] . '.' . $parts[count($parts) - 1];
|
||||
}
|
||||
setcookie('PVEAuthCookie', $response['ticket'], 0, '/', $paymenterDomain, false, true);
|
||||
setcookie('PVEAuthCookie', $response['ticket'], 0, '/', $paymenterDomain, true, true);
|
||||
|
||||
return rtrim($this->config('host'), '/') .
|
||||
'/?console=kvm' .
|
||||
@@ -888,6 +922,10 @@ class Proxmox extends ClassServer
|
||||
// Update server status
|
||||
$server = Server::where('service_id', $service->id)->first();
|
||||
|
||||
if (!$server) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Stop server
|
||||
$this->request('/nodes/' . $server->node->name . '/qemu/' . $server->vm_id . '/status/stop', 'post', [
|
||||
'vmid' => $server->vm_id,
|
||||
@@ -895,6 +933,8 @@ class Proxmox extends ClassServer
|
||||
|
||||
$server->status = 'suspended';
|
||||
$server->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -909,8 +949,14 @@ class Proxmox extends ClassServer
|
||||
// Update server status
|
||||
$server = Server::where('service_id', $service->id)->first();
|
||||
|
||||
if (!$server) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$server->status = 'active';
|
||||
$server->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -927,11 +973,10 @@ class Proxmox extends ClassServer
|
||||
}
|
||||
|
||||
$server = Server::where('service_id', $service->id)->first();
|
||||
// Kill the server
|
||||
$this->request('/nodes/' . $server->node->name . '/qemu/' . $server->vm_id . '/status/stop', 'post', [
|
||||
// Stop the VM and wait for completion before deleting
|
||||
$this->requestAndWait('/nodes/' . $server->node->name . '/qemu/' . $server->vm_id . '/status/stop', 'post', [
|
||||
'vmid' => $server->vm_id,
|
||||
]);
|
||||
sleep(3);
|
||||
], $server->node->name);
|
||||
// Delete proxmox server
|
||||
$this->request('/nodes/' . $server->node->name . '/qemu/' . $server->vm_id, 'delete');
|
||||
// Delete server
|
||||
|
||||
Reference in New Issue
Block a user