"""``get_vm_config``: a VM's virtual hardware as a VMConfigDict.""" from __future__ import annotations from typing import Any from napalm_device_types.models import VMConfigDict, VMDiskDict, VMNICDict from napalm_vmware.parse import vm_devices as dev from napalm_vmware.parse.networks import NetworkIndex, nic_network _GB = 1024**3 _BOOT_KIND = { "VirtualMachineBootOptionsBootableCdromDevice": "cdrom", "VirtualMachineBootOptionsBootableFloppyDevice": "floppy", } def _boot_order(vm: dict[str, Any], labels: dict[int, str]) -> list[str]: order: list[str] = [] for entry in vm.get("config.bootOptions.bootOrder") or []: kind = entry.get("_type", "") if kind in _BOOT_KIND: order.append(_BOOT_KIND[kind]) elif "deviceKey" in entry: order.append(labels.get(entry["deviceKey"], str(entry["deviceKey"]))) return order def _disks(vm: dict[str, Any], boot_order: list[str]) -> list[VMDiskDict]: disks = [d for d in dev.devices(vm) if dev.is_disk(d)] result: list[VMDiskDict] = [] for position, disk in enumerate(disks): name = dev.label(disk) # Without an explicit boot order the firmware boots the first disk. bootable = name in boot_order if boot_order else position == 0 result.append( { "device": name, "storage": dev.disk_datastore(disk), "size": dev.disk_bytes(disk) // _GB, "format": "vmdk", "bootable": bootable, } ) return result def _nics(vm: dict[str, Any], index: NetworkIndex) -> list[VMNICDict]: result: list[VMNICDict] = [] for nic in filter(dev.is_nic, dev.devices(vm)): network, vlan = nic_network(nic, index) result.append( { "device": dev.label(nic), "mac": nic.get("macAddress", "").upper(), "model": dev.nic_model(nic), "bridge": network, "vlan_id": vlan, } ) return result def vm_config(vm: dict[str, Any], index: NetworkIndex) -> VMConfigDict: """The VM's hardware. Raises ``ValueError`` for a VM without a config.""" if not vm.get("config.instanceUuid"): raise ValueError(f"VM {vm.get('name', vm.get('_moref'))!r} has no readable configuration") labels = {d["key"]: dev.label(d) for d in dev.devices(vm) if "key" in d} boot_order = _boot_order(vm, labels) vcpus = int(vm.get("config.hardware.numCPU") or 0) cores = int(vm.get("config.hardware.numCoresPerSocket") or 1) result: VMConfigDict = { "name": vm.get("name", ""), "vmid": vm["config.instanceUuid"], "vcpus": vcpus, "memory": int(vm.get("config.hardware.memoryMB") or 0), "os_type": vm.get("config.guestId", ""), "boot_order": boot_order, "disks": _disks(vm, boot_order), "nics": _nics(vm, index), "description": vm.get("config.annotation", ""), "tags": [], "os_name": vm.get("config.guestFullName", ""), "sockets": max(vcpus // cores, 1), "cores_per_socket": cores, "firmware": vm.get("config.firmware", "bios"), "passthrough": [ {"slot": dev.label(d), "kind": kind, "config": dev.summary(d)} for d in dev.devices(vm) if (kind := dev.passthrough_kind(d)) ], } if vm.get("config.version"): result["machine"] = vm["config.version"] return result