create_vm: add CD/DVD drive with optional ISO boot

Previously created VMs had no CD/DVD drive, so attach_iso failed with
'No CD/DVD drive found' and there was no way to install a guest from an
ISO. create_vm now always adds a CD/DVD drive on the default IDE
controller. New optional args iso_path/iso_datastore back the drive with
an ISO and boot_from_iso puts the CD/DVD first in the boot order, giving
MCP clients a complete create-and-install-from-ISO path.
This commit is contained in:
Ryan Malloy 2026-06-08 04:08:15 -06:00
parent c93c97a0de
commit 7888494efb

View File

@ -99,7 +99,7 @@ class VMLifecycleMixin(MCPMixin):
@mcp_tool(
name="create_vm",
description="Create a new virtual machine with specified resources",
description="Create a new virtual machine with specified resources and a CD/DVD drive (optionally booting from an ISO)",
annotations=ToolAnnotations(destructiveHint=False, idempotentHint=False),
)
def create_vm(
@ -111,8 +111,28 @@ class VMLifecycleMixin(MCPMixin):
datastore: str | None = None,
network: str | None = None,
guest_id: str = "otherGuest64",
iso_path: str | None = None,
iso_datastore: str | None = None,
boot_from_iso: bool = True,
) -> str:
"""Create a new virtual machine with specified configuration."""
"""Create a new virtual machine with specified configuration.
The VM always gets a CD/DVD drive. If ``iso_path`` is given, the drive
is backed by that ISO and connected at power-on; otherwise it is an
empty client device (so ``attach_iso`` can mount media later).
Args:
name: VM name
cpu: vCPU count
memory_mb: Memory in MB
disk_gb: Primary disk size in GB
datastore: Datastore for the VM (default: largest available)
network: Port group for the NIC (default: configured network)
guest_id: vSphere guest OS identifier
iso_path: ISO path on a datastore (e.g. 'iso/ubuntu.iso') to mount in the CD/DVD drive
iso_datastore: Datastore holding the ISO (default: the VM's datastore)
boot_from_iso: When an ISO is given, put the CD/DVD first in the boot order
"""
# Resolve datastore
datastore_obj = self.conn.datastore
if datastore:
@ -195,6 +215,40 @@ class VMLifecycleMixin(MCPMixin):
)
device_specs.append(nic_spec)
# Add a CD/DVD drive on the default IDE controller (vSphere auto-creates
# IDE controller key 200). Backed by an ISO if one was requested,
# otherwise an empty client device so media can be mounted later.
cdrom_spec = vim.vm.device.VirtualDeviceSpec()
cdrom_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
cdrom_spec.device = vim.vm.device.VirtualCdrom()
cdrom_spec.device.controllerKey = 200
cdrom_spec.device.unitNumber = 0
cdrom_spec.device.key = -2
connectable = vim.vm.device.VirtualDevice.ConnectInfo()
connectable.allowGuestControl = True
connectable.connected = False
if iso_path:
iso_ds = iso_datastore or datastore_obj.name
backing = vim.vm.device.VirtualCdrom.IsoBackingInfo()
backing.fileName = f"[{iso_ds}] {iso_path}"
connectable.startConnected = True
else:
backing = vim.vm.device.VirtualCdrom.RemotePassthroughBackingInfo()
backing.deviceName = ""
backing.exclusive = False
connectable.startConnected = False
cdrom_spec.device.backing = backing
cdrom_spec.device.connectable = connectable
device_specs.append(cdrom_spec)
# Boot from the CD/DVD first when installing from an ISO
if iso_path and boot_from_iso:
vm_spec.bootOptions = vim.vm.BootOptions(
bootOrder=[vim.vm.BootOptions.BootableCdromDevice()]
)
vm_spec.deviceChange = device_specs
# Create VM