Skip to content

Commit

Permalink
Add support for NVMe
Browse files Browse the repository at this point in the history
The sysfs contains some useful information about NVMe devices that
should be exporter by the Prometheus node exporter. Add a `NVMeClass`
function to collect the information for the node exporter.

See: prometheus/node_exporter#1891
Signed-off-by: Benjamin Drung <[email protected]>
  • Loading branch information
bdrung committed Mar 1, 2021
1 parent caa5b48 commit f514e44
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 0 deletions.
26 changes: 26 additions & 0 deletions fixtures.ttar
Original file line number Diff line number Diff line change
Expand Up @@ -3960,6 +3960,32 @@ Lines: 1
1
Mode: 644
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Directory: fixtures/sys/class/nvme
Mode: 775
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Directory: fixtures/sys/class/nvme/nvme0
Mode: 775
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Path: fixtures/sys/class/nvme/nvme0/firmware_rev
Lines: 1
1B2QEXP7
Mode: 664
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Path: fixtures/sys/class/nvme/nvme0/model
Lines: 1
Samsung SSD 970 PRO 512GB
Mode: 664
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Path: fixtures/sys/class/nvme/nvme0/serial
Lines: 1
S680HF8N190894I
Mode: 664
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Path: fixtures/sys/class/nvme/nvme0/state
Lines: 1
live
Mode: 664
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Directory: fixtures/sys/class/power_supply
Mode: 755
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Expand Down
87 changes: 87 additions & 0 deletions sysfs/class_nvme.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright 2021 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sysfs

import (
"fmt"
"io/ioutil"
"path/filepath"

"github.com/prometheus/procfs/internal/util"
)

const nvmeClassPath = "class/nvme"

// NVMeDevice contains info from files in /sys/class/nvme for a single NVMe device.
type NVMeDevice struct {
Name string
Serial string // /sys/class/nvme/<Name>/serial
Model string // /sys/class/nvme/<Name>/model
State string // /sys/class/nvme/<Name>/state
FirmwareRevision string // /sys/class/nvme/<Name>/firmware_rev
}

// NVMeClass is a collection of every NVMe device in /sys/class/nvme.
//
// The map keys are the names of the NVMe devices.
type NVMeClass map[string]NVMeDevice

// NVMeClass returns info for all NVMe devices read from /sys/class/nvme.
func (fs FS) NVMeClass() (NVMeClass, error) {
path := fs.sys.Path(nvmeClassPath)

dirs, err := ioutil.ReadDir(path)
if err != nil {
return nil, fmt.Errorf("failed to list NVMe devices at %q: %v", path, err)
}

nc := make(NVMeClass, len(dirs))
for _, d := range dirs {
device, err := fs.parseNVMeDevice(d.Name())
if err != nil {
return nil, err
}

nc[device.Name] = *device
}

return nc, nil
}

// Parse one NVMe device.
func (fs FS) parseNVMeDevice(name string) (*NVMeDevice, error) {
path := fs.sys.Path(nvmeClassPath, name)
device := NVMeDevice{Name: name}

for _, f := range [...]string{"firmware_rev", "model", "serial", "state"} {
name := filepath.Join(path, f)
value, err := util.SysReadFile(name)
if err != nil {
return nil, fmt.Errorf("failed to read file %q: %v", name, err)
}

switch f {
case "firmware_rev":
device.FirmwareRevision = value
case "model":
device.Model = value
case "serial":
device.Serial = value
case "state":
device.State = value
}
}

return &device, nil
}
48 changes: 48 additions & 0 deletions sysfs/class_nvme_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2021 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build !windows

package sysfs

import (
"testing"

"github.com/google/go-cmp/cmp"
)

func TestNVMeClass(t *testing.T) {
fs, err := NewFS(sysTestFixtures)
if err != nil {
t.Fatal(err)
}

got, err := fs.NVMeClass()
if err != nil {
t.Fatal(err)
}

want := NVMeClass{
"nvme0": NVMeDevice{
Name: "nvme0",
FirmwareRevision: "1B2QEXP7",
Model: "Samsung SSD 970 PRO 512GB",
Serial: "S680HF8N190894I",
State: "live",
},
}

if diff := cmp.Diff(want, got); diff != "" {
t.Fatalf("unexpected NVMe class (-want +got):\n%s", diff)
}
}

0 comments on commit f514e44

Please sign in to comment.