feat: collect individual disk config and onboot flag per VM

_get_vm_disk_and_boot() now returns a list of disk dicts (name, size_mb)
instead of a single total. Each disk entry is read from the VM config
via /qemu/{vmid}/config or /lxc/{vmid}/config. The onboot flag is also
read from the same config endpoint.

Both QEMU VMs and LXC containers are covered. The 'disks' and 'onboot'
keys are added to every entry in the vms_snapshot.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Christian Manivong
2026-06-23 00:44:17 +02:00
co-authored by Claude Sonnet 4.6
parent 50ccf654ba
commit 08d02d285a
+59
View File
@@ -255,6 +255,7 @@ class ProxmoxVMMixin:
"", "",
) )
disks, onboot = self._get_vm_disk_and_boot(vmid, "qemu")
result.append({ result.append({
"vmid": vmid, "vmid": vmid,
"name": name, "name": name,
@@ -270,6 +271,8 @@ class ProxmoxVMMixin:
"ipv4": ipv4, "ipv4": ipv4,
"agent_enabled": agent_enabled, "agent_enabled": agent_enabled,
"agent_running": agent_running, "agent_running": agent_running,
"disks": disks,
"onboot": onboot,
}) })
except Exception as exc: except Exception as exc:
logger.warning("get_vms: failed to list QEMU VMs: %s", exc) logger.warning("get_vms: failed to list QEMU VMs: %s", exc)
@@ -296,6 +299,7 @@ class ProxmoxVMMixin:
"", "",
) )
disks, onboot = self._get_vm_disk_and_boot(vmid, "lxc")
result.append({ result.append({
"vmid": vmid, "vmid": vmid,
"name": name, "name": name,
@@ -311,12 +315,67 @@ class ProxmoxVMMixin:
"ipv4": ipv4, "ipv4": ipv4,
"agent_enabled": agent_enabled, "agent_enabled": agent_enabled,
"agent_running": agent_running, "agent_running": agent_running,
"disks": disks,
"onboot": onboot,
}) })
except Exception as exc: except Exception as exc:
logger.warning("get_vms: failed to list LXC containers: %s", exc) logger.warning("get_vms: failed to list LXC containers: %s", exc)
return sorted(result, key=lambda x: x["vmid"]) return sorted(result, key=lambda x: x["vmid"])
# Disk-key prefixes for QEMU: scsi, virtio, ide, sata (exclude cdrom/none entries)
_DISK_KEYS_VM = re.compile(r"^(scsi|virtio|ide|sata)\d+$")
# Disk-key prefix for LXC: rootfs, mp (mount points)
_DISK_KEYS_CT = re.compile(r"^(rootfs|mp\d+)$")
def _get_vm_disk_and_boot(
self, vmid: int, vm_type: str
) -> tuple[list[dict], bool]:
"""Return (disks, onboot) for a VM or container.
Fetches config from /nodes/{node}/{qemu|lxc}/{vmid}/config.
Each disk entry is a dict with 'name' and 'size_mb'.
Returns ([], False) on any error.
"""
try:
if vm_type == "qemu":
cfg = self._node_api().qemu(vmid).config.get() or {}
disk_re = self._DISK_KEYS_VM
else:
cfg = self._node_api().lxc(vmid).config.get() or {}
disk_re = self._DISK_KEYS_CT
onboot = bool(int(cfg.get("onboot", 0) or 0))
disks: list[dict] = []
for key, value in sorted(cfg.items()):
if not disk_re.match(key):
continue
val_str = str(value or "")
# Skip CD-ROM / none entries
if "media=cdrom" in val_str or val_str.startswith("none"):
continue
# Extract size=NNX from the value string
m = re.search(r"\bsize=(\d+)([GMK]?)", val_str, re.I)
if not m:
continue
num = int(m.group(1))
unit = m.group(2).upper()
if unit == "G" or unit == "":
size_mb = num * 1024
elif unit == "M":
size_mb = num
elif unit == "K":
size_mb = num // 1024
else:
size_mb = num * 1024
disks.append({"name": key, "size_mb": size_mb})
return disks, onboot
except Exception as exc:
logger.debug("Failed to fetch disk/boot config for vmid %s: %s", vmid, exc)
return [], False
_POWER_ACTIONS_VM = {'start', 'stop', 'shutdown', 'reboot', 'reset'} _POWER_ACTIONS_VM = {'start', 'stop', 'shutdown', 'reboot', 'reset'}
_POWER_ACTIONS_CT = {'start', 'stop', 'shutdown', 'reboot'} _POWER_ACTIONS_CT = {'start', 'stop', 'shutdown', 'reboot'}