The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7194
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === This resolves #7189.
From 4867c824e309f655caf3eb16c4bfb1e9514e1081 Mon Sep 17 00:00:00 2001 From: Thomas Hipp <thomas.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel