[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