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'}