[lxc-devel] [lxd/master] Extend storage info on storage API

stgraber on Github lxc-bot at linuxcontainers.org
Sun Sep 15 17:08:54 UTC 2019


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/20190915/85ee471a/attachment.bin>
-------------- next part --------------
From 1d4cb2778c2c602ceadd81308e99e2ec7836450b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 12 Sep 2019 07:22:57 +0100
Subject: [PATCH 1/3] api: Add resources_disk_sata extension
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 doc/api-extensions.md | 9 +++++++++
 shared/version/api.go | 1 +
 2 files changed, 10 insertions(+)

diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index 98f0a39a83..a94285efce 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -829,3 +829,12 @@ This introduces the concept of instances, of which currently the only type is "c
 
 ## image\_types
 This introduces support for a new Type field on images, indicating what type of images they are.
+
+## resources\_disk\_sata
+Extends the disk resource API struct to include:
+ - Proper detection of sata devices (type)
+ - Device path
+ - Drive RPM
+ - Block size
+ - Firmware version
+ - Model revision
diff --git a/shared/version/api.go b/shared/version/api.go
index 48aa25a7d7..d6d182821d 100644
--- a/shared/version/api.go
+++ b/shared/version/api.go
@@ -166,6 +166,7 @@ var APIExtensions = []string{
 	"daemon_storage",
 	"instances",
 	"image_types",
+	"resources_disk_sata",
 }
 
 // APIExtensionsCount returns the number of available API extensions.

From fb546cd88bfde200e685958e5140c758130d26ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 12 Sep 2019 07:23:47 +0100
Subject: [PATCH 2/3] shared/api: Extend ResourcesStorageDisk
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 shared/api/resource.go | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/shared/api/resource.go b/shared/api/resource.go
index 6590398848..8b0be0220f 100644
--- a/shared/api/resource.go
+++ b/shared/api/resource.go
@@ -223,6 +223,14 @@ type ResourcesStorageDisk struct {
 	WWN       string `json:"wwn,omitempty" yaml:"wwn,omitempty"`
 	NUMANode  uint64 `json:"numa_node" yaml:"numa_node"`
 
+	// API extension: resources_disk_sata
+	DevicePath      string `json:"device_path" yaml:"device_path"`
+	BlockSize       uint64 `json:"block_size" yaml:"block_size"`
+	FirmwareVersion string `json:"firmware_version,omitempty" yaml:"firmware_version,omitempty"`
+	RPM             uint64 `json:"rpm" yaml:"rpm"`
+	ModelRevision   string `json:"model_revision,omitempty" yaml:"model_revision,omitempty"`
+	Serial          string `json:"serial,omitempty" yaml:"serial,omitempty"`
+
 	Partitions []ResourcesStorageDiskPartition `json:"partitions" yaml:"partitions"`
 }
 

From 35a2690a1e64b5a94dcaddd98dcd5f094fbd690d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Fri, 13 Sep 2019 02:21:56 +0200
Subject: [PATCH 3/3] lxd/resources: Add extra storage fields
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/resources/storage.go | 125 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 125 insertions(+)

diff --git a/lxd/resources/storage.go b/lxd/resources/storage.go
index ffd5d0fa4b..0a0fe6a1ad 100644
--- a/lxd/resources/storage.go
+++ b/lxd/resources/storage.go
@@ -1,17 +1,104 @@
 package resources
 
 import (
+	"bufio"
+	"fmt"
 	"io/ioutil"
+	"os"
 	"path/filepath"
+	"strconv"
 	"strings"
 
 	"github.com/pkg/errors"
+	"golang.org/x/sys/unix"
 
 	"github.com/lxc/lxd/shared/api"
 )
 
+var devDiskByPath = "/dev/disk/by-path"
+var runUdevData = "/run/udev/data"
 var sysClassBlock = "/sys/class/block"
 
+func storageAddDriveInfo(devicePath string, disk *api.ResourcesStorageDisk) error {
+	// Attempt to open the device path
+	f, err := os.Open(devicePath)
+	if err != nil {
+		if !os.IsPermission(err) && !os.IsNotExist(err) {
+			return err
+		}
+	} else {
+		defer f.Close()
+		fd := int(f.Fd())
+
+		// Retrieve the block size
+		res, err := unix.IoctlGetInt(fd, unix.BLKPBSZGET)
+		if err != nil {
+			return err
+		}
+
+		disk.BlockSize = uint64(res)
+	}
+
+	// Retrieve udev information
+	udevInfo := filepath.Join(runUdevData, fmt.Sprintf("b%s", disk.Device))
+	if sysfsExists(udevInfo) {
+		// Get the udev information
+		f, err := os.Open(udevInfo)
+		if err != nil {
+			return errors.Wrapf(err, "Failed to open \"%s\"", udevInfo)
+		}
+		defer f.Close()
+
+		udevInfo := bufio.NewScanner(f)
+		for udevInfo.Scan() {
+			line := strings.TrimSpace(udevInfo.Text())
+
+			if !strings.HasPrefix(line, "E:") {
+				continue
+			}
+
+			fields := strings.SplitN(line, "=", 2)
+			if len(fields) != 2 {
+				continue
+			}
+
+			key := strings.TrimSpace(fields[0])
+			value := strings.TrimSpace(fields[1])
+
+			// Finer grained disk type
+			if key == "E:ID_ATA_SATA" && value == "1" {
+				disk.Type = "sata"
+			}
+
+			if key == "E:ID_USB_DRIVER" && value == "usb-storage" {
+				disk.Type = "usb"
+			}
+
+			// Model revision number
+			if key == "E:ID_REVISION" && disk.ModelRevision == "" {
+				disk.ModelRevision = value
+			}
+
+			// Serial number
+			if key == "E:ID_SERIAL_SHORT" && disk.Serial == "" {
+				disk.Serial = value
+			}
+
+			// Rotation per minute
+			if key == "E:ID_ATA_ROTATION_RATE_RPM" && disk.RPM == 0 {
+				valueUint, err := strconv.ParseUint(value, 10, 64)
+				if err != nil {
+					return errors.Wrap(err, "Failed to parse RPM value")
+				}
+
+				disk.RPM = valueUint
+			}
+		}
+	}
+
+	return nil
+}
+
 // GetStorage returns a filled api.ResourcesStorage struct ready for use by LXD
 func GetStorage() (*api.ResourcesStorage, error) {
 	storage := api.ResourcesStorage{}
@@ -39,6 +126,16 @@ func GetStorage() (*api.ResourcesStorage, error) {
 			disk := api.ResourcesStorageDisk{}
 			disk.ID = entryName
 
+			// Firmware revision
+			if sysfsExists(filepath.Join(devicePath, "firmware_rev")) {
+				firmwareRevision, err := ioutil.ReadFile(filepath.Join(devicePath, "firmware_rev"))
+				if err != nil {
+					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(devicePath, "firmware_rev"))
+				}
+
+				disk.FirmwareVersion = strings.TrimSpace(string(firmwareRevision))
+			}
+
 			// Device node
 			diskDev, err := ioutil.ReadFile(filepath.Join(entryPath, "dev"))
 			if err != nil {
@@ -158,6 +255,34 @@ func GetStorage() (*api.ResourcesStorage, error) {
 				disk.Partitions = append(disk.Partitions, partition)
 			}
 
+			// Try to find the udev device path
+			if sysfsExists(devDiskByPath) {
+				links, err := ioutil.ReadDir(devDiskByPath)
+				if err != nil {
+					return nil, errors.Wrapf(err, "Failed to list the links in \"%s\"", devDiskByPath)
+				}
+
+				for _, link := range links {
+					linkName := link.Name()
+					linkPath := filepath.Join(devDiskByPath, linkName)
+
+					linkTarget, err := filepath.EvalSymlinks(linkPath)
+					if err != nil {
+						return nil, errors.Wrapf(err, "Failed to track down \"%s\"", linkPath)
+					}
+
+					if linkTarget == filepath.Join("/dev", entryName) {
+						disk.DevicePath = linkName
+					}
+				}
+			}
+
+			// Pull direct disk information
+			err = storageAddDriveInfo(filepath.Join("/dev", entryName), &disk)
+			if err != nil {
+				return nil, errors.Wrapf(err, "Failed to retrieve disk information from \"%s\"", filepath.Join("/dev", entryName))
+			}
+
 			// Add to list
 			storage.Disks = append(storage.Disks, disk)
 		}


More information about the lxc-devel mailing list