Skip to content

Commit 7af9d92

Browse files
mristoktenthirtyam
authored andcommitted
feat: extend d/host_pci_device support
Add support for the `vsphere_host_pci_device` data source to return all PCI devices which share the same details.
1 parent dea5add commit 7af9d92

File tree

3 files changed

+224
-16
lines changed

3 files changed

+224
-16
lines changed

docs/data-sources/host_pci_device.md

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,20 @@ subcategory: "Host and Cluster Management"
33
page_title: "VMware vSphere: vsphere_host_pci_device"
44
sidebar_current: "docs-vsphere-data-source-host_pci_device"
55
description: |-
6-
A data source that can be used to get information for a PCI passthrough
7-
device on an ESXi host.
6+
A data source that can be used to get information for PCI passthrough
7+
device(s) on an ESXi host. The returned attribute `pci_devices` will
8+
be a list of matching PCI Passthrough devices, based on the criteria:
9+
- name_regex
10+
- class_id
11+
- vendor_id
12+
13+
**NOTE** - The matching criteria above are evaluated in that order.
814
---
915

1016
# vsphere_host_pci_device
1117

12-
The `vsphere_host_pci_device` data source can be used to discover the device ID
13-
of a vSphere host's PCI device. This can then be used with
18+
The `vsphere_host_pci_device` data source can be used to discover the device ID(s)
19+
of a vSphere host's PCI device(s). This can then be used with
1420
`vsphere_virtual_machine`'s `pci_device_id`.
1521

1622
## Example Usage with Vendor ID and Class ID
@@ -58,14 +64,34 @@ The following arguments are supported:
5864
a host.
5965
* `name_regex` - (Optional) A regular expression that will be used to match the
6066
host PCI device name.
67+
* `class_id` - (Optional) The hexadecimal PCI device class ID.
6168
* `vendor_id` - (Optional) The hexadecimal PCI device vendor ID.
62-
* `class_id` - (Optional) The hexadecimal PCI device class ID
6369

6470
[docs-about-morefs]: /docs/providers/vsphere/index.html#use-of-managed-object-references-by-the-vsphere-provider
6571

66-
~> **NOTE:** `name_regex`, `vendor_id`, and `class_id` can all be used together.
72+
~> **NOTE:** `name_regex`, `class_id`, and `vendor_id` can all be used together.
73+
The above arguments are evaluated and filter PCI Device results in the above order.
6774

6875
## Attribute Reference
6976

70-
* `id` - The device ID of the PCI device.
71-
* `name` - The name of the PCI device.
77+
The following attributes are exported:
78+
79+
* `host_id` - The [managed objectID][docs-about-morefs] of the ESXi host.
80+
* `id` - Unique (SHA256) id based on the host_id if the ESXi host.
81+
* `name_regex` - (Optional) A regular expression that will be used to match the
82+
host vGPU profile name.
83+
* `class_id` - (Optional) The hexadecimal PCI device class ID.
84+
* `vendor_id` - (Optional) The hexadecimal PCI device vendor ID.
85+
* `pci_devices` - The list of matching PCI Devices available on the host.
86+
* `id` - The name ID of this PCI, composed of "bus:slot.function"
87+
* `name` - The name of the PCI device.
88+
* `bus` - The bus ID of the PCI device.
89+
* `class_id` - The hexadecimal value of the PCI device's class ID.
90+
* `device_id` - The hexadecimal value of the PCI device's device ID.
91+
* `function` - The function ID of the PCI device.
92+
* `parent_bridge` - The parent bridge of the PCI device.
93+
* `slot` - The slot ID of the PCI device.
94+
* `sub_device_id` - The hexadecimal value of the PCI device's sub device ID.
95+
* `sub_vendor_id` - The hexadecimal value of the PCI device's sub vendor ID.
96+
* `vendor_id` - The hexadecimal value of the PCI device's vendor ID.
97+
* `vendor_name` - The vendor name of the PCI device.

vsphere/data_source_vsphere_host_pci_device.go

Lines changed: 122 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
package vsphere
66

77
import (
8+
"crypto/sha256"
9+
"fmt"
810
"log"
911
"regexp"
1012
"strconv"
@@ -39,31 +41,114 @@ func dataSourceVSphereHostPciDevice() *schema.Resource {
3941
Optional: true,
4042
Description: "The hexadecimal value of the PCI device's vendor ID.",
4143
},
42-
"name": {
43-
Type: schema.TypeString,
44+
"pci_devices": {
45+
Type: schema.TypeList,
4446
Computed: true,
45-
Description: "The name of the PCI device.",
47+
Description: "The list of matching PCI Devices available on the host.",
48+
Elem: &schema.Resource{
49+
Schema: map[string]*schema.Schema{
50+
"id": {
51+
Type: schema.TypeString,
52+
Computed: true,
53+
Description: "The name ID of this PCI, composed of 'bus:slot.function'",
54+
},
55+
"name": {
56+
Type: schema.TypeString,
57+
Computed: true,
58+
Description: "The name of the PCI device.",
59+
},
60+
"bus": {
61+
Type: schema.TypeString,
62+
Computed: true,
63+
Description: "The bus ID of the PCI device.",
64+
},
65+
"slot": {
66+
Type: schema.TypeString,
67+
Computed: true,
68+
Description: "The slot ID of the PCI device.",
69+
},
70+
"function": {
71+
Type: schema.TypeString,
72+
Computed: true,
73+
Description: "The function ID of the PCI device.",
74+
},
75+
"class_id": {
76+
Type: schema.TypeString,
77+
Computed: true,
78+
Description: "The hexadecimal value of the PCI device's class ID.",
79+
},
80+
"vendor_id": {
81+
Type: schema.TypeString,
82+
Computed: true,
83+
Description: "The hexadecimal value of the PCI device's vendor ID.",
84+
},
85+
"sub_vendor_id": {
86+
Type: schema.TypeString,
87+
Computed: true,
88+
Description: "The hexadecimal value of the PCI device's sub vendor ID.",
89+
},
90+
"vendor_name": {
91+
Type: schema.TypeString,
92+
Computed: true,
93+
Description: "The vendor name of the PCI device.",
94+
},
95+
"device_id": {
96+
Type: schema.TypeString,
97+
Computed: true,
98+
Description: "The hexadecimal value of the PCI device's device ID.",
99+
},
100+
"sub_device_id": {
101+
Type: schema.TypeString,
102+
Computed: true,
103+
Description: "The hexadecimal value of the PCI device's sub device ID.",
104+
},
105+
"parent_bridge": {
106+
Type: schema.TypeString,
107+
Computed: true,
108+
Description: "The parent bridge of the PCI device.",
109+
},
110+
},
111+
},
46112
},
47113
},
48114
}
49115
}
50116

51117
func dataSourceVSphereHostPciDeviceRead(d *schema.ResourceData, meta interface{}) error {
52118
log.Printf("[DEBUG] DataHostPCIDev: Beginning PCI device lookup on %s", d.Get("host_id").(string))
119+
53120
client := meta.(*Client).vimClient
121+
54122
host, err := hostsystem.FromID(client, d.Get("host_id").(string))
55123
if err != nil {
56124
return err
57125
}
126+
58127
hprops, err := hostsystem.Properties(host)
59128
if err != nil {
60129
return err
61130
}
131+
132+
// Create unique ID based on the host_id
133+
idsum := sha256.New()
134+
if _, err := idsum.Write([]byte(fmt.Sprintf("%#v", d.Get("host_id").(string)))); err != nil {
135+
return err
136+
}
137+
138+
d.SetId(fmt.Sprintf("%x", idsum.Sum(nil)))
139+
140+
// Identify PCI devices matching name_regex (if any)
62141
devices, err := matchName(d, hprops.Hardware.PciDevice)
63142
if err != nil {
64143
return err
65144
}
145+
146+
// Output slice
147+
pciDevices := make([]interface{}, 0, len(devices))
148+
66149
log.Printf("[DEBUG] DataHostPCIDev: Looking for a device with matching class_id and vendor_id")
150+
151+
// Loop through devices
67152
for _, device := range devices {
68153
// Match the class_id if it is set.
69154
if class, exists := d.GetOk("class_id"); exists {
@@ -75,6 +160,7 @@ func dataSourceVSphereHostPciDeviceRead(d *schema.ResourceData, meta interface{}
75160
continue
76161
}
77162
}
163+
78164
// Now match the vendor_id if it is set.
79165
if vendor, exists := d.GetOk("vendor_id"); exists {
80166
vendorInt, err := strconv.ParseInt(vendor.(string), 16, 16)
@@ -85,15 +171,43 @@ func dataSourceVSphereHostPciDeviceRead(d *schema.ResourceData, meta interface{}
85171
continue
86172
}
87173
}
174+
175+
// Convertions
88176
classHex := strconv.FormatInt(int64(device.ClassId), 16)
89177
vendorHex := strconv.FormatInt(int64(device.VendorId), 16)
90-
d.SetId(device.Id)
91-
_ = d.Set("name", device.DeviceName)
92-
_ = d.Set("class_id", classHex)
93-
_ = d.Set("vendor_id", vendorHex)
178+
subVendorHex := strconv.FormatInt(int64(device.SubVendorId), 16)
179+
deviceHex := strconv.FormatInt(int64(device.DeviceId), 16)
180+
subDeviceHex := strconv.FormatInt(int64(device.SubDeviceId), 16)
181+
busString := fmt.Sprintf("%v", device.Bus)
182+
slotString := fmt.Sprintf("%v", device.Slot)
183+
functionString := fmt.Sprintf("%v", device.Function)
184+
185+
dev := map[string]interface{}{
186+
"id": device.Id,
187+
"name": device.DeviceName,
188+
"class_id": classHex,
189+
"vendor_id": vendorHex,
190+
"sub_vendor_id": subVendorHex,
191+
"device_id": deviceHex,
192+
"sub_device_id": subDeviceHex,
193+
"bus": busString,
194+
"slot": slotString,
195+
"function": functionString,
196+
"parent_bridge": device.ParentBridge,
197+
"vendor_name": device.VendorName,
198+
}
199+
200+
// Add PCI device to output slice
201+
pciDevices = append(pciDevices, dev)
202+
94203
log.Printf("[DEBUG] DataHostPCIDev: Matching PCI device found: %s", device.DeviceName)
95-
return nil
96204
}
205+
206+
// Set the `pci_devices` output to all PCI devices
207+
if err := d.Set("pci_devices", pciDevices); err != nil {
208+
return err
209+
}
210+
97211
return nil
98212
}
99213

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package vsphere
5+
6+
import (
7+
"fmt"
8+
"os"
9+
"testing"
10+
11+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
12+
"github.com/vmware/terraform-provider-vsphere/vsphere/internal/helper/testhelper"
13+
)
14+
15+
func TestAccDataSourceVSphereHostPciDevice_basic(t *testing.T) {
16+
resource.Test(t, resource.TestCase{
17+
PreCheck: func() {
18+
testAccPreCheck(t)
19+
testAccDataSourceVSphereHostPciDevicePreCheck(t)
20+
},
21+
Providers: testAccProviders,
22+
Steps: []resource.TestStep{
23+
{
24+
Config: testAccDataSourceVSphereHostPciDeviceConfig(),
25+
Check: resource.ComposeTestCheckFunc(
26+
resource.TestCheckResourceAttrSet(
27+
"data.vsphere_host_pci_device.device",
28+
"pci_devices.#",
29+
),
30+
),
31+
},
32+
{
33+
Config: testAccDataSourceVSphereHostPciDeviceConfig(),
34+
Check: resource.ComposeTestCheckFunc(
35+
resource.TestCheckResourceAttrSet(
36+
"data.vsphere_host_pci_device.device",
37+
"pci_devices.0.name",
38+
),
39+
),
40+
},
41+
},
42+
})
43+
}
44+
45+
func testAccDataSourceVSphereHostPciDevicePreCheck(t *testing.T) {
46+
if os.Getenv("TF_VAR_VSPHERE_DATACENTER") == "" {
47+
t.Skip("set TF_VAR_VSPHERE_DATACENTER to run vsphere_host_pci_device acceptance tests")
48+
}
49+
if os.Getenv("TF_VAR_VSPHERE_ESXI1") == "" {
50+
t.Skip("set TF_VAR_VSPHERE_ESXI1 to run vsphere_host_pci_device acceptance tests")
51+
}
52+
}
53+
54+
func testAccDataSourceVSphereHostPciDeviceConfig() string {
55+
return fmt.Sprintf(`
56+
%s
57+
58+
data "vsphere_host" "host" {
59+
name = "%s"
60+
datacenter_id = "${data.vsphere_datacenter.rootdc1.id}"
61+
}
62+
63+
data "vsphere_host_pci_device" "device" {
64+
host_id = "${data.vsphere_host.host.id}"
65+
name_regex = ""
66+
}
67+
`, testhelper.CombineConfigs(testhelper.ConfigDataRootDC1(), testhelper.ConfigDataRootPortGroup1()), os.Getenv("TF_VAR_VSPHERE_ESXI1"))
68+
}

0 commit comments

Comments
 (0)