In parts one and two of this series, I looked at connecting PyVmomi to vCenter and then creating a VM. Those code segments were taken almost directly from the examples on the PyVmomi community repository. It was when I needed to add more hard drives and spread them across multiple SCSI controllers that I ran into a gap in the repository, and the Googleable experience of the Internet. It is always a bit painful when you try to undertake a task without the support of somebody else who has done it before and written about the process. After a bit of flailing around and a lot of trial and error, I was able to get a routine together for adding SCSI controllers and disks to a VM.
The first trap was that adding the multiple SCSI controllers and disks to the hardware spec before creating the VM did not work as I expected. I could specify multiple disks and controllers, but all of the disks ended up attached to the last SCSI controller. To counter this I first create the VM with one SCSI controller and it’s boot disk. Then I change the VM configuration to add a SCSI controller and two more disks. Finally, I repeat that addition (third controller & final two disks) before powering the VM on.
The second trap was that the routine to create a VM does not seem to return an object for the VM. Once again, the PyVmomi community samples repository helped me out. I needed to use an existing “get_obj” function to search for VMs and return the one with the right name.
vm = get_obj(content, [vim.VirtualMachine], vm_name)
Once I had the VM object I could create a specification that adds a SCSI controller and disk. The SCSI controller and disk specifications are exactly the same form as in the VM creation routine, just a couple of changed parameters. The SCSI controller just needs a unique bus number, the first SCSI controller is bus number 0, this one is bus number 1.
devices =  spec = vim.vm.ConfigSpec() scsi_ctr = vim.vm.device.VirtualDeviceSpec() scsi_ctr.operation = vim.vm.device.VirtualDeviceSpec.Operation.add scsi_ctr.device = vim.vm.device.ParaVirtualSCSIController() scsi_ctr.device.busNumber = 1 scsi_ctr.device.hotAddRemove = True scsi_ctr.device.sharedBus = 'noSharing' scsi_ctr.device.scsiCtlrUnitNumber = 7 devices.append(scsi_ctr)
The unique number for the SCSI disk is its Unit Number, this is the disks SCSI ID on the bus number that we defined on the controller. SCSI3 unit number can be from 0 to 15, by convention the first disk is 0, and the SCSI controller is 7. You can see the “scsiCtlrUnitNumber = 7” line above, this is the same on every SCSI controller. In my script, I need two disks on each controller, so I have two of these disk blocks, with Unit Numbers 0 and 1.
unit_number = 0 new_disk_kb = size2GB * 1024 * 1024 controller = scsi_ctr.device disk_spec = vim.vm.device.VirtualDeviceSpec() disk_spec.fileOperation = "create" disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add disk_spec.device = vim.vm.device.VirtualDisk() disk_spec.device.backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo() disk_spec.device.backing.diskMode = 'persistent' disk_spec.device.unitNumber = unit_number disk_spec.device.capacityInKB = new_disk_kb disk_spec.device.controllerKey = controller.key devices.append(disk_spec)
Once we have the device list we attach it to the task specification and create a task to reconfigure our chosen VM.
spec.deviceChange = devices task = vm.ReconfigVM_Task(spec=spec) tasks.wait_for_tasks(service_instance, [task])
Once the reconfigure task for the second SCSI controller and its two disks completes, I run the same process with a third SCSI controller as bus number 2 and two more disks as unit numbers 0 and 1 on that bus.
Once the VM create task and two hardware update tasks complete, I can power the VM on and allow it to build. In my environment, there is a PXE boot server that installs CentOS on the first boot. If you needed to use an ISO to install an operating system then you would need to define that as part of the VM.
© 2018, Alastair. All rights reserved.