feat: add LXC container support to Proxmox extension

- Add is_lxc boolean column to ext_proxmox_nodes (default false, existing nodes unaffected)
- Add LXC checkbox to admin node creation form (disabled on edit)
- Dynamic API path selection via Node::vmType() (returns 'lxc' or 'qemu')
- LXC deployment: syncLxcSettings() for cores, memory, swap, hostname, rootfs, net config
- LXC network uses name=eth0 format with applyLxcPoolSettings() for VLAN/firewall/MTU
- All lifecycle operations LXC-aware: install, suspend, unsuspend, terminate, upgrade, reinstall
- VNC/xterm console uses correct type (lxc vs kvm)
- All 20+ Livewire components use vmType() for Proxmox API paths
- LXC user interface shows basic-only view (no advanced toggle, no KVM-specific tabs)
- Basic tabs for LXC: Overview, Network Configuration, Backups, Console
This commit is contained in:
2026-03-02 07:11:25 -05:00
parent a98bbd6d82
commit 5f2e591c6e
21 changed files with 330 additions and 140 deletions

View File

@@ -51,7 +51,8 @@ class Overview extends Component
// Load notes from Proxmox VM description
try {
$proxmox = new Proxmox;
$config = $proxmox->request('/nodes/' . $this->server->node->name . '/qemu/' . $this->server->vm_id . '/config')->json()['data'] ?? [];
$vmType = $this->server->node->vmType();
$config = $proxmox->request('/nodes/' . $this->server->node->name . '/' . $vmType . '/' . $this->server->vm_id . '/config')->json()['data'] ?? [];
$this->notes = $config['description'] ?? '';
} catch (\Exception $e) {
$this->notes = '';
@@ -87,7 +88,8 @@ class Overview extends Component
$cacheKey = 'proxmox-stats-' . $this->server->id . '-' . $graphType . '-' . $timeRange . '-' . $aggregation;
$data = Cache::remember($cacheKey, 60, function () use ($timeRange, $aggregation) {
$proxmox = new Proxmox;
$stats = $proxmox->request('/nodes/' . $this->server->node->name . '/qemu/' . $this->server->vm_id . '/rrddata', data: [
$vmType = $this->server->node->vmType();
$stats = $proxmox->request('/nodes/' . $this->server->node->name . '/' . $vmType . '/' . $this->server->vm_id . '/rrddata', data: [
'timeframe' => $timeRange,
'cf' => $aggregation === 'maximum' ? 'MAX' : 'AVERAGE',
]);
@@ -367,8 +369,9 @@ class Overview extends Component
// Update VM name - Proxmox uses the VM name as the hostname for cloud-init
// Cloud-init will pick up the new VM name on the next boot
$response = $proxmox->request('/nodes/' . $this->server->node->name . '/qemu/' . $this->server->vm_id . '/config', 'put', [
'name' => $this->hostname,
$vmType = $this->server->node->vmType();
$response = $proxmox->request('/nodes/' . $this->server->node->name . '/' . $vmType . '/' . $this->server->vm_id . '/config', 'put', [
$this->server->node->is_lxc ? 'hostname' : 'name' => $this->hostname,
]);
// The request() method throws on error, so if we get here, it was successful
@@ -377,7 +380,7 @@ class Overview extends Component
$this->hostnameError = '';
// Refresh status to get updated name
$this->status = (object) ($proxmox->request('/nodes/' . $this->server->node->name . '/qemu/' . $this->server->vm_id . '/status/current')->json()['data'] ?? []);
$this->status = (object) ($proxmox->request('/nodes/' . $this->server->node->name . '/' . $vmType . '/' . $this->server->vm_id . '/status/current')->json()['data'] ?? []);
} catch (\Exception $e) {
$this->hostnameError = 'Failed to apply hostname: ' . $e->getMessage();
$this->notify('Failed to apply hostname to Proxmox', 'error');
@@ -469,10 +472,13 @@ class Overview extends Component
// Apply password via Proxmox API using cloud-init
$proxmox = new Proxmox;
$vmType = $this->server->node->vmType();
// The cipassword parameter sets the password that will be applied via cloud-init on next boot
$response = $proxmox->request('/nodes/' . $this->server->node->name . '/qemu/' . $this->server->vm_id . '/config', 'put', [
'cipassword' => $this->password,
// For KVM: cipassword sets the password via cloud-init on next boot
// For LXC: password sets the root password directly
$passwordKey = $this->server->node->is_lxc ? 'password' : 'cipassword';
$response = $proxmox->request('/nodes/' . $this->server->node->name . '/' . $vmType . '/' . $this->server->vm_id . '/config', 'put', [
$passwordKey => $this->password,
]);
// The request() method throws on error, so if we get here, it was successful
@@ -501,7 +507,8 @@ class Overview extends Component
// Reload notes from Proxmox
try {
$proxmox = new Proxmox;
$config = $proxmox->request('/nodes/' . $this->server->node->name . '/qemu/' . $this->server->vm_id . '/config')->json()['data'] ?? [];
$vmType = $this->server->node->vmType();
$config = $proxmox->request('/nodes/' . $this->server->node->name . '/' . $vmType . '/' . $this->server->vm_id . '/config')->json()['data'] ?? [];
$this->notes = $config['description'] ?? '';
} catch (\Exception $e) {
$this->notes = '';
@@ -512,10 +519,11 @@ class Overview extends Component
{
try {
$proxmox = new Proxmox;
$vmType = $this->server->node->vmType();
// Save notes to Proxmox VM description (limit to 8KB to avoid bloating Proxmox config)
$notes = mb_substr($this->notes ?? '', 0, 8192);
$proxmox->request('/nodes/' . $this->server->node->name . '/qemu/' . $this->server->vm_id . '/config', 'put', [
$proxmox->request('/nodes/' . $this->server->node->name . '/' . $vmType . '/' . $this->server->vm_id . '/config', 'put', [
'description' => $notes,
]);