Skip to content

Commit

Permalink
feat:r/vsphere_virtual_machine add usb controller
Browse files Browse the repository at this point in the history
Add the ability to add usb controller on build and modification of virtual machine.

Signed-off-by: Jared Burns <jared.burns@broadcom.com>
  • Loading branch information
burnsjared0415 committed Oct 9, 2024
1 parent adf6714 commit 647a6a0
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 0 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# <!-- markdownlint-disable first-line-h1 no-inline-html -->

## 2.10.0 (Not Released)

FEATURES:

- `resource/vsphere_virtual_machine`: Adds ability to add `usb_controller` to virtual machine on creation or clone.
[#2280](https://github.com/hashicorp/terraform-provider-vsphere/pull/2280)
- `data/vsphere_virtual_machine`: Adds ability read `usb_controller` on virtual machine; will return `true` or `false` based on the configuration.
[#2280](https://github.com/hashicorp/terraform-provider-vsphere/pull/2280)

## 2.9.3 (October 8, 2024)

BUG FIX:
Expand Down
15 changes: 15 additions & 0 deletions vsphere/data_source_vsphere_virtual_machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ func dataSourceVSphereVirtualMachine() *schema.Resource {
Computed: true,
Description: "Instance UUID of this virtual machine.",
},
"usb_controller": {
Type: schema.TypeBool,
Computed: true,
Description: "Indicates whether a virtual USB controller device is present on the virtual machine.",
},
}

// Merge the VirtualMachineConfig structure so that we can include the number of
Expand Down Expand Up @@ -283,6 +288,16 @@ func dataSourceVSphereVirtualMachineRead(d *schema.ResourceData, meta interface{
return fmt.Errorf("error setting guest IP addresses: %s", err)
}
}

var isUSBPresent bool
for _, dev := range props.Config.Hardware.Device {
if _, ok := dev.(*types.VirtualUSBController); ok {
isUSBPresent = true
break
}
}
_ = d.Set("usb_controller", isUSBPresent)

log.Printf("[DEBUG] VM search for %q completed successfully (UUID %q)", name, props.Config.Uuid)
return nil
}
118 changes: 118 additions & 0 deletions vsphere/resource_vsphere_virtual_machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,23 @@ func resourceVSphereVirtualMachine() *schema.Resource {
Computed: true,
Description: "The power state of the virtual machine.",
},
"usb_controller": {
Type: schema.TypeList,
Optional: true,
Description: "A specification for a USB controller on the virtual machine.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"usb_version": {
Type: schema.TypeString,
Optional: true,
Default: "2.0",
Description: "The version of the USB controller.",
ValidateFunc: validation.StringInSlice([]string{"2.0", "3.1"}, false),
},
},
},
},

vSphereTagAttributeKey: tagsSchema(),
customattribute.ConfigKey: customattribute.ConfigSchema(),
}
Expand Down Expand Up @@ -594,6 +611,16 @@ func resourceVSphereVirtualMachineRead(d *schema.ResourceData, meta interface{})
d.Set("power_state", "suspended")
}

// Get USB Controller information
var isUSBPresent bool
for _, dev := range vprops.Config.Hardware.Device {
if _, ok := dev.(*types.VirtualUSBController); ok {
isUSBPresent = true
break
}
}
_ = d.Set("usb_controller", isUSBPresent)

log.Printf("[DEBUG] %s: Read complete", resourceVSphereVirtualMachineIDString(d))
return nil
}
Expand Down Expand Up @@ -708,6 +735,57 @@ func resourceVSphereVirtualMachineUpdate(d *schema.ResourceData, meta interface{
if spec.DeviceChange, err = applyVirtualDevices(d, client, devices); err != nil {
return err
}

// Add USB controller
if d.HasChange("usb_controller") {
usb := d.Get("usb_controller").([]interface{})
if len(usb) == 0 {
return fmt.Errorf("usb_controller is empty")
}

// Initialize a key counter
keyCounter := -100

for _, usbControllerInterface := range usb {
usbController := usbControllerInterface.(map[string]interface{})
usbVersion := usbController["usb_version"].(string)

var ehciEnabled *bool
var device types.BaseVirtualDevice

switch usbVersion {
case "2.0":
enabled := true
ehciEnabled = &enabled
device = &types.VirtualUSBController{
VirtualController: types.VirtualController{
VirtualDevice: types.VirtualDevice{
Key: int32(keyCounter),
},
},
EhciEnabled: ehciEnabled,
}
case "3.1":
device = &types.VirtualUSBXHCIController{
VirtualController: types.VirtualController{
VirtualDevice: types.VirtualDevice{
Key: int32(keyCounter),
},
},
}
default:
return fmt.Errorf("unsupported USB version: %s", usbVersion)
}

spec.DeviceChange = append(spec.DeviceChange, &types.VirtualDeviceConfigSpec{
Operation: types.VirtualDeviceConfigSpecOperationAdd,
Device: device,
})

// Increment the key counter for the next device
keyCounter--
}
}
// Only carry out the reconfigure if we actually have a change to process.
cv := virtualmachine.GetHardwareVersionNumber(vprops.Config.Version)
tv := d.Get("hardware_version").(int)
Expand Down Expand Up @@ -1366,6 +1444,46 @@ func resourceVSphereVirtualMachineCreateBareStandard(
VmPathName: fmt.Sprintf("[%s]", ds.Name()),
}

// Add USB controller
if usb, ok := d.GetOk("usb_controller"); ok && len(usb.([]interface{})) > 0 {
for _, usbControllerInterface := range usb.([]interface{}) {
usbController := usbControllerInterface.(map[string]interface{})
usbVersion := usbController["usb_version"].(string)

var ehciEnabled *bool
var device types.BaseVirtualDevice

switch usbVersion {
case "2.0":
enabled := true
ehciEnabled = &enabled
device = &types.VirtualUSBController{
VirtualController: types.VirtualController{
VirtualDevice: types.VirtualDevice{
Key: -1,
},
},
EhciEnabled: ehciEnabled,
}
case "3.1":
device = &types.VirtualUSBXHCIController{
VirtualController: types.VirtualController{
VirtualDevice: types.VirtualDevice{
Key: -1,
},
},
}
default:
return nil, fmt.Errorf("unsupported USB version: %s", usbVersion)
}

spec.DeviceChange = append(spec.DeviceChange, &types.VirtualDeviceConfigSpec{
Operation: types.VirtualDeviceConfigSpecOperationAdd,
Device: device,
})
}
}

timeout := meta.(*Client).timeout
vm, err := virtualmachine.Create(client, fo, spec, pool, hs, timeout)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions website/docs/d/virtual_machine.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ The following attributes are exported:
the VM is powered off, this value will be blank.
* `guest_ip_addresses` - A list of IP addresses as reported by VMware Tools.
* `instance_uuid` - The instance UUID of the virtual machine or template.
* `usb_controller` - Indicates whether a virtual USB controller device is present on the virtual machine.

~> **NOTE:** Keep in mind when using the results of `scsi_type` and
`network_interface_types`, that the `vsphere_virtual_machine` resource only
Expand Down
19 changes: 19 additions & 0 deletions website/docs/r/virtual_machine.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -1518,6 +1518,25 @@ When cloning from a template, there are additional requirements in both the reso

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.


## USB Controller

When creating a virtual machine or cloning one from a template, you have the option to add a virtual usb controller Module device.

**Example**:

```hcl
resource "vsphere_virtual_machine" "vm" {
# ... other configuration ...
usb_controller {
usb_version = "3.1"
}
# ... other configuration ...
}
```

~> **NOTE:** Supported versions include 2.0 or 3.0. This setting is only available on new builds and reconfiguration to add a usb controller module; removal is not supported in the provider.

## Virtual Machine Migration

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.
Expand Down

0 comments on commit 647a6a0

Please sign in to comment.