go.d rewrite python.d/adaptec_raid (#17428)
Ilya Mashchenko committed
Apr 17, 2024 at 15:23 UTC
b8760c60eb862c2c5af1429bfba494d131d409b3
21 files changed
+1448
src/go/collectors/go.d.plugin/README.md
+1
@@ -50,6 +50,7 @@ see the appropriate collector readme.
50
51
| Name | Monitors |
52
|:------------------------------------------------------------------------------------------------------------------------------|:-----------------------------:|
53
+| [adaptec_raid](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/adaptecraid) | Adaptec Hardware RAID |
54
| [activemq](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/activemq) | ActiveMQ |
55
| [apache](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/apache) | Apache |
56
| [bind](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/bind) | ISC Bind |
src/go/collectors/go.d.plugin/config/go.d.conf
+1
@@ -15,6 +15,7 @@ max_procs: 0
15
# If you want to change any value, you need to uncomment out it first.
16
# IMPORTANT: Do not remove all spaces, just remove # symbol. There should be a space before module name.
17
modules:
18
+# adaptec_raid: yes
19
# activemq: yes
20
# apache: yes
21
# bind: yes
src/go/collectors/go.d.plugin/config/go.d/adaptec_raid.conf
new
+5
@@ -0,0 +1,5 @@
1
+## All available configuration options, their descriptions and default values:
2
+## https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/adaptecraid#readme
3
+
4
+jobs:
5
+ - name: adaptec_raid
src/go/collectors/go.d.plugin/modules/adaptecraid/adaptec.go
new
+107
@@ -0,0 +1,107 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package adaptecraid
4
+
5
+import (
6
+ _ "embed"
7
+ "errors"
8
+ "time"
9
+
10
+ "github.com/netdata/netdata/go/go.d.plugin/agent/module"
11
+ "github.com/netdata/netdata/go/go.d.plugin/pkg/web"
12
+)
13
+
14
+//go:embed "config_schema.json"
15
+var configSchema string
16
+
17
+func init() {
18
+ module.Register("adaptec_raid", module.Creator{
19
+ JobConfigSchema: configSchema,
20
+ Defaults: module.Defaults{
21
+ UpdateEvery: 10,
22
+ },
23
+ Create: func() module.Module { return New() },
24
+ })
25
+}
26
+
27
+func New() *AdaptecRaid {
28
+ return &AdaptecRaid{
29
+ Config: Config{
30
+ Timeout: web.Duration(time.Second * 2),
31
+ },
32
+ charts: &module.Charts{},
33
+ lds: make(map[string]bool),
34
+ pds: make(map[string]bool),
35
+ }
36
+}
37
+
38
+type Config struct {
39
+ UpdateEvery int `yaml:"update_every" json:"update_every"`
40
+ Timeout web.Duration `yaml:"timeout" json:"timeout"`
41
+}
42
+
43
+type (
44
+ AdaptecRaid struct {
45
+ module.Base
46
+ Config `yaml:",inline" json:""`
47
+
48
+ charts *module.Charts
49
+
50
+ exec arcconfCli
51
+
52
+ lds map[string]bool
53
+ pds map[string]bool
54
+ }
55
+ arcconfCli interface {
56
+ logicalDevicesInfo() ([]byte, error)
57
+ physicalDevicesInfo() ([]byte, error)
58
+ }
59
+)
60
+
61
+func (a *AdaptecRaid) Configuration() any {
62
+ return a.Config
63
+}
64
+
65
+func (a *AdaptecRaid) Init() error {
66
+ arcconfExec, err := a.initArcconfCliExec()
67
+ if err != nil {
68
+ a.Errorf("arcconf exec initialization: %v", err)
69
+ return err
70
+ }
71
+ a.exec = arcconfExec
72
+
73
+ return nil
74
+}
75
+
76
+func (a *AdaptecRaid) Check() error {
77
+ mx, err := a.collect()
78
+ if err != nil {
79
+ a.Error(err)
80
+ return err
81
+ }
82
+
83
+ if len(mx) == 0 {
84
+ return errors.New("no metrics collected")
85
+ }
86
+
87
+ return nil
88
+}
89
+
90
+func (a *AdaptecRaid) Charts() *module.Charts {
91
+ return a.charts
92
+}
93
+
94
+func (a *AdaptecRaid) Collect() map[string]int64 {
95
+ mx, err := a.collect()
96
+ if err != nil {
97
+ a.Error(err)
98
+ }
99
+
100
+ if len(mx) == 0 {
101
+ return nil
102
+ }
103
+
104
+ return mx
105
+}
106
+
107
+func (a *AdaptecRaid) Cleanup() {}
src/go/collectors/go.d.plugin/modules/adaptecraid/adaptec_test.go
new
+281
@@ -0,0 +1,281 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package adaptecraid
4
+
5
+import (
6
+ "errors"
7
+ "os"
8
+ "testing"
9
+
10
+ "github.com/netdata/netdata/go/go.d.plugin/agent/module"
11
+
12
+ "github.com/stretchr/testify/assert"
13
+ "github.com/stretchr/testify/require"
14
+)
15
+
16
+var (
17
+ dataConfigJSON, _ = os.ReadFile("testdata/config.json")
18
+ dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
19
+
20
+ dataLogicalDevicesOld, _ = os.ReadFile("testdata/getconfig-ld-old.txt")
21
+ dataPhysicalDevicesOld, _ = os.ReadFile("testdata/getconfig-pd-old.txt")
22
+ dataLogicalDevicesCurrent, _ = os.ReadFile("testdata/getconfig-ld-current.txt")
23
+ dataPhysicalDevicesCurrent, _ = os.ReadFile("testdata/getconfig-pd-current.txt")
24
+)
25
+
26
+func Test_testDataIsValid(t *testing.T) {
27
+ for name, data := range map[string][]byte{
28
+ "dataConfigJSON": dataConfigJSON,
29
+ "dataConfigYAML": dataConfigYAML,
30
+
31
+ "dataLogicalDevicesOld": dataLogicalDevicesOld,
32
+ "dataPhysicalDevicesOld": dataPhysicalDevicesOld,
33
+ "dataLogicalDevicesCurrent": dataLogicalDevicesCurrent,
34
+ "dataPhysicalDevicesCurrent": dataPhysicalDevicesCurrent,
35
+ } {
36
+ require.NotNil(t, data, name)
37
+ }
38
+}
39
+
40
+func TestAdaptecRaid_ConfigurationSerialize(t *testing.T) {
41
+ module.TestConfigurationSerialize(t, &AdaptecRaid{}, dataConfigJSON, dataConfigYAML)
42
+}
43
+
44
+func TestAdaptecRaid_Init(t *testing.T) {
45
+ tests := map[string]struct {
46
+ config Config
47
+ wantFail bool
48
+ }{
49
+ "fails if 'ndsudo' not found": {
50
+ wantFail: true,
51
+ config: New().Config,
52
+ },
53
+ }
54
+
55
+ for name, test := range tests {
56
+ t.Run(name, func(t *testing.T) {
57
+ adaptec := New()
58
+
59
+ if test.wantFail {
60
+ assert.Error(t, adaptec.Init())
61
+ } else {
62
+ assert.NoError(t, adaptec.Init())
63
+ }
64
+ })
65
+ }
66
+}
67
+
68
+func TestAdaptecRaid_Cleanup(t *testing.T) {
69
+ tests := map[string]struct {
70
+ prepare func() *AdaptecRaid
71
+ }{
72
+ "not initialized exec": {
73
+ prepare: func() *AdaptecRaid {
74
+ return New()
75
+ },
76
+ },
77
+ "after check": {
78
+ prepare: func() *AdaptecRaid {
79
+ adaptec := New()
80
+ adaptec.exec = prepareMockOkCurrent()
81
+ _ = adaptec.Check()
82
+ return adaptec
83
+ },
84
+ },
85
+ "after collect": {
86
+ prepare: func() *AdaptecRaid {
87
+ adaptec := New()
88
+ adaptec.exec = prepareMockOkCurrent()
89
+ _ = adaptec.Collect()
90
+ return adaptec
91
+ },
92
+ },
93
+ }
94
+
95
+ for name, test := range tests {
96
+ t.Run(name, func(t *testing.T) {
97
+ adaptec := test.prepare()
98
+
99
+ assert.NotPanics(t, adaptec.Cleanup)
100
+ })
101
+ }
102
+}
103
+
104
+func TestAdaptecRaid_Charts(t *testing.T) {
105
+ assert.NotNil(t, New().Charts())
106
+}
107
+
108
+func TestAdaptecRaid_Check(t *testing.T) {
109
+ tests := map[string]struct {
110
+ prepareMock func() *mockArcconfExec
111
+ wantFail bool
112
+ }{
113
+ "success case old data": {
114
+ wantFail: false,
115
+ prepareMock: prepareMockOkOld,
116
+ },
117
+ "success case current data": {
118
+ wantFail: false,
119
+ prepareMock: prepareMockOkCurrent,
120
+ },
121
+ "err on exec": {
122
+ wantFail: true,
123
+ prepareMock: prepareMockErr,
124
+ },
125
+ "unexpected response": {
126
+ wantFail: true,
127
+ prepareMock: prepareMockUnexpectedResponse,
128
+ },
129
+ "empty response": {
130
+ wantFail: true,
131
+ prepareMock: prepareMockEmptyResponse,
132
+ },
133
+ }
134
+
135
+ for name, test := range tests {
136
+ t.Run(name, func(t *testing.T) {
137
+ adaptec := New()
138
+ mock := test.prepareMock()
139
+ adaptec.exec = mock
140
+
141
+ if test.wantFail {
142
+ assert.Error(t, adaptec.Check())
143
+ } else {
144
+ assert.NoError(t, adaptec.Check())
145
+ }
146
+ })
147
+ }
148
+}
149
+
150
+func TestAdaptecRaid_Collect(t *testing.T) {
151
+ tests := map[string]struct {
152
+ prepareMock func() *mockArcconfExec
153
+ wantMetrics map[string]int64
154
+ wantCharts int
155
+ }{
156
+ "success case old data": {
157
+ prepareMock: prepareMockOkOld,
158
+ wantCharts: len(ldChartsTmpl)*1 + (len(pdChartsTmpl)-1)*4,
159
+ wantMetrics: map[string]int64{
160
+ "ld_0_health_state_critical": 0,
161
+ "ld_0_health_state_ok": 1,
162
+ "pd_0_health_state_critical": 0,
163
+ "pd_0_health_state_ok": 1,
164
+ "pd_0_smart_warnings": 0,
165
+ "pd_1_health_state_critical": 0,
166
+ "pd_1_health_state_ok": 1,
167
+ "pd_1_smart_warnings": 0,
168
+ "pd_2_health_state_critical": 0,
169
+ "pd_2_health_state_ok": 1,
170
+ "pd_2_smart_warnings": 0,
171
+ "pd_3_health_state_critical": 0,
172
+ "pd_3_health_state_ok": 1,
173
+ "pd_3_smart_warnings": 0,
174
+ },
175
+ },
176
+ "success case current data": {
177
+ prepareMock: prepareMockOkCurrent,
178
+ wantCharts: len(ldChartsTmpl)*1 + (len(pdChartsTmpl)-1)*6,
179
+ wantMetrics: map[string]int64{
180
+ "ld_0_health_state_critical": 0,
181
+ "ld_0_health_state_ok": 1,
182
+ "pd_0_health_state_critical": 0,
183
+ "pd_0_health_state_ok": 1,
184
+ "pd_0_smart_warnings": 0,
185
+ "pd_1_health_state_critical": 0,
186
+ "pd_1_health_state_ok": 1,
187
+ "pd_1_smart_warnings": 0,
188
+ "pd_2_health_state_critical": 0,
189
+ "pd_2_health_state_ok": 1,
190
+ "pd_2_smart_warnings": 0,
191
+ "pd_3_health_state_critical": 0,
192
+ "pd_3_health_state_ok": 1,
193
+ "pd_3_smart_warnings": 0,
194
+ "pd_4_health_state_critical": 0,
195
+ "pd_4_health_state_ok": 1,
196
+ "pd_4_smart_warnings": 0,
197
+ "pd_5_health_state_critical": 0,
198
+ "pd_5_health_state_ok": 1,
199
+ "pd_5_smart_warnings": 0,
200
+ },
201
+ },
202
+ "err on exec": {
203
+ prepareMock: prepareMockErr,
204
+ },
205
+ "unexpected response": {
206
+ prepareMock: prepareMockUnexpectedResponse,
207
+ },
208
+ "empty response": {
209
+ prepareMock: prepareMockUnexpectedResponse,
210
+ },
211
+ }
212
+
213
+ for name, test := range tests {
214
+ t.Run(name, func(t *testing.T) {
215
+ adaptec := New()
216
+ mock := test.prepareMock()
217
+ adaptec.exec = mock
218
+
219
+ mx := adaptec.Collect()
220
+
221
+ assert.Equal(t, test.wantMetrics, mx)
222
+ assert.Len(t, *adaptec.Charts(), test.wantCharts)
223
+ })
224
+ }
225
+}
226
+
227
+func prepareMockOkOld() *mockArcconfExec {
228
+ return &mockArcconfExec{
229
+ ldData: dataLogicalDevicesOld,
230
+ pdData: dataPhysicalDevicesOld,
231
+ }
232
+}
233
+
234
+func prepareMockOkCurrent() *mockArcconfExec {
235
+ return &mockArcconfExec{
236
+ ldData: dataLogicalDevicesCurrent,
237
+ pdData: dataPhysicalDevicesCurrent,
238
+ }
239
+}
240
+
241
+func prepareMockErr() *mockArcconfExec {
242
+ return &mockArcconfExec{
243
+ errOnInfo: true,
244
+ }
245
+}
246
+
247
+func prepareMockUnexpectedResponse() *mockArcconfExec {
248
+ resp := []byte(`
249
+Lorem ipsum dolor sit amet, consectetur adipiscing elit.
250
+Nulla malesuada erat id magna mattis, eu viverra tellus rhoncus.
251
+Fusce et felis pulvinar, posuere sem non, porttitor eros.
252
+`)
253
+ return &mockArcconfExec{
254
+ ldData: resp,
255
+ pdData: resp,
256
+ }
257
+}
258
+
259
+func prepareMockEmptyResponse() *mockArcconfExec {
260
+ return &mockArcconfExec{}
261
+}
262
+
263
+type mockArcconfExec struct {
264
+ errOnInfo bool
265
+ ldData []byte
266
+ pdData []byte
267
+}
268
+
269
+func (m *mockArcconfExec) logicalDevicesInfo() ([]byte, error) {
270
+ if m.errOnInfo {
271
+ return nil, errors.New("mock.logicalDevicesInfo() error")
272
+ }
273
+ return m.ldData, nil
274
+}
275
+
276
+func (m *mockArcconfExec) physicalDevicesInfo() ([]byte, error) {
277
+ if m.errOnInfo {
278
+ return nil, errors.New("mock.physicalDevicesInfo() error")
279
+ }
280
+ return m.pdData, nil
281
+}
src/go/collectors/go.d.plugin/modules/adaptecraid/charts.go
new
+129
@@ -0,0 +1,129 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package adaptecraid
4
+
5
+import (
6
+ "fmt"
7
+ "strconv"
8
+
9
+ "github.com/netdata/netdata/go/go.d.plugin/agent/module"
10
+)
11
+
12
+const (
13
+ prioLDStatus = module.Priority + iota
14
+
15
+ prioPDState
16
+ prioPDSmartWarnings
17
+ prioPDSmartTemperature
18
+)
19
+
20
+var ldChartsTmpl = module.Charts{
21
+ ldStatusChartTmpl.Copy(),
22
+}
23
+
24
+var (
25
+ ldStatusChartTmpl = module.Chart{
26
+ ID: "logical_device_%s_status",
27
+ Title: "Logical Device status",
28
+ Units: "status",
29
+ Fam: "ld health",
30
+ Ctx: "adaptecraid.logical_device_status",
31
+ Type: module.Line,
32
+ Priority: prioLDStatus,
33
+ Dims: module.Dims{
34
+ {ID: "ld_%s_health_state_ok", Name: "ok"},
35
+ {ID: "ld_%s_health_state_critical", Name: "critical"},
36
+ },
37
+ }
38
+)
39
+
40
+var pdChartsTmpl = module.Charts{
41
+ pdStateChartTmpl.Copy(),
42
+ pdSmartWarningChartTmpl.Copy(),
43
+ pdTemperatureChartTmpl.Copy(),
44
+}
45
+
46
+var (
47
+ pdStateChartTmpl = module.Chart{
48
+ ID: "physical_device_%s_state",
49
+ Title: "Physical Device state",
50
+ Units: "state",
51
+ Fam: "pd health",
52
+ Ctx: "adaptecraid.physical_device_state",
53
+ Type: module.Line,
54
+ Priority: prioPDState,
55
+ Dims: module.Dims{
56
+ {ID: "pd_%s_health_state_ok", Name: "ok"},
57
+ {ID: "pd_%s_health_state_critical", Name: "critical"},
58
+ },
59
+ }
60
+ pdSmartWarningChartTmpl = module.Chart{
61
+ ID: "physical_device_%s_smart_warnings",
62
+ Title: "Physical Device SMART warnings",
63
+ Units: "warnings",
64
+ Fam: "pd smart",
65
+ Ctx: "adaptecraid.physical_device_smart_warnings",
66
+ Type: module.Line,
67
+ Priority: prioPDSmartWarnings,
68
+ Dims: module.Dims{
69
+ {ID: "pd_%s_smart_warnings", Name: "smart"},
70
+ },
71
+ }
72
+ pdTemperatureChartTmpl = module.Chart{
73
+ ID: "physical_device_%s_temperature",
74
+ Title: "Physical Device temperature",
75
+ Units: "Celsius",
76
+ Fam: "pd temperature",
77
+ Ctx: "adaptecraid.physical_device_temperature",
78
+ Type: module.Line,
79
+ Priority: prioPDSmartTemperature,
80
+ Dims: module.Dims{
81
+ {ID: "pd_%s_temperature", Name: "temperature"},
82
+ },
83
+ }
84
+)
85
+
86
+func (a *AdaptecRaid) addLogicalDeviceCharts(ld *logicalDevice) {
87
+ charts := ldChartsTmpl.Copy()
88
+
89
+ for _, chart := range *charts {
90
+ chart.ID = fmt.Sprintf(chart.ID, ld.number)
91
+ chart.Labels = []module.Label{
92
+ {Key: "ld_number", Value: ld.number},
93
+ {Key: "ld_name", Value: ld.name},
94
+ {Key: "raid_level", Value: ld.raidLevel},
95
+ }
96
+ for _, dim := range chart.Dims {
97
+ dim.ID = fmt.Sprintf(dim.ID, ld.number)
98
+ }
99
+ }
100
+
101
+ if err := a.Charts().Add(*charts...); err != nil {
102
+ a.Warning(err)
103
+ }
104
+}
105
+
106
+func (a *AdaptecRaid) addPhysicalDeviceCharts(pd *physicalDevice) {
107
+ charts := pdChartsTmpl.Copy()
108
+
109
+ if _, err := strconv.ParseInt(pd.temperature, 10, 64); err != nil {
110
+ _ = charts.Remove(pdTemperatureChartTmpl.ID)
111
+ }
112
+
113
+ for _, chart := range *charts {
114
+ chart.ID = fmt.Sprintf(chart.ID, pd.number)
115
+ chart.Labels = []module.Label{
116
+ {Key: "pd_number", Value: pd.number},
117
+ {Key: "location", Value: pd.location},
118
+ {Key: "vendor", Value: pd.vendor},
119
+ {Key: "model", Value: pd.model},
120
+ }
121
+ for _, dim := range chart.Dims {
122
+ dim.ID = fmt.Sprintf(dim.ID, pd.number)
123
+ }
124
+ }
125
+
126
+ if err := a.Charts().Add(*charts...); err != nil {
127
+ a.Warning(err)
128
+ }
129
+}
src/go/collectors/go.d.plugin/modules/adaptecraid/collect.go
new
+28
@@ -0,0 +1,28 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package adaptecraid
4
+
5
+import (
6
+ "strings"
7
+)
8
+
9
+func (a *AdaptecRaid) collect() (map[string]int64, error) {
10
+ mx := make(map[string]int64)
11
+
12
+ if err := a.collectLogicalDevices(mx); err != nil {
13
+ return nil, err
14
+ }
15
+ if err := a.collectPhysicalDevices(mx); err != nil {
16
+ return nil, err
17
+ }
18
+
19
+ return mx, nil
20
+}
21
+
22
+func getColonSepValue(line string) string {
23
+ i := strings.IndexByte(line, ':')
24
+ if i == -1 {
25
+ return ""
26
+ }
27
+ return strings.TrimSpace(line[i+1:])
28
+}
src/go/collectors/go.d.plugin/modules/adaptecraid/collect_ld.go
new
+100
@@ -0,0 +1,100 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package adaptecraid
4
+
5
+import (
6
+ "bufio"
7
+ "bytes"
8
+ "errors"
9
+ "fmt"
10
+ "strings"
11
+)
12
+
13
+type logicalDevice struct {
14
+ number string
15
+ name string
16
+ raidLevel string
17
+ status string
18
+ failedStripes string
19
+}
20
+
21
+func (a *AdaptecRaid) collectLogicalDevices(mx map[string]int64) error {
22
+ bs, err := a.exec.logicalDevicesInfo()
23
+ if err != nil {
24
+ return err
25
+ }
26
+
27
+ devices, err := parseLogicDevInfo(bs)
28
+ if err != nil {
29
+ return err
30
+ }
31
+
32
+ if len(devices) == 0 {
33
+ return errors.New("no logical devices found")
34
+ }
35
+
36
+ for _, ld := range devices {
37
+ if !a.lds[ld.number] {
38
+ a.lds[ld.number] = true
39
+ a.addLogicalDeviceCharts(ld)
40
+ }
41
+
42
+ px := fmt.Sprintf("ld_%s_", ld.number)
43
+
44
+ // Unfortunately, all available states are unknown.
45
+ mx[px+"health_state_ok"] = 0
46
+ mx[px+"health_state_critical"] = 0
47
+ if isOkLDStatus(ld) {
48
+ mx[px+"health_state_ok"] = 1
49
+ } else {
50
+ mx[px+"health_state_critical"] = 1
51
+ }
52
+ }
53
+
54
+ return nil
55
+}
56
+
57
+func isOkLDStatus(ld *logicalDevice) bool {
58
+ // https://github.com/thomas-krenn/check_adaptec_raid/blob/a104fd88deede87df4f07403b44394bffb30c5c3/check_adaptec_raid#L340
59
+ return ld.status == "Optimal"
60
+}
61
+
62
+func parseLogicDevInfo(bs []byte) (map[string]*logicalDevice, error) {
63
+ devices := make(map[string]*logicalDevice)
64
+
65
+ var ld *logicalDevice
66
+
67
+ sc := bufio.NewScanner(bytes.NewReader(bs))
68
+
69
+ for sc.Scan() {
70
+ line := strings.TrimSpace(sc.Text())
71
+
72
+ if strings.HasPrefix(line, "Logical device number") ||
73
+ strings.HasPrefix(line, "Logical Device number") {
74
+ parts := strings.Fields(line)
75
+ num := parts[len(parts)-1]
76
+ ld = &logicalDevice{number: num}
77
+ devices[num] = ld
78
+ continue
79
+ }
80
+
81
+ if ld == nil {
82
+ continue
83
+ }
84
+
85
+ switch {
86
+ case strings.HasPrefix(line, "Logical device name"),
87
+ strings.HasPrefix(line, "Logical Device name"):
88
+ ld.name = getColonSepValue(line)
89
+ case strings.HasPrefix(line, "RAID level"):
90
+ ld.raidLevel = getColonSepValue(line)
91
+ case strings.HasPrefix(line, "Status of logical device"),
92
+ strings.HasPrefix(line, "Status of Logical Device"):
93
+ ld.status = getColonSepValue(line)
94
+ case strings.HasPrefix(line, "Failed stripes"):
95
+ ld.failedStripes = getColonSepValue(line)
96
+ }
97
+ }
98
+
99
+ return devices, nil
100
+}
src/go/collectors/go.d.plugin/modules/adaptecraid/collect_pd.go
new
+128
@@ -0,0 +1,128 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package adaptecraid
4
+
5
+import (
6
+ "bufio"
7
+ "bytes"
8
+ "errors"
9
+ "fmt"
10
+ "strconv"
11
+ "strings"
12
+)
13
+
14
+type physicalDevice struct {
15
+ number string
16
+ state string
17
+ location string
18
+ vendor string
19
+ model string
20
+ smart string
21
+ smartWarnings string
22
+ powerState string
23
+ temperature string
24
+}
25
+
26
+func (a *AdaptecRaid) collectPhysicalDevices(mx map[string]int64) error {
27
+ bs, err := a.exec.physicalDevicesInfo()
28
+ if err != nil {
29
+ return err
30
+ }
31
+
32
+ devices, err := parsePhysDevInfo(bs)
33
+ if err != nil {
34
+ return err
35
+ }
36
+
37
+ if len(devices) == 0 {
38
+ return errors.New("no physical devices found")
39
+ }
40
+
41
+ for _, pd := range devices {
42
+ if !a.pds[pd.number] {
43
+ a.pds[pd.number] = true
44
+ a.addPhysicalDeviceCharts(pd)
45
+ }
46
+
47
+ px := fmt.Sprintf("pd_%s_", pd.number)
48
+
49
+ // Unfortunately, all available states are unknown.
50
+ mx[px+"health_state_ok"] = 0
51
+ mx[px+"health_state_critical"] = 0
52
+ if isOkPDState(pd) {
53
+ mx[px+"health_state_ok"] = 1
54
+ } else {
55
+ mx[px+"health_state_critical"] = 1
56
+ }
57
+
58
+ if v, err := strconv.ParseInt(pd.smartWarnings, 10, 64); err == nil {
59
+ mx[px+"smart_warnings"] = v
60
+ }
61
+ if v, err := strconv.ParseInt(pd.temperature, 10, 64); err == nil {
62
+ mx[px+"temperature"] = v
63
+ }
64
+ }
65
+
66
+ return nil
67
+}
68
+
69
+func isOkPDState(pd *physicalDevice) bool {
70
+ // https://github.com/thomas-krenn/check_adaptec_raid/blob/a104fd88deede87df4f07403b44394bffb30c5c3/check_adaptec_raid#L455
71
+ switch pd.state {
72
+ case "Online",
73
+ "Global Hot-Spare",
74
+ "Dedicated Hot-Spare",
75
+ "Pooled Hot-Spare",
76
+ "Hot Spare",
77
+ "Ready",
78
+ "Online (JBOD)",
79
+ "Raw (Pass Through)":
80
+ return true
81
+ }
82
+ return false
83
+}
84
+
85
+func parsePhysDevInfo(bs []byte) (map[string]*physicalDevice, error) {
86
+ devices := make(map[string]*physicalDevice)
87
+
88
+ var pd *physicalDevice
89
+
90
+ sc := bufio.NewScanner(bytes.NewReader(bs))
91
+
92
+ for sc.Scan() {
93
+ line := strings.TrimSpace(sc.Text())
94
+
95
+ if strings.HasPrefix(line, "Device #") {
96
+ num := strings.TrimPrefix(line, "Device #")
97
+ pd = &physicalDevice{number: num}
98
+ devices[num] = pd
99
+ continue
100
+ }
101
+
102
+ if pd == nil {
103
+ continue
104
+ }
105
+
106
+ switch {
107
+ case strings.HasPrefix(line, "State"):
108
+ pd.state = getColonSepValue(line)
109
+ case strings.HasPrefix(line, "Reported Location"):
110
+ pd.location = getColonSepValue(line)
111
+ case strings.HasPrefix(line, "Vendor"):
112
+ pd.vendor = getColonSepValue(line)
113
+ case strings.HasPrefix(line, "Model"):
114
+ pd.model = getColonSepValue(line)
115
+ case strings.HasPrefix(line, "S.M.A.R.T. warnings"):
116
+ pd.smartWarnings = getColonSepValue(line)
117
+ case strings.HasPrefix(line, "S.M.A.R.T."):
118
+ pd.smart = getColonSepValue(line)
119
+ case strings.HasPrefix(line, "Power State"):
120
+ pd.powerState = getColonSepValue(line)
121
+ case strings.HasPrefix(line, "Temperature"):
122
+ v := getColonSepValue(line) // '42 C/ 107 F' or 'Not Supported'
123
+ pd.temperature = strings.Fields(v)[0]
124
+ }
125
+ }
126
+
127
+ return devices, nil
128
+}
src/go/collectors/go.d.plugin/modules/adaptecraid/config_schema.json
new
+35
@@ -0,0 +1,35 @@
1
+{
2
+ "jsonSchema": {
3
+ "$schema": "http://json-schema.org/draft-07/schema#",
4
+ "title": "Adaptec RAID collector configuration.",
5
+ "type": "object",
6
+ "properties": {
7
+ "update_every": {
8
+ "title": "Update every",
9
+ "description": "Data collection interval, measured in seconds.",
10
+ "type": "integer",
11
+ "minimum": 1,
12
+ "default": 10
13
+ },
14
+ "timeout": {
15
+ "title": "Timeout",
16
+ "description": "Timeout for executing the binary, specified in seconds.",
17
+ "type": "number",
18
+ "minimum": 0.5,
19
+ "default": 2
20
+ }
21
+ },
22
+ "additionalProperties": false,
23
+ "patternProperties": {
24
+ "^name$": {}
25
+ }
26
+ },
27
+ "uiSchema": {
28
+ "uiOptions": {
29
+ "fullPage": true
30
+ },
31
+ "timeout": {
32
+ "ui:help": "Accepts decimals for precise control (e.g., type 1.5 for 1.5 seconds)."
33
+ }
34
+ }
35
+}
src/go/collectors/go.d.plugin/modules/adaptecraid/exec.go
new
+50
@@ -0,0 +1,50 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package adaptecraid
4
+
5
+import (
6
+ "context"
7
+ "fmt"
8
+ "os/exec"
9
+ "time"
10
+
11
+ "github.com/netdata/netdata/go/go.d.plugin/logger"
12
+)
13
+
14
+func newArcconfCliExec(ndsudoPath string, timeout time.Duration, log *logger.Logger) *arcconfCliExec {
15
+ return &arcconfCliExec{
16
+ Logger: log,
17
+ ndsudoPath: ndsudoPath,
18
+ timeout: timeout,
19
+ }
20
+}
21
+
22
+type arcconfCliExec struct {
23
+ *logger.Logger
24
+
25
+ ndsudoPath string
26
+ timeout time.Duration
27
+}
28
+
29
+func (e *arcconfCliExec) logicalDevicesInfo() ([]byte, error) {
30
+ return e.execute("arcconf-ld-info")
31
+}
32
+
33
+func (e *arcconfCliExec) physicalDevicesInfo() ([]byte, error) {
34
+ return e.execute("arcconf-pd-info")
35
+}
36
+
37
+func (e *arcconfCliExec) execute(args ...string) ([]byte, error) {
38
+ ctx, cancel := context.WithTimeout(context.Background(), e.timeout)
39
+ defer cancel()
40
+
41
+ cmd := exec.CommandContext(ctx, e.ndsudoPath, args...)
42
+ e.Debugf("executing '%s'", cmd)
43
+
44
+ bs, err := cmd.Output()
45
+ if err != nil {
46
+ return nil, fmt.Errorf("error on '%s': %v", cmd, err)
47
+ }
48
+
49
+ return bs, nil
50
+}
src/go/collectors/go.d.plugin/modules/adaptecraid/init.go
new
+23
@@ -0,0 +1,23 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package adaptecraid
4
+
5
+import (
6
+ "fmt"
7
+ "os"
8
+ "path/filepath"
9
+
10
+ "github.com/netdata/netdata/go/go.d.plugin/agent/executable"
11
+)
12
+
13
+func (a *AdaptecRaid) initArcconfCliExec() (arcconfCli, error) {
14
+ ndsudoPath := filepath.Join(executable.Directory, "ndsudo")
15
+
16
+ if _, err := os.Stat(ndsudoPath); err != nil {
17
+ return nil, fmt.Errorf("ndsudo executable not found: %v", err)
18
+ }
19
+
20
+ arcconfExec := newArcconfCliExec(ndsudoPath, a.Timeout.Duration(), a.Logger)
21
+
22
+ return arcconfExec, nil
23
+}
src/go/collectors/go.d.plugin/modules/adaptecraid/metadata.yaml
new
+138
@@ -0,0 +1,138 @@
1
+plugin_name: go.d.plugin
2
+modules:
3
+ - meta:
4
+ id: collector-go.d.plugin-adaptecraid
5
+ plugin_name: go.d.plugin
6
+ module_name: adaptec_raid
7
+ monitored_instance:
8
+ name: Adaptec Hardware Raid
9
+ link: "https://www.microchip.com/en-us/products/storage"
10
+ icon_filename: "adaptec.svg"
11
+ categories:
12
+ - data-collection.storage-mount-points-and-filesystems
13
+ keywords:
14
+ - storage
15
+ - raid-controller
16
+ - manage-disks
17
+ related_resources:
18
+ integrations:
19
+ list: []
20
+ info_provided_to_referring_integrations:
21
+ description: ""
22
+ most_popular: false
23
+ overview:
24
+ data_collection:
25
+ metrics_description: |
26
+ Monitors the health of Adaptec Hardware RAID by tracking the status of logical and physical devices in your storage system.
27
+ It relies on the `arcconf` CLI tool but avoids directly executing the binary.
28
+ Instead, it utilizes `ndsudo`, a Netdata helper specifically designed to run privileged commands securely within the Netdata environment.
29
+ This approach eliminates the need to use `sudo`, improving security and potentially simplifying permission management.
30
+
31
+ Executed commands:
32
+ - `arcconf GETCONFIG 1 LD`
33
+ - `arcconf GETCONFIG 1 PD`
34
+ method_description: ""
35
+ supported_platforms:
36
+ include: []
37
+ exclude: []
38
+ multi_instance: false
39
+ additional_permissions:
40
+ description: ""
41
+ default_behavior:
42
+ auto_detection:
43
+ description: ""
44
+ limits:
45
+ description: ""
46
+ performance_impact:
47
+ description: ""
48
+ setup:
49
+ prerequisites:
50
+ list: []
51
+ configuration:
52
+ file:
53
+ name: go.d/adaptec_raid.conf
54
+ options:
55
+ description: |
56
+ The following options can be defined globally: update_every.
57
+ folding:
58
+ title: Config options
59
+ enabled: true
60
+ list:
61
+ - name: update_every
62
+ description: Data collection frequency.
63
+ default_value: 10
64
+ required: false
65
+ - name: timeout
66
+ description: `arcconf` binary execution timeout.
67
+ default_value: 2
68
+ required: false
69
+ examples:
70
+ folding:
71
+ title: Config
72
+ enabled: true
73
+ list:
74
+ - name: Custom update_every
75
+ description: Allows you to override the default data collection interval.
76
+ config: |
77
+ jobs:
78
+ - name: adaptec_raid
79
+ update_every: 5 # Collect Adaptec Hardware RAID statistics every 5 seconds
80
+ troubleshooting:
81
+ problems:
82
+ list: []
83
+ alerts: []
84
+ metrics:
85
+ folding:
86
+ title: Metrics
87
+ enabled: false
88
+ description: ""
89
+ availability: []
90
+ scopes:
91
+ - name: logical device
92
+ description: These metrics refer to the Logical Device (LD).
93
+ labels:
94
+ - name: ld_number
95
+ description: Logical device index number
96
+ - name: ld_name
97
+ description: Logical device name
98
+ - name: raid_level
99
+ description: RAID level
100
+ metrics:
101
+ - name: adaptecraid.logical_device_status
102
+ description: Logical Device status
103
+ unit: status
104
+ chart_type: line
105
+ dimensions:
106
+ - name: ok
107
+ - name: critical
108
+ - name: physical device
109
+ description: These metrics refer to the Physical Device (PD).
110
+ labels:
111
+ - name: pd_number
112
+ description: Physical device index number
113
+ - name: location
114
+ description: Physical device location (e.g. Connector 0, Device 1)
115
+ - name: vendor
116
+ description: Physical device vendor
117
+ - name: model
118
+ description: Physical device model
119
+ metrics:
120
+ - name: adaptecraid.physical_device_state
121
+ description: Physical Device state
122
+ unit: status
123
+ chart_type: line
124
+ dimensions:
125
+ - name: ok
126
+ - name: critical
127
+ - name: adaptecraid.physical_device_smart_warnings
128
+ description: Physical Device SMART warnings
129
+ unit: warnings
130
+ chart_type: line
131
+ dimensions:
132
+ - name: smart
133
+ - name: adaptecraid.physical_device_temperature
134
+ description: Physical Device temperature
135
+ unit: Celsius
136
+ chart_type: line
137
+ dimensions:
138
+ - name: temperature
\ No newline at end of file
src/go/collectors/go.d.plugin/modules/adaptecraid/testdata/config.json
new
+4
@@ -0,0 +1,4 @@
1
+{
2
+ "update_every": 123,
3
+ "timeout": 123.123
4
+}
src/go/collectors/go.d.plugin/modules/adaptecraid/testdata/config.yaml
new
+2
@@ -0,0 +1,2 @@
1
+update_every: 123
2
+timeout: 123.123
src/go/collectors/go.d.plugin/modules/adaptecraid/testdata/getconfig-ld-current.txt
new
+30
@@ -0,0 +1,30 @@
1
+Logical device information
2
+----------------------------------------------------------------------
3
+Logical Device number 0
4
+ Logical Device name : LogicalDrv 0
5
+ Block Size of member drives : 512 Bytes
6
+ RAID level : 10
7
+ Unique Identifier : 488046B2
8
+ Status of Logical Device : Optimal
9
+ Additional details : Quick initialized
10
+ Size : 915446 MB
11
+ Parity space : 915456 MB
12
+ Stripe-unit size : 256 KB
13
+ Interface Type : Serial ATA
14
+ Device Type : HDD
15
+ Read-cache setting : Enabled
16
+ Read-cache status : On
17
+ Write-cache setting : Enabled
18
+ Write-cache status : On
19
+ Partitioned : Yes
20
+ Protected by Hot-Spare : No
21
+ Bootable : Yes
22
+ Failed stripes : No
23
+ Power settings : Disabled
24
+ --------------------------------------------------------
25
+ Logical Device segment information
26
+ --------------------------------------------------------
27
+ Group 0, Segment 0 : Present (457862MB, SATA, SSD, Connector:0, Device:0) 7CS009RP
28
+ Group 0, Segment 1 : Present (457862MB, SATA, SSD, Connector:0, Device:1) 7CS009RQ
29
+ Group 1, Segment 0 : Present (457862MB, SATA, SSD, Connector:0, Device:2) 7CS00AAD
30
+ Group 1, Segment 1 : Present (457862MB, SATA, SSD, Connector:0, Device:3) 7CS00AAH
src/go/collectors/go.d.plugin/modules/adaptecraid/testdata/getconfig-ld-old.txt
new
+33
@@ -0,0 +1,33 @@
1
+Controllers found: 1
2
+----------------------------------------------------------------------
3
+Logical device information
4
+----------------------------------------------------------------------
5
+Logical device number 0
6
+ Logical device name : LogicalDrv 0
7
+ Block Size of member drives : 512 Bytes
8
+ RAID level : 10
9
+ Unique Identifier : 488046B2
10
+ Status of logical device : Optimal
11
+ Size : 915446 MB
12
+ Parity space : 915456 MB
13
+ Stripe-unit size : 256 KB
14
+ Read-cache setting : Enabled
15
+ Read-cache status : On
16
+ Write-cache setting : Enabled
17
+ Write-cache status : On
18
+ Partitioned : Yes
19
+ Protected by Hot-Spare : No
20
+ Bootable : Yes
21
+ Failed stripes : No
22
+ Power settings : Disabled
23
+ --------------------------------------------------------
24
+ Logical device segment information
25
+ --------------------------------------------------------
26
+ Group 0, Segment 0 : Present (Controller:1,Connector:0,Device:0) 7CS009RP
27
+ Group 0, Segment 1 : Present (Controller:1,Connector:0,Device:1) 7CS009RQ
28
+ Group 1, Segment 0 : Present (Controller:1,Connector:0,Device:2) 7CS00AAD
29
+ Group 1, Segment 1 : Present (Controller:1,Connector:0,Device:3) 7CS00AAH
30
+
31
+
32
+
33
+Command completed successfully.
src/go/collectors/go.d.plugin/modules/adaptecraid/testdata/getconfig-pd-current.txt
new
+216
@@ -0,0 +1,216 @@
1
+Controllers found: 1
2
+----------------------------------------------------------------------
3
+Physical Device information
4
+----------------------------------------------------------------------
5
+ Device #0
6
+ Device is a Hard drive
7
+ State : Online
8
+ Block Size : 512 Bytes
9
+ Supported : Yes
10
+ Transfer Speed : SAS 6.0 Gb/s
11
+ Reported Channel,Device(T:L) : 0,1(1:0)
12
+ Reported Location : Connector 0, Device 1
13
+ Vendor : NETAPP
14
+ Model : X422_HCOBE600A10
15
+ Firmware : NA00
16
+ Reserved Size : 956312 KB
17
+ Used Size : 571392 MB
18
+ Unused Size : 64 KB
19
+ Total Size : 572325 MB
20
+ Write Cache : Enabled (write-back)
21
+ FRU : None
22
+ S.M.A.R.T. : No
23
+ S.M.A.R.T. warnings : 0
24
+ Power State : Full rpm
25
+ Supported Power States : Full rpm,Powered off
26
+ SSD : No
27
+ Temperature : Not Supported
28
+ ----------------------------------------------------------------
29
+ Device Phy Information
30
+ ----------------------------------------------------------------
31
+ Phy #0
32
+ PHY Identifier : 0
33
+ SAS Address : 5000
34
+ Attached PHY Identifier : 2
35
+ Attached SAS Address : 5000
36
+ Phy #1
37
+ PHY Identifier : 1
38
+ SAS Address : 5000
39
+
40
+ Device #1
41
+ Device is a Hard drive
42
+ State : Online
43
+ Block Size : 512 Bytes
44
+ Supported : Yes
45
+ Transfer Speed : SAS 6.0 Gb/s
46
+ Reported Channel,Device(T:L) : 0,2(2:0)
47
+ Reported Location : Connector 0, Device 2
48
+ Vendor : NETAPP
49
+ Model : X422_HCOBE600A10
50
+ Firmware : NA02
51
+ Reserved Size : 956312 KB
52
+ Used Size : 571392 MB
53
+ Unused Size : 64 KB
54
+ Total Size : 572325 MB
55
+ Write Cache : Enabled (write-back)
56
+ FRU : None
57
+ S.M.A.R.T. : No
58
+ S.M.A.R.T. warnings : 0
59
+ Power State : Full rpm
60
+ Supported Power States : Full rpm,Powered off
61
+ SSD : No
62
+ Temperature : Not Supported
63
+ ----------------------------------------------------------------
64
+ Device Phy Information
65
+ ----------------------------------------------------------------
66
+ Phy #0
67
+ PHY Identifier : 0
68
+ SAS Address : 5000
69
+ Attached PHY Identifier : 1
70
+ Attached SAS Address : 5000
71
+ Phy #1
72
+ PHY Identifier : 1
73
+ SAS Address : 5000
74
+
75
+ Device #2
76
+ Device is a Hard drive
77
+ State : Online
78
+ Block Size : 512 Bytes
79
+ Supported : Yes
80
+ Transfer Speed : SAS 6.0 Gb/s
81
+ Reported Channel,Device(T:L) : 0,4(4:0)
82
+ Reported Location : Connector 1, Device 0
83
+ Vendor : NETAPP
84
+ Model : X422_HCOBD600A10
85
+ Firmware : NA05
86
+ Reserved Size : 956312 KB
87
+ Used Size : 571392 MB
88
+ Unused Size : 64 KB
89
+ Total Size : 572325 MB
90
+ Write Cache : Enabled (write-back)
91
+ FRU : None
92
+ S.M.A.R.T. : No
93
+ S.M.A.R.T. warnings : 0
94
+ Power State : Full rpm
95
+ Supported Power States : Full rpm,Powered off
96
+ SSD : No
97
+ Temperature : Not Supported
98
+ ----------------------------------------------------------------
99
+ Device Phy Information
100
+ ----------------------------------------------------------------
101
+ Phy #0
102
+ PHY Identifier : 0
103
+ SAS Address : 5000
104
+ Attached PHY Identifier : 7
105
+ Attached SAS Address : 5000
106
+ Phy #1
107
+ PHY Identifier : 1
108
+ SAS Address : 5000
109
+
110
+ Device #3
111
+ Device is a Hard drive
112
+ State : Online
113
+ Block Size : 512 Bytes
114
+ Supported : Yes
115
+ Transfer Speed : SAS 6.0 Gb/s
116
+ Reported Channel,Device(T:L) : 0,5(5:0)
117
+ Reported Location : Connector 1, Device 1
118
+ Vendor : NETAPP
119
+ Model : X422_HCOBD600A10
120
+ Firmware : NA05
121
+ Reserved Size : 956312 KB
122
+ Used Size : 571392 MB
123
+ Unused Size : 64 KB
124
+ Total Size : 572325 MB
125
+ Write Cache : Enabled (write-back)
126
+ FRU : None
127
+ S.M.A.R.T. : No
128
+ S.M.A.R.T. warnings : 0
129
+ Power State : Full rpm
130
+ Supported Power States : Full rpm,Powered off
131
+ SSD : No
132
+ Temperature : Not Supported
133
+ ----------------------------------------------------------------
134
+ Device Phy Information
135
+ ----------------------------------------------------------------
136
+ Phy #0
137
+ PHY Identifier : 0
138
+ SAS Address : 5000
139
+ Attached PHY Identifier : 6
140
+ Attached SAS Address : 5000
141
+ Phy #1
142
+ PHY Identifier : 1
143
+ SAS Address : 5000
144
+
145
+ Device #4
146
+ Device is a Hard drive
147
+ State : Online
148
+ Block Size : 512 Bytes
149
+ Supported : Yes
150
+ Transfer Speed : SAS 6.0 Gb/s
151
+ Reported Channel,Device(T:L) : 0,6(6:0)
152
+ Reported Location : Connector 1, Device 2
153
+ Vendor : NETAPP
154
+ Model : X422_HCOBD600A10
155
+ Firmware : NA05
156
+ Reserved Size : 956312 KB
157
+ Used Size : 571392 MB
158
+ Unused Size : 64 KB
159
+ Total Size : 572325 MB
160
+ Write Cache : Enabled (write-back)
161
+ FRU : None
162
+ S.M.A.R.T. : No
163
+ S.M.A.R.T. warnings : 0
164
+ Power State : Full rpm
165
+ Supported Power States : Full rpm,Powered off
166
+ SSD : No
167
+ Temperature : Not Supported
168
+ ----------------------------------------------------------------
169
+ Device Phy Information
170
+ ----------------------------------------------------------------
171
+ Phy #0
172
+ PHY Identifier : 0
173
+ SAS Address : 5000
174
+ Attached PHY Identifier : 5
175
+ Attached SAS Address : 5000
176
+ Phy #1
177
+ PHY Identifier : 1
178
+ SAS Address : 5000
179
+
180
+ Device #5
181
+ Device is a Hard drive
182
+ State : Online
183
+ Block Size : 512 Bytes
184
+ Supported : Yes
185
+ Transfer Speed : SAS 6.0 Gb/s
186
+ Reported Channel,Device(T:L) : 0,7(7:0)
187
+ Reported Location : Connector 1, Device 3
188
+ Vendor : NETAPP
189
+ Model : X422_HCOBD600A10
190
+ Firmware : NA05
191
+ Reserved Size : 956312 KB
192
+ Used Size : 571392 MB
193
+ Unused Size : 64 KB
194
+ Total Size : 572325 MB
195
+ Write Cache : Enabled (write-back)
196
+ FRU : None
197
+ S.M.A.R.T. : No
198
+ S.M.A.R.T. warnings : 0
199
+ Power State : Full rpm
200
+ Supported Power States : Full rpm,Powered off
201
+ SSD : No
202
+ Temperature : Not Supported
203
+ ----------------------------------------------------------------
204
+ Device Phy Information
205
+ ----------------------------------------------------------------
206
+ Phy #0
207
+ PHY Identifier : 0
208
+ SAS Address : 5000
209
+ Attached PHY Identifier : 4
210
+ Attached SAS Address : 5000
211
+ PHY Identifier : 1
212
+ SAS Address : 5000
213
+
214
+
215
+
216
+Command completed successfully.
src/go/collectors/go.d.plugin/modules/adaptecraid/testdata/getconfig-pd-old.txt
new
+107
@@ -0,0 +1,107 @@
1
+Controllers found: 1
2
+----------------------------------------------------------------------
3
+Physical Device information
4
+----------------------------------------------------------------------
5
+ Device #0
6
+ Device is a Hard drive
7
+ State : Online
8
+ Block Size : 512 Bytes
9
+ Supported : Yes
10
+ Transfer Speed : SATA 6.0 Gb/s
11
+ Reported Channel,Device(T:L) : 0,0(0:0)
12
+ Reported Location : Connector 0, Device 0
13
+ Vendor : ATA
14
+ Model : XF1230-1A0480
15
+ Firmware : ST200354
16
+ Serial number : 7CS009RP
17
+ World-wide name : 5000C500813BF05B
18
+ Reserved Size : 138008 KB
19
+ Used Size : 457728 MB
20
+ Unused Size : 64 KB
21
+ Total Size : 457862 MB
22
+ Write Cache : Disabled (write-through)
23
+ FRU : None
24
+ S.M.A.R.T. : No
25
+ S.M.A.R.T. warnings : 0
26
+ Power State : Full rpm
27
+ Supported Power States : Full power,Powered off
28
+ SSD : Yes
29
+ NCQ status : Enabled
30
+ Device #1
31
+ Device is a Hard drive
32
+ State : Online
33
+ Block Size : 512 Bytes
34
+ Supported : Yes
35
+ Transfer Speed : SATA 6.0 Gb/s
36
+ Reported Channel,Device(T:L) : 0,1(1:0)
37
+ Reported Location : Connector 0, Device 1
38
+ Vendor : ATA
39
+ Model : XF1230-1A0480
40
+ Firmware : ST200354
41
+ Serial number : 7CS009RQ
42
+ World-wide name : 5000C500813BF05C
43
+ Reserved Size : 138008 KB
44
+ Used Size : 457728 MB
45
+ Unused Size : 64 KB
46
+ Total Size : 457862 MB
47
+ Write Cache : Disabled (write-through)
48
+ FRU : None
49
+ S.M.A.R.T. : No
50
+ S.M.A.R.T. warnings : 0
51
+ Power State : Full rpm
52
+ Supported Power States : Full power,Powered off
53
+ SSD : Yes
54
+ NCQ status : Enabled
55
+ Device #2
56
+ Device is a Hard drive
57
+ State : Online
58
+ Block Size : 512 Bytes
59
+ Supported : Yes
60
+ Transfer Speed : SATA 6.0 Gb/s
61
+ Reported Channel,Device(T:L) : 0,2(2:0)
62
+ Reported Location : Connector 0, Device 2
63
+ Vendor : ATA
64
+ Model : XF1230-1A0480
65
+ Firmware : ST200354
66
+ Serial number : 7CS00AAD
67
+ World-wide name : 5000C500813BF320
68
+ Reserved Size : 138008 KB
69
+ Used Size : 457728 MB
70
+ Unused Size : 64 KB
71
+ Total Size : 457862 MB
72
+ Write Cache : Disabled (write-through)
73
+ FRU : None
74
+ S.M.A.R.T. : No
75
+ S.M.A.R.T. warnings : 0
76
+ Power State : Full rpm
77
+ Supported Power States : Full power,Powered off
78
+ SSD : Yes
79
+ NCQ status : Enabled
80
+ Device #3
81
+ Device is a Hard drive
82
+ State : Online
83
+ Block Size : 512 Bytes
84
+ Supported : Yes
85
+ Transfer Speed : SATA 6.0 Gb/s
86
+ Reported Channel,Device(T:L) : 0,3(3:0)
87
+ Reported Location : Connector 0, Device 3
88
+ Vendor : ATA
89
+ Model : XF1230-1A0480
90
+ Firmware : ST200354
91
+ Serial number : 7CS00AAH
92
+ World-wide name : 5000C500813BF324
93
+ Reserved Size : 138008 KB
94
+ Used Size : 457728 MB
95
+ Unused Size : 64 KB
96
+ Total Size : 457862 MB
97
+ Write Cache : Disabled (write-through)
98
+ FRU : None
99
+ S.M.A.R.T. : No
100
+ S.M.A.R.T. warnings : 0
101
+ Power State : Full rpm
102
+ Supported Power States : Full power,Powered off
103
+ SSD : Yes
104
+ NCQ status : Enabled
105
+
106
+
107
+Command completed successfully.
src/go/collectors/go.d.plugin/modules/init.go
+1
@@ -4,6 +4,7 @@ package modules
4
5
import (
6
_ "github.com/netdata/netdata/go/go.d.plugin/modules/activemq"
7
+ _ "github.com/netdata/netdata/go/go.d.plugin/modules/adaptecraid"
8
_ "github.com/netdata/netdata/go/go.d.plugin/modules/apache"
9
_ "github.com/netdata/netdata/go/go.d.plugin/modules/bind"
10
_ "github.com/netdata/netdata/go/go.d.plugin/modules/cassandra"
src/health/health.d/adaptec_raid.conf
+29
@@ -1,4 +1,33 @@
1
+# you can disable an alarm notification by setting the 'to' line to: silent
2
3
+ template: adaptec_raid_ld_health_status
4
+ on: adaptecraid.logical_device_status
5
+ class: Errors
6
+ type: System
7
+component: RAID
8
+ lookup: average -1m unaligned percentage of ok
9
+ units: %
10
+ every: 10s
11
+ crit: $this < 100
12
+ delay: down 5m multiplier 1.5 max 1h
13
+ summary: Adaptec RAID LD (number ${label:ld_number}) health status
14
+ info: Adaptec RAID logical device (number ${label:ld_number} name ${label:ld_name}) health status is critical
15
+ to: sysadmin
16
+
17
+ template: adaptec_raid_pd_health_state
18
+ on: adaptecraid.physical_device_state
19
+ class: Errors
20
+ type: System
21
+component: RAID
22
+ lookup: average -1m unaligned percentage of ok
23
+ units: %
24
+ every: 10s
25
+ crit: $this < 100
26
+ delay: down 5m multiplier 1.5 max 1h
27
+ summary: Adaptec RAID PD (number ${label:pd_number}) health state
28
+ info: Adaptec RAID physical device (number ${label:pd_number} location ${label:location}) health state is critical
29
+ to: sysadmin
30
+
31
# logical device status check
32
33
template: adaptec_raid_ld_status