fix(collector): show correct nvme capacity
Some nvme devices do not report their capacity through the usual 'user_capacity' field, instead the total capacity is reported with the 'nvme_total_capacity' field. Fixes: #466
This commit is contained in:
@@ -3,13 +3,14 @@ package detect
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/analogj/scrutiny/collector/pkg/common/shell"
|
"github.com/analogj/scrutiny/collector/pkg/common/shell"
|
||||||
"github.com/analogj/scrutiny/collector/pkg/config"
|
"github.com/analogj/scrutiny/collector/pkg/config"
|
||||||
"github.com/analogj/scrutiny/collector/pkg/models"
|
"github.com/analogj/scrutiny/collector/pkg/models"
|
||||||
"github.com/analogj/scrutiny/webapp/backend/pkg/models/collector"
|
"github.com/analogj/scrutiny/webapp/backend/pkg/models/collector"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Detect struct {
|
type Detect struct {
|
||||||
@@ -47,7 +48,7 @@ func (d *Detect) SmartctlScan() ([]models.Device, error) {
|
|||||||
return detectedDevices, nil
|
return detectedDevices, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//updates a device model with information from smartctl --scan
|
// updates a device model with information from smartctl --scan
|
||||||
// It has a couple of issues however:
|
// It has a couple of issues however:
|
||||||
// - WWN is provided as component data, rather than a "string". We'll have to generate the WWN value ourselves
|
// - WWN is provided as component data, rather than a "string". We'll have to generate the WWN value ourselves
|
||||||
// - WWN from smartctl only provided for ATA protocol drives, NVMe and SCSI drives do not include WWN.
|
// - WWN from smartctl only provided for ATA protocol drives, NVMe and SCSI drives do not include WWN.
|
||||||
@@ -81,8 +82,9 @@ func (d *Detect) SmartCtlInfo(device *models.Device) error {
|
|||||||
device.SerialNumber = availableDeviceInfo.SerialNumber
|
device.SerialNumber = availableDeviceInfo.SerialNumber
|
||||||
device.Firmware = availableDeviceInfo.FirmwareVersion
|
device.Firmware = availableDeviceInfo.FirmwareVersion
|
||||||
device.RotationSpeed = availableDeviceInfo.RotationRate
|
device.RotationSpeed = availableDeviceInfo.RotationRate
|
||||||
device.Capacity = availableDeviceInfo.UserCapacity.Bytes
|
device.Capacity = availableDeviceInfo.Capacity()
|
||||||
device.FormFactor = availableDeviceInfo.FormFactor.Name
|
device.FormFactor = availableDeviceInfo.FormFactor.Name
|
||||||
|
device.DeviceType = availableDeviceInfo.Device.Type
|
||||||
device.DeviceProtocol = availableDeviceInfo.Device.Protocol
|
device.DeviceProtocol = availableDeviceInfo.Device.Protocol
|
||||||
if len(availableDeviceInfo.Vendor) > 0 {
|
if len(availableDeviceInfo.Vendor) > 0 {
|
||||||
device.Manufacturer = availableDeviceInfo.Vendor
|
device.Manufacturer = availableDeviceInfo.Vendor
|
||||||
|
|||||||
@@ -1,19 +1,22 @@
|
|||||||
package detect_test
|
package detect_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
mock_shell "github.com/analogj/scrutiny/collector/pkg/common/shell/mock"
|
mock_shell "github.com/analogj/scrutiny/collector/pkg/common/shell/mock"
|
||||||
mock_config "github.com/analogj/scrutiny/collector/pkg/config/mock"
|
mock_config "github.com/analogj/scrutiny/collector/pkg/config/mock"
|
||||||
"github.com/analogj/scrutiny/collector/pkg/detect"
|
"github.com/analogj/scrutiny/collector/pkg/detect"
|
||||||
"github.com/analogj/scrutiny/collector/pkg/models"
|
"github.com/analogj/scrutiny/collector/pkg/models"
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"io/ioutil"
|
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDetect_SmartctlScan(t *testing.T) {
|
func TestDetect_SmartctlScan(t *testing.T) {
|
||||||
//setup
|
// setup
|
||||||
mockCtrl := gomock.NewController(t)
|
mockCtrl := gomock.NewController(t)
|
||||||
defer mockCtrl.Finish()
|
defer mockCtrl.Finish()
|
||||||
fakeConfig := mock_config.NewMockInterface(mockCtrl)
|
fakeConfig := mock_config.NewMockInterface(mockCtrl)
|
||||||
@@ -23,7 +26,7 @@ func TestDetect_SmartctlScan(t *testing.T) {
|
|||||||
fakeConfig.EXPECT().GetString("commands.metrics_scan_args").AnyTimes().Return("--scan --json")
|
fakeConfig.EXPECT().GetString("commands.metrics_scan_args").AnyTimes().Return("--scan --json")
|
||||||
|
|
||||||
fakeShell := mock_shell.NewMockInterface(mockCtrl)
|
fakeShell := mock_shell.NewMockInterface(mockCtrl)
|
||||||
testScanResults, err := ioutil.ReadFile("testdata/smartctl_scan_simple.json")
|
testScanResults, err := os.ReadFile("testdata/smartctl_scan_simple.json")
|
||||||
fakeShell.EXPECT().Command(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(string(testScanResults), err)
|
fakeShell.EXPECT().Command(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(string(testScanResults), err)
|
||||||
|
|
||||||
d := detect.Detect{
|
d := detect.Detect{
|
||||||
@@ -32,17 +35,17 @@ func TestDetect_SmartctlScan(t *testing.T) {
|
|||||||
Config: fakeConfig,
|
Config: fakeConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
//test
|
// test
|
||||||
scannedDevices, err := d.SmartctlScan()
|
scannedDevices, err := d.SmartctlScan()
|
||||||
|
|
||||||
//assert
|
// assert
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 7, len(scannedDevices))
|
require.Equal(t, 7, len(scannedDevices))
|
||||||
require.Equal(t, "scsi", scannedDevices[0].DeviceType)
|
require.Equal(t, "scsi", scannedDevices[0].DeviceType)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDetect_SmartctlScan_Megaraid(t *testing.T) {
|
func TestDetect_SmartctlScan_Megaraid(t *testing.T) {
|
||||||
//setup
|
// setup
|
||||||
mockCtrl := gomock.NewController(t)
|
mockCtrl := gomock.NewController(t)
|
||||||
defer mockCtrl.Finish()
|
defer mockCtrl.Finish()
|
||||||
fakeConfig := mock_config.NewMockInterface(mockCtrl)
|
fakeConfig := mock_config.NewMockInterface(mockCtrl)
|
||||||
@@ -52,7 +55,7 @@ func TestDetect_SmartctlScan_Megaraid(t *testing.T) {
|
|||||||
fakeConfig.EXPECT().GetString("commands.metrics_scan_args").AnyTimes().Return("--scan --json")
|
fakeConfig.EXPECT().GetString("commands.metrics_scan_args").AnyTimes().Return("--scan --json")
|
||||||
|
|
||||||
fakeShell := mock_shell.NewMockInterface(mockCtrl)
|
fakeShell := mock_shell.NewMockInterface(mockCtrl)
|
||||||
testScanResults, err := ioutil.ReadFile("testdata/smartctl_scan_megaraid.json")
|
testScanResults, err := os.ReadFile("testdata/smartctl_scan_megaraid.json")
|
||||||
fakeShell.EXPECT().Command(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(string(testScanResults), err)
|
fakeShell.EXPECT().Command(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(string(testScanResults), err)
|
||||||
|
|
||||||
d := detect.Detect{
|
d := detect.Detect{
|
||||||
@@ -61,20 +64,20 @@ func TestDetect_SmartctlScan_Megaraid(t *testing.T) {
|
|||||||
Config: fakeConfig,
|
Config: fakeConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
//test
|
// test
|
||||||
scannedDevices, err := d.SmartctlScan()
|
scannedDevices, err := d.SmartctlScan()
|
||||||
|
|
||||||
//assert
|
// assert
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 2, len(scannedDevices))
|
require.Equal(t, 2, len(scannedDevices))
|
||||||
require.Equal(t, []models.Device{
|
require.Equal(t, []models.Device{
|
||||||
models.Device{DeviceName: "bus/0", DeviceType: "megaraid,0"},
|
{DeviceName: "bus/0", DeviceType: "megaraid,0"},
|
||||||
models.Device{DeviceName: "bus/0", DeviceType: "megaraid,1"},
|
{DeviceName: "bus/0", DeviceType: "megaraid,1"},
|
||||||
}, scannedDevices)
|
}, scannedDevices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDetect_SmartctlScan_Nvme(t *testing.T) {
|
func TestDetect_SmartctlScan_Nvme(t *testing.T) {
|
||||||
//setup
|
// setup
|
||||||
mockCtrl := gomock.NewController(t)
|
mockCtrl := gomock.NewController(t)
|
||||||
defer mockCtrl.Finish()
|
defer mockCtrl.Finish()
|
||||||
fakeConfig := mock_config.NewMockInterface(mockCtrl)
|
fakeConfig := mock_config.NewMockInterface(mockCtrl)
|
||||||
@@ -84,7 +87,7 @@ func TestDetect_SmartctlScan_Nvme(t *testing.T) {
|
|||||||
fakeConfig.EXPECT().GetString("commands.metrics_scan_args").AnyTimes().Return("--scan --json")
|
fakeConfig.EXPECT().GetString("commands.metrics_scan_args").AnyTimes().Return("--scan --json")
|
||||||
|
|
||||||
fakeShell := mock_shell.NewMockInterface(mockCtrl)
|
fakeShell := mock_shell.NewMockInterface(mockCtrl)
|
||||||
testScanResults, err := ioutil.ReadFile("testdata/smartctl_scan_nvme.json")
|
testScanResults, err := os.ReadFile("testdata/smartctl_scan_nvme.json")
|
||||||
fakeShell.EXPECT().Command(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(string(testScanResults), err)
|
fakeShell.EXPECT().Command(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(string(testScanResults), err)
|
||||||
|
|
||||||
d := detect.Detect{
|
d := detect.Detect{
|
||||||
@@ -93,19 +96,19 @@ func TestDetect_SmartctlScan_Nvme(t *testing.T) {
|
|||||||
Config: fakeConfig,
|
Config: fakeConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
//test
|
// test
|
||||||
scannedDevices, err := d.SmartctlScan()
|
scannedDevices, err := d.SmartctlScan()
|
||||||
|
|
||||||
//assert
|
// assert
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 1, len(scannedDevices))
|
require.Equal(t, 1, len(scannedDevices))
|
||||||
require.Equal(t, []models.Device{
|
require.Equal(t, []models.Device{
|
||||||
models.Device{DeviceName: "nvme0", DeviceType: "nvme"},
|
{DeviceName: "nvme0", DeviceType: "nvme"},
|
||||||
}, scannedDevices)
|
}, scannedDevices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDetect_TransformDetectedDevices_Empty(t *testing.T) {
|
func TestDetect_TransformDetectedDevices_Empty(t *testing.T) {
|
||||||
//setup
|
// setup
|
||||||
mockCtrl := gomock.NewController(t)
|
mockCtrl := gomock.NewController(t)
|
||||||
defer mockCtrl.Finish()
|
defer mockCtrl.Finish()
|
||||||
fakeConfig := mock_config.NewMockInterface(mockCtrl)
|
fakeConfig := mock_config.NewMockInterface(mockCtrl)
|
||||||
@@ -129,16 +132,16 @@ func TestDetect_TransformDetectedDevices_Empty(t *testing.T) {
|
|||||||
Config: fakeConfig,
|
Config: fakeConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
//test
|
// test
|
||||||
transformedDevices := d.TransformDetectedDevices(detectedDevices)
|
transformedDevices := d.TransformDetectedDevices(detectedDevices)
|
||||||
|
|
||||||
//assert
|
// assert
|
||||||
require.Equal(t, "sda", transformedDevices[0].DeviceName)
|
require.Equal(t, "sda", transformedDevices[0].DeviceName)
|
||||||
require.Equal(t, "scsi", transformedDevices[0].DeviceType)
|
require.Equal(t, "scsi", transformedDevices[0].DeviceType)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDetect_TransformDetectedDevices_Ignore(t *testing.T) {
|
func TestDetect_TransformDetectedDevices_Ignore(t *testing.T) {
|
||||||
//setup
|
// setup
|
||||||
mockCtrl := gomock.NewController(t)
|
mockCtrl := gomock.NewController(t)
|
||||||
defer mockCtrl.Finish()
|
defer mockCtrl.Finish()
|
||||||
fakeConfig := mock_config.NewMockInterface(mockCtrl)
|
fakeConfig := mock_config.NewMockInterface(mockCtrl)
|
||||||
@@ -162,15 +165,15 @@ func TestDetect_TransformDetectedDevices_Ignore(t *testing.T) {
|
|||||||
Config: fakeConfig,
|
Config: fakeConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
//test
|
// test
|
||||||
transformedDevices := d.TransformDetectedDevices(detectedDevices)
|
transformedDevices := d.TransformDetectedDevices(detectedDevices)
|
||||||
|
|
||||||
//assert
|
// assert
|
||||||
require.Equal(t, []models.Device{}, transformedDevices)
|
require.Equal(t, []models.Device{}, transformedDevices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDetect_TransformDetectedDevices_Raid(t *testing.T) {
|
func TestDetect_TransformDetectedDevices_Raid(t *testing.T) {
|
||||||
//setup
|
// setup
|
||||||
mockCtrl := gomock.NewController(t)
|
mockCtrl := gomock.NewController(t)
|
||||||
defer mockCtrl.Finish()
|
defer mockCtrl.Finish()
|
||||||
fakeConfig := mock_config.NewMockInterface(mockCtrl)
|
fakeConfig := mock_config.NewMockInterface(mockCtrl)
|
||||||
@@ -187,7 +190,8 @@ func TestDetect_TransformDetectedDevices_Raid(t *testing.T) {
|
|||||||
Device: "/dev/twa0",
|
Device: "/dev/twa0",
|
||||||
DeviceType: []string{"3ware,0", "3ware,1", "3ware,2", "3ware,3", "3ware,4", "3ware,5"},
|
DeviceType: []string{"3ware,0", "3ware,1", "3ware,2", "3ware,3", "3ware,4", "3ware,5"},
|
||||||
Ignore: false,
|
Ignore: false,
|
||||||
}})
|
},
|
||||||
|
})
|
||||||
detectedDevices := models.Scan{
|
detectedDevices := models.Scan{
|
||||||
Devices: []models.ScanDevice{
|
Devices: []models.ScanDevice{
|
||||||
{
|
{
|
||||||
@@ -203,15 +207,15 @@ func TestDetect_TransformDetectedDevices_Raid(t *testing.T) {
|
|||||||
Config: fakeConfig,
|
Config: fakeConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
//test
|
// test
|
||||||
transformedDevices := d.TransformDetectedDevices(detectedDevices)
|
transformedDevices := d.TransformDetectedDevices(detectedDevices)
|
||||||
|
|
||||||
//assert
|
// assert
|
||||||
require.Equal(t, 12, len(transformedDevices))
|
require.Equal(t, 12, len(transformedDevices))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDetect_TransformDetectedDevices_Simple(t *testing.T) {
|
func TestDetect_TransformDetectedDevices_Simple(t *testing.T) {
|
||||||
//setup
|
// setup
|
||||||
mockCtrl := gomock.NewController(t)
|
mockCtrl := gomock.NewController(t)
|
||||||
defer mockCtrl.Finish()
|
defer mockCtrl.Finish()
|
||||||
fakeConfig := mock_config.NewMockInterface(mockCtrl)
|
fakeConfig := mock_config.NewMockInterface(mockCtrl)
|
||||||
@@ -234,17 +238,17 @@ func TestDetect_TransformDetectedDevices_Simple(t *testing.T) {
|
|||||||
Config: fakeConfig,
|
Config: fakeConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
//test
|
// test
|
||||||
transformedDevices := d.TransformDetectedDevices(detectedDevices)
|
transformedDevices := d.TransformDetectedDevices(detectedDevices)
|
||||||
|
|
||||||
//assert
|
// assert
|
||||||
require.Equal(t, 1, len(transformedDevices))
|
require.Equal(t, 1, len(transformedDevices))
|
||||||
require.Equal(t, "sat+megaraid", transformedDevices[0].DeviceType)
|
require.Equal(t, "sat+megaraid", transformedDevices[0].DeviceType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// test https://github.com/AnalogJ/scrutiny/issues/255#issuecomment-1164024126
|
// test https://github.com/AnalogJ/scrutiny/issues/255#issuecomment-1164024126
|
||||||
func TestDetect_TransformDetectedDevices_WithoutDeviceTypeOverride(t *testing.T) {
|
func TestDetect_TransformDetectedDevices_WithoutDeviceTypeOverride(t *testing.T) {
|
||||||
//setup
|
// setup
|
||||||
mockCtrl := gomock.NewController(t)
|
mockCtrl := gomock.NewController(t)
|
||||||
defer mockCtrl.Finish()
|
defer mockCtrl.Finish()
|
||||||
fakeConfig := mock_config.NewMockInterface(mockCtrl)
|
fakeConfig := mock_config.NewMockInterface(mockCtrl)
|
||||||
@@ -267,16 +271,16 @@ func TestDetect_TransformDetectedDevices_WithoutDeviceTypeOverride(t *testing.T)
|
|||||||
Config: fakeConfig,
|
Config: fakeConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
//test
|
// test
|
||||||
transformedDevices := d.TransformDetectedDevices(detectedDevices)
|
transformedDevices := d.TransformDetectedDevices(detectedDevices)
|
||||||
|
|
||||||
//assert
|
// assert
|
||||||
require.Equal(t, 1, len(transformedDevices))
|
require.Equal(t, 1, len(transformedDevices))
|
||||||
require.Equal(t, "scsi", transformedDevices[0].DeviceType)
|
require.Equal(t, "scsi", transformedDevices[0].DeviceType)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDetect_TransformDetectedDevices_WhenDeviceNotDetected(t *testing.T) {
|
func TestDetect_TransformDetectedDevices_WhenDeviceNotDetected(t *testing.T) {
|
||||||
//setup
|
// setup
|
||||||
mockCtrl := gomock.NewController(t)
|
mockCtrl := gomock.NewController(t)
|
||||||
defer mockCtrl.Finish()
|
defer mockCtrl.Finish()
|
||||||
fakeConfig := mock_config.NewMockInterface(mockCtrl)
|
fakeConfig := mock_config.NewMockInterface(mockCtrl)
|
||||||
@@ -290,10 +294,69 @@ func TestDetect_TransformDetectedDevices_WhenDeviceNotDetected(t *testing.T) {
|
|||||||
Config: fakeConfig,
|
Config: fakeConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
//test
|
// test
|
||||||
transformedDevices := d.TransformDetectedDevices(detectedDevices)
|
transformedDevices := d.TransformDetectedDevices(detectedDevices)
|
||||||
|
|
||||||
//assert
|
// assert
|
||||||
require.Equal(t, 1, len(transformedDevices))
|
require.Equal(t, 1, len(transformedDevices))
|
||||||
require.Equal(t, "ata", transformedDevices[0].DeviceType)
|
require.Equal(t, "ata", transformedDevices[0].DeviceType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDetect_SmartCtlInfo(t *testing.T) {
|
||||||
|
t.Run("should report nvme info", func(t *testing.T) {
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
|
||||||
|
const (
|
||||||
|
someArgs = "--info --json"
|
||||||
|
|
||||||
|
// device info
|
||||||
|
someDeviceName = "some-device-name"
|
||||||
|
someModelName = "KCD61LUL3T84"
|
||||||
|
someSerialNumber = "61Q0A05UT7B8"
|
||||||
|
someFirmware = "8002"
|
||||||
|
someDeviceProtocol = "NVMe"
|
||||||
|
someDeviceType = "nvme"
|
||||||
|
someCapacity int64 = 3840755982336
|
||||||
|
)
|
||||||
|
|
||||||
|
fakeConfig := mock_config.NewMockInterface(ctrl)
|
||||||
|
fakeConfig.EXPECT().
|
||||||
|
GetCommandMetricsInfoArgs("/dev/" + someDeviceName).
|
||||||
|
Return(someArgs)
|
||||||
|
fakeConfig.EXPECT().
|
||||||
|
GetString("commands.metrics_smartctl_bin").
|
||||||
|
Return("smartctl")
|
||||||
|
|
||||||
|
someLogger := logrus.WithFields(logrus.Fields{})
|
||||||
|
|
||||||
|
smartctlInfoResults, err := os.ReadFile("testdata/smartctl_info_nvme.json")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
fakeShell := mock_shell.NewMockInterface(ctrl)
|
||||||
|
fakeShell.EXPECT().
|
||||||
|
Command(someLogger, "smartctl", append(strings.Split(someArgs, " "), "/dev/"+someDeviceName), "", gomock.Any()).
|
||||||
|
Return(string(smartctlInfoResults), err)
|
||||||
|
|
||||||
|
d := detect.Detect{
|
||||||
|
Logger: someLogger,
|
||||||
|
Shell: fakeShell,
|
||||||
|
Config: fakeConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
someDevice := &models.Device{
|
||||||
|
WWN: "some wwn",
|
||||||
|
DeviceName: someDeviceName,
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NoError(t, d.SmartCtlInfo(someDevice))
|
||||||
|
|
||||||
|
assert.Equal(t, someDeviceName, someDevice.DeviceName)
|
||||||
|
assert.Equal(t, someModelName, someDevice.ModelName)
|
||||||
|
assert.Equal(t, someSerialNumber, someDevice.SerialNumber)
|
||||||
|
assert.Equal(t, someFirmware, someDevice.Firmware)
|
||||||
|
assert.Equal(t, someDeviceProtocol, someDevice.DeviceProtocol)
|
||||||
|
assert.Equal(t, someDeviceType, someDevice.DeviceType)
|
||||||
|
assert.Equal(t, someCapacity, someDevice.Capacity)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"json_format_version": [
|
||||||
|
1,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"smartctl": {
|
||||||
|
"version": [
|
||||||
|
7,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
"svn_revision": "5155",
|
||||||
|
"platform_info": "x86_64-linux-6.1.69-talos",
|
||||||
|
"build_info": "(local build)",
|
||||||
|
"argv": [
|
||||||
|
"smartctl",
|
||||||
|
"--info",
|
||||||
|
"--json",
|
||||||
|
"/dev/nvme4"
|
||||||
|
],
|
||||||
|
"exit_status": 0
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"name": "/dev/nvme4",
|
||||||
|
"info_name": "/dev/nvme4",
|
||||||
|
"type": "nvme",
|
||||||
|
"protocol": "NVMe"
|
||||||
|
},
|
||||||
|
"model_name": "KCD61LUL3T84",
|
||||||
|
"serial_number": "61Q0A05UT7B8",
|
||||||
|
"firmware_version": "8002",
|
||||||
|
"nvme_pci_vendor": {
|
||||||
|
"id": 7695,
|
||||||
|
"subsystem_id": 7695
|
||||||
|
},
|
||||||
|
"nvme_ieee_oui_identifier": 9233294,
|
||||||
|
"nvme_total_capacity": 3840755982336,
|
||||||
|
"nvme_unallocated_capacity": 0,
|
||||||
|
"nvme_controller_id": 1,
|
||||||
|
"nvme_version": {
|
||||||
|
"string": "1.4",
|
||||||
|
"value": 66560
|
||||||
|
},
|
||||||
|
"nvme_number_of_namespaces": 16,
|
||||||
|
"local_time": {
|
||||||
|
"time_t": 1706045146,
|
||||||
|
"asctime": "Tue Jan 23 21:25:46 2024 UTC"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,14 +27,11 @@ type SmartInfo struct {
|
|||||||
Oui uint64 `json:"oui"`
|
Oui uint64 `json:"oui"`
|
||||||
ID uint64 `json:"id"`
|
ID uint64 `json:"id"`
|
||||||
} `json:"wwn"`
|
} `json:"wwn"`
|
||||||
FirmwareVersion string `json:"firmware_version"`
|
FirmwareVersion string `json:"firmware_version"`
|
||||||
UserCapacity struct {
|
UserCapacity UserCapacity `json:"user_capacity"`
|
||||||
Blocks int64 `json:"blocks"`
|
LogicalBlockSize int `json:"logical_block_size"`
|
||||||
Bytes int64 `json:"bytes"`
|
PhysicalBlockSize int `json:"physical_block_size"`
|
||||||
} `json:"user_capacity"`
|
RotationRate int `json:"rotation_rate"`
|
||||||
LogicalBlockSize int `json:"logical_block_size"`
|
|
||||||
PhysicalBlockSize int `json:"physical_block_size"`
|
|
||||||
RotationRate int `json:"rotation_rate"`
|
|
||||||
FormFactor struct {
|
FormFactor struct {
|
||||||
AtaValue int `json:"ata_value"`
|
AtaValue int `json:"ata_value"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@@ -210,9 +207,10 @@ type SmartInfo struct {
|
|||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
SubsystemID int `json:"subsystem_id"`
|
SubsystemID int `json:"subsystem_id"`
|
||||||
} `json:"nvme_pci_vendor"`
|
} `json:"nvme_pci_vendor"`
|
||||||
NvmeIeeeOuiIdentifier int `json:"nvme_ieee_oui_identifier"`
|
NvmeIeeeOuiIdentifier int `json:"nvme_ieee_oui_identifier"`
|
||||||
NvmeControllerID int `json:"nvme_controller_id"`
|
NvmeTotalCapacity int64 `json:"nvme_total_capacity"`
|
||||||
NvmeNumberOfNamespaces int `json:"nvme_number_of_namespaces"`
|
NvmeControllerID int `json:"nvme_controller_id"`
|
||||||
|
NvmeNumberOfNamespaces int `json:"nvme_number_of_namespaces"`
|
||||||
NvmeNamespaces []struct {
|
NvmeNamespaces []struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Size struct {
|
Size struct {
|
||||||
@@ -239,7 +237,23 @@ type SmartInfo struct {
|
|||||||
ScsiErrorCounterLog ScsiErrorCounterLog `json:"scsi_error_counter_log"`
|
ScsiErrorCounterLog ScsiErrorCounterLog `json:"scsi_error_counter_log"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//Primary Attribute Structs
|
// Capacity finds the total capacity of the device in bytes, or 0 if unknown.
|
||||||
|
func (s *SmartInfo) Capacity() int64 {
|
||||||
|
switch {
|
||||||
|
case s.NvmeTotalCapacity > 0:
|
||||||
|
return s.NvmeTotalCapacity
|
||||||
|
case s.UserCapacity.Bytes > 0:
|
||||||
|
return s.UserCapacity.Bytes
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserCapacity struct {
|
||||||
|
Blocks int64 `json:"blocks"`
|
||||||
|
Bytes int64 `json:"bytes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Primary Attribute Structs
|
||||||
type AtaSmartAttributesTableItem struct {
|
type AtaSmartAttributesTableItem struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSmartInfo_Capacity(t *testing.T) {
|
||||||
|
t.Run("should report nvme capacity", func(t *testing.T) {
|
||||||
|
smartInfo := SmartInfo{
|
||||||
|
UserCapacity: UserCapacity{
|
||||||
|
Bytes: 1234,
|
||||||
|
},
|
||||||
|
NvmeTotalCapacity: 5678,
|
||||||
|
}
|
||||||
|
assert.Equal(t, int64(5678), smartInfo.Capacity())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should report user capacity", func(t *testing.T) {
|
||||||
|
smartInfo := SmartInfo{
|
||||||
|
UserCapacity: UserCapacity{
|
||||||
|
Bytes: 1234,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Equal(t, int64(1234), smartInfo.Capacity())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should report 0 for unknown capacities", func(t *testing.T) {
|
||||||
|
var smartInfo SmartInfo
|
||||||
|
assert.Zero(t, smartInfo.Capacity())
|
||||||
|
})
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user