diff --git a/simulator/esx/virtual_device.go b/simulator/esx/virtual_device.go index 01ce2e81d..0e906ff1d 100644 --- a/simulator/esx/virtual_device.go +++ b/simulator/esx/virtual_device.go @@ -6,193 +6,156 @@ package esx import "github.com/vmware/govmomi/vim25/types" -// VirtualDevice is the default set of VirtualDevice types created for a VirtualMachine -// Capture method: -// -// govc vm.create foo -// govc object.collect -s -dump vm/foo config.hardware.device -var VirtualDevice = []types.BaseVirtualDevice{ - &types.VirtualIDEController{ - VirtualController: types.VirtualController{ - VirtualDevice: types.VirtualDevice{ - DynamicData: types.DynamicData{}, - Key: 200, - DeviceInfo: &types.Description{ - DynamicData: types.DynamicData{}, - Label: "IDE 0", - Summary: "IDE 0", - }, - Backing: nil, - Connectable: (*types.VirtualDeviceConnectInfo)(nil), - SlotInfo: nil, - ControllerKey: 0, - UnitNumber: (*int32)(nil), - }, - BusNumber: 0, - Device: nil, - }, - }, - &types.VirtualIDEController{ - VirtualController: types.VirtualController{ - VirtualDevice: types.VirtualDevice{ - DynamicData: types.DynamicData{}, - Key: 201, - DeviceInfo: &types.Description{ - DynamicData: types.DynamicData{}, - Label: "IDE 1", - Summary: "IDE 1", - }, - Backing: nil, - Connectable: (*types.VirtualDeviceConnectInfo)(nil), - SlotInfo: nil, - ControllerKey: 0, - UnitNumber: (*int32)(nil), - }, - BusNumber: 1, - Device: nil, - }, - }, - &types.VirtualPS2Controller{ - VirtualController: types.VirtualController{ - VirtualDevice: types.VirtualDevice{ - DynamicData: types.DynamicData{}, - Key: 300, - DeviceInfo: &types.Description{ - DynamicData: types.DynamicData{}, - Label: "PS2 controller 0", - Summary: "PS2 controller 0", - }, - Backing: nil, - Connectable: (*types.VirtualDeviceConnectInfo)(nil), - SlotInfo: nil, - ControllerKey: 0, - UnitNumber: (*int32)(nil), +const ( + VirtualMachineDefaultDevicePCIControllerKey = int32(100) + VirtualMachineDefaultDevicePS2ControllerKey = int32(300) +) + +var VirtualMachineDefaultDevicePCIController = &types.VirtualPCIController{ + VirtualController: types.VirtualController{ + VirtualDevice: types.VirtualDevice{ + Key: VirtualMachineDefaultDevicePCIControllerKey, + DeviceInfo: &types.Description{ + Label: "PCI controller 0", + Summary: "PCI controller 0", }, - BusNumber: 0, - Device: []int32{600, 700}, }, - }, - &types.VirtualPCIController{ - VirtualController: types.VirtualController{ - VirtualDevice: types.VirtualDevice{ - DynamicData: types.DynamicData{}, - Key: 100, - DeviceInfo: &types.Description{ - DynamicData: types.DynamicData{}, - Label: "PCI controller 0", - Summary: "PCI controller 0", - }, - Backing: nil, - Connectable: (*types.VirtualDeviceConnectInfo)(nil), - SlotInfo: nil, - ControllerKey: 0, - UnitNumber: (*int32)(nil), - }, - BusNumber: 0, - Device: []int32{500, 12000}, + Device: []int32{ + VirtualMachineDefaultDeviceVideoCard.Key, + VirtualMachineDefaultDeviceVMCIDevice.Key, }, }, - &types.VirtualSIOController{ - VirtualController: types.VirtualController{ - VirtualDevice: types.VirtualDevice{ - DynamicData: types.DynamicData{}, - Key: 400, - DeviceInfo: &types.Description{ - DynamicData: types.DynamicData{}, - Label: "SIO controller 0", - Summary: "SIO controller 0", - }, - Backing: nil, - Connectable: (*types.VirtualDeviceConnectInfo)(nil), - SlotInfo: nil, - ControllerKey: 0, - UnitNumber: (*int32)(nil), +} + +var VirtualMachineDefaultDeviceIDEControllerBus0 = &types.VirtualIDEController{ + VirtualController: types.VirtualController{ + VirtualDevice: types.VirtualDevice{ + Key: 200, + DeviceInfo: &types.Description{ + Label: "IDE 0", + Summary: "IDE 0", }, - BusNumber: 0, - Device: nil, }, + BusNumber: 0, }, - &types.VirtualKeyboard{ +} + +var VirtualMachineDefaultDeviceIDEControllerBus1 = &types.VirtualIDEController{ + VirtualController: types.VirtualController{ VirtualDevice: types.VirtualDevice{ - DynamicData: types.DynamicData{}, - Key: 600, + Key: 201, DeviceInfo: &types.Description{ - DynamicData: types.DynamicData{}, - Label: "Keyboard ", - Summary: "Keyboard", + Label: "IDE 1", + Summary: "IDE 1", }, - Backing: nil, - Connectable: (*types.VirtualDeviceConnectInfo)(nil), - SlotInfo: nil, - ControllerKey: 300, - UnitNumber: types.NewInt32(0), }, + BusNumber: 1, }, - &types.VirtualPointingDevice{ +} + +var VirtualMachineDefaultDevicePS2Controller = &types.VirtualPS2Controller{ + VirtualController: types.VirtualController{ VirtualDevice: types.VirtualDevice{ - DynamicData: types.DynamicData{}, - Key: 700, + Key: VirtualMachineDefaultDevicePS2ControllerKey, DeviceInfo: &types.Description{ - DynamicData: types.DynamicData{}, - Label: "Pointing device", - Summary: "Pointing device; Device", - }, - Backing: &types.VirtualPointingDeviceDeviceBackingInfo{ - VirtualDeviceDeviceBackingInfo: types.VirtualDeviceDeviceBackingInfo{ - VirtualDeviceBackingInfo: types.VirtualDeviceBackingInfo{}, - DeviceName: "", - UseAutoDetect: types.NewBool(false), - }, - HostPointingDevice: "autodetect", + Label: "PS2 controller 0", + Summary: "PS2 controller 0", }, - Connectable: (*types.VirtualDeviceConnectInfo)(nil), - SlotInfo: nil, - ControllerKey: 300, - UnitNumber: types.NewInt32(1), + }, + Device: []int32{ + VirtualMachineDefaultDeviceVirtualKeyboard.Key, + VirtualMachineDefaultDeviceVirtualPointingDevice.Key, }, }, - &types.VirtualMachineVideoCard{ +} + +var VirtualMachineDefaultDeviceSIOController = &types.VirtualSIOController{ + VirtualController: types.VirtualController{ VirtualDevice: types.VirtualDevice{ - DynamicData: types.DynamicData{}, - Key: 500, + Key: 400, DeviceInfo: &types.Description{ - DynamicData: types.DynamicData{}, - Label: "Video card ", - Summary: "Video card", + Label: "SIO controller 0", + Summary: "SIO controller 0", }, - Backing: nil, - Connectable: (*types.VirtualDeviceConnectInfo)(nil), - SlotInfo: nil, - ControllerKey: 100, - UnitNumber: types.NewInt32(0), }, - VideoRamSizeInKB: 4096, - NumDisplays: 1, - UseAutoDetect: types.NewBool(false), - Enable3DSupport: types.NewBool(false), - Use3dRenderer: "automatic", - GraphicsMemorySizeInKB: 262144, }, - &types.VirtualMachineVMCIDevice{ - VirtualDevice: types.VirtualDevice{ - DynamicData: types.DynamicData{}, - Key: 12000, - DeviceInfo: &types.Description{ - DynamicData: types.DynamicData{}, - Label: "VMCI device", - Summary: "Device on the virtual machine PCI bus that provides support for the virtual machine communication interface", +} +var VirtualMachineDefaultDeviceVirtualKeyboard = &types.VirtualKeyboard{ + VirtualDevice: types.VirtualDevice{ + Key: 600, + DeviceInfo: &types.Description{ + Label: "Keyboard ", + Summary: "Keyboard", + }, + ControllerKey: VirtualMachineDefaultDevicePS2ControllerKey, + UnitNumber: types.NewInt32(0), + }, +} +var VirtualMachineDefaultDeviceVirtualPointingDevice = &types.VirtualPointingDevice{ + VirtualDevice: types.VirtualDevice{ + Key: 700, + DeviceInfo: &types.Description{ + Label: "Pointing device", + Summary: "Pointing device; Device", + }, + Backing: &types.VirtualPointingDeviceDeviceBackingInfo{ + VirtualDeviceDeviceBackingInfo: types.VirtualDeviceDeviceBackingInfo{ + UseAutoDetect: types.NewBool(false), }, - Backing: nil, - Connectable: (*types.VirtualDeviceConnectInfo)(nil), - SlotInfo: nil, - ControllerKey: 100, - UnitNumber: types.NewInt32(17), + HostPointingDevice: "autodetect", + }, + ControllerKey: VirtualMachineDefaultDevicePS2ControllerKey, + UnitNumber: types.NewInt32(1), + }, +} +var VirtualMachineDefaultDeviceVideoCard = &types.VirtualMachineVideoCard{ + VirtualDevice: types.VirtualDevice{ + Key: 500, + DeviceInfo: &types.Description{ + Label: "Video card ", + Summary: "Video card", + }, + ControllerKey: VirtualMachineDefaultDevicePCIControllerKey, + UnitNumber: types.NewInt32(0), + }, + VideoRamSizeInKB: 4096, + NumDisplays: 1, + UseAutoDetect: types.NewBool(false), + Enable3DSupport: types.NewBool(false), + Use3dRenderer: "automatic", + GraphicsMemorySizeInKB: 262144, +} + +var VirtualMachineDefaultDeviceVMCIDevice = &types.VirtualMachineVMCIDevice{ + VirtualDevice: types.VirtualDevice{ + Key: 12000, + DeviceInfo: &types.Description{ + Label: "VMCI device", + Summary: "Device on the virtual machine PCI bus that provides support for the virtual machine communication interface", }, - Id: -1, - AllowUnrestrictedCommunication: types.NewBool(false), - FilterEnable: types.NewBool(true), - FilterInfo: (*types.VirtualMachineVMCIDeviceFilterInfo)(nil), + ControllerKey: VirtualMachineDefaultDevicePCIControllerKey, + UnitNumber: types.NewInt32(17), }, + Id: -1, + AllowUnrestrictedCommunication: types.NewBool(false), + FilterEnable: types.NewBool(true), +} + +// VirtualDevice is the default set of VirtualDevice types created for a VirtualMachine +// Capture method: +// +// govc vm.create foo +// govc object.collect -s -dump vm/foo config.hardware.device +var VirtualDevice = []types.BaseVirtualDevice{ + VirtualMachineDefaultDevicePCIController, + VirtualMachineDefaultDeviceIDEControllerBus0, + VirtualMachineDefaultDeviceIDEControllerBus1, + VirtualMachineDefaultDevicePS2Controller, + VirtualMachineDefaultDeviceSIOController, + VirtualMachineDefaultDeviceVirtualKeyboard, + VirtualMachineDefaultDeviceVirtualPointingDevice, + VirtualMachineDefaultDeviceVideoCard, + VirtualMachineDefaultDeviceVMCIDevice, } // EthernetCard template for types.VirtualEthernetCard diff --git a/simulator/virtual_machine.go b/simulator/virtual_machine.go index bb55d62d3..d99199c20 100644 --- a/simulator/virtual_machine.go +++ b/simulator/virtual_machine.go @@ -142,8 +142,8 @@ func NewVirtualMachine(ctx *Context, parent types.ManagedObjectReference, spec * }, } - // Add the default devices - defaults.DeviceChange, _ = object.VirtualDeviceList(esx.VirtualDevice).ConfigSpec(types.VirtualDeviceConfigSpecOperationAdd) + // Add the default devices. + vm.addDefaultDevices(&defaults, spec) err := vm.configure(ctx, &defaults) if err != nil { @@ -168,6 +168,98 @@ func NewVirtualMachine(ctx *Context, parent types.ManagedObjectReference, spec * return vm, nil } +func (o VirtualMachine) addDefaultDevices( + dst, src *types.VirtualMachineConfigSpec) { + + var ( + oldControllerKeysToNew = map[int32]int32{} + existingDefaultDeviceMap = map[int32]struct{}{} + ) + + for i := range src.DeviceChange { + var ( + dc = src.DeviceChange[i] + vd = dc.GetVirtualDeviceConfigSpec() + de = vd.Device.GetVirtualDevice() + oldKey = de.Key + ) + + fn := func(bvd types.BaseVirtualDevice) { + d := bvd.GetVirtualDevice() + vd.Device = bvd + existingDefaultDeviceMap[d.Key] = struct{}{} + dst.DeviceChange = append(dst.DeviceChange, dc) + if _, ok := bvd.(types.BaseVirtualController); ok { + oldControllerKeysToNew[oldKey] = d.Key + } + } + + switch td := vd.Device.(type) { + case *types.VirtualIDEController: + switch td.BusNumber { + case 0: + fn(esx.VirtualMachineDefaultDeviceIDEControllerBus0) + case 1: + fn(esx.VirtualMachineDefaultDeviceIDEControllerBus1) + } + case *types.VirtualPS2Controller: + fn(esx.VirtualMachineDefaultDevicePS2Controller) + case *types.VirtualPCIController: + fn(esx.VirtualMachineDefaultDevicePCIController) + case *types.VirtualSIOController: + fn(esx.VirtualMachineDefaultDeviceSIOController) + case *types.VirtualKeyboard: + fn(esx.VirtualMachineDefaultDeviceVirtualKeyboard) + case *types.VirtualPointingDevice: + fn(esx.VirtualMachineDefaultDeviceVirtualPointingDevice) + case *types.VirtualMachineVideoCard: + fn(esx.VirtualMachineDefaultDeviceVideoCard) + case *types.VirtualMachineVMCIDevice: + fn(esx.VirtualMachineDefaultDeviceVMCIDevice) + } + } + + // Add any of the missing default devices. + for i := range esx.VirtualDevice { + vd := esx.VirtualDevice[i].GetVirtualDevice() + if _, ok := existingDefaultDeviceMap[vd.Key]; !ok { + dst.DeviceChange = append( + dst.DeviceChange, + &types.VirtualDeviceConfigSpec{ + Operation: types.VirtualDeviceConfigSpecOperationAdd, + Device: esx.VirtualDevice[i], + }) + } + } + + // Remove the default devices from the source config spec so they are not + // added twice. + src.DeviceChange = slices.DeleteFunc( + src.DeviceChange, + func(bdc types.BaseVirtualDeviceConfigSpec) bool { + var ( + vd = bdc.GetVirtualDeviceConfigSpec() + de = vd.Device.GetVirtualDevice() + ) + _, ok := existingDefaultDeviceMap[de.Key] + return ok + }) + + // Update the source config spec so any children point to any updated + // controller keys. + for i := range src.DeviceChange { + var ( + dc = src.DeviceChange[i] + vd = dc.GetVirtualDeviceConfigSpec() + de = vd.Device.GetVirtualDevice() + ck = de.ControllerKey + ) + if nk, ok := oldControllerKeysToNew[ck]; ok { + de.ControllerKey = nk + } + } +} + func (o *VirtualMachine) RenameTask(ctx *Context, r *types.Rename_Task) soap.HasFault { return RenameTask(ctx, o, r) } diff --git a/simulator/virtual_machine_test.go b/simulator/virtual_machine_test.go index 402bd4032..091572212 100644 --- a/simulator/virtual_machine_test.go +++ b/simulator/virtual_machine_test.go @@ -1331,6 +1331,9 @@ func TestCreateVmWithDevices(t *testing.T) { vm := m.Map().Get(info.Result.(types.ManagedObjectReference)).(*VirtualMachine) expect := len(esx.VirtualDevice) + len(devices) + + expect-- // Do not double-count the IDE controller as it's a default device. + ndevice := len(vm.Config.Hardware.Device) if expect != ndevice {