Skip to content

Commit 6feba9c

Browse files
feat:r/vsphere_virtual_machine add usb controller
Add the ability to add usb controller on build and modification of virtual machine. Signed-off-by: Jared Burns <[email protected]>
1 parent adf6714 commit 6feba9c

File tree

5 files changed

+162
-0
lines changed

5 files changed

+162
-0
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# <!-- markdownlint-disable first-line-h1 no-inline-html -->
22

3+
## 2.10.0 (Not Released)
4+
5+
FEATURES:
6+
7+
- `resource/vsphere_virtual_machine`: Adds ability to add `usb_controller` to virtual machine on creation or clone.
8+
[#2280](https://github.com/hashicorp/terraform-provider-vsphere/pull/2280)
9+
- `data/vsphere_virtual_machine`: Adds ability read `usb_controller` on virtual machine; will return `true` or `false` based on the configuration.
10+
[#2280](https://github.com/hashicorp/terraform-provider-vsphere/pull/2280)
11+
312
## 2.9.3 (October 8, 2024)
413

514
BUG FIX:

vsphere/data_source_vsphere_virtual_machine.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,11 @@ func dataSourceVSphereVirtualMachine() *schema.Resource {
165165
Computed: true,
166166
Description: "Instance UUID of this virtual machine.",
167167
},
168+
"usb_controller": {
169+
Type: schema.TypeBool,
170+
Computed: true,
171+
Description: "Indicates whether a virtual USB controller device is present on the virtual machine.",
172+
},
168173
}
169174

170175
// Merge the VirtualMachineConfig structure so that we can include the number of
@@ -283,6 +288,16 @@ func dataSourceVSphereVirtualMachineRead(d *schema.ResourceData, meta interface{
283288
return fmt.Errorf("error setting guest IP addresses: %s", err)
284289
}
285290
}
291+
292+
var isUSBPresent bool
293+
for _, dev := range props.Config.Hardware.Device {
294+
if _, ok := dev.(*types.VirtualUSBController); ok {
295+
isUSBPresent = true
296+
break
297+
}
298+
}
299+
_ = d.Set("usb_controller", isUSBPresent)
300+
286301
log.Printf("[DEBUG] VM search for %q completed successfully (UUID %q)", name, props.Config.Uuid)
287302
return nil
288303
}

vsphere/resource_vsphere_virtual_machine.go

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,23 @@ func resourceVSphereVirtualMachine() *schema.Resource {
283283
Computed: true,
284284
Description: "The power state of the virtual machine.",
285285
},
286+
"usb_controller": {
287+
Type: schema.TypeList,
288+
Optional: true,
289+
Description: "A specification for a USB controller on the virtual machine.",
290+
Elem: &schema.Resource{
291+
Schema: map[string]*schema.Schema{
292+
"usb_version": {
293+
Type: schema.TypeString,
294+
Optional: true,
295+
Default: "2.0",
296+
Description: "The version of the USB controller.",
297+
ValidateFunc: validation.StringInSlice([]string{"2.0", "3.1"}, false),
298+
},
299+
},
300+
},
301+
},
302+
286303
vSphereTagAttributeKey: tagsSchema(),
287304
customattribute.ConfigKey: customattribute.ConfigSchema(),
288305
}
@@ -594,6 +611,16 @@ func resourceVSphereVirtualMachineRead(d *schema.ResourceData, meta interface{})
594611
d.Set("power_state", "suspended")
595612
}
596613

614+
// Get USB Controller information
615+
var isUSBPresent bool
616+
for _, dev := range vprops.Config.Hardware.Device {
617+
if _, ok := dev.(*types.VirtualUSBController); ok {
618+
isUSBPresent = true
619+
break
620+
}
621+
}
622+
_ = d.Set("usb_controller", isUSBPresent)
623+
597624
log.Printf("[DEBUG] %s: Read complete", resourceVSphereVirtualMachineIDString(d))
598625
return nil
599626
}
@@ -708,6 +735,57 @@ func resourceVSphereVirtualMachineUpdate(d *schema.ResourceData, meta interface{
708735
if spec.DeviceChange, err = applyVirtualDevices(d, client, devices); err != nil {
709736
return err
710737
}
738+
739+
// Add USB controller
740+
if d.HasChange("usb_controller") {
741+
usb := d.Get("usb_controller").([]interface{})
742+
if len(usb) == 0 {
743+
return fmt.Errorf("usb_controller is empty")
744+
}
745+
746+
// Initialize a key counter
747+
keyCounter := -100
748+
749+
for _, usbControllerInterface := range usb {
750+
usbController := usbControllerInterface.(map[string]interface{})
751+
usbVersion := usbController["usb_version"].(string)
752+
753+
var ehciEnabled *bool
754+
var device types.BaseVirtualDevice
755+
756+
switch usbVersion {
757+
case "2.0":
758+
enabled := true
759+
ehciEnabled = &enabled
760+
device = &types.VirtualUSBController{
761+
VirtualController: types.VirtualController{
762+
VirtualDevice: types.VirtualDevice{
763+
Key: int32(keyCounter),
764+
},
765+
},
766+
EhciEnabled: ehciEnabled,
767+
}
768+
case "3.1":
769+
device = &types.VirtualUSBXHCIController{
770+
VirtualController: types.VirtualController{
771+
VirtualDevice: types.VirtualDevice{
772+
Key: int32(keyCounter),
773+
},
774+
},
775+
}
776+
default:
777+
return fmt.Errorf("unsupported USB version: %s", usbVersion)
778+
}
779+
780+
spec.DeviceChange = append(spec.DeviceChange, &types.VirtualDeviceConfigSpec{
781+
Operation: types.VirtualDeviceConfigSpecOperationAdd,
782+
Device: device,
783+
})
784+
785+
// Increment the key counter for the next device
786+
keyCounter--
787+
}
788+
}
711789
// Only carry out the reconfigure if we actually have a change to process.
712790
cv := virtualmachine.GetHardwareVersionNumber(vprops.Config.Version)
713791
tv := d.Get("hardware_version").(int)
@@ -1366,6 +1444,46 @@ func resourceVSphereVirtualMachineCreateBareStandard(
13661444
VmPathName: fmt.Sprintf("[%s]", ds.Name()),
13671445
}
13681446

1447+
// Add USB controller
1448+
if usb, ok := d.GetOk("usb_controller"); ok && len(usb.([]interface{})) > 0 {
1449+
for _, usbControllerInterface := range usb.([]interface{}) {
1450+
usbController := usbControllerInterface.(map[string]interface{})
1451+
usbVersion := usbController["usb_version"].(string)
1452+
1453+
var ehciEnabled *bool
1454+
var device types.BaseVirtualDevice
1455+
1456+
switch usbVersion {
1457+
case "2.0":
1458+
enabled := true
1459+
ehciEnabled = &enabled
1460+
device = &types.VirtualUSBController{
1461+
VirtualController: types.VirtualController{
1462+
VirtualDevice: types.VirtualDevice{
1463+
Key: -1,
1464+
},
1465+
},
1466+
EhciEnabled: ehciEnabled,
1467+
}
1468+
case "3.1":
1469+
device = &types.VirtualUSBXHCIController{
1470+
VirtualController: types.VirtualController{
1471+
VirtualDevice: types.VirtualDevice{
1472+
Key: -1,
1473+
},
1474+
},
1475+
}
1476+
default:
1477+
return nil, fmt.Errorf("unsupported USB version: %s", usbVersion)
1478+
}
1479+
1480+
spec.DeviceChange = append(spec.DeviceChange, &types.VirtualDeviceConfigSpec{
1481+
Operation: types.VirtualDeviceConfigSpecOperationAdd,
1482+
Device: device,
1483+
})
1484+
}
1485+
}
1486+
13691487
timeout := meta.(*Client).timeout
13701488
vm, err := virtualmachine.Create(client, fo, spec, pool, hs, timeout)
13711489
if err != nil {

website/docs/d/virtual_machine.html.markdown

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ The following attributes are exported:
159159
the VM is powered off, this value will be blank.
160160
* `guest_ip_addresses` - A list of IP addresses as reported by VMware Tools.
161161
* `instance_uuid` - The instance UUID of the virtual machine or template.
162+
* `usb_controller` - Indicates whether a virtual USB controller device is present on the virtual machine.
162163

163164
~> **NOTE:** Keep in mind when using the results of `scsi_type` and
164165
`network_interface_types`, that the `vsphere_virtual_machine` resource only

website/docs/r/virtual_machine.html.markdown

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1518,6 +1518,25 @@ When cloning from a template, there are additional requirements in both the reso
15181518

15191519
You can use the [`vsphere_virtual_machine`][tf-vsphere-virtual-machine-ds] data source, which provides disk attributes, network interface types, SCSI bus types, and the guest ID of the source template, to return this information. See the section on [cloning and customization](#cloning-and-customization) for more information.
15201520

1521+
1522+
## USB Controller
1523+
1524+
When creating a virtual machine or cloning one from a template, you have the option to add a virtual USB controller device.
1525+
1526+
**Example**:
1527+
1528+
```hcl
1529+
resource "vsphere_virtual_machine" "vm" {
1530+
# ... other configuration ...
1531+
usb_controller {
1532+
usb_version = "3.1"
1533+
}
1534+
# ... other configuration ...
1535+
}
1536+
```
1537+
1538+
~> **NOTE:** Supported versions include 2.0 or 3.1. This setting is only available on new builds and reconfiguration to add a USB controller; removal is not supported in the provider.
1539+
15211540
## Virtual Machine Migration
15221541

15231542
The `vsphere_virtual_machine` resource supports live migration both on the host and storage level. You can migrate the virtual machine to another host, cluster, resource pool, or datastore. You can also migrate or pin a virtual disk to a specific datastore.

0 commit comments

Comments
 (0)