From 17f1b279608f8f15060aa1f5b0db32040634238b Mon Sep 17 00:00:00 2001 From: Shireesh Anjal Date: Tue, 26 Sep 2023 17:41:23 +0530 Subject: [PATCH 1/2] Add drive model to partitions in health report Capture the drive model in partitions data in the health report. It will be read from `/sys/class/block//device/model` --- health.go | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/health.go b/health.go index 96e1d62..7d40205 100644 --- a/health.go +++ b/health.go @@ -25,10 +25,12 @@ import ( "encoding/json" "errors" "io" + "io/ioutil" "net/http" "net/url" "os" "os/exec" + "path" "path/filepath" "runtime" "strconv" @@ -69,6 +71,12 @@ const ( SrvNotInstalled = "not-installed" ) +const ( + sysClassBlock = "/sys/class/block" + devDir = "/dev/" + devLoopDir = "/dev/loop" +) + // NodeInfo - Interface to abstract any struct that contains address/endpoint and error fields type NodeInfo interface { GetAddr() string @@ -222,6 +230,7 @@ type Partition struct { Error string `json:"error,omitempty"` Device string `json:"device,omitempty"` + Model string `json:"model,omitempty"` Mountpoint string `json:"mountpoint,omitempty"` FSType string `json:"fs_type,omitempty"` MountOptions string `json:"mount_options,omitempty"` @@ -239,6 +248,40 @@ type Partitions struct { Partitions []Partition `json:"partitions,omitempty"` } +func getDeviceModel(partDevice string) (string, error) { + var model string + + partDevName := strings.ReplaceAll(partDevice, devDir, "") + partDevPath := path.Join(sysClassBlock, partDevName) + devPath, err := os.Readlink(partDevPath) + if err != nil { + return model, err + } + + if !path.IsAbs(devPath) { + devPath = path.Join(sysClassBlock, devPath) + } + + devModelPath := path.Join(devPath, "device", "model") + + _, err = os.Stat(devModelPath) + if err != nil { + // check parent dir + devModelPath = path.Join(devPath, "..", "device", "model") + _, err = os.Stat(devModelPath) + if err != nil { + return model, err + } + } + + data, err := ioutil.ReadFile(devModelPath) + if err == nil { + model = strings.TrimSpace(string(data)) + } + + return model, err +} + // GetPartitions returns all disk partitions information of a node running linux only operating system. func GetPartitions(ctx context.Context, addr string) Partitions { if runtime.GOOS != "linux" { @@ -270,8 +313,15 @@ func GetPartitions(ctx context.Context, addr string) Partitions { Error: err.Error(), }) } else { + var model string + device := parts[i].Device + if strings.HasPrefix(device, devDir) && !strings.HasPrefix(device, devLoopDir) { + // ignore any error in finding device model + model, _ = getDeviceModel(device) + } + partitions = append(partitions, Partition{ - Device: parts[i].Device, + Device: device, Mountpoint: parts[i].Mountpoint, FSType: parts[i].Fstype, MountOptions: strings.Join(parts[i].Opts, ","), @@ -280,6 +330,7 @@ func GetPartitions(ctx context.Context, addr string) Partitions { SpaceFree: usage.Free, InodeTotal: usage.InodesTotal, InodeFree: usage.InodesFree, + Model: model, }) } } From dd464f8bc421f0f57f7bf0aeeb644b90dafbb3e6 Mon Sep 17 00:00:00 2001 From: Shireesh Anjal Date: Thu, 28 Sep 2023 20:11:44 +0530 Subject: [PATCH 2/2] Read model from file under /run/udev/data/ --- health.go | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/health.go b/health.go index 7d40205..5e1d775 100644 --- a/health.go +++ b/health.go @@ -73,6 +73,7 @@ const ( const ( sysClassBlock = "/sys/class/block" + runDevDataPfx = "/run/udev/data/b" devDir = "/dev/" devLoopDir = "/dev/loop" ) @@ -252,31 +253,34 @@ func getDeviceModel(partDevice string) (string, error) { var model string partDevName := strings.ReplaceAll(partDevice, devDir, "") - partDevPath := path.Join(sysClassBlock, partDevName) - devPath, err := os.Readlink(partDevPath) + devPath := path.Join(sysClassBlock, partDevName, "dev") + + _, err := os.Stat(devPath) if err != nil { return model, err } - if !path.IsAbs(devPath) { - devPath = path.Join(sysClassBlock, devPath) + data, err := ioutil.ReadFile(devPath) + if err != nil { + return model, err } - devModelPath := path.Join(devPath, "device", "model") + majorMinor := strings.TrimSpace(string(data)) + driveInfoPath := runDevDataPfx + majorMinor - _, err = os.Stat(devModelPath) + f, err := os.Open(driveInfoPath) if err != nil { - // check parent dir - devModelPath = path.Join(devPath, "..", "device", "model") - _, err = os.Stat(devModelPath) - if err != nil { - return model, err - } + return model, err } + defer f.Close() - data, err := ioutil.ReadFile(devModelPath) - if err == nil { - model = strings.TrimSpace(string(data)) + buf := bufio.NewScanner(f) + for buf.Scan() { + field := strings.SplitN(buf.Text(), "=", 2) + if len(field) == 2 && field[0] == "E:ID_MODEL" { + model = field[1] + break + } } return model, err