From 3e435e3d5f11a44be7950381746fb389a57a3510 Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Mon, 8 Jun 2026 06:12:20 -0600 Subject: [PATCH] Add set_boot_order tool Set a VM's BIOS boot device order on an existing VM, e.g. set_boot_order(name, ['cdrom','disk']) to boot an installer first, or ['disk','cdrom'] post-install. Maps cdrom/disk/ethernet/floppy to the corresponding Bootable*Device, resolving disk/NIC device keys. Host-aware. --- src/mcvsphere/mixins/vm_lifecycle.py | 68 ++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/mcvsphere/mixins/vm_lifecycle.py b/src/mcvsphere/mixins/vm_lifecycle.py index f3873cb..311bc26 100644 --- a/src/mcvsphere/mixins/vm_lifecycle.py +++ b/src/mcvsphere/mixins/vm_lifecycle.py @@ -394,3 +394,71 @@ class VMLifecycleMixin(VSphereMixin): conn.wait_for_task(task) return f"VM renamed from '{name}' to '{new_name}'" + + @mcp_tool( + name="set_boot_order", + description="Set a VM's BIOS boot device order (e.g. ['cdrom','disk'])", + annotations=ToolAnnotations(destructiveHint=True, idempotentHint=True), + ) + def set_boot_order( + self, name: str, order: list[str], host: str | None = None + ) -> dict[str, Any]: + """Set the VM's boot device order. + + Args: + name: VM name + order: Boot devices in priority order. Each entry is one of: + 'cdrom' (CD/DVD), 'disk' (hard disk), 'ethernet'/'network' (PXE), + or 'floppy'. Devices not listed are tried after those listed. + host: Managed ESXi host to target (default: the default host) + + Returns: + Dict with the applied boot order + """ + conn = self._conn(host) + vm = conn.find_vm(name) + if not vm: + raise ValueError(f"VM '{name}' not found") + + disk_key = next( + (d.key for d in vm.config.hardware.device + if isinstance(d, vim.vm.device.VirtualDisk)), + None, + ) + nic_key = next( + (d.key for d in vm.config.hardware.device + if isinstance(d, vim.vm.device.VirtualEthernetCard)), + None, + ) + + boot_devices = [] + for item in order: + kind = item.strip().lower() + if kind in ("cdrom", "cd", "dvd"): + boot_devices.append(vim.vm.BootOptions.BootableCdromDevice()) + elif kind in ("disk", "hdd", "hd"): + if disk_key is None: + raise ValueError("VM has no virtual disk to boot from") + boot_devices.append( + vim.vm.BootOptions.BootableDiskDevice(deviceKey=disk_key) + ) + elif kind in ("ethernet", "nic", "network", "pxe"): + if nic_key is None: + raise ValueError("VM has no network adapter to boot from") + boot_devices.append( + vim.vm.BootOptions.BootableEthernetDevice(deviceKey=nic_key) + ) + elif kind in ("floppy", "fd"): + boot_devices.append(vim.vm.BootOptions.BootableFloppyDevice()) + else: + raise ValueError( + f"Unknown boot device '{item}'. Use cdrom/disk/ethernet/floppy." + ) + + config_spec = vim.vm.ConfigSpec( + bootOptions=vim.vm.BootOptions(bootOrder=boot_devices) + ) + task = vm.ReconfigVM_Task(spec=config_spec) + conn.wait_for_task(task) + + return {"vm": name, "boot_order": [d.strip().lower() for d in order]}