@cryptotaxi247 / netdata-1 / commits / 7102eb799

rewrite megacli in go (#17410)

Ilya Mashchenko committed Apr 16, 2024 at 17:38 UTC 7102eb799ca753ff9309fc271a22acafbc2083b1
20 files changed +1806 -5
src/go/collectors/go.d.plugin/README.md
+1
@@ -86,6 +86,7 @@ see the appropriate collector readme.
86 | [logind](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/logind) | systemd-logind |
87 | [logstash](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/logstash) | Logstash |
88 | [lvm](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/lvm) | LVM logical volumes |
89 +| [megacli](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/megacli) | MegaCli Hardware Raid |
90 | [mongoDB](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/mongodb) | MongoDB |
91 | [mysql](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/mysql) | MySQL |
92 | [nginx](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/nginx) | NGINX |
src/go/collectors/go.d.plugin/config/go.d.conf
+1
@@ -48,6 +48,7 @@ modules:
48 # logind: yes
49 # logstash: yes
50 # lvm: yes
51 +# megacli: yes
52 # mongodb: yes
53 # mysql: yes
54 # nginx: yes
src/go/collectors/go.d.plugin/config/go.d/megacli.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/megacli#readme
3 +
4 +jobs:
5 + - name: megacli
src/go/collectors/go.d.plugin/modules/init.go
+1
@@ -39,6 +39,7 @@ import (
39 _ "github.com/netdata/netdata/go/go.d.plugin/modules/logind"
40 _ "github.com/netdata/netdata/go/go.d.plugin/modules/logstash"
41 _ "github.com/netdata/netdata/go/go.d.plugin/modules/lvm"
42 + _ "github.com/netdata/netdata/go/go.d.plugin/modules/megacli"
43 _ "github.com/netdata/netdata/go/go.d.plugin/modules/mongodb"
44 _ "github.com/netdata/netdata/go/go.d.plugin/modules/mysql"
45 _ "github.com/netdata/netdata/go/go.d.plugin/modules/nginx"
src/go/collectors/go.d.plugin/modules/megacli/charts.go new
+178
@@ -0,0 +1,178 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package megacli
4 +
5 +import (
6 + "fmt"
7 +
8 + "github.com/netdata/netdata/go/go.d.plugin/agent/module"
9 +)
10 +
11 +const (
12 + prioAdapterHealthState = module.Priority + iota
13 +
14 + prioPhysDriveMediaErrorsRate
15 + prioPhysDrivePredictiveFailuresRate
16 +
17 + prioBBURelativeCharge
18 + prioBBURechargeCycles
19 + prioBBUTemperature
20 +)
21 +
22 +var adapterChartsTmpl = module.Charts{
23 + adapterHealthStateChartTmpl.Copy(),
24 +}
25 +
26 +var (
27 + adapterHealthStateChartTmpl = module.Chart{
28 + ID: "adapter_%s_health_state",
29 + Title: "Adapter health state",
30 + Units: "state",
31 + Fam: "adapter health",
32 + Ctx: "megacli.adapter_health_state",
33 + Type: module.Line,
34 + Priority: prioAdapterHealthState,
35 + Dims: module.Dims{
36 + {ID: "adapter_%s_health_state_optimal", Name: "optimal"},
37 + {ID: "adapter_%s_health_state_degraded", Name: "degraded"},
38 + {ID: "adapter_%s_health_state_partially_degraded", Name: "partially_degraded"},
39 + {ID: "adapter_%s_health_state_failed", Name: "failed"},
40 + },
41 + }
42 +)
43 +
44 +var physDriveChartsTmpl = module.Charts{
45 + physDriveMediaErrorsRateChartTmpl.Copy(),
46 + physDrivePredictiveFailuresRateChartTmpl.Copy(),
47 +}
48 +
49 +var (
50 + physDriveMediaErrorsRateChartTmpl = module.Chart{
51 + ID: "phys_drive_%s_media_errors_rate",
52 + Title: "Physical Drive media errors rate",
53 + Units: "errors/s",
54 + Fam: "phys drive errors",
55 + Ctx: "megacli.phys_drive_media_errors",
56 + Type: module.Line,
57 + Priority: prioPhysDriveMediaErrorsRate,
58 + Dims: module.Dims{
59 + {ID: "phys_drive_%s_media_error_count", Name: "media_errors"},
60 + },
61 + }
62 + physDrivePredictiveFailuresRateChartTmpl = module.Chart{
63 + ID: "phys_drive_%s_predictive_failures_rate",
64 + Title: "Physical Drive predictive failures rate",
65 + Units: "failures/s",
66 + Fam: "phys drive errors",
67 + Ctx: "megacli.phys_drive_predictive_failures",
68 + Type: module.Line,
69 + Priority: prioPhysDrivePredictiveFailuresRate,
70 + Dims: module.Dims{
71 + {ID: "phys_drive_%s_predictive_failure_count", Name: "predictive_failures"},
72 + },
73 + }
74 +)
75 +
76 +var bbuChartsTmpl = module.Charts{
77 + bbuRelativeChargeChartsTmpl.Copy(),
78 + bbuRechargeCyclesChartsTmpl.Copy(),
79 + bbuTemperatureChartsTmpl.Copy(),
80 +}
81 +
82 +var (
83 + bbuRelativeChargeChartsTmpl = module.Chart{
84 + ID: "bbu_adapter_%s_relative_charge",
85 + Title: "BBU relative charge",
86 + Units: "percentage",
87 + Fam: "bbu charge",
88 + Ctx: "megacli.bbu_charge",
89 + Type: module.Area,
90 + Priority: prioBBURelativeCharge,
91 + Dims: module.Dims{
92 + {ID: "bbu_adapter_%s_relative_state_of_charge", Name: "charge"},
93 + },
94 + }
95 + bbuRechargeCyclesChartsTmpl = module.Chart{
96 + ID: "bbu_adapter_%s_recharge_cycles",
97 + Title: "BBU recharge cycles",
98 + Units: "cycles",
99 + Fam: "bbu charge",
100 + Ctx: "megacli.bbu_recharge_cycles",
101 + Type: module.Line,
102 + Priority: prioBBURechargeCycles,
103 + Dims: module.Dims{
104 + {ID: "bbu_adapter_%s_cycle_count", Name: "recharge"},
105 + },
106 + }
107 + bbuTemperatureChartsTmpl = module.Chart{
108 + ID: "bbu_adapter_%s_temperature",
109 + Title: "BBU temperature",
110 + Units: "Celsius",
111 + Fam: "bbu temperature",
112 + Ctx: "megacli.bbu_temperature",
113 + Type: module.Line,
114 + Priority: prioBBUTemperature,
115 + Dims: module.Dims{
116 + {ID: "bbu_adapter_%s_temperature", Name: "temperature"},
117 + },
118 + }
119 +)
120 +
121 +func (m *MegaCli) addAdapterCharts(ad *megaAdapter) {
122 + charts := adapterChartsTmpl.Copy()
123 +
124 + for _, chart := range *charts {
125 + chart.ID = fmt.Sprintf(chart.ID, ad.number)
126 + chart.Labels = []module.Label{
127 + {Key: "adapter_number", Value: ad.number},
128 + }
129 + for _, dim := range chart.Dims {
130 + dim.ID = fmt.Sprintf(dim.ID, ad.number)
131 + }
132 + }
133 +
134 + if err := m.Charts().Add(*charts...); err != nil {
135 + m.Warning(err)
136 + }
137 +}
138 +
139 +func (m *MegaCli) addPhysDriveCharts(pd *megaPhysDrive) {
140 + charts := physDriveChartsTmpl.Copy()
141 +
142 + for _, chart := range *charts {
143 + chart.ID = fmt.Sprintf(chart.ID, pd.wwn)
144 + chart.Labels = []module.Label{
145 + {Key: "adapter_number", Value: pd.adapterNumber},
146 + {Key: "wwn", Value: pd.wwn},
147 + {Key: "slot_number", Value: pd.slotNumber},
148 + {Key: "drive_position", Value: pd.drivePosition},
149 + {Key: "drive_type", Value: pd.pdType},
150 + }
151 + for _, dim := range chart.Dims {
152 + dim.ID = fmt.Sprintf(dim.ID, pd.wwn)
153 + }
154 + }
155 +
156 + if err := m.Charts().Add(*charts...); err != nil {
157 + m.Warning(err)
158 + }
159 +}
160 +
161 +func (m *MegaCli) addBBUCharts(bbu *megaBBU) {
162 + charts := bbuChartsTmpl.Copy()
163 +
164 + for _, chart := range *charts {
165 + chart.ID = fmt.Sprintf(chart.ID, bbu.adapterNumber)
166 + chart.Labels = []module.Label{
167 + {Key: "adapter_number", Value: bbu.adapterNumber},
168 + {Key: "battery_type", Value: bbu.batteryType},
169 + }
170 + for _, dim := range chart.Dims {
171 + dim.ID = fmt.Sprintf(dim.ID, bbu.adapterNumber)
172 + }
173 + }
174 +
175 + if err := m.Charts().Add(*charts...); err != nil {
176 + m.Warning(err)
177 + }
178 +}
src/go/collectors/go.d.plugin/modules/megacli/collect.go new
+46
@@ -0,0 +1,46 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package megacli
4 +
5 +import (
6 + "strconv"
7 + "strings"
8 +)
9 +
10 +func (m *MegaCli) collect() (map[string]int64, error) {
11 + mx := make(map[string]int64)
12 +
13 + if err := m.collectPhysDrives(mx); err != nil {
14 + return nil, err
15 + }
16 + if err := m.collectBBU(mx); err != nil {
17 + return nil, err
18 + }
19 +
20 + return mx, nil
21 +}
22 +
23 +func writeInt(mx map[string]int64, key, value string) {
24 + v, err := strconv.ParseInt(value, 10, 64)
25 + if err != nil {
26 + return
27 + }
28 + mx[key] = v
29 +}
30 +
31 +func getColonSepValue(line string) string {
32 + i := strings.IndexByte(line, ':')
33 + if i == -1 {
34 + return ""
35 + }
36 + return strings.TrimSpace(line[i+1:])
37 +}
38 +
39 +func getColonSepNumValue(line string) string {
40 + v := getColonSepValue(line)
41 + i := strings.IndexByte(v, ' ')
42 + if i == -1 {
43 + return v
44 + }
45 + return v[:i]
46 +}
src/go/collectors/go.d.plugin/modules/megacli/collect_bbu.go new
+105
@@ -0,0 +1,105 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package megacli
4 +
5 +import (
6 + "bufio"
7 + "bytes"
8 + "fmt"
9 + "strings"
10 +)
11 +
12 +type megaBBU struct {
13 + adapterNumber string
14 + batteryType string
15 + temperature string
16 + relativeStateOfCharge string
17 + absoluteStateOfCharge string // apparently can be 0 while relative > 0 (e.g. relative 91%, absolute 0%)
18 + cycleCount string
19 +}
20 +
21 +func (m *MegaCli) collectBBU(mx map[string]int64) error {
22 + bs, err := m.exec.bbuInfo()
23 + if err != nil {
24 + return err
25 + }
26 +
27 + bbus, err := parseBBUInfo(bs)
28 + if err != nil {
29 + return err
30 + }
31 +
32 + for _, bbu := range bbus {
33 + if !m.bbu[bbu.adapterNumber] {
34 + m.bbu[bbu.adapterNumber] = true
35 + m.addBBUCharts(bbu)
36 + }
37 +
38 + px := fmt.Sprintf("bbu_adapter_%s_", bbu.adapterNumber)
39 +
40 + writeInt(mx, px+"temperature", bbu.temperature)
41 + writeInt(mx, px+"relative_state_of_charge", bbu.relativeStateOfCharge)
42 + writeInt(mx, px+"absolute_state_of_charge", bbu.absoluteStateOfCharge)
43 + writeInt(mx, px+"cycle_count", bbu.cycleCount)
44 + }
45 +
46 + return nil
47 +}
48 +
49 +func parseBBUInfo(bs []byte) (map[string]*megaBBU, error) {
50 + bbus := make(map[string]*megaBBU)
51 +
52 + var section string
53 + var bbu *megaBBU
54 +
55 + sc := bufio.NewScanner(bytes.NewReader(bs))
56 +
57 + for sc.Scan() {
58 + line := strings.TrimSpace(sc.Text())
59 +
60 + switch {
61 + case strings.HasPrefix(line, "BBU status for Adapter"):
62 + section = "status"
63 + ad := getColonSepValue(line)
64 + if _, ok := bbus[ad]; !ok {
65 + bbu = &megaBBU{adapterNumber: ad}
66 + bbus[ad] = bbu
67 + }
68 + continue
69 + case strings.HasPrefix(line, "BBU Capacity Info for Adapter"):
70 + section = "capacity"
71 + continue
72 + case strings.HasPrefix(line, "BBU Firmware Status"),
73 + strings.HasPrefix(line, "BBU GasGauge Status"),
74 + strings.HasPrefix(line, "BBU Design Info for Adapter"),
75 + strings.HasPrefix(line, "BBU Properties for Adapter"):
76 + section = ""
77 + continue
78 + }
79 +
80 + if bbu == nil {
81 + continue
82 + }
83 +
84 + switch section {
85 + case "status":
86 + switch {
87 + case strings.HasPrefix(line, "BatteryType:"):
88 + bbu.batteryType = getColonSepValue(line)
89 + case strings.HasPrefix(line, "Temperature:"):
90 + bbu.temperature = getColonSepNumValue(line)
91 + }
92 + case "capacity":
93 + switch {
94 + case strings.HasPrefix(line, "Relative State of Charge:"):
95 + bbu.relativeStateOfCharge = getColonSepNumValue(line)
96 + case strings.HasPrefix(line, "Absolute State of charge:"):
97 + bbu.absoluteStateOfCharge = getColonSepNumValue(line)
98 + case strings.HasPrefix(line, "Cycle Count:"):
99 + bbu.cycleCount = getColonSepNumValue(line)
100 + }
101 + }
102 + }
103 +
104 + return bbus, nil
105 +}
src/go/collectors/go.d.plugin/modules/megacli/collect_phys_drives.go new
+120
@@ -0,0 +1,120 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package megacli
4 +
5 +import (
6 + "bufio"
7 + "bytes"
8 + "fmt"
9 + "strings"
10 +)
11 +
12 +type (
13 + megaAdapter struct {
14 + number string
15 + name string
16 + state string
17 + physDrives map[string]*megaPhysDrive
18 + }
19 + megaPhysDrive struct {
20 + adapterNumber string
21 + number string
22 + wwn string
23 + slotNumber string
24 + drivePosition string
25 + pdType string
26 + mediaErrorCount string
27 + predictiveFailureCount string
28 + }
29 +)
30 +
31 +var adapterStates = []string{
32 + "optimal",
33 + "degraded",
34 + "partially_degraded",
35 + "failed",
36 +}
37 +
38 +func (m *MegaCli) collectPhysDrives(mx map[string]int64) error {
39 + bs, err := m.exec.physDrivesInfo()
40 + if err != nil {
41 + return err
42 + }
43 +
44 + adapters, err := parsePhysDrivesInfo(bs)
45 + if err != nil {
46 + return err
47 + }
48 +
49 + for _, ad := range adapters {
50 + if !m.adapters[ad.number] {
51 + m.adapters[ad.number] = true
52 + m.addAdapterCharts(ad)
53 + }
54 +
55 + px := fmt.Sprintf("adapter_%s_health_state_", ad.number)
56 + for _, st := range adapterStates {
57 + mx[px+st] = 0
58 + }
59 + st := strings.ReplaceAll(strings.ToLower(ad.state), " ", "_")
60 + mx[px+st] = 1
61 +
62 + for _, pd := range ad.physDrives {
63 + if !m.adapters[pd.wwn] {
64 + m.adapters[pd.wwn] = true
65 + m.addPhysDriveCharts(pd)
66 + }
67 +
68 + px := fmt.Sprintf("phys_drive_%s_", pd.wwn)
69 +
70 + writeInt(mx, px+"media_error_count", pd.mediaErrorCount)
71 + writeInt(mx, px+"predictive_failure_count", pd.predictiveFailureCount)
72 + }
73 + }
74 +
75 + return nil
76 +}
77 +
78 +func parsePhysDrivesInfo(bs []byte) (map[string]*megaAdapter, error) {
79 + adapters := make(map[string]*megaAdapter)
80 +
81 + var ad *megaAdapter
82 + var pd *megaPhysDrive
83 +
84 + sc := bufio.NewScanner(bytes.NewReader(bs))
85 +
86 + for sc.Scan() {
87 + line := strings.TrimSpace(sc.Text())
88 +
89 + switch {
90 + case strings.HasPrefix(line, "Adapter #"):
91 + idx := strings.TrimPrefix(line, "Adapter #")
92 + ad = &megaAdapter{number: idx, physDrives: make(map[string]*megaPhysDrive)}
93 + adapters[idx] = ad
94 + case strings.HasPrefix(line, "Name") && ad != nil:
95 + ad.name = getColonSepValue(line)
96 + case strings.HasPrefix(line, "State") && ad != nil:
97 + ad.state = getColonSepValue(line)
98 + case strings.HasPrefix(line, "PD:") && ad != nil:
99 + if parts := strings.Fields(line); len(parts) == 3 {
100 + idx := parts[1]
101 + pd = &megaPhysDrive{number: idx, adapterNumber: ad.number}
102 + ad.physDrives[idx] = pd
103 + }
104 + case strings.HasPrefix(line, "Slot Number:") && pd != nil:
105 + pd.slotNumber = getColonSepValue(line)
106 + case strings.HasPrefix(line, "Drive's position:") && pd != nil:
107 + pd.drivePosition = getColonSepValue(line)
108 + case strings.HasPrefix(line, "WWN:") && pd != nil:
109 + pd.wwn = getColonSepValue(line)
110 + case strings.HasPrefix(line, "PD Type:") && pd != nil:
111 + pd.pdType = getColonSepValue(line)
112 + case strings.HasPrefix(line, "Media Error Count:") && pd != nil:
113 + pd.mediaErrorCount = getColonSepNumValue(line)
114 + case strings.HasPrefix(line, "Predictive Failure Count:") && pd != nil:
115 + pd.predictiveFailureCount = getColonSepNumValue(line)
116 + }
117 + }
118 +
119 + return adapters, nil
120 +}
src/go/collectors/go.d.plugin/modules/megacli/config_schema.json new
+35
@@ -0,0 +1,35 @@
1 +{
2 + "jsonSchema": {
3 + "$schema": "http://json-schema.org/draft-07/schema#",
4 + "title": "MegaCli 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/megacli/exec.go new
+50
@@ -0,0 +1,50 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package megacli
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 newMegaCliExec(ndsudoPath string, timeout time.Duration, log *logger.Logger) *megaCliExec {
15 + return &megaCliExec{
16 + Logger: log,
17 + ndsudoPath: ndsudoPath,
18 + timeout: timeout,
19 + }
20 +}
21 +
22 +type megaCliExec struct {
23 + *logger.Logger
24 +
25 + ndsudoPath string
26 + timeout time.Duration
27 +}
28 +
29 +func (e *megaCliExec) physDrivesInfo() ([]byte, error) {
30 + return e.execute("megacli-disk-info")
31 +}
32 +
33 +func (e *megaCliExec) bbuInfo() ([]byte, error) {
34 + return e.execute("megacli-battery-info")
35 +}
36 +
37 +func (e *megaCliExec) 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/megacli/init.go new
+23
@@ -0,0 +1,23 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package megacli
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 (m *MegaCli) initMegaCliExec() (megaCli, 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 + megaExec := newMegaCliExec(ndsudoPath, m.Timeout.Duration(), m.Logger)
21 +
22 + return megaExec, nil
23 +}
src/go/collectors/go.d.plugin/modules/megacli/megacli.go new
+109
@@ -0,0 +1,109 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package megacli
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("megacli", 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() *MegaCli {
28 + return &MegaCli{
29 + Config: Config{
30 + Timeout: web.Duration(time.Second * 2),
31 + },
32 + charts: &module.Charts{},
33 + adapters: make(map[string]bool),
34 + drives: make(map[string]bool),
35 + bbu: make(map[string]bool),
36 + }
37 +}
38 +
39 +type Config struct {
40 + UpdateEvery int `yaml:"update_every" json:"update_every"`
41 + Timeout web.Duration `yaml:"timeout" json:"timeout"`
42 +}
43 +
44 +type (
45 + MegaCli struct {
46 + module.Base
47 + Config `yaml:",inline" json:""`
48 +
49 + charts *module.Charts
50 +
51 + exec megaCli
52 +
53 + adapters map[string]bool
54 + drives map[string]bool
55 + bbu map[string]bool
56 + }
57 + megaCli interface {
58 + physDrivesInfo() ([]byte, error)
59 + bbuInfo() ([]byte, error)
60 + }
61 +)
62 +
63 +func (m *MegaCli) Configuration() any {
64 + return m.Config
65 +}
66 +
67 +func (m *MegaCli) Init() error {
68 + lvmExec, err := m.initMegaCliExec()
69 + if err != nil {
70 + m.Errorf("megacli exec initialization: %v", err)
71 + return err
72 + }
73 + m.exec = lvmExec
74 +
75 + return nil
76 +}
77 +
78 +func (m *MegaCli) Check() error {
79 + mx, err := m.collect()
80 + if err != nil {
81 + m.Error(err)
82 + return err
83 + }
84 +
85 + if len(mx) == 0 {
86 + return errors.New("no metrics collected")
87 + }
88 +
89 + return nil
90 +}
91 +
92 +func (m *MegaCli) Charts() *module.Charts {
93 + return m.charts
94 +}
95 +
96 +func (m *MegaCli) Collect() map[string]int64 {
97 + mx, err := m.collect()
98 + if err != nil {
99 + m.Error(err)
100 + }
101 +
102 + if len(mx) == 0 {
103 + return nil
104 + }
105 +
106 + return mx
107 +}
108 +
109 +func (m *MegaCli) Cleanup() {}
src/go/collectors/go.d.plugin/modules/megacli/megacli_test.go new
+296
@@ -0,0 +1,296 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package megacli
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 + dataBBUInfoOld, _ = os.ReadFile("testdata/mega-bbu-info-old.txt")
21 + dataBBUInfoRecent, _ = os.ReadFile("testdata/mega-bbu-info-recent.txt")
22 + dataPhysDrivesInfo, _ = os.ReadFile("testdata/mega-phys-drives-info.txt")
23 +)
24 +
25 +func Test_testDataIsValid(t *testing.T) {
26 + for name, data := range map[string][]byte{
27 + "dataConfigJSON": dataConfigJSON,
28 + "dataConfigYAML": dataConfigYAML,
29 +
30 + "dataBBUInfoOld": dataBBUInfoOld,
31 + "dataBBUInfoRecent": dataBBUInfoRecent,
32 + "dataPhysDrivesInfo": dataPhysDrivesInfo,
33 + } {
34 + require.NotNil(t, data, name)
35 + }
36 +}
37 +
38 +func TestMegaCli_ConfigurationSerialize(t *testing.T) {
39 + module.TestConfigurationSerialize(t, &MegaCli{}, dataConfigJSON, dataConfigYAML)
40 +}
41 +
42 +func TestMegaCli_Init(t *testing.T) {
43 + tests := map[string]struct {
44 + config Config
45 + wantFail bool
46 + }{
47 + "fails if 'ndsudo' not found": {
48 + wantFail: true,
49 + config: New().Config,
50 + },
51 + }
52 +
53 + for name, test := range tests {
54 + t.Run(name, func(t *testing.T) {
55 + mega := New()
56 +
57 + if test.wantFail {
58 + assert.Error(t, mega.Init())
59 + } else {
60 + assert.NoError(t, mega.Init())
61 + }
62 + })
63 + }
64 +}
65 +
66 +func TestMegaCli_Cleanup(t *testing.T) {
67 + tests := map[string]struct {
68 + prepare func() *MegaCli
69 + }{
70 + "not initialized exec": {
71 + prepare: func() *MegaCli {
72 + return New()
73 + },
74 + },
75 + "after check": {
76 + prepare: func() *MegaCli {
77 + mega := New()
78 + mega.exec = prepareMockOK()
79 + _ = mega.Check()
80 + return mega
81 + },
82 + },
83 + "after collect": {
84 + prepare: func() *MegaCli {
85 + mega := New()
86 + mega.exec = prepareMockOK()
87 + _ = mega.Collect()
88 + return mega
89 + },
90 + },
91 + }
92 +
93 + for name, test := range tests {
94 + t.Run(name, func(t *testing.T) {
95 + mega := test.prepare()
96 +
97 + assert.NotPanics(t, mega.Cleanup)
98 + })
99 + }
100 +}
101 +
102 +func TestMegaCli_Charts(t *testing.T) {
103 + assert.NotNil(t, New().Charts())
104 +}
105 +
106 +func TestMegaCli_Check(t *testing.T) {
107 + tests := map[string]struct {
108 + prepareMock func() *mockMegaCliExec
109 + wantFail bool
110 + }{
111 + "success case": {
112 + wantFail: false,
113 + prepareMock: prepareMockOK,
114 + },
115 + "success case old bbu": {
116 + wantFail: false,
117 + prepareMock: prepareMockOldBbuOK,
118 + },
119 + "err on exec": {
120 + wantFail: true,
121 + prepareMock: prepareMockErr,
122 + },
123 + "unexpected response": {
124 + wantFail: true,
125 + prepareMock: prepareMockUnexpectedResponse,
126 + },
127 + "empty response": {
128 + wantFail: true,
129 + prepareMock: prepareMockEmptyResponse,
130 + },
131 + }
132 +
133 + for name, test := range tests {
134 + t.Run(name, func(t *testing.T) {
135 + mega := New()
136 + mock := test.prepareMock()
137 + mega.exec = mock
138 +
139 + if test.wantFail {
140 + assert.Error(t, mega.Check())
141 + } else {
142 + assert.NoError(t, mega.Check())
143 + }
144 + })
145 + }
146 +}
147 +
148 +func TestMegaCli_Collect(t *testing.T) {
149 + tests := map[string]struct {
150 + prepareMock func() *mockMegaCliExec
151 + wantMetrics map[string]int64
152 + wantCharts int
153 + }{
154 + "success case": {
155 + prepareMock: prepareMockOK,
156 + wantCharts: len(adapterChartsTmpl)*1 + len(physDriveChartsTmpl)*8 + len(bbuChartsTmpl)*1,
157 + wantMetrics: map[string]int64{
158 + "adapter_0_health_state_degraded": 0,
159 + "adapter_0_health_state_failed": 0,
160 + "adapter_0_health_state_optimal": 1,
161 + "adapter_0_health_state_partially_degraded": 0,
162 + "bbu_adapter_0_absolute_state_of_charge": 63,
163 + "bbu_adapter_0_cycle_count": 4,
164 + "bbu_adapter_0_relative_state_of_charge": 71,
165 + "bbu_adapter_0_temperature": 33,
166 + "phys_drive_5002538c00019b96_media_error_count": 0,
167 + "phys_drive_5002538c00019b96_predictive_failure_count": 0,
168 + "phys_drive_5002538c4002da83_media_error_count": 0,
169 + "phys_drive_5002538c4002da83_predictive_failure_count": 0,
170 + "phys_drive_5002538c4002dade_media_error_count": 0,
171 + "phys_drive_5002538c4002dade_predictive_failure_count": 0,
172 + "phys_drive_5002538c4002e6e9_media_error_count": 0,
173 + "phys_drive_5002538c4002e6e9_predictive_failure_count": 0,
174 + "phys_drive_5002538c4002e707_media_error_count": 0,
175 + "phys_drive_5002538c4002e707_predictive_failure_count": 0,
176 + "phys_drive_5002538c4002e70f_media_error_count": 0,
177 + "phys_drive_5002538c4002e70f_predictive_failure_count": 0,
178 + "phys_drive_5002538c4002e712_media_error_count": 0,
179 + "phys_drive_5002538c4002e712_predictive_failure_count": 0,
180 + "phys_drive_5002538c4002e713_media_error_count": 0,
181 + "phys_drive_5002538c4002e713_predictive_failure_count": 0,
182 + },
183 + },
184 + "success case old bbu": {
185 + prepareMock: prepareMockOldBbuOK,
186 + wantCharts: len(adapterChartsTmpl)*1 + len(physDriveChartsTmpl)*8 + len(bbuChartsTmpl)*1,
187 + wantMetrics: map[string]int64{
188 + "adapter_0_health_state_degraded": 0,
189 + "adapter_0_health_state_failed": 0,
190 + "adapter_0_health_state_optimal": 1,
191 + "adapter_0_health_state_partially_degraded": 0,
192 + "bbu_adapter_0_absolute_state_of_charge": 83,
193 + "bbu_adapter_0_cycle_count": 61,
194 + "bbu_adapter_0_relative_state_of_charge": 100,
195 + "bbu_adapter_0_temperature": 31,
196 + "phys_drive_5002538c00019b96_media_error_count": 0,
197 + "phys_drive_5002538c00019b96_predictive_failure_count": 0,
198 + "phys_drive_5002538c4002da83_media_error_count": 0,
199 + "phys_drive_5002538c4002da83_predictive_failure_count": 0,
200 + "phys_drive_5002538c4002dade_media_error_count": 0,
201 + "phys_drive_5002538c4002dade_predictive_failure_count": 0,
202 + "phys_drive_5002538c4002e6e9_media_error_count": 0,
203 + "phys_drive_5002538c4002e6e9_predictive_failure_count": 0,
204 + "phys_drive_5002538c4002e707_media_error_count": 0,
205 + "phys_drive_5002538c4002e707_predictive_failure_count": 0,
206 + "phys_drive_5002538c4002e70f_media_error_count": 0,
207 + "phys_drive_5002538c4002e70f_predictive_failure_count": 0,
208 + "phys_drive_5002538c4002e712_media_error_count": 0,
209 + "phys_drive_5002538c4002e712_predictive_failure_count": 0,
210 + "phys_drive_5002538c4002e713_media_error_count": 0,
211 + "phys_drive_5002538c4002e713_predictive_failure_count": 0,
212 + },
213 + },
214 + "err on exec": {
215 + prepareMock: prepareMockErr,
216 + wantMetrics: nil,
217 + },
218 + "unexpected response": {
219 + prepareMock: prepareMockUnexpectedResponse,
220 + wantMetrics: nil,
221 + },
222 + "empty response": {
223 + prepareMock: prepareMockEmptyResponse,
224 + wantMetrics: nil,
225 + },
226 + }
227 +
228 + for name, test := range tests {
229 + t.Run(name, func(t *testing.T) {
230 + mega := New()
231 + mock := test.prepareMock()
232 + mega.exec = mock
233 +
234 + mx := mega.Collect()
235 +
236 + assert.Equal(t, test.wantMetrics, mx)
237 + assert.Len(t, *mega.Charts(), test.wantCharts)
238 + })
239 + }
240 +}
241 +
242 +func prepareMockOK() *mockMegaCliExec {
243 + return &mockMegaCliExec{
244 + physDrivesInfoData: dataPhysDrivesInfo,
245 + bbuInfoData: dataBBUInfoRecent,
246 + }
247 +}
248 +
249 +func prepareMockOldBbuOK() *mockMegaCliExec {
250 + return &mockMegaCliExec{
251 + physDrivesInfoData: dataPhysDrivesInfo,
252 + bbuInfoData: dataBBUInfoOld,
253 + }
254 +}
255 +
256 +func prepareMockErr() *mockMegaCliExec {
257 + return &mockMegaCliExec{
258 + errOnInfo: true,
259 + }
260 +}
261 +
262 +func prepareMockUnexpectedResponse() *mockMegaCliExec {
263 + resp := []byte(`
264 +Lorem ipsum dolor sit amet, consectetur adipiscing elit.
265 +Nulla malesuada erat id magna mattis, eu viverra tellus rhoncus.
266 +Fusce et felis pulvinar, posuere sem non, porttitor eros.
267 +`)
268 + return &mockMegaCliExec{
269 + physDrivesInfoData: resp,
270 + bbuInfoData: resp,
271 + }
272 +}
273 +
274 +func prepareMockEmptyResponse() *mockMegaCliExec {
275 + return &mockMegaCliExec{}
276 +}
277 +
278 +type mockMegaCliExec struct {
279 + errOnInfo bool
280 + physDrivesInfoData []byte
281 + bbuInfoData []byte
282 +}
283 +
284 +func (m *mockMegaCliExec) physDrivesInfo() ([]byte, error) {
285 + if m.errOnInfo {
286 + return nil, errors.New("mock.physDrivesInfo() error")
287 + }
288 + return m.physDrivesInfoData, nil
289 +}
290 +
291 +func (m *mockMegaCliExec) bbuInfo() ([]byte, error) {
292 + if m.errOnInfo {
293 + return nil, errors.New("mock.bbuInfo() error")
294 + }
295 + return m.bbuInfoData, nil
296 +}
src/go/collectors/go.d.plugin/modules/megacli/metadata.yaml new
+157
@@ -0,0 +1,157 @@
1 +plugin_name: go.d.plugin
2 +modules:
3 + - meta:
4 + id: collector-go.d.plugin-megacli
5 + plugin_name: go.d.plugin
6 + module_name: megacli
7 + monitored_instance:
8 + name: MegaCli Hardware Raid
9 + link: "https://wikitech.wikimedia.org/wiki/MegaCli"
10 + icon_filename: "hard-drive.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 MegaCLI Hardware RAID by tracking the status of RAID adapters, physical drives, and backup batteries in your storage system.
27 + It relies on the `megacli` 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 + - `megacli -LDPDInfo -aAll -NoLog`
33 + - `megacli -AdpBbuCmd -aAll -NoLog`
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/megacli.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: lvs 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: megacli
79 + update_every: 5 # Collect MegaCli 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: adapter
92 + description: These metrics refer to the MegaCLI Adapter.
93 + labels:
94 + - name: adapter_number
95 + description: Adapter number
96 + metrics:
97 + - name: megacli.adapter_health_state
98 + description: Adapter health state
99 + unit: state
100 + chart_type: line
101 + dimensions:
102 + - name: optimal
103 + - name: degraded
104 + - name: partially_degraded
105 + - name: failed
106 + - name: physical drive
107 + description: These metrics refer to the MegaCLI Physical Drive.
108 + labels:
109 + - name: adapter_number
110 + description: Adapter number
111 + - name: wwn
112 + description: World Wide Name
113 + - name: slot_number
114 + description: Slot number
115 + - name: drive_position
116 + description: "Position (e.g. DiskGroup: 0, Span: 0, Arm: 2)"
117 + - name: drive_type
118 + description: Type (e.g. SATA)
119 + metrics:
120 + - name: megacli.phys_drive_media_errors_rate
121 + description: Physical Drive media errors rate
122 + unit: errors/s
123 + chart_type: line
124 + dimensions:
125 + - name: media_errors
126 + - name: megacli.phys_drive_predictive_failures_rate
127 + description: Physical Drive predictive failures rate
128 + unit: failures/s
129 + chart_type: line
130 + dimensions:
131 + - name: predictive_failures
132 + - name: backup battery unit
133 + description: These metrics refer to the MegaCLI Backup Battery Unit.
134 + labels:
135 + - name: adapter_number
136 + description: Adapter number
137 + - name: battery_type
138 + description: Battery type (e.g. BBU)
139 + metrics:
140 + - name: megacli.bbu_relative_charge
141 + description: BBU relative charge
142 + unit: percentage
143 + chart_type: area
144 + dimensions:
145 + - name: charge
146 + - name: megacli.bbu_recharge_cycles
147 + description: BBU relative charge
148 + unit: cycles
149 + chart_type: line
150 + dimensions:
151 + - name: recharge
152 + - name: megacli.bbu_temperature
153 + description: BBU bbu_temperature
154 + unit: Celsius
155 + chart_type: line
156 + dimensions:
157 + - name: temperature
src/go/collectors/go.d.plugin/modules/megacli/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/megacli/testdata/config.yaml new
+2
@@ -0,0 +1,2 @@
1 +update_every: 123
2 +timeout: 123.123
src/go/collectors/go.d.plugin/modules/megacli/testdata/mega-bbu-info-old.txt new
+84
@@ -0,0 +1,84 @@
1 +BBU status for Adapter: 0
2 +
3 +BatteryType: BBU
4 +Voltage: 4073 mV
5 +Current: 0 mA
6 +Temperature: 31 C
7 +Battery State: Optimal
8 +BBU Firmware Status:
9 +
10 + Charging Status : None
11 + Voltage : OK
12 + Temperature : OK
13 + Learn Cycle Requested : No
14 + Learn Cycle Active : No
15 + Learn Cycle Status : OK
16 + Learn Cycle Timeout : No
17 + I2c Errors Detected : No
18 + Battery Pack Missing : No
19 + Battery Replacement required : No
20 + Remaining Capacity Low : No
21 + Periodic Learn Required : No
22 + Transparent Learn : No
23 + No space to cache offload : No
24 + Pack is about to fail & should be replaced : No
25 + Cache Offload premium feature required : No
26 + Module microcode update required : No
27 +
28 +
29 +GasGuageStatus:
30 + Fully Discharged : No
31 + Fully Charged : Yes
32 + Discharging : Yes
33 + Initialized : Yes
34 + Remaining Time Alarm : No
35 + Discharge Terminated : No
36 + Over Temperature : No
37 + Charging Terminated : Yes
38 + Over Charged : No
39 +Relative State of Charge: 100 %
40 +Charger Status: Complete
41 +Remaining Capacity: 1477 mAh
42 +Full Charge Capacity: 1477 mAh
43 +isSOHGood: Yes
44 + Battery backup charge time : 0 hours
45 +
46 +BBU Capacity Info for Adapter: 0
47 +
48 + Relative State of Charge: 100 %
49 + Absolute State of charge: 83 %
50 + Remaining Capacity: 1477 mAh
51 + Full Charge Capacity: 1477 mAh
52 + Run time to empty: Battery is not being charged.
53 + Average time to empty: Battery is not being charged.
54 + Estimated Time to full recharge: Battery is not being charged.
55 + Cycle Count: 61
56 +Max Error = 2 %
57 +Remaining Capacity Alarm = 180 mAh
58 +Remining Time Alarm = 10 Min
59 +
60 +BBU Design Info for Adapter: 0
61 +
62 + Date of Manufacture: 07/08, 2010
63 + Design Capacity: 1800 mAh
64 + Design Voltage: 3700 mV
65 + Specification Info: 49
66 + Serial Number: 4069
67 + Pack Stat Configuration: 0x0014
68 + Manufacture Name: SMP-PA1.9
69 + Firmware Version : �
70 + Device Name: DLFR463
71 + Device Chemistry: LION
72 + Battery FRU: N/A
73 +Module Version = �
74 + Transparent Learn = 0
75 + App Data = 0
76 +
77 +BBU Properties for Adapter: 0
78 +
79 + Auto Learn Period: 90 Days
80 + Next Learn time: Fri Jan 28 13:07:56 2022
81 + Learn Delay Interval:0 Hours
82 + Auto-Learn Mode: Enabled
83 +
84 +Exit Code: 0x00
src/go/collectors/go.d.plugin/modules/megacli/testdata/mega-bbu-info-recent.txt new
+74
@@ -0,0 +1,74 @@
1 +BBU status for Adapter: 0
2 +
3 +BatteryType: iBBU08
4 +Voltage: 3922 mV
5 +Current: 0 mA
6 +Temperature: 33 C
7 +Battery State: Optimal
8 +Design Mode : 48+ Hrs retention with a non-transparent learn cycle and balanced service life.
9 +
10 +BBU Firmware Status:
11 +
12 + Charging Status : None
13 + Voltage : OK
14 + Temperature : OK
15 + Learn Cycle Requested : No
16 + Learn Cycle Active : No
17 + Learn Cycle Status : OK
18 + Learn Cycle Timeout : No
19 + I2c Errors Detected : No
20 + Battery Pack Missing : No
21 + Battery Replacement required : No
22 + Remaining Capacity Low : No
23 + Periodic Learn Required : No
24 + Transparent Learn : No
25 + No space to cache offload : No
26 + Pack is about to fail & should be replaced : No
27 + Cache Offload premium feature required : No
28 + Module microcode update required : No
29 +
30 +BBU GasGauge Status: 0x0100
31 + Relative State of Charge: 71 %
32 + Charger System State: 1
33 + Charger System Ctrl: 0
34 + Charging current: 0 mA
35 + Absolute state of charge: 63 %
36 + Max Error: 0 %
37 + Battery backup charge time : 48 hours +
38 +
39 +BBU Capacity Info for Adapter: 0
40 +
41 + Relative State of Charge: 71 %
42 + Absolute State of charge: 63 %
43 + Remaining Capacity: 969 mAh
44 + Full Charge Capacity: 1365 mAh
45 + Run time to empty: Battery is not being charged.
46 + Average time to empty: 1 Hour, 56 Min.
47 + Estimated Time to full recharge: Battery is not being charged.
48 + Cycle Count: 4
49 +
50 +BBU Design Info for Adapter: 0
51 +
52 + Date of Manufacture: 03/18, 2011
53 + Design Capacity: 1530 mAh
54 + Design Voltage: 4100 mV
55 + Specification Info: 0
56 + Serial Number: 5164
57 + Pack Stat Configuration: 0x0000
58 + Manufacture Name: LS36681
59 + Firmware Version :
60 + Device Name: bq27541
61 + Device Chemistry: LPMR
62 + Battery FRU: N/A
63 + Transparent Learn = 0
64 + App Data = 0
65 +
66 +BBU Properties for Adapter: 0
67 +
68 + Auto Learn Period: 28 Days
69 + Next Learn time: Thu Dec 21 18:32:56 2023
70 + Learn Delay Interval:0 Hours
71 + Auto-Learn Mode: Enabled
72 + BBU Mode = 4
73 +
74 +Exit Code: 0x00
src/go/collectors/go.d.plugin/modules/megacli/testdata/mega-phys-drives-info.txt new
+433
@@ -0,0 +1,433 @@
1 +Adapter #0
2 +
3 +Number of Virtual Disks: 1
4 +Virtual Drive: 0 (Target Id: 0)
5 +Name :Virtual Disk 0
6 +RAID Level : Primary-1, Secondary-0, RAID Level Qualifier-0
7 +Size : 3.491 TB
8 +Sector Size : 512
9 +Is VD emulated : No
10 +Mirror Data : 3.491 TB
11 +State : Optimal
12 +Strip Size : 64 KB
13 +Number Of Drives : 8
14 +Span Depth : 1
15 +Default Cache Policy: WriteBack, ReadAhead, Direct, No Write Cache if Bad BBU
16 +Current Cache Policy: WriteBack, ReadAhead, Direct, No Write Cache if Bad BBU
17 +Default Access Policy: Read/Write
18 +Current Access Policy: Read/Write
19 +Disk Cache Policy : Disk's Default
20 +Encryption Type : None
21 +Default Power Savings Policy: Controller Defined
22 +Current Power Savings Policy: None
23 +Can spin up in 1 minute: No
24 +LD has drives that support T10 power conditions: No
25 +LD's IO profile supports MAX power savings with cached writes: No
26 +Bad Blocks Exist: No
27 +PI type: No PI
28 +
29 +Is VD Cached: No
30 +Number of Spans: 1
31 +Span: 0 - Number of PDs: 8
32 +
33 +PD: 0 Information
34 +Enclosure Device ID: 32
35 +Slot Number: 0
36 +Drive's position: DiskGroup: 0, Span: 0, Arm: 0
37 +Enclosure position: 1
38 +Device Id: 0
39 +WWN: 5002538c4002e713
40 +Sequence Number: 2
41 +Media Error Count: 0
42 +Other Error Count: 0
43 +Predictive Failure Count: 0
44 +Last Predictive Failure Event Seq Number: 0
45 +PD Type: SATA
46 +
47 +Raw Size: 894.252 GB [0x6fc81ab0 Sectors]
48 +Non Coerced Size: 893.752 GB [0x6fb81ab0 Sectors]
49 +Coerced Size: 893.75 GB [0x6fb80000 Sectors]
50 +Sector Size: 512
51 +Logical Sector Size: 512
52 +Physical Sector Size: 512
53 +Firmware state: Online, Spun Up
54 +Device Firmware Level: 003Q
55 +Shield Counter: 0
56 +Successful diagnostics completion on : N/A
57 +SAS Address(0): 0x4433221104000000
58 +Connected Port Number: 4(path0)
59 +Inquiry Data: S1YHNXAG804005 SAMSUNG MZ7LM960HCHP-00003 GXT3003Q
60 +FDE Capable: Not Capable
61 +FDE Enable: Disable
62 +Secured: Unsecured
63 +Locked: Unlocked
64 +Needs EKM Attention: No
65 +Foreign State: None
66 +Device Speed: 6.0Gb/s
67 +Link Speed: 6.0Gb/s
68 +Media Type: Solid State Device
69 +Drive: Not Certified
70 +Drive Temperature :33C (91.40 F)
71 +PI Eligibility: No
72 +Drive is formatted for PI information: No
73 +PI: No PI
74 +Drive's NCQ setting : N/A
75 +Port-0 :
76 +Port status: Active
77 +Port's Linkspeed: 6.0Gb/s
78 +Drive has flagged a S.M.A.R.T alert : No
79 +
80 +
81 +
82 +
83 +PD: 1 Information
84 +Enclosure Device ID: 32
85 +Slot Number: 2
86 +Drive's position: DiskGroup: 0, Span: 0, Arm: 1
87 +Enclosure position: 1
88 +Device Id: 2
89 +WWN: 5002538c00019b96
90 +Sequence Number: 2
91 +Media Error Count: 0
92 +Other Error Count: 0
93 +Predictive Failure Count: 0
94 +Last Predictive Failure Event Seq Number: 0
95 +PD Type: SATA
96 +
97 +Raw Size: 894.252 GB [0x6fc81ab0 Sectors]
98 +Non Coerced Size: 893.752 GB [0x6fb81ab0 Sectors]
99 +Coerced Size: 893.75 GB [0x6fb80000 Sectors]
100 +Sector Size: 512
101 +Logical Sector Size: 512
102 +Physical Sector Size: 512
103 +Firmware state: Online, Spun Up
104 +Device Firmware Level: 003Q
105 +Shield Counter: 0
106 +Successful diagnostics completion on : N/A
107 +SAS Address(0): 0x4433221106000000
108 +Connected Port Number: 6(path0)
109 +Inquiry Data: S1YHNYAG600061 SAMSUNG MZ7LM960HCHP-00003 GXT3003Q
110 +FDE Capable: Not Capable
111 +FDE Enable: Disable
112 +Secured: Unsecured
113 +Locked: Unlocked
114 +Needs EKM Attention: No
115 +Foreign State: None
116 +Device Speed: 6.0Gb/s
117 +Link Speed: 6.0Gb/s
118 +Media Type: Solid State Device
119 +Drive: Not Certified
120 +Drive Temperature :33C (91.40 F)
121 +PI Eligibility: No
122 +Drive is formatted for PI information: No
123 +PI: No PI
124 +Drive's NCQ setting : N/A
125 +Port-0 :
126 +Port status: Active
127 +Port's Linkspeed: 6.0Gb/s
128 +Drive has flagged a S.M.A.R.T alert : No
129 +
130 +
131 +
132 +
133 +PD: 2 Information
134 +Enclosure Device ID: 32
135 +Slot Number: 1
136 +Drive's position: DiskGroup: 0, Span: 0, Arm: 2
137 +Enclosure position: 1
138 +Device Id: 1
139 +WWN: 5002538c4002e707
140 +Sequence Number: 2
141 +Media Error Count: 0
142 +Other Error Count: 0
143 +Predictive Failure Count: 0
144 +Last Predictive Failure Event Seq Number: 0
145 +PD Type: SATA
146 +
147 +Raw Size: 894.252 GB [0x6fc81ab0 Sectors]
148 +Non Coerced Size: 893.752 GB [0x6fb81ab0 Sectors]
149 +Coerced Size: 893.75 GB [0x6fb80000 Sectors]
150 +Sector Size: 512
151 +Logical Sector Size: 512
152 +Physical Sector Size: 512
153 +Firmware state: Online, Spun Up
154 +Device Firmware Level: 003Q
155 +Shield Counter: 0
156 +Successful diagnostics completion on : N/A
157 +SAS Address(0): 0x4433221100000000
158 +Connected Port Number: 0(path0)
159 +Inquiry Data: S1YHNXAG803993 SAMSUNG MZ7LM960HCHP-00003 GXT3003Q
160 +FDE Capable: Not Capable
161 +FDE Enable: Disable
162 +Secured: Unsecured
163 +Locked: Unlocked
164 +Needs EKM Attention: No
165 +Foreign State: None
166 +Device Speed: 6.0Gb/s
167 +Link Speed: 6.0Gb/s
168 +Media Type: Solid State Device
169 +Drive: Not Certified
170 +Drive Temperature :34C (93.20 F)
171 +PI Eligibility: No
172 +Drive is formatted for PI information: No
173 +PI: No PI
174 +Drive's NCQ setting : N/A
175 +Port-0 :
176 +Port status: Active
177 +Port's Linkspeed: 6.0Gb/s
178 +Drive has flagged a S.M.A.R.T alert : No
179 +
180 +
181 +
182 +
183 +PD: 3 Information
184 +Enclosure Device ID: 32
185 +Slot Number: 3
186 +Drive's position: DiskGroup: 0, Span: 0, Arm: 3
187 +Enclosure position: 1
188 +Device Id: 3
189 +WWN: 5002538c4002e70f
190 +Sequence Number: 2
191 +Media Error Count: 0
192 +Other Error Count: 0
193 +Predictive Failure Count: 0
194 +Last Predictive Failure Event Seq Number: 0
195 +PD Type: SATA
196 +
197 +Raw Size: 894.252 GB [0x6fc81ab0 Sectors]
198 +Non Coerced Size: 893.752 GB [0x6fb81ab0 Sectors]
199 +Coerced Size: 893.75 GB [0x6fb80000 Sectors]
200 +Sector Size: 512
201 +Logical Sector Size: 512
202 +Physical Sector Size: 512
203 +Firmware state: Online, Spun Up
204 +Device Firmware Level: 003Q
205 +Shield Counter: 0
206 +Successful diagnostics completion on : N/A
207 +SAS Address(0): 0x4433221102000000
208 +Connected Port Number: 2(path0)
209 +Inquiry Data: S1YHNXAG804001 SAMSUNG MZ7LM960HCHP-00003 GXT3003Q
210 +FDE Capable: Not Capable
211 +FDE Enable: Disable
212 +Secured: Unsecured
213 +Locked: Unlocked
214 +Needs EKM Attention: No
215 +Foreign State: None
216 +Device Speed: 6.0Gb/s
217 +Link Speed: 6.0Gb/s
218 +Media Type: Solid State Device
219 +Drive: Not Certified
220 +Drive Temperature :34C (93.20 F)
221 +PI Eligibility: No
222 +Drive is formatted for PI information: No
223 +PI: No PI
224 +Drive's NCQ setting : N/A
225 +Port-0 :
226 +Port status: Active
227 +Port's Linkspeed: 6.0Gb/s
228 +Drive has flagged a S.M.A.R.T alert : No
229 +
230 +
231 +
232 +
233 +PD: 4 Information
234 +Enclosure Device ID: 32
235 +Slot Number: 5
236 +Drive's position: DiskGroup: 0, Span: 0, Arm: 4
237 +Enclosure position: 1
238 +Device Id: 5
239 +WWN: 5002538c4002e712
240 +Sequence Number: 2
241 +Media Error Count: 0
242 +Other Error Count: 0
243 +Predictive Failure Count: 0
244 +Last Predictive Failure Event Seq Number: 0
245 +PD Type: SATA
246 +
247 +Raw Size: 894.252 GB [0x6fc81ab0 Sectors]
248 +Non Coerced Size: 893.752 GB [0x6fb81ab0 Sectors]
249 +Coerced Size: 893.75 GB [0x6fb80000 Sectors]
250 +Sector Size: 512
251 +Logical Sector Size: 512
252 +Physical Sector Size: 512
253 +Firmware state: Online, Spun Up
254 +Device Firmware Level: 003Q
255 +Shield Counter: 0
256 +Successful diagnostics completion on : N/A
257 +SAS Address(0): 0x4433221101000000
258 +Connected Port Number: 1(path0)
259 +Inquiry Data: S1YHNXAG804004 SAMSUNG MZ7LM960HCHP-00003 GXT3003Q
260 +FDE Capable: Not Capable
261 +FDE Enable: Disable
262 +Secured: Unsecured
263 +Locked: Unlocked
264 +Needs EKM Attention: No
265 +Foreign State: None
266 +Device Speed: 6.0Gb/s
267 +Link Speed: 6.0Gb/s
268 +Media Type: Solid State Device
269 +Drive: Not Certified
270 +Drive Temperature :34C (93.20 F)
271 +PI Eligibility: No
272 +Drive is formatted for PI information: No
273 +PI: No PI
274 +Drive's NCQ setting : N/A
275 +Port-0 :
276 +Port status: Active
277 +Port's Linkspeed: 6.0Gb/s
278 +Drive has flagged a S.M.A.R.T alert : No
279 +
280 +
281 +
282 +
283 +PD: 5 Information
284 +Enclosure Device ID: 32
285 +Slot Number: 4
286 +Drive's position: DiskGroup: 0, Span: 0, Arm: 5
287 +Enclosure position: 1
288 +Device Id: 4
289 +WWN: 5002538c4002e6e9
290 +Sequence Number: 2
291 +Media Error Count: 0
292 +Other Error Count: 0
293 +Predictive Failure Count: 0
294 +Last Predictive Failure Event Seq Number: 0
295 +PD Type: SATA
296 +
297 +Raw Size: 894.252 GB [0x6fc81ab0 Sectors]
298 +Non Coerced Size: 893.752 GB [0x6fb81ab0 Sectors]
299 +Coerced Size: 893.75 GB [0x6fb80000 Sectors]
300 +Sector Size: 512
301 +Logical Sector Size: 512
302 +Physical Sector Size: 512
303 +Firmware state: Online, Spun Up
304 +Device Firmware Level: 003Q
305 +Shield Counter: 0
306 +Successful diagnostics completion on : N/A
307 +SAS Address(0): 0x4433221105000000
308 +Connected Port Number: 5(path0)
309 +Inquiry Data: S1YHNXAG803963 SAMSUNG MZ7LM960HCHP-00003 GXT3003Q
310 +FDE Capable: Not Capable
311 +FDE Enable: Disable
312 +Secured: Unsecured
313 +Locked: Unlocked
314 +Needs EKM Attention: No
315 +Foreign State: None
316 +Device Speed: 6.0Gb/s
317 +Link Speed: 6.0Gb/s
318 +Media Type: Solid State Device
319 +Drive: Not Certified
320 +Drive Temperature :33C (91.40 F)
321 +PI Eligibility: No
322 +Drive is formatted for PI information: No
323 +PI: No PI
324 +Drive's NCQ setting : N/A
325 +Port-0 :
326 +Port status: Active
327 +Port's Linkspeed: 6.0Gb/s
328 +Drive has flagged a S.M.A.R.T alert : No
329 +
330 +
331 +
332 +
333 +PD: 6 Information
334 +Enclosure Device ID: 32
335 +Slot Number: 6
336 +Drive's position: DiskGroup: 0, Span: 0, Arm: 6
337 +Enclosure position: 1
338 +Device Id: 6
339 +WWN: 5002538c4002da83
340 +Sequence Number: 2
341 +Media Error Count: 0
342 +Other Error Count: 0
343 +Predictive Failure Count: 0
344 +Last Predictive Failure Event Seq Number: 0
345 +PD Type: SATA
346 +
347 +Raw Size: 894.252 GB [0x6fc81ab0 Sectors]
348 +Non Coerced Size: 893.752 GB [0x6fb81ab0 Sectors]
349 +Coerced Size: 893.75 GB [0x6fb80000 Sectors]
350 +Sector Size: 512
351 +Logical Sector Size: 512
352 +Physical Sector Size: 512
353 +Firmware state: Online, Spun Up
354 +Device Firmware Level: 003Q
355 +Shield Counter: 0
356 +Successful diagnostics completion on : N/A
357 +SAS Address(0): 0x4433221107000000
358 +Connected Port Number: 7(path0)
359 +Inquiry Data: S1YHNXAG801029 SAMSUNG MZ7LM960HCHP-00003 GXT3003Q
360 +FDE Capable: Not Capable
361 +FDE Enable: Disable
362 +Secured: Unsecured
363 +Locked: Unlocked
364 +Needs EKM Attention: No
365 +Foreign State: None
366 +Device Speed: 6.0Gb/s
367 +Link Speed: 6.0Gb/s
368 +Media Type: Solid State Device
369 +Drive: Not Certified
370 +Drive Temperature :33C (91.40 F)
371 +PI Eligibility: No
372 +Drive is formatted for PI information: No
373 +PI: No PI
374 +Drive's NCQ setting : N/A
375 +Port-0 :
376 +Port status: Active
377 +Port's Linkspeed: 6.0Gb/s
378 +Drive has flagged a S.M.A.R.T alert : No
379 +
380 +
381 +
382 +
383 +PD: 7 Information
384 +Enclosure Device ID: 32
385 +Slot Number: 7
386 +Drive's position: DiskGroup: 0, Span: 0, Arm: 7
387 +Enclosure position: 1
388 +Device Id: 7
389 +WWN: 5002538c4002dade
390 +Sequence Number: 2
391 +Media Error Count: 0
392 +Other Error Count: 0
393 +Predictive Failure Count: 0
394 +Last Predictive Failure Event Seq Number: 0
395 +PD Type: SATA
396 +
397 +Raw Size: 894.252 GB [0x6fc81ab0 Sectors]
398 +Non Coerced Size: 893.752 GB [0x6fb81ab0 Sectors]
399 +Coerced Size: 893.75 GB [0x6fb80000 Sectors]
400 +Sector Size: 512
401 +Logical Sector Size: 512
402 +Physical Sector Size: 512
403 +Firmware state: Online, Spun Up
404 +Device Firmware Level: 003Q
405 +Shield Counter: 0
406 +Successful diagnostics completion on : N/A
407 +SAS Address(0): 0x4433221103000000
408 +Connected Port Number: 3(path0)
409 +Inquiry Data: S1YHNXAG801120 SAMSUNG MZ7LM960HCHP-00003 GXT3003Q
410 +FDE Capable: Not Capable
411 +FDE Enable: Disable
412 +Secured: Unsecured
413 +Locked: Unlocked
414 +Needs EKM Attention: No
415 +Foreign State: None
416 +Device Speed: 6.0Gb/s
417 +Link Speed: 6.0Gb/s
418 +Media Type: Solid State Device
419 +Drive: Not Certified
420 +Drive Temperature :34C (93.20 F)
421 +PI Eligibility: No
422 +Drive is formatted for PI information: No
423 +PI: No PI
424 +Drive's NCQ setting : N/A
425 +Port-0 :
426 +Port status: Active
427 +Port's Linkspeed: 6.0Gb/s
428 +Drive has flagged a S.M.A.R.T alert : No
429 +
430 +
431 +
432 +
433 +Exit Code: 0x00
\ No newline at end of file
src/health/health.d/megacli.conf
+82 -5
@@ -1,5 +1,86 @@
1 +# you can disable an alarm notification by setting the 'to' line to: silent
2
2 -## Adapters (controllers)
3 +# go.d/megacli
4 +
5 +# Adapters (controllers)
6 +
7 + template: megacli_adapter_health_state
8 + on: megacli.adapter_health_state
9 + class: Errors
10 + type: System
11 +component: RAID
12 + lookup: average -1m unaligned percentage of optimal
13 + units: %
14 + every: 10s
15 + crit: $this < 100
16 + delay: down 5m multiplier 2 max 10m
17 + summary: MegaCLI adapter ${label:adapter_number} health
18 + info: MegaCLI adapter ${label:adapter_number} is in the degraded state
19 + to: sysadmin
20 +
21 + template: megacli_phys_drive_media_errors
22 + on: megacli.phys_drive_media_errors_rate
23 + class: Errors
24 + type: System
25 +component: RAID
26 + lookup: sum -10s
27 + units: media errors
28 + every: 10s
29 + warn: $this > 0
30 + delay: up 1m down 5m multiplier 2 max 10m
31 + summary: MegaCLI PD adapter ${label:adapter_number} slot ${label:slot_number} media errors
32 + info: MegaCLI physical drive adapter ${label:adapter_number} slot ${label:slot_number} media errors
33 + to: sysadmin
34 +
35 +# Physical Drives
36 +
37 + template: megacli_phys_drive_predictive_failures
38 + on: megacli.phys_drive_predictive_failures
39 + class: Errors
40 + type: System
41 +component: RAID
42 + lookup: sum -10s
43 + units: media errors
44 + every: 10s
45 + warn: $this > 0
46 + delay: up 1m down 5m multiplier 2 max 10m
47 + summary: MegaCLI PD adapter ${label:adapter_number} slot ${label:slot_number} predictive failures
48 + info: MegaCLI physical drive (adapter ${label:adapter_number} slot ${label:slot_number}) predictive failures
49 + to: sysadmin
50 +
51 +# Backup Battery Unit
52 +
53 + template: megacli_bbu_charge
54 + on: megacli.bbu_charge
55 + class: Workload
56 + type: System
57 +component: RAID
58 + lookup: average -10s
59 + units: percent
60 + every: 10s
61 + warn: $this <= (($status >= $WARNING) ? (85) : (80))
62 + crit: $this <= (($status == $CRITICAL) ? (50) : (40))
63 + summary: MegaCLI BBU charge
64 + info: MegaCLI Backup Battery Unit (adapter ${label:adapter_number}) average charge over the last minute
65 + to: sysadmin
66 +
67 + template: megacli_bbu_recharge_cycles
68 + on: megacli.bbu_recharge_cycles
69 + class: Workload
70 + type: System
71 +component: RAID
72 + lookup: average -10s
73 + units: cycles
74 + every: 10s
75 + warn: $this >= 100
76 + crit: $this >= 500
77 + summary: MegaCLI BBU recharge cycles
78 + info: MegaCLI Backup Battery Unit (adapter ${label:adapter_number}) recharge cycles
79 + to: sysadmin
80 +
81 +# --------------------------------------------------------------------------------------------------------------------
82 +
83 +# python.d/megacli
84
85 template: megacli_adapter_state
86 on: megacli.adapter_degraded
@@ -15,8 +96,6 @@ component: RAID
96 info: Adapter is in the degraded state (0: false, 1: true)
97 to: sysadmin
98
18 -## Physical Disks
19 -
99 template: megacli_pd_predictive_failures
100 on: megacli.pd_predictive_failure
101 class: Errors
@@ -45,8 +124,6 @@ component: RAID
124 info: Number of physical drive media errors
125 to: sysadmin
126
48 -## Battery Backup Units (BBU)
49 -
127 template: megacli_bbu_relative_charge
128 on: megacli.bbu_relative_charge
129 class: Workload