[lxc-devel] [lxd/master] Add USB and PCI devices to resources API
monstermunchkin on Github
lxc-bot at linuxcontainers.org
Wed Mar 25 17:41:50 UTC 2020
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200325/1587eb5f/attachment.bin>
-------------- next part --------------
From ab6c532d7dd48b5e3364aeb0a7b47fb9a4958ae4 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Wed, 25 Mar 2020 18:21:26 +0100
Subject: [PATCH 1/5] shared/version/api: Add usb_pci_resources API extension
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
shared/version/api.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/shared/version/api.go b/shared/version/api.go
index ba5f2f00ee..fc92e2bfb2 100644
--- a/shared/version/api.go
+++ b/shared/version/api.go
@@ -198,6 +198,7 @@ var APIExtensions = []string{
"volume_snapshot_scheduling",
"trust_ca_certificates",
"snapshot_disk_usage",
+ "usb_pci_resources",
}
// APIExtensionsCount returns the number of available API extensions.
From d4ee5abd1d794eb82b648424424bd60fb2d7f9a5 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Wed, 25 Mar 2020 18:24:47 +0100
Subject: [PATCH 2/5] doc: Add usb_pci_resources
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
doc/api-extensions.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index 3340012872..a1eb7a29a3 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -972,3 +972,6 @@ In this case, it will ask for the password.
## snapshot\_disk\_usage
This adds a new `size` field to the output of `/1.0/instances/<name>/snapshots/<snapshot>` which represents the disk usage of the snapshot.
+
+## usb\_pci\_resources
+This adds USB and PCI devices to the output of `/1.0/resources`.
From f763623152dbf339eb74f1b1c1425a8503489f29 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Wed, 25 Mar 2020 14:42:25 +0100
Subject: [PATCH 3/5] shared/api: Add USB and PCI resources
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
shared/api/resource.go | 44 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/shared/api/resource.go b/shared/api/resource.go
index c3d3c0ff9d..08aac037a3 100644
--- a/shared/api/resource.go
+++ b/shared/api/resource.go
@@ -12,6 +12,10 @@ type Resources struct {
// API extension: resources_v2
Network ResourcesNetwork `json:"network" yaml:"network"`
Storage ResourcesStorage `json:"storage" yaml:"storage"`
+
+ // API extension: usb_pci_resources
+ USB ResourcesUSB `json:"usb" yaml:"usb"`
+ PCI ResourcesPCI `json:"pci" yaml:"pci"`
}
// ResourcesCPU represents the cpu resources available on the system
@@ -294,3 +298,43 @@ type ResourcesStoragePoolInodes struct {
Used uint64 `json:"used" yaml:"used"`
Total uint64 `json:"total" yaml:"total"`
}
+
+// ResourcesUSB represents the USB devices available on the system
+// API extension: usb_pci_resources
+type ResourcesUSB struct {
+ Devices []ResourcesUSBDevice `json:"devices" yaml:"devices"`
+ Total uint64 `json:"total" yaml:"total"`
+}
+
+// ResourcesUSBDevice represents a USB device
+// API extension: usb_pci_resources
+type ResourcesUSBDevice struct {
+ BusAddress uint64 `json:"bus_address" yaml:"bus_address"`
+ DeviceAddress uint64 `json:"device_address" yaml:"device_address"`
+ Driver string `json:"driver" yaml:"driver"`
+ DriverVersion string `json:"driver_version" yaml:"driver_version"`
+ Product string `json:"product" yaml:"product"`
+ ProductID string `json:"product_id" yaml:"product_id"`
+ Vendor string `json:"vendor" yaml:"vendor"`
+ VendorID string `json:"vendor_id" yaml:"vendor_id"`
+}
+
+// ResourcesPCI represents the PCI devices available on the system
+// API extension: usb_pci_resources
+type ResourcesPCI struct {
+ Devices []ResourcesPCIDevice `json:"devices" yaml:"devices"`
+ Total uint64 `json:"total" yaml:"total"`
+}
+
+// ResourcesPCIDevice represents a PCI device
+// API extension: usb_pci_resources
+type ResourcesPCIDevice struct {
+ Driver string `json:"driver" yaml:"driver"`
+ DriverVersion string `json:"driver_version" yaml:"driver_version"`
+ NumaNode string `json:"numa_node" yaml:"numa_node"`
+ PCIAddress string `json:"pci_address" yaml:"pci_address"`
+ Product string `json:"product" yaml:"product"`
+ ProductID string `json:"product_id" yaml:"product_id"`
+ Vendor string `json:"vendor" yaml:"vendor"`
+ VendorID string `json:"vendor_id" yaml:"vendor_id"`
+}
From 66298740002724a11c9344044cc5e9d1244bf4e6 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Wed, 25 Mar 2020 14:43:03 +0100
Subject: [PATCH 4/5] lxd/resources: Add USB resource
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/resources/resources.go | 7 ++
lxd/resources/usb.go | 158 +++++++++++++++++++++++++++++++++++++
2 files changed, 165 insertions(+)
create mode 100644 lxd/resources/usb.go
diff --git a/lxd/resources/resources.go b/lxd/resources/resources.go
index a8c2ba6437..2b7185e171 100644
--- a/lxd/resources/resources.go
+++ b/lxd/resources/resources.go
@@ -38,6 +38,12 @@ func GetResources() (*api.Resources, error) {
return nil, errors.Wrap(err, "Failed to retrieve storage information")
}
+ // Get USB information
+ usb, err := GetUSB()
+ if err != nil {
+ return nil, errors.Wrap(err, "Failed to retrieve USB information")
+ }
+
// Build the final struct
resources := api.Resources{
CPU: *cpu,
@@ -45,6 +51,7 @@ func GetResources() (*api.Resources, error) {
GPU: *gpu,
Network: *network,
Storage: *storage,
+ USB: *usb,
}
return &resources, nil
diff --git a/lxd/resources/usb.go b/lxd/resources/usb.go
new file mode 100644
index 0000000000..34c69b0475
--- /dev/null
+++ b/lxd/resources/usb.go
@@ -0,0 +1,158 @@
+package resources
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "reflect"
+ "strconv"
+ "strings"
+
+ "github.com/lxc/lxd/shared/api"
+ "github.com/pkg/errors"
+)
+
+var sysBusUSB = "/sys/bus/usb/devices"
+
+// GetUSB returns a filled api.ResourcesUSB struct ready for use by LXD
+func GetUSB() (*api.ResourcesUSB, error) {
+ usb := api.ResourcesUSB{}
+ devices := []api.ResourcesUSBDevice{}
+
+ // List all USB devices
+ entries, err := ioutil.ReadDir(sysBusUSB)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to list %q", sysBusUSB)
+ }
+
+ for _, entry := range entries {
+ entryPath := filepath.Join(sysBusUSB, entry.Name())
+
+ // Skip entries without a bus address
+ if !sysfsExists(filepath.Join(entryPath, "busnum")) {
+ continue
+ }
+
+ devClassFile := filepath.Join(entryPath, "bDeviceClass")
+
+ if sysfsExists(devClassFile) {
+ content, err := ioutil.ReadFile(devClassFile)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", devClassFile)
+ }
+
+ devClass, err := strconv.ParseUint(strings.TrimSpace(string(content)), 16, 64)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to parse device class %q", content)
+ }
+
+ // Skip USB hubs
+ if devClass == 9 {
+ continue
+ }
+ }
+
+ busAddress, err := readUint(filepath.Join(entryPath, "busnum"))
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", filepath.Join(entryPath, "busnum"))
+ }
+
+ devAddress, err := readUint(filepath.Join(entryPath, "devnum"))
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", filepath.Join(entryPath, "devnum"))
+ }
+
+ var product string
+
+ if sysfsExists(filepath.Join(entryPath, "product")) {
+ productBytes, err := ioutil.ReadFile(filepath.Join(entryPath, "product"))
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", filepath.Join(entryPath, "product"))
+ }
+
+ product = strings.TrimSpace(string(productBytes))
+ }
+
+ productID, err := ioutil.ReadFile(filepath.Join(entryPath, "idProduct"))
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", filepath.Join(entryPath, "idProduct"))
+ }
+
+ var vendor string
+
+ if sysfsExists(filepath.Join(entryPath, "vendor")) {
+ vendorBytes, err := ioutil.ReadFile(filepath.Join(entryPath, "vendor"))
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", filepath.Join(entryPath, "vendor"))
+ }
+
+ vendor = strings.TrimSpace(string(vendorBytes))
+
+ }
+
+ vendorID, err := ioutil.ReadFile(filepath.Join(entryPath, "idVendor"))
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", filepath.Join(entryPath, "idVendor"))
+ }
+
+ subEntries, err := ioutil.ReadDir(entryPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to list %q", entryPath)
+ }
+
+ for _, subEntry := range subEntries {
+ // Skip irrelevant directories and file entries
+ if !subEntry.IsDir() || !strings.HasPrefix(subEntry.Name(), entry.Name()) {
+ continue
+ }
+
+ device := api.ResourcesUSBDevice{
+ BusAddress: busAddress,
+ DeviceAddress: devAddress,
+ Product: strings.TrimSpace(string(product)),
+ ProductID: strings.TrimSpace(string(productID)),
+ Vendor: strings.TrimSpace(string(vendor)),
+ VendorID: strings.TrimSpace(string(vendorID)),
+ }
+
+ driverPath := filepath.Join(entryPath, subEntry.Name(), "driver")
+
+ if sysfsExists(driverPath) {
+ target, err := os.Readlink(driverPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to get driver of %q", filepath.Join(entryPath, subEntry.Name()))
+ }
+
+ device.Driver = filepath.Base(target)
+ }
+
+ driverModuleVersion := filepath.Join(entryPath, subEntry.Name(), "driver", "module", "version")
+
+ if sysfsExists(driverModuleVersion) {
+ version, err := ioutil.ReadFile(driverModuleVersion)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", driverModuleVersion)
+ }
+
+ device.DriverVersion = strings.TrimSpace(string(version))
+ }
+
+ devices = append(devices, device)
+ }
+ }
+
+ usb.Devices = append(usb.Devices, devices[0])
+
+ // Remove duplicates
+ for i, device := range devices {
+ if i == 0 || reflect.DeepEqual(device, devices[i-1]) {
+ continue
+ }
+
+ usb.Devices = append(usb.Devices, device)
+ }
+
+ usb.Total = uint64(len(usb.Devices))
+
+ return &usb, nil
+}
From 5ed9db1fb5a697dbf1019fa3a95d6e02e408b704 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Wed, 25 Mar 2020 17:35:38 +0100
Subject: [PATCH 5/5] lxd/resources: Add PCI resource
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/resources/pci.go | 8 ++++++++
lxd/resources/resources.go | 7 +++++++
2 files changed, 15 insertions(+)
create mode 100644 lxd/resources/pci.go
diff --git a/lxd/resources/pci.go b/lxd/resources/pci.go
new file mode 100644
index 0000000000..200d5b38a0
--- /dev/null
+++ b/lxd/resources/pci.go
@@ -0,0 +1,8 @@
+package resources
+
+import "github.com/lxc/lxd/shared/api"
+
+// GetPCI returns a filled api.ResourcesPCI struct ready for use by LXD
+func GetPCI() (*api.ResourcesPCI, error) {
+ return &api.ResourcesPCI{}, nil
+}
diff --git a/lxd/resources/resources.go b/lxd/resources/resources.go
index 2b7185e171..c43acc43b7 100644
--- a/lxd/resources/resources.go
+++ b/lxd/resources/resources.go
@@ -44,6 +44,12 @@ func GetResources() (*api.Resources, error) {
return nil, errors.Wrap(err, "Failed to retrieve USB information")
}
+ // Get PCI information
+ pci, err := GetPCI()
+ if err != nil {
+ return nil, errors.Wrap(err, "Failed to retrieve PCI information")
+ }
+
// Build the final struct
resources := api.Resources{
CPU: *cpu,
@@ -52,6 +58,7 @@ func GetResources() (*api.Resources, error) {
Network: *network,
Storage: *storage,
USB: *usb,
+ PCI: *pci,
}
return &resources, nil
More information about the lxc-devel
mailing list