diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-26 08:15:24 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-26 08:15:35 +0000 |
commit | f09848204fa5283d21ea43e262ee41aa578e1808 (patch) | |
tree | c62385d7adf209fa6a798635954d887f718fb3fb /src/go/plugin/go.d/modules/adaptecraid | |
parent | Releasing debian version 1.46.3-2. (diff) | |
download | netdata-f09848204fa5283d21ea43e262ee41aa578e1808.tar.xz netdata-f09848204fa5283d21ea43e262ee41aa578e1808.zip |
Merging upstream version 1.47.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/go/plugin/go.d/modules/adaptecraid')
18 files changed, 1650 insertions, 0 deletions
diff --git a/src/go/plugin/go.d/modules/adaptecraid/README.md b/src/go/plugin/go.d/modules/adaptecraid/README.md new file mode 120000 index 00000000..0a156618 --- /dev/null +++ b/src/go/plugin/go.d/modules/adaptecraid/README.md @@ -0,0 +1 @@ +integrations/adaptec_raid.md
\ No newline at end of file diff --git a/src/go/plugin/go.d/modules/adaptecraid/adaptec.go b/src/go/plugin/go.d/modules/adaptecraid/adaptec.go new file mode 100644 index 00000000..264390e1 --- /dev/null +++ b/src/go/plugin/go.d/modules/adaptecraid/adaptec.go @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package adaptecraid + +import ( + _ "embed" + "errors" + "time" + + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module" + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web" +) + +//go:embed "config_schema.json" +var configSchema string + +func init() { + module.Register("adaptec_raid", module.Creator{ + JobConfigSchema: configSchema, + Defaults: module.Defaults{ + UpdateEvery: 10, + }, + Create: func() module.Module { return New() }, + Config: func() any { return &Config{} }, + }) +} + +func New() *AdaptecRaid { + return &AdaptecRaid{ + Config: Config{ + Timeout: web.Duration(time.Second * 2), + }, + charts: &module.Charts{}, + lds: make(map[string]bool), + pds: make(map[string]bool), + } +} + +type Config struct { + UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"` + Timeout web.Duration `yaml:"timeout,omitempty" json:"timeout"` +} + +type ( + AdaptecRaid struct { + module.Base + Config `yaml:",inline" json:""` + + charts *module.Charts + + exec arcconfCli + + lds map[string]bool + pds map[string]bool + } + arcconfCli interface { + logicalDevicesInfo() ([]byte, error) + physicalDevicesInfo() ([]byte, error) + } +) + +func (a *AdaptecRaid) Configuration() any { + return a.Config +} + +func (a *AdaptecRaid) Init() error { + arcconfExec, err := a.initArcconfCliExec() + if err != nil { + a.Errorf("arcconf exec initialization: %v", err) + return err + } + a.exec = arcconfExec + + return nil +} + +func (a *AdaptecRaid) Check() error { + mx, err := a.collect() + if err != nil { + a.Error(err) + return err + } + + if len(mx) == 0 { + return errors.New("no metrics collected") + } + + return nil +} + +func (a *AdaptecRaid) Charts() *module.Charts { + return a.charts +} + +func (a *AdaptecRaid) Collect() map[string]int64 { + mx, err := a.collect() + if err != nil { + a.Error(err) + } + + if len(mx) == 0 { + return nil + } + + return mx +} + +func (a *AdaptecRaid) Cleanup() {} diff --git a/src/go/plugin/go.d/modules/adaptecraid/adaptec_test.go b/src/go/plugin/go.d/modules/adaptecraid/adaptec_test.go new file mode 100644 index 00000000..9abe5c98 --- /dev/null +++ b/src/go/plugin/go.d/modules/adaptecraid/adaptec_test.go @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package adaptecraid + +import ( + "errors" + "os" + "testing" + + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + dataConfigJSON, _ = os.ReadFile("testdata/config.json") + dataConfigYAML, _ = os.ReadFile("testdata/config.yaml") + + dataLogicalDevicesOld, _ = os.ReadFile("testdata/getconfig-ld-old.txt") + dataPhysicalDevicesOld, _ = os.ReadFile("testdata/getconfig-pd-old.txt") + dataLogicalDevicesCurrent, _ = os.ReadFile("testdata/getconfig-ld-current.txt") + dataPhysicalDevicesCurrent, _ = os.ReadFile("testdata/getconfig-pd-current.txt") +) + +func Test_testDataIsValid(t *testing.T) { + for name, data := range map[string][]byte{ + "dataConfigJSON": dataConfigJSON, + "dataConfigYAML": dataConfigYAML, + + "dataLogicalDevicesOld": dataLogicalDevicesOld, + "dataPhysicalDevicesOld": dataPhysicalDevicesOld, + "dataLogicalDevicesCurrent": dataLogicalDevicesCurrent, + "dataPhysicalDevicesCurrent": dataPhysicalDevicesCurrent, + } { + require.NotNil(t, data, name) + } +} + +func TestAdaptecRaid_ConfigurationSerialize(t *testing.T) { + module.TestConfigurationSerialize(t, &AdaptecRaid{}, dataConfigJSON, dataConfigYAML) +} + +func TestAdaptecRaid_Init(t *testing.T) { + tests := map[string]struct { + config Config + wantFail bool + }{ + "fails if 'ndsudo' not found": { + wantFail: true, + config: New().Config, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + adaptec := New() + + if test.wantFail { + assert.Error(t, adaptec.Init()) + } else { + assert.NoError(t, adaptec.Init()) + } + }) + } +} + +func TestAdaptecRaid_Cleanup(t *testing.T) { + tests := map[string]struct { + prepare func() *AdaptecRaid + }{ + "not initialized exec": { + prepare: func() *AdaptecRaid { + return New() + }, + }, + "after check": { + prepare: func() *AdaptecRaid { + adaptec := New() + adaptec.exec = prepareMockOkCurrent() + _ = adaptec.Check() + return adaptec + }, + }, + "after collect": { + prepare: func() *AdaptecRaid { + adaptec := New() + adaptec.exec = prepareMockOkCurrent() + _ = adaptec.Collect() + return adaptec + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + adaptec := test.prepare() + + assert.NotPanics(t, adaptec.Cleanup) + }) + } +} + +func TestAdaptecRaid_Charts(t *testing.T) { + assert.NotNil(t, New().Charts()) +} + +func TestAdaptecRaid_Check(t *testing.T) { + tests := map[string]struct { + prepareMock func() *mockArcconfExec + wantFail bool + }{ + "success case old data": { + wantFail: false, + prepareMock: prepareMockOkOld, + }, + "success case current data": { + wantFail: false, + prepareMock: prepareMockOkCurrent, + }, + "err on exec": { + wantFail: true, + prepareMock: prepareMockErr, + }, + "unexpected response": { + wantFail: true, + prepareMock: prepareMockUnexpectedResponse, + }, + "empty response": { + wantFail: true, + prepareMock: prepareMockEmptyResponse, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + adaptec := New() + mock := test.prepareMock() + adaptec.exec = mock + + if test.wantFail { + assert.Error(t, adaptec.Check()) + } else { + assert.NoError(t, adaptec.Check()) + } + }) + } +} + +func TestAdaptecRaid_Collect(t *testing.T) { + tests := map[string]struct { + prepareMock func() *mockArcconfExec + wantMetrics map[string]int64 + wantCharts int + }{ + "success case old data": { + prepareMock: prepareMockOkOld, + wantCharts: len(ldChartsTmpl)*1 + (len(pdChartsTmpl)-1)*4, + wantMetrics: map[string]int64{ + "ld_0_health_state_critical": 0, + "ld_0_health_state_ok": 1, + "pd_0_health_state_critical": 0, + "pd_0_health_state_ok": 1, + "pd_0_smart_warnings": 0, + "pd_1_health_state_critical": 0, + "pd_1_health_state_ok": 1, + "pd_1_smart_warnings": 0, + "pd_2_health_state_critical": 0, + "pd_2_health_state_ok": 1, + "pd_2_smart_warnings": 0, + "pd_3_health_state_critical": 0, + "pd_3_health_state_ok": 1, + "pd_3_smart_warnings": 0, + }, + }, + "success case current data": { + prepareMock: prepareMockOkCurrent, + wantCharts: len(ldChartsTmpl)*1 + (len(pdChartsTmpl)-1)*6, + wantMetrics: map[string]int64{ + "ld_0_health_state_critical": 0, + "ld_0_health_state_ok": 1, + "pd_0_health_state_critical": 0, + "pd_0_health_state_ok": 1, + "pd_0_smart_warnings": 0, + "pd_1_health_state_critical": 0, + "pd_1_health_state_ok": 1, + "pd_1_smart_warnings": 0, + "pd_2_health_state_critical": 0, + "pd_2_health_state_ok": 1, + "pd_2_smart_warnings": 0, + "pd_3_health_state_critical": 0, + "pd_3_health_state_ok": 1, + "pd_3_smart_warnings": 0, + "pd_4_health_state_critical": 0, + "pd_4_health_state_ok": 1, + "pd_4_smart_warnings": 0, + "pd_5_health_state_critical": 0, + "pd_5_health_state_ok": 1, + "pd_5_smart_warnings": 0, + }, + }, + "err on exec": { + prepareMock: prepareMockErr, + }, + "unexpected response": { + prepareMock: prepareMockUnexpectedResponse, + }, + "empty response": { + prepareMock: prepareMockUnexpectedResponse, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + adaptec := New() + mock := test.prepareMock() + adaptec.exec = mock + + mx := adaptec.Collect() + + assert.Equal(t, test.wantMetrics, mx) + assert.Len(t, *adaptec.Charts(), test.wantCharts) + }) + } +} + +func prepareMockOkOld() *mockArcconfExec { + return &mockArcconfExec{ + ldData: dataLogicalDevicesOld, + pdData: dataPhysicalDevicesOld, + } +} + +func prepareMockOkCurrent() *mockArcconfExec { + return &mockArcconfExec{ + ldData: dataLogicalDevicesCurrent, + pdData: dataPhysicalDevicesCurrent, + } +} + +func prepareMockErr() *mockArcconfExec { + return &mockArcconfExec{ + errOnInfo: true, + } +} + +func prepareMockUnexpectedResponse() *mockArcconfExec { + resp := []byte(` +Lorem ipsum dolor sit amet, consectetur adipiscing elit. +Nulla malesuada erat id magna mattis, eu viverra tellus rhoncus. +Fusce et felis pulvinar, posuere sem non, porttitor eros. +`) + return &mockArcconfExec{ + ldData: resp, + pdData: resp, + } +} + +func prepareMockEmptyResponse() *mockArcconfExec { + return &mockArcconfExec{} +} + +type mockArcconfExec struct { + errOnInfo bool + ldData []byte + pdData []byte +} + +func (m *mockArcconfExec) logicalDevicesInfo() ([]byte, error) { + if m.errOnInfo { + return nil, errors.New("mock.logicalDevicesInfo() error") + } + return m.ldData, nil +} + +func (m *mockArcconfExec) physicalDevicesInfo() ([]byte, error) { + if m.errOnInfo { + return nil, errors.New("mock.physicalDevicesInfo() error") + } + return m.pdData, nil +} diff --git a/src/go/plugin/go.d/modules/adaptecraid/charts.go b/src/go/plugin/go.d/modules/adaptecraid/charts.go new file mode 100644 index 00000000..65be2019 --- /dev/null +++ b/src/go/plugin/go.d/modules/adaptecraid/charts.go @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package adaptecraid + +import ( + "fmt" + "strconv" + + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module" +) + +const ( + prioLDStatus = module.Priority + iota + + prioPDState + prioPDSmartWarnings + prioPDSmartTemperature +) + +var ldChartsTmpl = module.Charts{ + ldStatusChartTmpl.Copy(), +} + +var ( + ldStatusChartTmpl = module.Chart{ + ID: "logical_device_%s_status", + Title: "Logical Device status", + Units: "status", + Fam: "ld health", + Ctx: "adaptecraid.logical_device_status", + Type: module.Line, + Priority: prioLDStatus, + Dims: module.Dims{ + {ID: "ld_%s_health_state_ok", Name: "ok"}, + {ID: "ld_%s_health_state_critical", Name: "critical"}, + }, + } +) + +var pdChartsTmpl = module.Charts{ + pdStateChartTmpl.Copy(), + pdSmartWarningChartTmpl.Copy(), + pdTemperatureChartTmpl.Copy(), +} + +var ( + pdStateChartTmpl = module.Chart{ + ID: "physical_device_%s_state", + Title: "Physical Device state", + Units: "state", + Fam: "pd health", + Ctx: "adaptecraid.physical_device_state", + Type: module.Line, + Priority: prioPDState, + Dims: module.Dims{ + {ID: "pd_%s_health_state_ok", Name: "ok"}, + {ID: "pd_%s_health_state_critical", Name: "critical"}, + }, + } + pdSmartWarningChartTmpl = module.Chart{ + ID: "physical_device_%s_smart_warnings", + Title: "Physical Device SMART warnings", + Units: "warnings", + Fam: "pd smart", + Ctx: "adaptecraid.physical_device_smart_warnings", + Type: module.Line, + Priority: prioPDSmartWarnings, + Dims: module.Dims{ + {ID: "pd_%s_smart_warnings", Name: "smart"}, + }, + } + pdTemperatureChartTmpl = module.Chart{ + ID: "physical_device_%s_temperature", + Title: "Physical Device temperature", + Units: "Celsius", + Fam: "pd temperature", + Ctx: "adaptecraid.physical_device_temperature", + Type: module.Line, + Priority: prioPDSmartTemperature, + Dims: module.Dims{ + {ID: "pd_%s_temperature", Name: "temperature"}, + }, + } +) + +func (a *AdaptecRaid) addLogicalDeviceCharts(ld *logicalDevice) { + charts := ldChartsTmpl.Copy() + + for _, chart := range *charts { + chart.ID = fmt.Sprintf(chart.ID, ld.number) + chart.Labels = []module.Label{ + {Key: "ld_number", Value: ld.number}, + {Key: "ld_name", Value: ld.name}, + {Key: "raid_level", Value: ld.raidLevel}, + } + for _, dim := range chart.Dims { + dim.ID = fmt.Sprintf(dim.ID, ld.number) + } + } + + if err := a.Charts().Add(*charts...); err != nil { + a.Warning(err) + } +} + +func (a *AdaptecRaid) addPhysicalDeviceCharts(pd *physicalDevice) { + charts := pdChartsTmpl.Copy() + + if _, err := strconv.ParseInt(pd.temperature, 10, 64); err != nil { + _ = charts.Remove(pdTemperatureChartTmpl.ID) + } + + for _, chart := range *charts { + chart.ID = fmt.Sprintf(chart.ID, pd.number) + chart.Labels = []module.Label{ + {Key: "pd_number", Value: pd.number}, + {Key: "location", Value: pd.location}, + {Key: "vendor", Value: pd.vendor}, + {Key: "model", Value: pd.model}, + } + for _, dim := range chart.Dims { + dim.ID = fmt.Sprintf(dim.ID, pd.number) + } + } + + if err := a.Charts().Add(*charts...); err != nil { + a.Warning(err) + } +} diff --git a/src/go/plugin/go.d/modules/adaptecraid/collect.go b/src/go/plugin/go.d/modules/adaptecraid/collect.go new file mode 100644 index 00000000..b4439ba8 --- /dev/null +++ b/src/go/plugin/go.d/modules/adaptecraid/collect.go @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package adaptecraid + +import ( + "strings" +) + +func (a *AdaptecRaid) collect() (map[string]int64, error) { + mx := make(map[string]int64) + + if err := a.collectLogicalDevices(mx); err != nil { + return nil, err + } + if err := a.collectPhysicalDevices(mx); err != nil { + return nil, err + } + + return mx, nil +} + +func getColonSepValue(line string) string { + i := strings.IndexByte(line, ':') + if i == -1 { + return "" + } + return strings.TrimSpace(line[i+1:]) +} diff --git a/src/go/plugin/go.d/modules/adaptecraid/collect_ld.go b/src/go/plugin/go.d/modules/adaptecraid/collect_ld.go new file mode 100644 index 00000000..180f9749 --- /dev/null +++ b/src/go/plugin/go.d/modules/adaptecraid/collect_ld.go @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package adaptecraid + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "strings" +) + +type logicalDevice struct { + number string + name string + raidLevel string + status string + failedStripes string +} + +func (a *AdaptecRaid) collectLogicalDevices(mx map[string]int64) error { + bs, err := a.exec.logicalDevicesInfo() + if err != nil { + return err + } + + devices, err := parseLogicDevInfo(bs) + if err != nil { + return err + } + + if len(devices) == 0 { + return errors.New("no logical devices found") + } + + for _, ld := range devices { + if !a.lds[ld.number] { + a.lds[ld.number] = true + a.addLogicalDeviceCharts(ld) + } + + px := fmt.Sprintf("ld_%s_", ld.number) + + // Unfortunately, all available states are unknown. + mx[px+"health_state_ok"] = 0 + mx[px+"health_state_critical"] = 0 + if isOkLDStatus(ld) { + mx[px+"health_state_ok"] = 1 + } else { + mx[px+"health_state_critical"] = 1 + } + } + + return nil +} + +func isOkLDStatus(ld *logicalDevice) bool { + // https://github.com/thomas-krenn/check_adaptec_raid/blob/a104fd88deede87df4f07403b44394bffb30c5c3/check_adaptec_raid#L340 + return ld.status == "Optimal" +} + +func parseLogicDevInfo(bs []byte) (map[string]*logicalDevice, error) { + devices := make(map[string]*logicalDevice) + + var ld *logicalDevice + + sc := bufio.NewScanner(bytes.NewReader(bs)) + + for sc.Scan() { + line := strings.TrimSpace(sc.Text()) + + if strings.HasPrefix(line, "Logical device number") || + strings.HasPrefix(line, "Logical Device number") { + parts := strings.Fields(line) + num := parts[len(parts)-1] + ld = &logicalDevice{number: num} + devices[num] = ld + continue + } + + if ld == nil { + continue + } + + switch { + case strings.HasPrefix(line, "Logical device name"), + strings.HasPrefix(line, "Logical Device name"): + ld.name = getColonSepValue(line) + case strings.HasPrefix(line, "RAID level"): + ld.raidLevel = getColonSepValue(line) + case strings.HasPrefix(line, "Status of logical device"), + strings.HasPrefix(line, "Status of Logical Device"): + ld.status = getColonSepValue(line) + case strings.HasPrefix(line, "Failed stripes"): + ld.failedStripes = getColonSepValue(line) + } + } + + return devices, nil +} diff --git a/src/go/plugin/go.d/modules/adaptecraid/collect_pd.go b/src/go/plugin/go.d/modules/adaptecraid/collect_pd.go new file mode 100644 index 00000000..272266b4 --- /dev/null +++ b/src/go/plugin/go.d/modules/adaptecraid/collect_pd.go @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package adaptecraid + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "strconv" + "strings" +) + +type physicalDevice struct { + number string + state string + location string + vendor string + model string + smart string + smartWarnings string + powerState string + temperature string +} + +func (a *AdaptecRaid) collectPhysicalDevices(mx map[string]int64) error { + bs, err := a.exec.physicalDevicesInfo() + if err != nil { + return err + } + + devices, err := parsePhysDevInfo(bs) + if err != nil { + return err + } + + if len(devices) == 0 { + return errors.New("no physical devices found") + } + + for _, pd := range devices { + if !a.pds[pd.number] { + a.pds[pd.number] = true + a.addPhysicalDeviceCharts(pd) + } + + px := fmt.Sprintf("pd_%s_", pd.number) + + // Unfortunately, all available states are unknown. + mx[px+"health_state_ok"] = 0 + mx[px+"health_state_critical"] = 0 + if isOkPDState(pd) { + mx[px+"health_state_ok"] = 1 + } else { + mx[px+"health_state_critical"] = 1 + } + + if v, err := strconv.ParseInt(pd.smartWarnings, 10, 64); err == nil { + mx[px+"smart_warnings"] = v + } + if v, err := strconv.ParseInt(pd.temperature, 10, 64); err == nil { + mx[px+"temperature"] = v + } + } + + return nil +} + +func isOkPDState(pd *physicalDevice) bool { + // https://github.com/thomas-krenn/check_adaptec_raid/blob/a104fd88deede87df4f07403b44394bffb30c5c3/check_adaptec_raid#L455 + switch pd.state { + case "Online", + "Global Hot-Spare", + "Dedicated Hot-Spare", + "Pooled Hot-Spare", + "Hot Spare", + "Ready", + "Online (JBOD)", + "Raw (Pass Through)": + return true + } + return false +} + +func parsePhysDevInfo(bs []byte) (map[string]*physicalDevice, error) { + devices := make(map[string]*physicalDevice) + + var pd *physicalDevice + + sc := bufio.NewScanner(bytes.NewReader(bs)) + + for sc.Scan() { + line := strings.TrimSpace(sc.Text()) + + if strings.HasPrefix(line, "Device #") { + num := strings.TrimPrefix(line, "Device #") + pd = &physicalDevice{number: num} + devices[num] = pd + continue + } + + if pd == nil { + continue + } + + switch { + case strings.HasPrefix(line, "State"): + pd.state = getColonSepValue(line) + case strings.HasPrefix(line, "Reported Location"): + pd.location = getColonSepValue(line) + case strings.HasPrefix(line, "Vendor"): + pd.vendor = getColonSepValue(line) + case strings.HasPrefix(line, "Model"): + pd.model = getColonSepValue(line) + case strings.HasPrefix(line, "S.M.A.R.T. warnings"): + pd.smartWarnings = getColonSepValue(line) + case strings.HasPrefix(line, "S.M.A.R.T."): + pd.smart = getColonSepValue(line) + case strings.HasPrefix(line, "Power State"): + pd.powerState = getColonSepValue(line) + case strings.HasPrefix(line, "Temperature"): + v := getColonSepValue(line) // '42 C/ 107 F' or 'Not Supported' + pd.temperature = strings.Fields(v)[0] + } + } + + return devices, nil +} diff --git a/src/go/plugin/go.d/modules/adaptecraid/config_schema.json b/src/go/plugin/go.d/modules/adaptecraid/config_schema.json new file mode 100644 index 00000000..ad54f158 --- /dev/null +++ b/src/go/plugin/go.d/modules/adaptecraid/config_schema.json @@ -0,0 +1,35 @@ +{ + "jsonSchema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Adaptec RAID collector configuration.", + "type": "object", + "properties": { + "update_every": { + "title": "Update every", + "description": "Data collection interval, measured in seconds.", + "type": "integer", + "minimum": 1, + "default": 10 + }, + "timeout": { + "title": "Timeout", + "description": "Timeout for executing the binary, specified in seconds.", + "type": "number", + "minimum": 0.5, + "default": 2 + } + }, + "additionalProperties": false, + "patternProperties": { + "^name$": {} + } + }, + "uiSchema": { + "uiOptions": { + "fullPage": true + }, + "timeout": { + "ui:help": "Accepts decimals for precise control (e.g., type 1.5 for 1.5 seconds)." + } + } +} diff --git a/src/go/plugin/go.d/modules/adaptecraid/exec.go b/src/go/plugin/go.d/modules/adaptecraid/exec.go new file mode 100644 index 00000000..0577e623 --- /dev/null +++ b/src/go/plugin/go.d/modules/adaptecraid/exec.go @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package adaptecraid + +import ( + "context" + "fmt" + "os/exec" + "time" + + "github.com/netdata/netdata/go/plugins/logger" +) + +func newArcconfCliExec(ndsudoPath string, timeout time.Duration, log *logger.Logger) *arcconfCliExec { + return &arcconfCliExec{ + Logger: log, + ndsudoPath: ndsudoPath, + timeout: timeout, + } +} + +type arcconfCliExec struct { + *logger.Logger + + ndsudoPath string + timeout time.Duration +} + +func (e *arcconfCliExec) logicalDevicesInfo() ([]byte, error) { + return e.execute("arcconf-ld-info") +} + +func (e *arcconfCliExec) physicalDevicesInfo() ([]byte, error) { + return e.execute("arcconf-pd-info") +} + +func (e *arcconfCliExec) execute(args ...string) ([]byte, error) { + ctx, cancel := context.WithTimeout(context.Background(), e.timeout) + defer cancel() + + cmd := exec.CommandContext(ctx, e.ndsudoPath, args...) + e.Debugf("executing '%s'", cmd) + + bs, err := cmd.Output() + if err != nil { + return nil, fmt.Errorf("error on '%s': %v", cmd, err) + } + + return bs, nil +} diff --git a/src/go/plugin/go.d/modules/adaptecraid/init.go b/src/go/plugin/go.d/modules/adaptecraid/init.go new file mode 100644 index 00000000..de8acc27 --- /dev/null +++ b/src/go/plugin/go.d/modules/adaptecraid/init.go @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package adaptecraid + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/netdata/netdata/go/plugins/pkg/executable" +) + +func (a *AdaptecRaid) initArcconfCliExec() (arcconfCli, error) { + ndsudoPath := filepath.Join(executable.Directory, "ndsudo") + + if _, err := os.Stat(ndsudoPath); err != nil { + return nil, fmt.Errorf("ndsudo executable not found: %v", err) + } + + arcconfExec := newArcconfCliExec(ndsudoPath, a.Timeout.Duration(), a.Logger) + + return arcconfExec, nil +} diff --git a/src/go/plugin/go.d/modules/adaptecraid/integrations/adaptec_raid.md b/src/go/plugin/go.d/modules/adaptecraid/integrations/adaptec_raid.md new file mode 100644 index 00000000..a38207ff --- /dev/null +++ b/src/go/plugin/go.d/modules/adaptecraid/integrations/adaptec_raid.md @@ -0,0 +1,229 @@ +<!--startmeta +custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/go/plugin/go.d/modules/adaptecraid/README.md" +meta_yaml: "https://github.com/netdata/netdata/edit/master/src/go/plugin/go.d/modules/adaptecraid/metadata.yaml" +sidebar_label: "Adaptec RAID" +learn_status: "Published" +learn_rel_path: "Collecting Metrics/Storage, Mount Points and Filesystems" +most_popular: False +message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE COLLECTOR'S metadata.yaml FILE" +endmeta--> + +# Adaptec RAID + + +<img src="https://netdata.cloud/img/adaptec.svg" width="150"/> + + +Plugin: go.d.plugin +Module: adaptec_raid + +<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" /> + +## Overview + +Monitors the health of Adaptec Hardware RAID by tracking the status of logical and physical devices in your storage system. +It relies on the `arcconf` CLI tool but avoids directly executing the binary. +Instead, it utilizes `ndsudo`, a Netdata helper specifically designed to run privileged commands securely within the Netdata environment. +This approach eliminates the need to use `sudo`, improving security and potentially simplifying permission management. + +Executed commands: +- `arcconf GETCONFIG 1 LD` +- `arcconf GETCONFIG 1 PD` + + + + +This collector is supported on all platforms. + +This collector only supports collecting metrics from a single instance of this integration. + + +### Default Behavior + +#### Auto-Detection + +This integration doesn't support auto-detection. + +#### Limits + +The default configuration for this integration does not impose any limits on data collection. + +#### Performance Impact + +The default configuration for this integration is not expected to impose a significant performance impact on the system. + + +## Metrics + +Metrics grouped by *scope*. + +The scope defines the instance that the metric belongs to. An instance is uniquely identified by a set of labels. + + + +### Per logical device + +These metrics refer to the Logical Device (LD). + +Labels: + +| Label | Description | +|:-----------|:----------------| +| ld_number | Logical device index number | +| ld_name | Logical device name | +| raid_level | RAID level | + +Metrics: + +| Metric | Dimensions | Unit | +|:------|:----------|:----| +| adaptecraid.logical_device_status | ok, critical | status | + +### Per physical device + +These metrics refer to the Physical Device (PD). + +Labels: + +| Label | Description | +|:-----------|:----------------| +| pd_number | Physical device index number | +| location | Physical device location (e.g. Connector 0, Device 1) | +| vendor | Physical device vendor | +| model | Physical device model | + +Metrics: + +| Metric | Dimensions | Unit | +|:------|:----------|:----| +| adaptecraid.physical_device_state | ok, critical | status | +| adaptecraid.physical_device_smart_warnings | smart | warnings | +| adaptecraid.physical_device_temperature | temperature | Celsius | + + + +## Alerts + + +The following alerts are available: + +| Alert name | On metric | Description | +|:------------|:----------|:------------| +| [ adaptec_raid_ld_health_status ](https://github.com/netdata/netdata/blob/master/src/health/health.d/adaptec_raid.conf) | adaptecraid.logical_device_status | Adaptec RAID logical device (number ${label:ld_number} name ${label:ld_name}) health status is critical | +| [ adaptec_raid_pd_health_state ](https://github.com/netdata/netdata/blob/master/src/health/health.d/adaptec_raid.conf) | adaptecraid.physical_device_state | Adaptec RAID physical device (number ${label:pd_number} location ${label:location}) health state is critical | + + +## Setup + +### Prerequisites + +No action required. + +### Configuration + +#### File + +The configuration file name for this integration is `go.d/adaptec_raid.conf`. + + +You can edit the configuration file using the `edit-config` script from the +Netdata [config directory](/docs/netdata-agent/configuration/README.md#the-netdata-config-directory). + +```bash +cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata +sudo ./edit-config go.d/adaptec_raid.conf +``` +#### Options + +The following options can be defined globally: update_every. + + +<details open><summary>Config options</summary> + +| Name | Description | Default | Required | +|:----|:-----------|:-------|:--------:| +| update_every | Data collection frequency. | 10 | no | +| timeout | arcconf binary execution timeout. | 2 | no | + +</details> + +#### Examples + +##### Custom update_every + +Allows you to override the default data collection interval. + +<details open><summary>Config</summary> + +```yaml +jobs: + - name: adaptec_raid + update_every: 5 # Collect Adaptec Hardware RAID statistics every 5 seconds + +``` +</details> + + + +## Troubleshooting + +### Debug Mode + +**Important**: Debug mode is not supported for data collection jobs created via the UI using the Dyncfg feature. + +To troubleshoot issues with the `adaptec_raid` collector, run the `go.d.plugin` with the debug option enabled. The output +should give you clues as to why the collector isn't working. + +- Navigate to the `plugins.d` directory, usually at `/usr/libexec/netdata/plugins.d/`. If that's not the case on + your system, open `netdata.conf` and look for the `plugins` setting under `[directories]`. + + ```bash + cd /usr/libexec/netdata/plugins.d/ + ``` + +- Switch to the `netdata` user. + + ```bash + sudo -u netdata -s + ``` + +- Run the `go.d.plugin` to debug the collector: + + ```bash + ./go.d.plugin -d -m adaptec_raid + ``` + +### Getting Logs + +If you're encountering problems with the `adaptec_raid` collector, follow these steps to retrieve logs and identify potential issues: + +- **Run the command** specific to your system (systemd, non-systemd, or Docker container). +- **Examine the output** for any warnings or error messages that might indicate issues. These messages should provide clues about the root cause of the problem. + +#### System with systemd + +Use the following command to view logs generated since the last Netdata service restart: + +```bash +journalctl _SYSTEMD_INVOCATION_ID="$(systemctl show --value --property=InvocationID netdata)" --namespace=netdata --grep adaptec_raid +``` + +#### System without systemd + +Locate the collector log file, typically at `/var/log/netdata/collector.log`, and use `grep` to filter for collector's name: + +```bash +grep adaptec_raid /var/log/netdata/collector.log +``` + +**Note**: This method shows logs from all restarts. Focus on the **latest entries** for troubleshooting current issues. + +#### Docker Container + +If your Netdata runs in a Docker container named "netdata" (replace if different), use this command: + +```bash +docker logs netdata 2>&1 | grep adaptec_raid +``` + + diff --git a/src/go/plugin/go.d/modules/adaptecraid/metadata.yaml b/src/go/plugin/go.d/modules/adaptecraid/metadata.yaml new file mode 100644 index 00000000..e573994f --- /dev/null +++ b/src/go/plugin/go.d/modules/adaptecraid/metadata.yaml @@ -0,0 +1,146 @@ +plugin_name: go.d.plugin +modules: + - meta: + id: collector-go.d.plugin-adaptecraid + plugin_name: go.d.plugin + module_name: adaptec_raid + monitored_instance: + name: Adaptec RAID + link: "https://www.microchip.com/en-us/products/storage" + icon_filename: "adaptec.svg" + categories: + - data-collection.storage-mount-points-and-filesystems + keywords: + - storage + - raid-controller + - manage-disks + related_resources: + integrations: + list: [] + info_provided_to_referring_integrations: + description: "" + most_popular: false + overview: + data_collection: + metrics_description: | + Monitors the health of Adaptec Hardware RAID by tracking the status of logical and physical devices in your storage system. + It relies on the `arcconf` CLI tool but avoids directly executing the binary. + Instead, it utilizes `ndsudo`, a Netdata helper specifically designed to run privileged commands securely within the Netdata environment. + This approach eliminates the need to use `sudo`, improving security and potentially simplifying permission management. + + Executed commands: + - `arcconf GETCONFIG 1 LD` + - `arcconf GETCONFIG 1 PD` + method_description: "" + supported_platforms: + include: [] + exclude: [] + multi_instance: false + additional_permissions: + description: "" + default_behavior: + auto_detection: + description: "" + limits: + description: "" + performance_impact: + description: "" + setup: + prerequisites: + list: [] + configuration: + file: + name: go.d/adaptec_raid.conf + options: + description: | + The following options can be defined globally: update_every. + folding: + title: Config options + enabled: true + list: + - name: update_every + description: Data collection frequency. + default_value: 10 + required: false + - name: timeout + description: arcconf binary execution timeout. + default_value: 2 + required: false + examples: + folding: + title: Config + enabled: true + list: + - name: Custom update_every + description: Allows you to override the default data collection interval. + config: | + jobs: + - name: adaptec_raid + update_every: 5 # Collect Adaptec Hardware RAID statistics every 5 seconds + troubleshooting: + problems: + list: [] + alerts: + - name: adaptec_raid_ld_health_status + metric: adaptecraid.logical_device_status + info: Adaptec RAID logical device (number ${label:ld_number} name ${label:ld_name}) health status is critical + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/adaptec_raid.conf + - name: adaptec_raid_pd_health_state + metric: adaptecraid.physical_device_state + info: Adaptec RAID physical device (number ${label:pd_number} location ${label:location}) health state is critical + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/adaptec_raid.conf + metrics: + folding: + title: Metrics + enabled: false + description: "" + availability: [] + scopes: + - name: logical device + description: These metrics refer to the Logical Device (LD). + labels: + - name: ld_number + description: Logical device index number + - name: ld_name + description: Logical device name + - name: raid_level + description: RAID level + metrics: + - name: adaptecraid.logical_device_status + description: Logical Device status + unit: status + chart_type: line + dimensions: + - name: ok + - name: critical + - name: physical device + description: These metrics refer to the Physical Device (PD). + labels: + - name: pd_number + description: Physical device index number + - name: location + description: Physical device location (e.g. Connector 0, Device 1) + - name: vendor + description: Physical device vendor + - name: model + description: Physical device model + metrics: + - name: adaptecraid.physical_device_state + description: Physical Device state + unit: status + chart_type: line + dimensions: + - name: ok + - name: critical + - name: adaptecraid.physical_device_smart_warnings + description: Physical Device SMART warnings + unit: warnings + chart_type: line + dimensions: + - name: smart + - name: adaptecraid.physical_device_temperature + description: Physical Device temperature + unit: Celsius + chart_type: line + dimensions: + - name: temperature
\ No newline at end of file diff --git a/src/go/plugin/go.d/modules/adaptecraid/testdata/config.json b/src/go/plugin/go.d/modules/adaptecraid/testdata/config.json new file mode 100644 index 00000000..291ecee3 --- /dev/null +++ b/src/go/plugin/go.d/modules/adaptecraid/testdata/config.json @@ -0,0 +1,4 @@ +{ + "update_every": 123, + "timeout": 123.123 +} diff --git a/src/go/plugin/go.d/modules/adaptecraid/testdata/config.yaml b/src/go/plugin/go.d/modules/adaptecraid/testdata/config.yaml new file mode 100644 index 00000000..25b0b4c7 --- /dev/null +++ b/src/go/plugin/go.d/modules/adaptecraid/testdata/config.yaml @@ -0,0 +1,2 @@ +update_every: 123 +timeout: 123.123 diff --git a/src/go/plugin/go.d/modules/adaptecraid/testdata/getconfig-ld-current.txt b/src/go/plugin/go.d/modules/adaptecraid/testdata/getconfig-ld-current.txt new file mode 100644 index 00000000..b5a14b66 --- /dev/null +++ b/src/go/plugin/go.d/modules/adaptecraid/testdata/getconfig-ld-current.txt @@ -0,0 +1,30 @@ +Logical device information +---------------------------------------------------------------------- +Logical Device number 0 + Logical Device name : LogicalDrv 0 + Block Size of member drives : 512 Bytes + RAID level : 10 + Unique Identifier : 488046B2 + Status of Logical Device : Optimal + Additional details : Quick initialized + Size : 915446 MB + Parity space : 915456 MB + Stripe-unit size : 256 KB + Interface Type : Serial ATA + Device Type : HDD + Read-cache setting : Enabled + Read-cache status : On + Write-cache setting : Enabled + Write-cache status : On + Partitioned : Yes + Protected by Hot-Spare : No + Bootable : Yes + Failed stripes : No + Power settings : Disabled + -------------------------------------------------------- + Logical Device segment information + -------------------------------------------------------- + Group 0, Segment 0 : Present (457862MB, SATA, SSD, Connector:0, Device:0) 7CS009RP + Group 0, Segment 1 : Present (457862MB, SATA, SSD, Connector:0, Device:1) 7CS009RQ + Group 1, Segment 0 : Present (457862MB, SATA, SSD, Connector:0, Device:2) 7CS00AAD + Group 1, Segment 1 : Present (457862MB, SATA, SSD, Connector:0, Device:3) 7CS00AAH diff --git a/src/go/plugin/go.d/modules/adaptecraid/testdata/getconfig-ld-old.txt b/src/go/plugin/go.d/modules/adaptecraid/testdata/getconfig-ld-old.txt new file mode 100644 index 00000000..0c3b4691 --- /dev/null +++ b/src/go/plugin/go.d/modules/adaptecraid/testdata/getconfig-ld-old.txt @@ -0,0 +1,33 @@ +Controllers found: 1 +---------------------------------------------------------------------- +Logical device information +---------------------------------------------------------------------- +Logical device number 0 + Logical device name : LogicalDrv 0 + Block Size of member drives : 512 Bytes + RAID level : 10 + Unique Identifier : 488046B2 + Status of logical device : Optimal + Size : 915446 MB + Parity space : 915456 MB + Stripe-unit size : 256 KB + Read-cache setting : Enabled + Read-cache status : On + Write-cache setting : Enabled + Write-cache status : On + Partitioned : Yes + Protected by Hot-Spare : No + Bootable : Yes + Failed stripes : No + Power settings : Disabled + -------------------------------------------------------- + Logical device segment information + -------------------------------------------------------- + Group 0, Segment 0 : Present (Controller:1,Connector:0,Device:0) 7CS009RP + Group 0, Segment 1 : Present (Controller:1,Connector:0,Device:1) 7CS009RQ + Group 1, Segment 0 : Present (Controller:1,Connector:0,Device:2) 7CS00AAD + Group 1, Segment 1 : Present (Controller:1,Connector:0,Device:3) 7CS00AAH + + + +Command completed successfully. diff --git a/src/go/plugin/go.d/modules/adaptecraid/testdata/getconfig-pd-current.txt b/src/go/plugin/go.d/modules/adaptecraid/testdata/getconfig-pd-current.txt new file mode 100644 index 00000000..62beff83 --- /dev/null +++ b/src/go/plugin/go.d/modules/adaptecraid/testdata/getconfig-pd-current.txt @@ -0,0 +1,216 @@ +Controllers found: 1 +---------------------------------------------------------------------- +Physical Device information +---------------------------------------------------------------------- + Device #0 + Device is a Hard drive + State : Online + Block Size : 512 Bytes + Supported : Yes + Transfer Speed : SAS 6.0 Gb/s + Reported Channel,Device(T:L) : 0,1(1:0) + Reported Location : Connector 0, Device 1 + Vendor : NETAPP + Model : X422_HCOBE600A10 + Firmware : NA00 + Reserved Size : 956312 KB + Used Size : 571392 MB + Unused Size : 64 KB + Total Size : 572325 MB + Write Cache : Enabled (write-back) + FRU : None + S.M.A.R.T. : No + S.M.A.R.T. warnings : 0 + Power State : Full rpm + Supported Power States : Full rpm,Powered off + SSD : No + Temperature : Not Supported + ---------------------------------------------------------------- + Device Phy Information + ---------------------------------------------------------------- + Phy #0 + PHY Identifier : 0 + SAS Address : 5000 + Attached PHY Identifier : 2 + Attached SAS Address : 5000 + Phy #1 + PHY Identifier : 1 + SAS Address : 5000 + + Device #1 + Device is a Hard drive + State : Online + Block Size : 512 Bytes + Supported : Yes + Transfer Speed : SAS 6.0 Gb/s + Reported Channel,Device(T:L) : 0,2(2:0) + Reported Location : Connector 0, Device 2 + Vendor : NETAPP + Model : X422_HCOBE600A10 + Firmware : NA02 + Reserved Size : 956312 KB + Used Size : 571392 MB + Unused Size : 64 KB + Total Size : 572325 MB + Write Cache : Enabled (write-back) + FRU : None + S.M.A.R.T. : No + S.M.A.R.T. warnings : 0 + Power State : Full rpm + Supported Power States : Full rpm,Powered off + SSD : No + Temperature : Not Supported + ---------------------------------------------------------------- + Device Phy Information + ---------------------------------------------------------------- + Phy #0 + PHY Identifier : 0 + SAS Address : 5000 + Attached PHY Identifier : 1 + Attached SAS Address : 5000 + Phy #1 + PHY Identifier : 1 + SAS Address : 5000 + + Device #2 + Device is a Hard drive + State : Online + Block Size : 512 Bytes + Supported : Yes + Transfer Speed : SAS 6.0 Gb/s + Reported Channel,Device(T:L) : 0,4(4:0) + Reported Location : Connector 1, Device 0 + Vendor : NETAPP + Model : X422_HCOBD600A10 + Firmware : NA05 + Reserved Size : 956312 KB + Used Size : 571392 MB + Unused Size : 64 KB + Total Size : 572325 MB + Write Cache : Enabled (write-back) + FRU : None + S.M.A.R.T. : No + S.M.A.R.T. warnings : 0 + Power State : Full rpm + Supported Power States : Full rpm,Powered off + SSD : No + Temperature : Not Supported + ---------------------------------------------------------------- + Device Phy Information + ---------------------------------------------------------------- + Phy #0 + PHY Identifier : 0 + SAS Address : 5000 + Attached PHY Identifier : 7 + Attached SAS Address : 5000 + Phy #1 + PHY Identifier : 1 + SAS Address : 5000 + + Device #3 + Device is a Hard drive + State : Online + Block Size : 512 Bytes + Supported : Yes + Transfer Speed : SAS 6.0 Gb/s + Reported Channel,Device(T:L) : 0,5(5:0) + Reported Location : Connector 1, Device 1 + Vendor : NETAPP + Model : X422_HCOBD600A10 + Firmware : NA05 + Reserved Size : 956312 KB + Used Size : 571392 MB + Unused Size : 64 KB + Total Size : 572325 MB + Write Cache : Enabled (write-back) + FRU : None + S.M.A.R.T. : No + S.M.A.R.T. warnings : 0 + Power State : Full rpm + Supported Power States : Full rpm,Powered off + SSD : No + Temperature : Not Supported + ---------------------------------------------------------------- + Device Phy Information + ---------------------------------------------------------------- + Phy #0 + PHY Identifier : 0 + SAS Address : 5000 + Attached PHY Identifier : 6 + Attached SAS Address : 5000 + Phy #1 + PHY Identifier : 1 + SAS Address : 5000 + + Device #4 + Device is a Hard drive + State : Online + Block Size : 512 Bytes + Supported : Yes + Transfer Speed : SAS 6.0 Gb/s + Reported Channel,Device(T:L) : 0,6(6:0) + Reported Location : Connector 1, Device 2 + Vendor : NETAPP + Model : X422_HCOBD600A10 + Firmware : NA05 + Reserved Size : 956312 KB + Used Size : 571392 MB + Unused Size : 64 KB + Total Size : 572325 MB + Write Cache : Enabled (write-back) + FRU : None + S.M.A.R.T. : No + S.M.A.R.T. warnings : 0 + Power State : Full rpm + Supported Power States : Full rpm,Powered off + SSD : No + Temperature : Not Supported + ---------------------------------------------------------------- + Device Phy Information + ---------------------------------------------------------------- + Phy #0 + PHY Identifier : 0 + SAS Address : 5000 + Attached PHY Identifier : 5 + Attached SAS Address : 5000 + Phy #1 + PHY Identifier : 1 + SAS Address : 5000 + + Device #5 + Device is a Hard drive + State : Online + Block Size : 512 Bytes + Supported : Yes + Transfer Speed : SAS 6.0 Gb/s + Reported Channel,Device(T:L) : 0,7(7:0) + Reported Location : Connector 1, Device 3 + Vendor : NETAPP + Model : X422_HCOBD600A10 + Firmware : NA05 + Reserved Size : 956312 KB + Used Size : 571392 MB + Unused Size : 64 KB + Total Size : 572325 MB + Write Cache : Enabled (write-back) + FRU : None + S.M.A.R.T. : No + S.M.A.R.T. warnings : 0 + Power State : Full rpm + Supported Power States : Full rpm,Powered off + SSD : No + Temperature : Not Supported + ---------------------------------------------------------------- + Device Phy Information + ---------------------------------------------------------------- + Phy #0 + PHY Identifier : 0 + SAS Address : 5000 + Attached PHY Identifier : 4 + Attached SAS Address : 5000 + PHY Identifier : 1 + SAS Address : 5000 + + + +Command completed successfully. diff --git a/src/go/plugin/go.d/modules/adaptecraid/testdata/getconfig-pd-old.txt b/src/go/plugin/go.d/modules/adaptecraid/testdata/getconfig-pd-old.txt new file mode 100644 index 00000000..2114df6b --- /dev/null +++ b/src/go/plugin/go.d/modules/adaptecraid/testdata/getconfig-pd-old.txt @@ -0,0 +1,107 @@ +Controllers found: 1 +---------------------------------------------------------------------- +Physical Device information +---------------------------------------------------------------------- + Device #0 + Device is a Hard drive + State : Online + Block Size : 512 Bytes + Supported : Yes + Transfer Speed : SATA 6.0 Gb/s + Reported Channel,Device(T:L) : 0,0(0:0) + Reported Location : Connector 0, Device 0 + Vendor : ATA + Model : XF1230-1A0480 + Firmware : ST200354 + Serial number : 7CS009RP + World-wide name : 5000C500813BF05B + Reserved Size : 138008 KB + Used Size : 457728 MB + Unused Size : 64 KB + Total Size : 457862 MB + Write Cache : Disabled (write-through) + FRU : None + S.M.A.R.T. : No + S.M.A.R.T. warnings : 0 + Power State : Full rpm + Supported Power States : Full power,Powered off + SSD : Yes + NCQ status : Enabled + Device #1 + Device is a Hard drive + State : Online + Block Size : 512 Bytes + Supported : Yes + Transfer Speed : SATA 6.0 Gb/s + Reported Channel,Device(T:L) : 0,1(1:0) + Reported Location : Connector 0, Device 1 + Vendor : ATA + Model : XF1230-1A0480 + Firmware : ST200354 + Serial number : 7CS009RQ + World-wide name : 5000C500813BF05C + Reserved Size : 138008 KB + Used Size : 457728 MB + Unused Size : 64 KB + Total Size : 457862 MB + Write Cache : Disabled (write-through) + FRU : None + S.M.A.R.T. : No + S.M.A.R.T. warnings : 0 + Power State : Full rpm + Supported Power States : Full power,Powered off + SSD : Yes + NCQ status : Enabled + Device #2 + Device is a Hard drive + State : Online + Block Size : 512 Bytes + Supported : Yes + Transfer Speed : SATA 6.0 Gb/s + Reported Channel,Device(T:L) : 0,2(2:0) + Reported Location : Connector 0, Device 2 + Vendor : ATA + Model : XF1230-1A0480 + Firmware : ST200354 + Serial number : 7CS00AAD + World-wide name : 5000C500813BF320 + Reserved Size : 138008 KB + Used Size : 457728 MB + Unused Size : 64 KB + Total Size : 457862 MB + Write Cache : Disabled (write-through) + FRU : None + S.M.A.R.T. : No + S.M.A.R.T. warnings : 0 + Power State : Full rpm + Supported Power States : Full power,Powered off + SSD : Yes + NCQ status : Enabled + Device #3 + Device is a Hard drive + State : Online + Block Size : 512 Bytes + Supported : Yes + Transfer Speed : SATA 6.0 Gb/s + Reported Channel,Device(T:L) : 0,3(3:0) + Reported Location : Connector 0, Device 3 + Vendor : ATA + Model : XF1230-1A0480 + Firmware : ST200354 + Serial number : 7CS00AAH + World-wide name : 5000C500813BF324 + Reserved Size : 138008 KB + Used Size : 457728 MB + Unused Size : 64 KB + Total Size : 457862 MB + Write Cache : Disabled (write-through) + FRU : None + S.M.A.R.T. : No + S.M.A.R.T. warnings : 0 + Power State : Full rpm + Supported Power States : Full power,Powered off + SSD : Yes + NCQ status : Enabled + + +Command completed successfully. |