Skip to content

Commit afe256f

Browse files
aarnaudtenthirtyam
authored andcommitted
feat: add vgpu to vm resource
Add a new option `shared-pci-device-id` to the `virtual machine` resource. This enables users to 1 or more vGPU to the VM as an update to the resource or during the clone operation.
1 parent b3eeb8e commit afe256f

File tree

3 files changed

+452
-252
lines changed

3 files changed

+452
-252
lines changed

vsphere/internal/virtualdevice/virtual_machine_device_subresource.go

Lines changed: 146 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1018,7 +1018,7 @@ func (c *pciApplyConfig) modifyVirtualPciDevices(devList *schema.Set, op types.V
10181018
}
10191019

10201020
// PciPassthroughApplyOperation checks for changes in a virtual machine's
1021-
// PCI passthrough devices and creates config specs to apply apply to the
1021+
// PCI passthrough devices and creates config specs to apply to the
10221022
// virtual machine.
10231023
func PciPassthroughApplyOperation(d *schema.ResourceData, c *govmomi.Client, l object.VirtualDeviceList) (object.VirtualDeviceList, []types.BaseVirtualDeviceConfigSpec, error) {
10241024
old, newValue := d.GetChange("pci_device_id")
@@ -1095,3 +1095,148 @@ func PciPassthroughPostCloneOperation(d *schema.ResourceData, c *govmomi.Client,
10951095
}
10961096
return applyConfig.VirtualDevice, applyConfig.Spec, nil
10971097
}
1098+
1099+
// modifyVirtualSharedPciDevices will take a list of devices and an operation and
1100+
// will create the appropriate config spec.
1101+
func (c *pciApplyConfig) modifyVirtualSharedPciDevices(devList *schema.Set, op types.VirtualDeviceConfigSpecOperation) error {
1102+
log.Printf("VirtualMachine: Creating Shared PCI device specs %v", op)
1103+
for _, devId := range devList.List() {
1104+
log.Printf("[DEBUG] modifyVirtualSharedPciDevices: Appending %v spec for %s", op, devId.(string))
1105+
1106+
dev := &types.VirtualPCIPassthrough{
1107+
VirtualDevice: types.VirtualDevice{
1108+
DynamicData: types.DynamicData{},
1109+
Backing: &types.VirtualPCIPassthroughVmiopBackingInfo{
1110+
Vgpu: devId.(string),
1111+
},
1112+
},
1113+
}
1114+
1115+
vm, err := virtualmachine.FromUUID(c.Client, c.ResourceData.Id())
1116+
if err != nil {
1117+
return err
1118+
}
1119+
1120+
vprops, err := virtualmachine.Properties(vm)
1121+
if err != nil {
1122+
return err
1123+
}
1124+
1125+
// This will only find a device for delete operations.
1126+
for _, vmDevP := range vprops.Config.Hardware.Device {
1127+
if vmDev, ok := vmDevP.(*types.VirtualPCIPassthrough); ok {
1128+
if vmDev.Backing.(*types.VirtualPCIPassthroughVmiopBackingInfo).Vgpu == devId {
1129+
dev = vmDev
1130+
}
1131+
}
1132+
}
1133+
1134+
dspec, err := object.VirtualDeviceList{dev}.ConfigSpec(op)
1135+
if err != nil {
1136+
return err
1137+
}
1138+
1139+
c.Spec = append(c.Spec, dspec...)
1140+
c.VirtualDevice = applyDeviceChange(c.VirtualDevice, dspec)
1141+
}
1142+
log.Printf("VirtualMachine: Shared PCI device specs created")
1143+
return nil
1144+
}
1145+
1146+
// SharedPciApplyOperation checks for changes in a virtual machine's
1147+
// Shared PCI device and creates config specs to apply to the
1148+
// virtual machine.
1149+
func SharedPciApplyOperation(d *schema.ResourceData, c *govmomi.Client, l object.VirtualDeviceList) (object.VirtualDeviceList, []types.BaseVirtualDeviceConfigSpec, error) {
1150+
log.Printf("[DEBUG] SharedPciApplyOperation: Looking for shared PCI device changes")
1151+
1152+
// Get current (old) and new devices
1153+
old, newValue := d.GetChange("shared_pci_device_id")
1154+
oldDevIds := old.(*schema.Set)
1155+
newDevIds := newValue.(*schema.Set)
1156+
1157+
// Compare
1158+
delDevs := oldDevIds.Difference(newDevIds)
1159+
addDevs := newDevIds.Difference(oldDevIds)
1160+
1161+
// Create base apply config
1162+
applyConfig := &pciApplyConfig{
1163+
Client: c,
1164+
ResourceData: d,
1165+
Spec: []types.BaseVirtualDeviceConfigSpec{},
1166+
VirtualDevice: l,
1167+
}
1168+
1169+
// If there are no changes, return as is
1170+
if addDevs.Len() == 0 && delDevs.Len() == 0 {
1171+
log.Printf("[DEBUG] SharedPciApplyOperation: No shared PCI device additions/deletions")
1172+
return applyConfig.VirtualDevice, applyConfig.Spec, nil
1173+
}
1174+
1175+
// Set reboot
1176+
_ = d.Set("reboot_required", true)
1177+
1178+
// Add new Shared PCI devices
1179+
log.Printf("[DEBUG] SharedPciApplyOperation: Identified %d shared PCI device additions",
1180+
addDevs.Len())
1181+
err := applyConfig.modifyVirtualSharedPciDevices(addDevs, types.VirtualDeviceConfigSpecOperationAdd)
1182+
if err != nil {
1183+
return nil, nil, err
1184+
}
1185+
1186+
// Remove deleted Shared PCI devices
1187+
log.Printf("[DEBUG] SharedPciApplyOperation: Identified %d shared PCI device deletions",
1188+
delDevs.Len())
1189+
err = applyConfig.modifyVirtualSharedPciDevices(delDevs, types.VirtualDeviceConfigSpecOperationRemove)
1190+
if err != nil {
1191+
return nil, nil, err
1192+
}
1193+
1194+
return applyConfig.VirtualDevice, applyConfig.Spec, nil
1195+
}
1196+
1197+
// SharedPciPostCloneOperation normalizes the Shared PCI devices
1198+
// on a newly-cloned virtual machine and outputs any necessary device change
1199+
// operations. It also sets the state in advance of the post-create read.
1200+
func SharedPciPostCloneOperation(d *schema.ResourceData, c *govmomi.Client, l object.VirtualDeviceList) (object.VirtualDeviceList, []types.BaseVirtualDeviceConfigSpec, error) {
1201+
log.Printf("[DEBUG] SharedPCIPostCloneOperation: Looking for shared PCI device changes post-clone")
1202+
1203+
// Get current (old) and new devices
1204+
old, newValue := d.GetChange("shared_pci_device_id")
1205+
oldDevIds := old.(*schema.Set)
1206+
newDevIds := newValue.(*schema.Set)
1207+
1208+
// Compare
1209+
delDevs := oldDevIds.Difference(newDevIds)
1210+
addDevs := newDevIds.Difference(oldDevIds)
1211+
1212+
// Create base apply config
1213+
applyConfig := &pciApplyConfig{
1214+
Client: c,
1215+
ResourceData: d,
1216+
Spec: []types.BaseVirtualDeviceConfigSpec{},
1217+
VirtualDevice: l,
1218+
}
1219+
1220+
// If there are no changes, return as is
1221+
if addDevs.Len() <= 0 && delDevs.Len() <= 0 {
1222+
log.Printf("[DEBUG] SharedPCIPostCloneOperation: No shared PCI device additions/deletions post-clone")
1223+
return applyConfig.VirtualDevice, applyConfig.Spec, nil
1224+
}
1225+
1226+
// Add new Shared PCI devices
1227+
log.Printf("[DEBUG] SharedPCIPostCloneOperation: Identified %d shared PCI device additions post-clone",
1228+
addDevs.Len())
1229+
err := applyConfig.modifyVirtualSharedPciDevices(addDevs, types.VirtualDeviceConfigSpecOperationAdd)
1230+
if err != nil {
1231+
return nil, nil, err
1232+
}
1233+
1234+
// Remove deleted Shared PCI devices
1235+
log.Printf("[DEBUG] SharedPCIPostCloneOperation: Identified %d shared PCI device deletions post-clone",
1236+
delDevs.Len())
1237+
err = applyConfig.modifyVirtualSharedPciDevices(delDevs, types.VirtualDeviceConfigSpecOperationRemove)
1238+
if err != nil {
1239+
return nil, nil, err
1240+
}
1241+
return applyConfig.VirtualDevice, applyConfig.Spec, nil
1242+
}

vsphere/resource_vsphere_virtual_machine.go

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ import (
77
"context"
88
"errors"
99
"fmt"
10-
"github.com/hashicorp/terraform-provider-vsphere/vsphere/internal/helper/guestoscustomizations"
1110
"log"
1211
"net"
1312
"os"
1413
"path/filepath"
1514
"strings"
1615
"time"
1716

17+
"github.com/hashicorp/terraform-provider-vsphere/vsphere/internal/helper/guestoscustomizations"
18+
1819
"github.com/hashicorp/terraform-provider-vsphere/vsphere/internal/helper/contentlibrary"
1920
"github.com/hashicorp/terraform-provider-vsphere/vsphere/internal/helper/ovfdeploy"
2021

@@ -244,6 +245,12 @@ func resourceVSphereVirtualMachine() *schema.Resource {
244245
Description: "A list of PCI passthrough devices",
245246
Elem: &schema.Schema{Type: schema.TypeString},
246247
},
248+
"shared_pci_device_id": {
249+
Type: schema.TypeSet,
250+
Optional: true,
251+
Description: "A list of Shared PCI passthrough device, 'grid_rtx8000-8q'",
252+
Elem: &schema.Schema{Type: schema.TypeString},
253+
},
247254
"clone": {
248255
Type: schema.TypeList,
249256
Optional: true,
@@ -530,20 +537,34 @@ func resourceVSphereVirtualMachineRead(d *schema.ResourceData, meta interface{})
530537

531538
// Read the virtual machine PCI passthrough devices
532539
var pciDevs []string
540+
var sharedPciDevs []string
533541
for _, dev := range vprops.Config.Hardware.Device {
534542
if pci, ok := dev.(*types.VirtualPCIPassthrough); ok {
535-
if pciBacking, ok := pci.Backing.(*types.VirtualPCIPassthroughDeviceBackingInfo); ok {
536-
devId := pciBacking.Id
543+
switch t := pci.Backing.(type) {
544+
case *types.VirtualPCIPassthroughDeviceBackingInfo:
545+
devId := t.Id
537546
pciDevs = append(pciDevs, devId)
538-
} else {
539-
log.Printf("[DEBUG] %s: PCI passthrough device %q has no backing ID", resourceVSphereVirtualMachineIDString(d), pci.GetVirtualDevice().DeviceInfo.GetDescription())
547+
log.Printf("[DEBUG] Identified VM %q VirtualPCIPassthrough device %s with backing type of %T",
548+
vm.InventoryPath, devId, pci.Backing)
549+
case *types.VirtualPCIPassthroughVmiopBackingInfo:
550+
dev := t.Vgpu
551+
sharedPciDevs = append(sharedPciDevs, dev)
552+
log.Printf("[DEBUG] Identified VM %q VirtualPCIPassthrough device %s with backing type of %T",
553+
vm.InventoryPath, dev, pci.Backing)
554+
default:
555+
log.Printf("[WARN] Ignoring VM %q VirtualPCIPassthrough device with backing type of %T",
556+
vm.InventoryPath, pci.Backing)
540557
}
541558
}
542559
}
543560
err = d.Set("pci_device_id", pciDevs)
544561
if err != nil {
545562
return err
546563
}
564+
err = d.Set("shared_pci_device_id", sharedPciDevs)
565+
if err != nil {
566+
return err
567+
}
547568

548569
// Perform pending device read operations.
549570
devices := object.VirtualDeviceList(vprops.Config.Hardware.Device)
@@ -1685,6 +1706,17 @@ func resourceVSphereVirtualMachinePostDeployChanges(d *schema.ResourceData, meta
16851706
)
16861707
}
16871708
cfgSpec.DeviceChange = virtualdevice.AppendDeviceChangeSpec(cfgSpec.DeviceChange, delta...)
1709+
// Shared PCI devices
1710+
devices, delta, err = virtualdevice.SharedPciPostCloneOperation(d, client, devices)
1711+
if err != nil {
1712+
return resourceVSphereVirtualMachineRollbackCreate(
1713+
d,
1714+
meta,
1715+
vm,
1716+
fmt.Errorf("error processing shared PCI device changes post-clone: %s", err),
1717+
)
1718+
}
1719+
cfgSpec.DeviceChange = virtualdevice.AppendDeviceChangeSpec(cfgSpec.DeviceChange, delta...)
16881720
log.Printf("[DEBUG] %s: Final device list: %s", resourceVSphereVirtualMachineIDString(d), virtualdevice.DeviceListString(devices))
16891721
log.Printf("[DEBUG] %s: Final device change cfgSpec: %s", resourceVSphereVirtualMachineIDString(d), virtualdevice.DeviceChangeString(cfgSpec.DeviceChange))
16901722

@@ -1988,6 +2020,12 @@ func applyVirtualDevices(d *schema.ResourceData, c *govmomi.Client, l object.Vir
19882020
return nil, err
19892021
}
19902022
spec = virtualdevice.AppendDeviceChangeSpec(spec, delta...)
2023+
// Shared PCI device
2024+
l, delta, err = virtualdevice.SharedPciApplyOperation(d, c, l)
2025+
if err != nil {
2026+
return nil, err
2027+
}
2028+
spec = virtualdevice.AppendDeviceChangeSpec(spec, delta...)
19912029
log.Printf("[DEBUG] %s: Final device list: %s", resourceVSphereVirtualMachineIDString(d), virtualdevice.DeviceListString(l))
19922030
log.Printf("[DEBUG] %s: Final device change spec: %s", resourceVSphereVirtualMachineIDString(d), virtualdevice.DeviceChangeString(spec))
19932031
return spec, nil

0 commit comments

Comments
 (0)