diff --git a/vsphere/internal/virtualdevice/virtual_machine_device_subresource.go b/vsphere/internal/virtualdevice/virtual_machine_device_subresource.go index c5a3235de..98f5bcf01 100644 --- a/vsphere/internal/virtualdevice/virtual_machine_device_subresource.go +++ b/vsphere/internal/virtualdevice/virtual_machine_device_subresource.go @@ -1087,3 +1087,63 @@ func PciPassthroughPostCloneOperation(d *schema.ResourceData, c *govmomi.Client, } return applyConfig.VirtualDevice, applyConfig.Spec, nil } + +// SharedPciPassthroughApplyOperation checks for changes in a virtual machine's +// Shared PCI passthrough device and creates config specs to apply apply to the +// virtual machine. +func SharedPciPassthroughApplyOperation(d *schema.ResourceData, c *govmomi.Client, l object.VirtualDeviceList) (object.VirtualDeviceList, []types.BaseVirtualDeviceConfigSpec, error) { + old, new := d.GetChange("shared_pci_device_id") + oldDevId := old.(string) + newDevId := new.(string) + + var specs []types.BaseVirtualDeviceConfigSpec + if oldDevId == newDevId { + return l, specs, nil + } + + if oldDevId != "" { + vm, err := virtualmachine.FromUUID(c, d.Id()) + if err != nil { + return nil, nil, err + } + vprops, err := virtualmachine.Properties(vm) + if err != nil { + return nil, nil, err + } + // This will only find a device for delete operations. + for _, vmDevP := range vprops.Config.Hardware.Device { + if vmDev, ok := vmDevP.(*types.VirtualPCIPassthrough); ok { + if vmDev.Backing.(*types.VirtualPCIPassthroughVmiopBackingInfo).Vgpu == oldDevId { + dspec, err := object.VirtualDeviceList{vmDev}.ConfigSpec(types.VirtualDeviceConfigSpecOperationRemove) + if err != nil { + return nil, nil, err + } + specs = append(specs, dspec...) + + l = applyDeviceChange(l, dspec) + d.Set("reboot_required", true) + } + } + } + } + + if newDevId != "" { + dev := &types.VirtualPCIPassthrough{ + VirtualDevice: types.VirtualDevice{ + DynamicData: types.DynamicData{}, + Backing: &types.VirtualPCIPassthroughVmiopBackingInfo{ + Vgpu: newDevId, + }, + }, + } + dspec, err := object.VirtualDeviceList{dev}.ConfigSpec(types.VirtualDeviceConfigSpecOperationAdd) + if err != nil { + return nil, nil, err + } + specs = append(specs, dspec...) + l = applyDeviceChange(l, dspec) + d.Set("reboot_required", true) + } + + return l, specs, nil +} diff --git a/vsphere/resource_vsphere_virtual_machine.go b/vsphere/resource_vsphere_virtual_machine.go index 654e93033..2aad36955 100644 --- a/vsphere/resource_vsphere_virtual_machine.go +++ b/vsphere/resource_vsphere_virtual_machine.go @@ -239,6 +239,12 @@ func resourceVSphereVirtualMachine() *schema.Resource { Description: "A list of PCI passthrough devices", Elem: &schema.Schema{Type: schema.TypeString}, }, + "shared_pci_device_id": { + Type: schema.TypeString, + Optional: true, + Description: "Id of Shared PCI passthrough device, 'grid_rtx8000-8q'", + Elem: &schema.Schema{Type: schema.TypeString}, + }, "clone": { Type: schema.TypeList, Optional: true, @@ -516,7 +522,15 @@ func resourceVSphereVirtualMachineRead(d *schema.ResourceData, meta interface{}) devId := pciBacking.Id pciDevs = append(pciDevs, devId) } else { - log.Printf("[DEBUG] %s: PCI passthrough device %q has no backing ID", resourceVSphereVirtualMachineIDString(d), pci.GetVirtualDevice().DeviceInfo.GetDescription()) + if pciBacking, ok := pci.Backing.(*types.VirtualPCIPassthroughVmiopBackingInfo); ok { + err = d.Set("shared_pci_device_id", pciBacking.Vgpu) + if err != nil { + return err + } + } else { + log.Printf("[WARN] Ignoring VM %q VirtualPCIPassthrough device with backing type of %T", + vm.InventoryPath, pci.Backing) + } } } } @@ -1888,6 +1902,12 @@ func applyVirtualDevices(d *schema.ResourceData, c *govmomi.Client, l object.Vir return nil, err } spec = virtualdevice.AppendDeviceChangeSpec(spec, delta...) + // Shared PCI passthrough device + l, delta, err = virtualdevice.SharedPciPassthroughApplyOperation(d, c, l) + if err != nil { + return nil, err + } + spec = virtualdevice.AppendDeviceChangeSpec(spec, delta...) log.Printf("[DEBUG] %s: Final device list: %s", resourceVSphereVirtualMachineIDString(d), virtualdevice.DeviceListString(l)) log.Printf("[DEBUG] %s: Final device change spec: %s", resourceVSphereVirtualMachineIDString(d), virtualdevice.DeviceChangeString(spec)) return spec, nil diff --git a/website/docs/r/virtual_machine.html.markdown b/website/docs/r/virtual_machine.html.markdown index c638fd389..311eb7450 100644 --- a/website/docs/r/virtual_machine.html.markdown +++ b/website/docs/r/virtual_machine.html.markdown @@ -662,6 +662,8 @@ The following options are general virtual machine and provider workflow options: * `pci_device_id` - (Optional) List of host PCI device IDs in which to create PCI passthroughs. +* `shared_pci_device_id` - (Optional) A shared PCI device ID to create PCI passthrough. + ~> **NOTE:** Cloning requires vCenter Server and is not supported on direct ESXi host connections. * `ovf_deploy` - (Optional) When specified, the virtual machine will be deployed from the provided OVF/OVA template. See [creating a virtual machine from an OVF/OVA template](#creating-a-virtual-machine-from-an-ovf-ova-template) for more information.