[lxc-devel] [lxd/master] Provide system information
monstermunchkin on Github
lxc-bot at linuxcontainers.org
Wed Apr 15 11:02:41 UTC 2020
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 322 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200415/3a44ad2c/attachment-0001.bin>
-------------- next part --------------
From 4867c824e309f655caf3eb16c4bfb1e9514e1081 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Wed, 15 Apr 2020 11:03:37 +0200
Subject: [PATCH 1/5] shared/version/api: Add resources_system 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 87e58fd56b..7f85dd1243 100644
--- a/shared/version/api.go
+++ b/shared/version/api.go
@@ -205,6 +205,7 @@ var APIExtensions = []string{
"resources_cpu_threads_numa",
"resources_cpu_core_die",
"api_os",
+ "resources_system",
}
// APIExtensionsCount returns the number of available API extensions.
From aad4e285db780bbbbfa34d0092cecf24ab29b0c2 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Wed, 15 Apr 2020 12:54:02 +0200
Subject: [PATCH 2/5] doc/api-extensions: Add resources_system
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 82fb120b81..7601e96ed8 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -1013,3 +1013,6 @@ Exposes the die\_id information on each core.
This introduces two new fields in `/1.0`, `os` and `os\_version`.
Those are taken from the os-release data on the system.
+
+## resources\_system
+This adds system information to the output of `/1.0/resources`.
From 14aec82ceb1e21ca3e9f518bfc8118a461465a0a Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Wed, 15 Apr 2020 12:49:00 +0200
Subject: [PATCH 3/5] shared/api/resource: Add system resources
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
shared/api/resource.go | 46 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/shared/api/resource.go b/shared/api/resource.go
index 8cd2fc0dc4..bff1ca95df 100644
--- a/shared/api/resource.go
+++ b/shared/api/resource.go
@@ -16,6 +16,9 @@ type Resources struct {
// API extension: resources_usb_pci
USB ResourcesUSB `json:"usb" yaml:"usb"`
PCI ResourcesPCI `json:"pci" yaml:"pci"`
+
+ // API extention: resources_system
+ System ResourcesSystem `json:"system" yaml:"system"`
}
// ResourcesCPU represents the cpu resources available on the system
@@ -353,3 +356,46 @@ type ResourcesPCIDevice struct {
Vendor string `json:"vendor" yaml:"vendor"`
VendorID string `json:"vendor_id" yaml:"vendor_id"`
}
+
+// ResourcesSystem represents the system
+// API extension: resources_system
+type ResourcesSystem struct {
+ UUID string `json:"uuid" yaml:"uuid"`
+ Vendor string `json:"vendor" yaml:"vendor"`
+ Product string `json:"product" yaml:"product"`
+ Family string `json:"family" yaml:"family"`
+ Version string `json:"version" yaml:"version"`
+ Sku string `json:"sku" yaml:"sku"`
+ Serial string `json:"serial" yaml:"serial"`
+ Type string `json:"type" yaml:"type"`
+
+ Firmware *ResourcesSystemFirmware `json:"firmware" yaml:"firmware"`
+ Chassis *ResourcesSystemChassis `json:"chassis" yaml:"chassis"`
+ Motherboard *ResourcesSystemMotherboard `json:"motherboard" yaml:"motherboard"`
+}
+
+// ResourcesSystemFirmware represents the system firmware
+// API extension: resources_system
+type ResourcesSystemFirmware struct {
+ Vendor string `json:"vendor" yaml:"vendor"`
+ Date string `json:"date" yaml:"date"`
+ Version string `json:"version" yaml:"version"`
+}
+
+// ResourcesSystemChassis represents the system chassis
+// API extension: resources_system
+type ResourcesSystemChassis struct {
+ Vendor string `json:"vendor" yaml:"vendor"`
+ Type string `json:"type" yaml:"type"`
+ Serial string `json:"serial" yaml:"serial"`
+ Version string `json:"version" yaml:"version"`
+}
+
+// ResourcesSystemMotherboard represents the motherboard
+// API extension: resources_system
+type ResourcesSystemMotherboard struct {
+ Vendor string `json:"vendor" yaml:"vendor"`
+ Product string `json:"product" yaml:"product"`
+ Serial string `json:"serial" yaml:"serial"`
+ Version string `json:"version" yaml:"version"`
+}
From f12b1242fcf3f7c5f54412eb08bc499572ef0944 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Wed, 15 Apr 2020 12:49:42 +0200
Subject: [PATCH 4/5] lxd/resources: Add new system resources
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/resources/system.go | 328 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 328 insertions(+)
create mode 100644 lxd/resources/system.go
diff --git a/lxd/resources/system.go b/lxd/resources/system.go
new file mode 100644
index 0000000000..57cc889e78
--- /dev/null
+++ b/lxd/resources/system.go
@@ -0,0 +1,328 @@
+package resources
+
+import (
+ "io/ioutil"
+ "path/filepath"
+ "strings"
+
+ "github.com/pkg/errors"
+
+ "github.com/lxc/lxd/shared"
+ "github.com/lxc/lxd/shared/api"
+)
+
+var sysClassDMIID = "/sys/class/dmi/id"
+var systemType string
+
+// GetSystem returns a filled api.ResourcesSystem struct ready for use by LXD
+func GetSystem() (*api.ResourcesSystem, error) {
+ var err error
+ system := api.ResourcesSystem{}
+
+ // Cache the system type
+ if systemType == "" {
+ // According to the man page, if a virtualization technology is detected, 0 is returned, a non-zero code otherwise.
+ out, err := shared.RunCommand("systemd-detect-virt")
+ if err != nil {
+ systemType = "physical"
+ } else {
+ systemType = out
+ }
+ }
+
+ system.Type = systemType
+
+ if !sysfsExists(sysClassDMIID) {
+ return &system, nil
+ }
+
+ // Product UUID
+ productUUIDPath := filepath.Join(sysClassDMIID, "product_uuid")
+ if sysfsExists(productUUIDPath) {
+ content, err := ioutil.ReadFile(productUUIDPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", productUUIDPath)
+
+ }
+
+ system.UUID = strings.TrimSpace(string(content))
+ }
+
+ // Vendor
+ vendorPath := filepath.Join(sysClassDMIID, "sys_vendor")
+ if sysfsExists(vendorPath) {
+ content, err := ioutil.ReadFile(vendorPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", vendorPath)
+
+ }
+
+ system.Vendor = strings.TrimSpace(string(content))
+ }
+
+ // Product name
+ productNamePath := filepath.Join(sysClassDMIID, "product_name")
+ if sysfsExists(productNamePath) {
+ content, err := ioutil.ReadFile(productNamePath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", productNamePath)
+
+ }
+
+ system.Product = strings.TrimSpace(string(content))
+ }
+
+ // Product family
+ productFamilyPath := filepath.Join(sysClassDMIID, "product_family")
+ if sysfsExists(productFamilyPath) {
+ content, err := ioutil.ReadFile(productFamilyPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", productFamilyPath)
+
+ }
+
+ system.Family = strings.TrimSpace(string(content))
+ }
+
+ // Product version
+ productVersion := filepath.Join(sysClassDMIID, "product_version")
+ if sysfsExists(productVersion) {
+ content, err := ioutil.ReadFile(productVersion)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", productVersion)
+
+ }
+
+ system.Version = strings.TrimSpace(string(content))
+ }
+
+ // Product SKU
+ productSKUPath := filepath.Join(sysClassDMIID, "product_sku")
+ if sysfsExists(productSKUPath) {
+ content, err := ioutil.ReadFile(productSKUPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", productSKUPath)
+
+ }
+
+ system.Sku = strings.TrimSpace(string(content))
+ }
+
+ // Product serial
+ productSerialPath := filepath.Join(sysClassDMIID, "product_serial")
+ if sysfsExists(productSerialPath) {
+ content, err := ioutil.ReadFile(productSerialPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", productSerialPath)
+
+ }
+
+ system.Serial = strings.TrimSpace(string(content))
+ }
+
+ system.Firmware, err = getSystemFirmware()
+ if err != nil {
+ return nil, err
+ }
+
+ system.Chassis, err = getSystemChassis()
+ if err != nil {
+ return nil, err
+ }
+
+ system.Motherboard, err = getSystemMotherboard()
+ if err != nil {
+ return nil, err
+ }
+
+ return &system, nil
+}
+
+func getSystemFirmware() (*api.ResourcesSystemFirmware, error) {
+ firmware := api.ResourcesSystemFirmware{}
+
+ // Firmware vendor
+ biosVendorPath := filepath.Join(sysClassDMIID, "bios_vendor")
+ if sysfsExists(biosVendorPath) {
+ content, err := ioutil.ReadFile(biosVendorPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", biosVendorPath)
+
+ }
+
+ firmware.Vendor = strings.TrimSpace(string(content))
+ }
+
+ // Firmware date
+ biosDatePath := filepath.Join(sysClassDMIID, "bios_date")
+ if sysfsExists(biosDatePath) {
+ content, err := ioutil.ReadFile(biosDatePath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", biosDatePath)
+
+ }
+
+ firmware.Date = strings.TrimSpace(string(content))
+ }
+
+ // Firmware version
+ biosVersionPath := filepath.Join(sysClassDMIID, "bios_version")
+ if sysfsExists(biosVersionPath) {
+ content, err := ioutil.ReadFile(biosVersionPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", biosVersionPath)
+
+ }
+
+ firmware.Version = strings.TrimSpace(string(content))
+ }
+
+ return &firmware, nil
+}
+
+func getSystemChassis() (*api.ResourcesSystemChassis, error) {
+ chassis := api.ResourcesSystemChassis{}
+
+ // Chassis vendor
+ chassisVendorPath := filepath.Join(sysClassDMIID, "chassis_vendor")
+ if sysfsExists(chassisVendorPath) {
+ content, err := ioutil.ReadFile(chassisVendorPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", chassisVendorPath)
+
+ }
+
+ chassis.Vendor = strings.TrimSpace(string(content))
+ }
+
+ // Chassis types according to the DMTF SMBIOS Spec
+ chassisTypes := map[uint64]string{
+ 0x1: "Other",
+ 0x2: "Unknown",
+ 0x3: "Desktop",
+ 0x4: "Low Profile Desktop",
+ 0x5: "Pizza Box",
+ 0x6: "Mini Tower",
+ 0x7: "Tower",
+ 0x8: "Portable",
+ 0x9: "Laptop",
+ 0xA: "Notebook",
+ 0xB: "Hand Held",
+ 0xC: "Docking Station",
+ 0xD: "All in One",
+ 0xE: "Sub Notebook",
+ 0xF: "Space-saving",
+ 0x10: "Lunch Box",
+ 0x11: "Main Server Chassis",
+ 0x12: "Expansion Chassis",
+ 0x13: "SubChassis",
+ 0x14: "Bus Expansion Chassis",
+ 0x15: "Peripheral Chassis",
+ 0x16: "RAID Chassis",
+ 0x17: "Rack Mount Chassis",
+ 0x18: "Sealed-case PC",
+ 0x19: "Multi-system chassis",
+ 0x1A: "Compact PCI",
+ 0x1B: "Advanced TCA",
+ 0x1C: "Blade",
+ 0x1D: "Blade Enclosure",
+ 0x1E: "Tablet",
+ 0x1F: "Convertible",
+ 0x20: "Detachable",
+ 0x21: "IoT Gateway",
+ 0x22: "Embedded PC",
+ 0x23: "Mini PC",
+ 0x24: "Stick PC",
+ }
+
+ // Chassis type
+ chassisTypePath := filepath.Join(sysClassDMIID, "chassis_type")
+ if sysfsExists(chassisTypePath) {
+ chassisType, err := readUint(chassisTypePath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to parse %q", chassisTypePath)
+ }
+
+ chassis.Type = chassisTypes[chassisType]
+ }
+
+ // Chassis serial
+ chassisSerialPath := filepath.Join(sysClassDMIID, "chassis_serial")
+ if sysfsExists(chassisSerialPath) {
+ content, err := ioutil.ReadFile(chassisSerialPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", chassisSerialPath)
+
+ }
+
+ chassis.Serial = strings.TrimSpace(string(content))
+ }
+
+ // Chassis version
+ chassisVersionPath := filepath.Join(sysClassDMIID, "chassis_version")
+ if sysfsExists(chassisVersionPath) {
+ content, err := ioutil.ReadFile(chassisVersionPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", chassisVersionPath)
+
+ }
+
+ chassis.Version = strings.TrimSpace(string(content))
+ }
+
+ return &chassis, nil
+}
+
+func getSystemMotherboard() (*api.ResourcesSystemMotherboard, error) {
+ motherboard := api.ResourcesSystemMotherboard{}
+
+ // Motherboard vendor name
+ boardVendorPath := filepath.Join(sysClassDMIID, "board_vendor")
+ if sysfsExists(boardVendorPath) {
+ content, err := ioutil.ReadFile(boardVendorPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", boardVendorPath)
+
+ }
+
+ motherboard.Vendor = strings.TrimSpace(string(content))
+ }
+
+ // Motherboard product name
+ boardNamePath := filepath.Join(sysClassDMIID, "board_name")
+ if sysfsExists(boardNamePath) {
+ content, err := ioutil.ReadFile(boardNamePath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", boardNamePath)
+
+ }
+
+ motherboard.Product = strings.TrimSpace(string(content))
+ }
+
+ // Motherboard serial
+ boardSerialPath := filepath.Join(sysClassDMIID, "board_serial")
+ if sysfsExists(boardSerialPath) {
+ content, err := ioutil.ReadFile(boardSerialPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", boardSerialPath)
+
+ }
+
+ motherboard.Serial = strings.TrimSpace(string(content))
+ }
+
+ // Motherboard version
+ boardVersionPath := filepath.Join(sysClassDMIID, "board_version")
+ if sysfsExists(boardVersionPath) {
+ content, err := ioutil.ReadFile(boardVersionPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to read %q", boardVersionPath)
+
+ }
+
+ motherboard.Version = strings.TrimSpace(string(content))
+ }
+
+ return &motherboard, nil
+}
From 928ff91ccfd5a8866154cf257e85fbaa32e57e84 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Wed, 15 Apr 2020 12:50:02 +0200
Subject: [PATCH 5/5] lxd/resources: Retrieve system information
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/resources/resources.go | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/lxd/resources/resources.go b/lxd/resources/resources.go
index c43acc43b7..c35f8876eb 100644
--- a/lxd/resources/resources.go
+++ b/lxd/resources/resources.go
@@ -50,6 +50,12 @@ func GetResources() (*api.Resources, error) {
return nil, errors.Wrap(err, "Failed to retrieve PCI information")
}
+ // Get system information
+ system, err := GetSystem()
+ if err != nil {
+ return nil, errors.Wrap(err, "Failed to retrieve system information")
+ }
+
// Build the final struct
resources := api.Resources{
CPU: *cpu,
@@ -59,6 +65,7 @@ func GetResources() (*api.Resources, error) {
Storage: *storage,
USB: *usb,
PCI: *pci,
+ System: *system,
}
return &resources, nil
More information about the lxc-devel
mailing list