@cryptotaxi247 / netdata-1 / commits / b8760c60e

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