megacli: initial version added
lgz committed
Jul 4, 2018 at 23:33 UTC
17b153700acfb6df1c3b8defcc93e24e5826f793
1 file changed
+171
python.d/megacli.chart.py
new
+171
@@ -0,0 +1,171 @@
1
+# -*- coding: utf-8 -*-
2
+# Description: megacli netdata python.d module
3
+# Author: Ilya Mashchenko (l2isbad)
4
+# SPDX-License-Identifier: GPL-3.0+
5
+
6
+
7
+import re
8
+
9
+from bases.FrameworkServices.ExecutableService import ExecutableService
10
+from bases.collection import find_binary
11
+
12
+
13
+update_every = 5
14
+
15
+
16
+def adapter_charts(ads):
17
+ order = [
18
+ 'adapter_degraded',
19
+ ]
20
+
21
+ def dims(ad):
22
+ return [['adapter_{0}_degraded'.format(a.id), 'adapter {0}'.format(a.id)] for a in ad]
23
+
24
+ charts = {
25
+ 'adapter_degraded': {
26
+ 'options': [
27
+ None, 'Adapter State', 'is degraded', 'adapter', 'megacli.adapter_degraded', 'line'],
28
+ 'lines': dims(ads)
29
+ },
30
+ }
31
+
32
+ return order, charts
33
+
34
+
35
+def pd_charts(pds):
36
+ order = [
37
+ 'pd_media_error',
38
+ 'pd_predictive_failure',
39
+ ]
40
+
41
+ def dims(k, pd):
42
+ return [['slot_{0}_{1}'.format(p.id, k), 'slot {0}'.format(p.id)] for p in pd]
43
+
44
+ charts = {
45
+ 'pd_media_error': {
46
+ 'options': [
47
+ None, 'Physical Drives Media Errors', 'errors/s', 'pd', 'megacli.pd_media_error', 'line'
48
+ ],
49
+ 'lines': dims("media_error", pds)},
50
+ 'pd_predictive_failure': {
51
+ 'options': [
52
+ None, 'Physical Drives Predictive Failures', 'failures/s', 'pd', 'megacli.pd_predictive_failure', 'line'
53
+ ],
54
+ 'lines': dims("predictive_failure", pds)}
55
+ }
56
+
57
+ return order, charts
58
+
59
+
60
+RE_ADAPTER = re.compile(
61
+ r'Adapter #([0-9]+) State\s+: ([a-zA-Z]+)'
62
+)
63
+
64
+RE_VD = re.compile(
65
+ r'Slot Number: ([0-9]+) Media Error Count: ([0-9]+) Predictive Failure Count: ([0-9]+)'
66
+)
67
+
68
+
69
+def find_adapters(d):
70
+ keys = ("Adapter #", "State")
71
+ d = ' '.join(v.strip() for v in d if v.startswith(keys))
72
+ return [Adapter(*v) for v in RE_ADAPTER.findall(d)]
73
+
74
+
75
+def find_pds(d):
76
+ keys = ("Slot Number", "Media Error Count", "Predictive Failure Count")
77
+ d = ' '.join(v.strip() for v in d if v.startswith(keys))
78
+ return [PD(*v) for v in RE_VD.findall(d)]
79
+
80
+
81
+class Adapter:
82
+ def __init__(self, n, state):
83
+ self.id = n
84
+ self.state = int(state == 'Degraded')
85
+
86
+ def data(self):
87
+ return {
88
+ 'adapter_{0}_degraded'.format(self.id): self.state,
89
+ }
90
+
91
+
92
+class PD:
93
+ def __init__(self, n, media_err, predict_fail):
94
+ self.id = n
95
+ self.media_err = media_err
96
+ self.predict_fail = predict_fail
97
+
98
+ def data(self):
99
+ return {
100
+ 'slot_{0}_media_error'.format(self.id): self.media_err,
101
+ 'slot_{0}_predictive_failure'.format(self.id): self.predict_fail,
102
+ }
103
+
104
+
105
+class Command:
106
+ def __init__(self):
107
+ self.command = find_binary('megacli')
108
+ self.disk_info = [self.command, '-LDPDInfo', '-aAll']
109
+ self.battery_info = [self.command, '-AdpBbuCmd', '-a0']
110
+
111
+ def __bool__(self):
112
+ return bool(self.command)
113
+
114
+ def __nonzero__(self):
115
+ return self.__bool__()
116
+
117
+
118
+class Service(ExecutableService):
119
+ def __init__(self, configuration=None, name=None):
120
+ ExecutableService.__init__(self, configuration=configuration, name=name)
121
+ self.order = list()
122
+ self.definitions = dict()
123
+ self.command = Command()
124
+
125
+ def check(self):
126
+ if not self.command:
127
+ self.error("can't locate \"megacli\" binary or binary is not executable by netdata")
128
+ return None
129
+
130
+ d = self._get_raw_data(command=self.command.disk_info)
131
+
132
+ if not d:
133
+ return None
134
+
135
+ ads = find_adapters(d)
136
+ pds = find_pds(d)
137
+
138
+ if not (ads and pds):
139
+ self.error('failed to parse "{0}" output'.format(' '.join(self.command.disk_info)))
140
+ return None
141
+
142
+ self.create_charts(ads, pds)
143
+ return True
144
+
145
+ def get_data(self):
146
+ return self.get_adapter_pd_data()
147
+
148
+ def get_adapter_pd_data(self):
149
+ raw = self._get_raw_data(command=self.command.disk_info)
150
+
151
+ if not raw:
152
+ return None
153
+
154
+ data = dict()
155
+
156
+ for a in find_adapters(raw):
157
+ data.update(a.data())
158
+
159
+ for p in find_pds(raw):
160
+ data.update(p.data())
161
+
162
+ return data
163
+
164
+ def create_charts(self, ads, pds):
165
+ o, c = adapter_charts(ads)
166
+ self.order.extend(o)
167
+ self.definitions.update(c)
168
+
169
+ o, c = pd_charts(pds)
170
+ self.order.extend(o)
171
+ self.definitions.update(c)