Skip to content

Commit

Permalink
feat: add vgpu to vm resource
Browse files Browse the repository at this point in the history
  • Loading branch information
mristok authored and tenthirtyam committed Apr 29, 2024
1 parent 69f2bdd commit 0abcb2c
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 50 deletions.
167 changes: 126 additions & 41 deletions vsphere/internal/virtualdevice/virtual_machine_device_subresource.go
Original file line number Diff line number Diff line change
Expand Up @@ -1018,7 +1018,7 @@ func (c *pciApplyConfig) modifyVirtualPciDevices(devList *schema.Set, op types.V
}

// PciPassthroughApplyOperation checks for changes in a virtual machine's
// PCI passthrough devices and creates config specs to apply apply to the
// PCI passthrough devices and creates config specs to apply to the
// virtual machine.
func PciPassthroughApplyOperation(d *schema.ResourceData, c *govmomi.Client, l object.VirtualDeviceList) (object.VirtualDeviceList, []types.BaseVirtualDeviceConfigSpec, error) {
old, newValue := d.GetChange("pci_device_id")
Expand Down Expand Up @@ -1096,62 +1096,147 @@ 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)
// modifyVirtualSharedPciDevices will take a list of devices and an operation and
// will create the appropriate config spec.
func (c *pciApplyConfig) modifyVirtualSharedPciDevices(devList *schema.Set, op types.VirtualDeviceConfigSpecOperation) error {
log.Printf("VirtualMachine: Creating Shared PCI device specs %v", op)
for _, devId := range devList.List() {
log.Printf("[DEBUG] modifyVirtualSharedPciDevices: Appending %v spec for %s", op, devId.(string))

var specs []types.BaseVirtualDeviceConfigSpec
if oldDevId == newDevId {
return l, specs, nil
}
dev := &types.VirtualPCIPassthrough{
VirtualDevice: types.VirtualDevice{
DynamicData: types.DynamicData{},
Backing: &types.VirtualPCIPassthroughVmiopBackingInfo{
Vgpu: devId.(string),
},
},
}

if oldDevId != "" {
vm, err := virtualmachine.FromUUID(c, d.Id())
vm, err := virtualmachine.FromUUID(c.Client, c.ResourceData.Id())
if err != nil {
return nil, nil, err
return err
}

vprops, err := virtualmachine.Properties(vm)
if err != nil {
return nil, nil, err
return 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 vmDev.Backing.(*types.VirtualPCIPassthroughVmiopBackingInfo).Vgpu == devId {
dev = vmDev
}
}
}
}

if newDevId != "" {
dev := &types.VirtualPCIPassthrough{
VirtualDevice: types.VirtualDevice{
DynamicData: types.DynamicData{},
Backing: &types.VirtualPCIPassthroughVmiopBackingInfo{
Vgpu: newDevId,
},
},
}
dspec, err := object.VirtualDeviceList{dev}.ConfigSpec(types.VirtualDeviceConfigSpecOperationAdd)
dspec, err := object.VirtualDeviceList{dev}.ConfigSpec(op)
if err != nil {
return nil, nil, err
return err
}
specs = append(specs, dspec...)
l = applyDeviceChange(l, dspec)
d.Set("reboot_required", true)

c.Spec = append(c.Spec, dspec...)
c.VirtualDevice = applyDeviceChange(c.VirtualDevice, dspec)
}
log.Printf("VirtualMachine: Shared PCI device specs created")
return nil
}

// SharedPciApplyOperation checks for changes in a virtual machine's
// Shared PCI device and creates config specs to apply to the
// virtual machine.
func SharedPciApplyOperation(d *schema.ResourceData, c *govmomi.Client, l object.VirtualDeviceList) (object.VirtualDeviceList, []types.BaseVirtualDeviceConfigSpec, error) {
log.Printf("[DEBUG] SharedPciApplyOperation: Looking for shared PCI device changes")

// Get current (old) and new devices
old, newValue := d.GetChange("shared_pci_device_id")
oldDevIds := old.(*schema.Set)
newDevIds := newValue.(*schema.Set)

// Compare
delDevs := oldDevIds.Difference(newDevIds)
addDevs := newDevIds.Difference(oldDevIds)

// Create base apply config
applyConfig := &pciApplyConfig{
Client: c,
ResourceData: d,
Spec: []types.BaseVirtualDeviceConfigSpec{},
VirtualDevice: l,
}

// If there are no changes, return as is
if addDevs.Len() == 0 && delDevs.Len() == 0 {
log.Printf("[DEBUG] SharedPciApplyOperation: No shared PCI device additions/deletions")
return applyConfig.VirtualDevice, applyConfig.Spec, nil
}

// Set reboot
_ = d.Set("reboot_required", true)

// Add new Shared PCI devices
log.Printf("[DEBUG] SharedPciApplyOperation: Identified %d shared PCI device additions",
addDevs.Len())
err := applyConfig.modifyVirtualSharedPciDevices(addDevs, types.VirtualDeviceConfigSpecOperationAdd)
if err != nil {
return nil, nil, err
}

return l, specs, nil
// Remove deleted Shared PCI devices
log.Printf("[DEBUG] SharedPciApplyOperation: Identified %d shared PCI device deletions",
delDevs.Len())
err = applyConfig.modifyVirtualSharedPciDevices(delDevs, types.VirtualDeviceConfigSpecOperationRemove)
if err != nil {
return nil, nil, err
}

return applyConfig.VirtualDevice, applyConfig.Spec, nil
}

// SharedPciPostCloneOperation normalizes the Shared PCI devices
// on a newly-cloned virtual machine and outputs any necessary device change
// operations. It also sets the state in advance of the post-create read.
func SharedPciPostCloneOperation(d *schema.ResourceData, c *govmomi.Client, l object.VirtualDeviceList) (object.VirtualDeviceList, []types.BaseVirtualDeviceConfigSpec, error) {
log.Printf("[DEBUG] SharedPCIPostCloneOperation: Looking for shared PCI device changes post-clone")

// Get current (old) and new devices
old, newValue := d.GetChange("shared_pci_device_id")
oldDevIds := old.(*schema.Set)
newDevIds := newValue.(*schema.Set)

// Compare
delDevs := oldDevIds.Difference(newDevIds)
addDevs := newDevIds.Difference(oldDevIds)

// Create base apply config
applyConfig := &pciApplyConfig{
Client: c,
ResourceData: d,
Spec: []types.BaseVirtualDeviceConfigSpec{},
VirtualDevice: l,
}

// If there are no changes, return as is
if addDevs.Len() <= 0 && delDevs.Len() <= 0 {
log.Printf("[DEBUG] SharedPCIPostCloneOperation: No shared PCI device additions/deletions post-clone")
return applyConfig.VirtualDevice, applyConfig.Spec, nil
}

// Add new Shared PCI devices
log.Printf("[DEBUG] SharedPCIPostCloneOperation: Identified %d shared PCI device additions post-clone",
addDevs.Len())
err := applyConfig.modifyVirtualSharedPciDevices(addDevs, types.VirtualDeviceConfigSpecOperationAdd)
if err != nil {
return nil, nil, err
}

// Remove deleted Shared PCI devices
log.Printf("[DEBUG] SharedPCIPostCloneOperation: Identified %d shared PCI device deletions post-clone",
delDevs.Len())
err = applyConfig.modifyVirtualSharedPciDevices(delDevs, types.VirtualDeviceConfigSpecOperationRemove)
if err != nil {
return nil, nil, err
}
return applyConfig.VirtualDevice, applyConfig.Spec, nil
}
19 changes: 15 additions & 4 deletions vsphere/resource_vsphere_virtual_machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,9 @@ func resourceVSphereVirtualMachine() *schema.Resource {
Elem: &schema.Schema{Type: schema.TypeString},
},
"shared_pci_device_id": {
Type: schema.TypeString,
Type: schema.TypeSet,
Optional: true,
Description: "Id of Shared PCI passthrough device, 'grid_rtx8000-8q'",
Description: "A list of Shared PCI passthrough device, 'grid_rtx8000-8q'",
Elem: &schema.Schema{Type: schema.TypeString},
},
"clone": {
Expand Down Expand Up @@ -1706,6 +1706,17 @@ func resourceVSphereVirtualMachinePostDeployChanges(d *schema.ResourceData, meta
)
}
cfgSpec.DeviceChange = virtualdevice.AppendDeviceChangeSpec(cfgSpec.DeviceChange, delta...)
// Shared PCI devices
devices, delta, err = virtualdevice.SharedPciPostCloneOperation(d, client, devices)
if err != nil {
return resourceVSphereVirtualMachineRollbackCreate(
d,
meta,
vm,
fmt.Errorf("error processing shared PCI device changes post-clone: %s", err),
)
}
cfgSpec.DeviceChange = virtualdevice.AppendDeviceChangeSpec(cfgSpec.DeviceChange, delta...)
log.Printf("[DEBUG] %s: Final device list: %s", resourceVSphereVirtualMachineIDString(d), virtualdevice.DeviceListString(devices))
log.Printf("[DEBUG] %s: Final device change cfgSpec: %s", resourceVSphereVirtualMachineIDString(d), virtualdevice.DeviceChangeString(cfgSpec.DeviceChange))

Expand Down Expand Up @@ -2009,8 +2020,8 @@ 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)
// Shared PCI device
l, delta, err = virtualdevice.SharedPciApplyOperation(d, c, l)
if err != nil {
return nil, err
}
Expand Down
14 changes: 9 additions & 5 deletions website/docs/r/virtual_machine.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,9 @@ The following options are general virtual machine and provider workflow options:

- `cdrom` - (Optional) A specification for a CD-ROM device on the virtual machine. See [CD-ROM options](#cd-rom-options) for more information.

- `clone` - (Optional) When specified, the virtual machine will be created as a clone of a specified template. Optional customization options can be submitted for the resource. See [creating a virtual machine from a template](#creating-a-virtual-machine-from-a-template) for more information.
* `clone` - (Optional) When specified, the virtual machine will be created as a clone of a specified template. Optional customization options can be submitted for the resource. See [creating a virtual machine from a template](#creating-a-virtual-machine-from-a-template) for more information.

~> **NOTE:** Cloning requires vCenter Server and is not supported on direct ESXi host connections.

- `extra_config_reboot_required` - (Optional) Allow the virtual machine to be rebooted when a change to `extra_config` occurs. Default: `true`.

Expand Down Expand Up @@ -659,15 +661,17 @@ The following options are general virtual machine and provider workflow options:

- `name` - (Required) The name of the virtual machine.

- `network_interface` - (Required) A specification for a virtual NIC on the virtual machine. See [network interface options](#network-interface-options) for more information.
* `network_interface` - (Required) A specification for a virtual NIC on the virtual machine. See [network interface options](#network-interface-options) for more information.

* `pci_device_id` - (Optional) List of host PCI device IDs in which to create PCI passthroughs.

- `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.

- `replace_trigger` - (Optional) Triggers replacement of resource whenever it changes.
* `replace_trigger` - (Optional) Triggers replacement of resource whenever it changes.

For example, `replace_trigger = sha256(format("%s-%s",data.template_file.cloud_init_metadata.rendered,data.template_file.cloud_init_userdata.rendered))` will fingerprint the changes in cloud-init metadata and userdata templates. This will enable a replacement of the resource whenever the dependant template renders a new configuration. (Forces a replacement.)

Expand All @@ -681,7 +685,7 @@ For example, `replace_trigger = sha256(format("%s-%s",data.template_file.cloud_i

- `scsi_type` - (Optional) The SCSI controller type for the virtual machine. One of `lsilogic` (LSI Logic Parallel), `lsilogic-sas` (LSI Logic SAS) or `pvscsi` (VMware Paravirtual). Default: `pvscsi`.

- `scsi_bus_sharing` - (Optional) The type of SCSI bus sharing for the virtual machine SCSI controller. One of `physicalSharing`, `virtualSharing`, and `noSharing`. Default: `noSharing`.
* `scsi_bus_sharing` - (Optional) The type of SCSI bus sharing for the virtual machine SCSI controller. One of `physicalSharing`, `virtualSharing`, and `noSharing`. Default: `noSharing`.

- `storage_policy_id` - (Optional) The ID of the storage policy to assign to the home directory of a virtual machine.

Expand Down

0 comments on commit 0abcb2c

Please sign in to comment.