From 08d02d285a0e5aa0e0f179e1b249c450c61a8870 Mon Sep 17 00:00:00 2001 From: Christian Manivong Date: Tue, 23 Jun 2026 00:44:17 +0200 Subject: [PATCH] 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 --- napalm_proxmox/vm_mixin.py | 59 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/napalm_proxmox/vm_mixin.py b/napalm_proxmox/vm_mixin.py index 3e2ad12..ee26d95 100644 --- a/napalm_proxmox/vm_mixin.py +++ b/napalm_proxmox/vm_mixin.py @@ -255,6 +255,7 @@ class ProxmoxVMMixin: "", ) + disks, onboot = self._get_vm_disk_and_boot(vmid, "qemu") result.append({ "vmid": vmid, "name": name, @@ -270,6 +271,8 @@ class ProxmoxVMMixin: "ipv4": ipv4, "agent_enabled": agent_enabled, "agent_running": agent_running, + "disks": disks, + "onboot": onboot, }) except Exception as 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({ "vmid": vmid, "name": name, @@ -311,12 +315,67 @@ class ProxmoxVMMixin: "ipv4": ipv4, "agent_enabled": agent_enabled, "agent_running": agent_running, + "disks": disks, + "onboot": onboot, }) except Exception as exc: logger.warning("get_vms: failed to list LXC containers: %s", exc) 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_CT = {'start', 'stop', 'shutdown', 'reboot'}