Skip to content

Commit

Permalink
feat: added or data sources to extract node and device information (d…
Browse files Browse the repository at this point in the history
  • Loading branch information
muresan authored and dmacvicar committed Sep 28, 2024
1 parent 4bf8192 commit d31004d
Show file tree
Hide file tree
Showing 13 changed files with 1,218 additions and 0 deletions.
750 changes: 750 additions & 0 deletions libvirt/data_source_libvirt_node_device_info.go

Large diffs are not rendered by default.

40 changes: 40 additions & 0 deletions libvirt/data_source_libvirt_node_device_info_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package libvirt

import (
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccLibvirtNodeDeviceInfoDataSource(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceNodeDeviceInfoPCI,
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr(
"data.libvirt_node_device_info.device", "name", regexp.MustCompile(`^pci_0000_00_00_0$`)),
),
}, {
Config: testAccDataSourceNodeDeviceInfoSystem,
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr(
"data.libvirt_node_device_info.device", "name", regexp.MustCompile(`^computer$`)),
),
},
},
})
}

const testAccDataSourceNodeDeviceInfoPCI = `
data "libvirt_node_device_info" "device" {
name = "pci_0000_00_00_0"
}`

const testAccDataSourceNodeDeviceInfoSystem = `
data "libvirt_node_device_info" "device" {
name = "computer"
}`
73 changes: 73 additions & 0 deletions libvirt/data_source_libvirt_node_devices.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package libvirt

import (
"fmt"
"log"
"sort"
"strconv"

libvirt "github.com/digitalocean/go-libvirt"
"github.com/dmacvicar/terraform-provider-libvirt/libvirt/helper/hashcode"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

// a libvirt nodeinfo datasource
//
// Datasource example:
//
// data "libvirt_node_devices" "list" {
// }
//
// output "cpus" {
// value = data.libvirt_node_devices.list.devices
// }
func datasourceLibvirtNodeDevices() *schema.Resource {
return &schema.Resource{
Read: resourceLibvirtNodeDevicesRead,
Schema: map[string]*schema.Schema{
"capability": {
Type: schema.TypeString,
Optional: true,
},
"devices": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
}
}

func resourceLibvirtNodeDevicesRead(d *schema.ResourceData, meta interface{}) error {
log.Printf("[DEBUG] Read data source libvirt_nodedevices")

virConn := meta.(*Client).libvirt
if virConn == nil {
return fmt.Errorf(LibVirtConIsNil)
}

var cap libvirt.OptString

if capability, ok := d.GetOk("capability"); ok {
cap = append(cap, capability.(string))
log.Printf("[DEBUG] Got capability: %v", cap)
}

rnum, err := virConn.NodeNumOfDevices(libvirt.OptString(cap), 0)
if err != nil {
return fmt.Errorf("failed to retrieve number of devices: %w", err)
}

devices, err := virConn.NodeListDevices(cap, rnum, 0)
if err != nil {
return fmt.Errorf("failed to retrieve list of node devices: %w", err)
}

sort.Strings(devices)
d.Set("devices", devices)
d.SetId(strconv.Itoa(hashcode.String(fmt.Sprintf("%v", devices))))

return nil
}
41 changes: 41 additions & 0 deletions libvirt/data_source_libvirt_node_devices_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package libvirt

import (
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccLibvirtNodeDevicesDataSource(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceNodeDevicesPci,
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr(
"data.libvirt_node_devices.node", "devices[0]", regexp.MustCompile(`^pci_\d{4}_\d{2}_\d{2}_\d{1}`)),
),
},
{
Config: testAccDataSourceNodeDevicesSystem,
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr(
"data.libvirt_node_devices.node", "devices[0]", regexp.MustCompile(`^computer$`)),
),
},
},
})
}

const testAccDataSourceNodeDevicesPci = `
data "libvirt_node_devices" "node" {
capability = "pci"
}`

const testAccDataSourceNodeDevicesSystem = `
data "libvirt_node_devices" "node" {
capability = "system"
}`
94 changes: 94 additions & 0 deletions libvirt/data_source_libvirt_node_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package libvirt

import (
"fmt"
"log"
"strconv"

"github.com/dmacvicar/terraform-provider-libvirt/libvirt/helper/hashcode"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

// a libvirt nodeinfo datasource
//
// Datasource example:
//
// data "libvirt_nodeinfo" "info" {
// }
//
// output "cpus" {
// value = data.libvirt_nodeinfo.info.cpus
// }
func datasourceLibvirtNodeInfo() *schema.Resource {
return &schema.Resource{
Read: resourceLibvirtNodeInfoRead,
Schema: map[string]*schema.Schema{
"cpu_model": {
Type: schema.TypeString,
Computed: true,
},
"memory_total_kb": {
Type: schema.TypeInt,
Computed: true,
},
"cpu_cores_total": {
Type: schema.TypeInt,
Computed: true,
},
"numa_nodes": {
Type: schema.TypeInt,
Computed: true,
},
"cpu_sockets": {
Type: schema.TypeInt,
Computed: true,
},
"cpu_cores_per_socket": {
Type: schema.TypeInt,
Computed: true,
},
"cpu_threads_per_core": {
Type: schema.TypeInt,
Computed: true,
},
},
}
}

func resourceLibvirtNodeInfoRead(d *schema.ResourceData, meta interface{}) error {
log.Printf("[DEBUG] Read data source libvirt_nodeinfo")

virConn := meta.(*Client).libvirt
if virConn == nil {
return fmt.Errorf(LibVirtConIsNil)
}

model, memory, cpus, _, nodes, sockets, cores, threads, err := virConn.NodeGetInfo()

if err != nil {
return fmt.Errorf("failed to retrieve domains: %w", err)
}

d.Set("cpu_model", int8ToString(model))
d.Set("cpu_cores_total", cpus)
d.Set("cpu_cores_per_socket", cores)
d.Set("numa_nodes", nodes)
d.Set("cpu_sockets", sockets)
d.Set("cpu_threads_per_core", threads)
d.Set("numa_nodes", nodes)
d.Set("memory_total_kb", memory)
d.SetId(strconv.Itoa(hashcode.String(fmt.Sprintf("%v%v%v%v%v%v%v", model, memory, cpus, nodes, sockets, cores, threads))))

return nil
}

func int8ToString(bs [32]int8) string {
ba := []uint8{}
for _, b := range bs {
if b == 0 {
break
}
ba = append(ba, uint8(b))
}
return string(ba)
}
35 changes: 35 additions & 0 deletions libvirt/data_source_libvirt_node_info_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package libvirt

import (
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccLibvirtNodeInfoDataSource(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceNodeInfo,
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr(
"data.libvirt_node_info.info", "cpus", regexp.MustCompile(`^\d+`)),
),
}, {
Config: testAccDataSourceNodeInfo,
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr(
"data.libvirt_node_info.info", "numa_nodes", regexp.MustCompile(`^\d+`)),
),
},
},
})
}

const testAccDataSourceNodeInfo = `
data "libvirt_node_info" "info" {
}`
3 changes: 3 additions & 0 deletions libvirt/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ func Provider() *schema.Provider {
"libvirt_network_dns_host_template": datasourceLibvirtNetworkDNSHostTemplate(),
"libvirt_network_dns_srv_template": datasourceLibvirtNetworkDNSSRVTemplate(),
"libvirt_network_dnsmasq_options_template": datasourceLibvirtNetworkDnsmasqOptionsTemplate(),
"libvirt_node_info": datasourceLibvirtNodeInfo(),
"libvirt_node_device_info": datasourceLibvirtNodeDeviceInfo(),
"libvirt_node_devices": datasourceLibvirtNodeDevices(),
},

ConfigureFunc: providerConfigure,
Expand Down
89 changes: 89 additions & 0 deletions website/docs/d/node_device_info.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
---
layout: "libvirt"
page_title: "Libvirt: libvirt_node_device_info"
sidebar_current: "docs-libvirt-node-device-info"
description: |-
Use this data source to get information about a specific device on the current node
---

# Data Source: libvirt\_node\_device\_info

Retrieve information about a specific device on the current node

## Example Usage

```hcl
data "libvirt_node_device_info" "device" {
name = "pci_0000_00_00_0"
}
```

## Argument Reference

* `name` - (Required) The name of the device name as expected by [libvirt](https://www.libvirt.org/manpages/virsh.html#nodedev-commands).

## Attribute Reference

This data source exports the following attributes in addition to the arguments above:

* `capability` - A map of the various attributes for the device, depending on the type of device.
Currently implemented are `pci`, `storage`, `usb`
* `type` - Device type: `pci`, `storage`, `usb`
* `devnode`: For devices with a `/dev` special file. A mandatory attribute type specify the kind of file `path`, which may be either dev for the main name, or `link` for additional symlinks.

For `pci` devices the additional attributes are:
* `class` - Device PCI class
* `domain` - Device PCI domain
* `bus` - Device PCI bus
* `slot` - Device PCI slot
* `function` - Device PCI function
* `product` - Device PCI product map of `id` and `name`
* `vendor` - Device PCI vendor map of `id` and `name`
* `iommu_group` - Structure that holds IOMMU Group `number` and the list of devices that are part of the group

For `storage` devices the additional attributes are:
* `block` - Block device name
* `drive_type` - Device drive type
* `model` - Device model
* `serial` - Device serial number
* `size` - Device size in bytes
* `logical_block_size` - Device logical block size
* `num_blocks` - Number of blocks on the device

For `usb` devices the additional attributes are:
* `number` - Device number
* `class` - Device class
* `subclass` - Device subclass
* `protocol` - Device protocol

For `usb_device` devices the additional attributes are:
* `bus` - Which bus the device belongs to
* `device` - Which device within the \
* `product` - If present, the product `id` and `name` from the device ROM
* `vendor` - If present, the vendor `id` and `name` from the device ROM

For `net` devices the additional attributes are:
* `interface` - The interface name tied to this device
* `address` - If present, the MAC address of the device
* `link` - Optional to reflect the status of the link via `speed` and `state` keys
* `feature` - List of features supported by the network interface
* `capability` - Holds key `type` that describes the type of network interface: `80203` for IEEE 802.3 or `80211` for IEEE 802.11

For `scsi_host` devices the additional attributes are:
* `host` - The SCSI host number
* `unique_id` - This optionally provides the value from the 'unique_id' file found in the scsi_host's directory

For `scsi` devices the additional attributes are:
* `host` - The SCSI host containing the device
* `bus` - The bus within the host
* `target` - The target within the bus
* `lun` - The lun within the target
* `scsi_type` - The type of SCSI device

For `drm` devices the additional attributes are:
* `drm_type` - Type of DRM device: `render` or `card`

* `parent` - The parent of this device in the hierarchy
* `path` - Full path of the device
* `xml` - The XML returned by the libvirt API call
* `devnode` - For type `drm` holds the `path` and `link` that point to the device
Loading

0 comments on commit d31004d

Please sign in to comment.