Repository: vmware/govmomi
Pull request #2772 (2022-03-02 17:39:06)

api: add GPU support to VirtualDeviceList.SelectByBackingInfo
## Description

Simplify finding VM GPU devices with `VirtualDeviceList.SelectByBackingInfo` and add example.

Closes: #2769

## Type of change

Please mark options that are relevant:

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to
  not work as expected)
- [ ] This change requires a documentation update
- [ ] Build related change

## Checklist:

- [x] My code follows the CONTRIBUTION [guidelines](./../CONTRIBUTING.md) of
  this project
- [x] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] I have added tests that prove my fix is effective or that my feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged


Patch:
diff --git a/object/virtual_device_list.go b/object/virtual_device_list.go
index 65265453..39eae0d5 100644
--- a/object/virtual_device_list.go
+++ b/object/virtual_device_list.go
@@ -157,6 +157,25 @@ func (l VirtualDeviceList) SelectByBackingInfo(backing types.BaseVirtualDeviceBa
 		case types.BaseVirtualDeviceFileBackingInfo:
 			b := backing.(types.BaseVirtualDeviceFileBackingInfo)
 			return a.GetVirtualDeviceFileBackingInfo().FileName == b.GetVirtualDeviceFileBackingInfo().FileName
+		case *types.VirtualPCIPassthroughVmiopBackingInfo:
+			b := backing.(*types.VirtualPCIPassthroughVmiopBackingInfo)
+			return a.Vgpu == b.Vgpu
+		case *types.VirtualPCIPassthroughDynamicBackingInfo:
+			b := backing.(*types.VirtualPCIPassthroughDynamicBackingInfo)
+			if b.CustomLabel != "" && b.CustomLabel != a.CustomLabel {
+				return false
+			}
+			if len(b.AllowedDevice) == 0 {
+				return true
+			}
+			for _, x := range a.AllowedDevice {
+				for _, y := range b.AllowedDevice {
+					if x.DeviceId == y.DeviceId && x.VendorId == y.VendorId {
+						return true
+					}
+				}
+			}
+			return false
 		default:
 			return false
 		}


Test patch:
diff --git a/object/example_test.go b/object/example_test.go
index be22e77d..addcf4da 100644
--- a/object/example_test.go
+++ b/object/example_test.go
@@ -536,6 +536,60 @@ func ExampleNetworkReference_EthernetCardBackingInfo() {
 	// Output: 1 of 2 NICs match backing
 }
 
+func ExampleVirtualDeviceList_SelectByBackingInfo() {
+	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
+		finder := find.NewFinder(c)
+		vm, err := finder.VirtualMachine(ctx, "DC0_H0_VM0")
+		if err != nil {
+			return err
+		}
+
+		backing := &types.VirtualPCIPassthroughVmiopBackingInfo{
+			Vgpu: "grid_v100-4q",
+		}
+
+		gpu := &types.VirtualPCIPassthrough{
+			VirtualDevice: types.VirtualDevice{Backing: backing},
+		}
+
+		err = vm.AddDevice(ctx, gpu) // add a GPU to this VM
+		if err != nil {
+			return err
+		}
+
+		device, err := vm.Device(ctx) // get the VM's virtual device list
+		if err != nil {
+			return err
+		}
+
+		// find the device with the given backing info
+		gpus := device.SelectByBackingInfo(backing)
+
+		name := gpus[0].(*types.VirtualPCIPassthrough).Backing.(*types.VirtualPCIPassthroughVmiopBackingInfo).Vgpu
+
+		fmt.Println(name)
+
+		// example alternative to using SelectByBackingInfo for the use-case above:
+		for i := range device {
+			switch d := device[i].(type) {
+			case *types.VirtualPCIPassthrough:
+				switch b := d.Backing.(type) {
+				case *types.VirtualPCIPassthroughVmiopBackingInfo:
+					if b.Vgpu == backing.Vgpu {
+						fmt.Println(b.Vgpu)
+					}
+				}
+			}
+		}
+
+		return nil
+	})
+
+	// Output:
+	// grid_v100-4q
+	// grid_v100-4q
+}
+
 // Find a VirtualMachine's Cluster
 func ExampleVirtualMachine_resourcePoolOwner() {
 	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
diff --git a/object/virtual_device_list_test.go b/object/virtual_device_list_test.go
index a50867f0..b0e11175 100644
--- a/object/virtual_device_list_test.go
+++ b/object/virtual_device_list_test.go
@@ -455,6 +455,50 @@ var devices = VirtualDeviceList([]types.BaseVirtualDevice{
 		},
 		YieldOnPoll: true,
 	},
+	&types.VirtualPCIPassthrough{
+		VirtualDevice: types.VirtualDevice{
+			Key: 13000,
+			DeviceInfo: &types.Description{
+				Label:   "PCI device 0",
+				Summary: "NVIDIA GRID vGPU grid_v100-4q",
+			},
+			Backing: &types.VirtualPCIPassthroughVmiopBackingInfo{
+				VirtualPCIPassthroughPluginBackingInfo: types.VirtualPCIPassthroughPluginBackingInfo{},
+				Vgpu:                                   "grid_v100-4q",
+				MigrateSupported:                       (*bool)(nil),
+			},
+			Connectable: (*types.VirtualDeviceConnectInfo)(nil),
+			SlotInfo: &types.VirtualDevicePciBusSlotInfo{
+				VirtualDeviceBusSlotInfo: types.VirtualDeviceBusSlotInfo{},
+				PciSlotNumber:            33,
+			},
+			ControllerKey: 100,
+			UnitNumber:    types.NewInt32(18),
+		},
+	},
+	&types.VirtualPCIPassthrough{
+		VirtualDevice: types.VirtualDevice{
+			Key: 14000,
+			DeviceInfo: &types.Description{
+				Label:   "PCI device 1",
+				Summary: "NVIDIA GPU",
+			},
+			Backing: &types.VirtualPCIPassthroughDynamicBackingInfo{
+				AllowedDevice: []types.VirtualPCIPassthroughAllowedDevice{{
+					VendorId: int32(111),
+					DeviceId: int32(222),
+				}},
+				CustomLabel: "mygpu",
+			},
+			Connectable: (*types.VirtualDeviceConnectInfo)(nil),
+			SlotInfo: &types.VirtualDevicePciBusSlotInfo{
+				VirtualDeviceBusSlotInfo: types.VirtualDeviceBusSlotInfo{},
+				PciSlotNumber:            34,
+			},
+			ControllerKey: 100,
+			UnitNumber:    types.NewInt32(19),
+		},
+	},
 })
 
 func TestSelectByType(t *testing.T) {
@@ -540,6 +584,20 @@ func TestSelectByBackingInfo(t *testing.T) {
 			},
 		},
 		(*types.VirtualSerialPortURIBackingInfo)(nil),
+		&types.VirtualPCIPassthroughVmiopBackingInfo{
+			Vgpu: "grid_v100-4q",
+		},
+		(*types.VirtualPCIPassthroughVmiopBackingInfo)(nil),
+		(*types.VirtualPCIPassthroughDynamicBackingInfo)(nil),
+		&types.VirtualPCIPassthroughDynamicBackingInfo{
+			CustomLabel: "mygpu",
+		},
+		&types.VirtualPCIPassthroughDynamicBackingInfo{
+			AllowedDevice: []types.VirtualPCIPassthroughAllowedDevice{{
+				VendorId: int32(111),
+				DeviceId: int32(222),
+			}},
+		},
 	}
 
 	for _, test := range tests {