Search code examples
vmwarepyvmomi

Listing valid controllerKey values with pyVmomi


I'm using some example code to attach a new disk to a virtual machine as I create it using pyVmomi. Right now I have the controllerKey hardcoded to 200 (which happens to be an IDE controller in my setup--I have no idea how consistent this value is across installations).

I would like to remove the hardcoded controller key, giving the user a choice between IDE and SCSI controllers at the very least.

Does anyone know how to get a list of valid VirtualController keys?

For posterity, the example code I'm using is as follows:

def create_virtual_disk(capacity, controller_key, unit_number, in_bytes=False):
    """
    :param capacity: Capacity of new disk in Bytes
    :param unit_number: device unit
    :return:
    """
    virtual_disk = vim.vm.device.VirtualDisk()
    if in_bytes:
        virtual_disk.capacityInBytes = capacity
    else:
        virtual_disk.capacityInKB = capacity

    # Verify this.
    virtual_disk.unitNumber = unit_number
    virtual_disk.controllerKey = controller_key

    # backing info
    virtual_disk_backing_info = vim.vm.device.VirtualDisk.FlatVer2BackingInfo()
    virtual_disk_backing_info.diskMode = "persistent"
    virtual_disk_backing_info.thinProvisioned = True

    # assigning backing info to virtual disk device backing
    virtual_disk.backing = virtual_disk_backing_info

    # creating virtualdevice spec and assigning recently created virtual disk
    virtual_disk_spec = vim.vm.device.VirtualDeviceSpec()
    virtual_disk_spec.device = virtual_disk
    virtual_disk_spec.fileOperation = "create"
    virtual_disk_spec.operation = "add"

    return virtual_disk_spec

Solution

  • short story: For details see a,b,or c. The general recommendation is to stick with either a) or a hardcoded list of controllerKeys for a specific vmware hardware model as it is faster than c) (big size response) and less of a hustle to implement.

    a) find controllerkey from existing devicespec

    Our codebase tends to only add device-types that are already present in our vms therefore the following snippet is pretty much sufficient for us and might be as well for you:

    Get the key from an already existing controller of type==ctrl_type

    def _find_controller(self, ctrl_type, max_devs=None):
            for dev in self._machine._vm.config.hardware.device:
                if isinstance(dev, ctrl_type):
                    if not max_devs or len(dev.device) < max_devs:
                        return dev
    
            raise ControllerNotFoundException(ctrl_type)
    

    a concrete use case for this is to add another IDE type CDRom (this is only added to the referenced spec and committed all at once later):

    def _add_cdrom(self, spec, path):
        spec.device.controllerKey = self._find_controller(vim.vm.device.VirtualIDEController, max_devs=2).key
        dev = VSphereMediaDevice(spec.device, self._machine)
        dev._spec.device.backing = vim.vm.device.VirtualCdrom.IsoBackingInfo()
        dev.mount(path)
        spec.device.backing = dev._spec.device.backing
    

    b) list of valid controllerkeys for your hw version

    have a look at /etc/vmware/hostd/env/vmconfigoption-esx-hw8.xml (esxi, defaults for hardware version 8 vms) which contains all available controllerKeys for a specific vmware hardware version. The controllerKeys are pretty consistent for a hardware version but there is always the unlikely possibility that it will change in future versions.

    <deviceInfo>
      <_type>vim.Description</_type>
      <label>VirtualIDEController 0</label>
      <summary>VirtualIDEController 0</summary>
    </deviceInfo>
    <key>200</key>
    

    c) list vmconfigoptions via SOAP

    The following SOAP request is executed whenever a new virtual machine is created via vsphere client. Its response contains hardware-profiles (win8, win7, winlonghorn, ...) with controllerKeys to most of the devices. But I guess this may be kind of an overkill if you'll have to do this many times due to the heavy response.

        POST /sdk HTTP/1.1
        User-Agent: VMware VI Client/xxx
        Content-Type: text/xml; charset="utf-8"
        SOAPAction: "urn:internalvim25/5.0"
        Host: xxx
        Cookie: vmware_soap_session="xxxx"
        Content-Length: 526
    
        ...<soap:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
            <soap:Header>
                <operationID>xxx</operationID>
            </soap:Header>
            <soap:Body>
                <QueryConfigOption xmlns="urn:internalvim25">
                    <_this xsi:type="ManagedObjectReference" type="EnvironmentBrowser" serverGuid="">ha-env-browser-vmx-08</_this>
                    <key>vmx-08</key>
                </QueryConfigOption>    
            </soap:Body>
        </soap:Envelope>
    

    response (truncated):

    HTTP/1.1 200 OK
    Date: xxx
    Cache-Control: no-cache
    Connection: Keep-Alive
    Content-Type: text/xml; charset=utf-8
    Transfer-Encoding: chunked
    
    7ED8
    <?xml version="1.0" encoding="UTF-8"?>
    <soapenv:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
     xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
     xmlns:xsd="http://www.w3.org/2001/XMLSchema"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
    <QueryConfigOptionResponse xmlns="urn:internalvim25"><returnval><version>vmx-08</version><description>Hardware version 8 virtual machine</description><guestOSDescriptor><id>windows8Server64Guest
    ....
    <defaultDevice xsi:type="VirtualIDEController"><key>200</key><deviceInfo><label>IDE 0</label><summary>IDE 0</summary></deviceInfo><busNumber>0</busNumber></defaultDevice><defaultDevice xsi:type="VirtualIDEController"><key>201</key><deviceInfo><label>IDE 1</label><summary>IDE 1</summary></deviceInfo><busNumber>1</busNumber></defaultDevice><defaultDevice xsi:type="VirtualPS2Controller"><key>300</key><deviceInfo><label>PS2 controller 0</label><summary>PS2 controller 0</summary></deviceInfo><busNumber>0</busNumber></defaultDevice><defaultDevice xsi:type="VirtualPCIController"><key>100</key><deviceInfo><label>PCI controller 0</label><summary>PCI controller 0</summary></deviceInfo><busNumber>0</busNumber></defaultDevice><defaultDevice xsi:type="VirtualSIOController"><key>400</key><deviceInfo><label>SIO controller 0</label><summary>SIO controller 0</summary></deviceInfo><busNumber>0</busNumber></defaultDevice><defaultDevice xsi:type="VirtualKeyboard"><key>600</key><deviceInfo><label>Keyboard </label><summary>Keyboard</summary></deviceInfo><controllerKey>300</controllerKey><unitNumber>0</unitNumber></defaultDevice><defaultDevice xsi:type="VirtualPointingDevice"><key>700</key><deviceInfo><label>Pointing device</label><summary>Pointing device; Device</summary></deviceInfo><backing xsi:type="VirtualPointingDeviceDeviceBackingInfo"><deviceName></deviceName><useAutoDetect>false</useAutoDetect><hostPointingDevice>autodetect</hostPointingDevice></backing><controllerKey>300</controllerKey><unitNumber>1</unitNumber></defaultDevice><defaultDevice xsi:type="VirtualMachineVideoCard"><key>500</key><deviceInfo><label>Video card </label><summary>Video card</summary></deviceInfo>