megacli: add battery stats
lgz committed
Jul 6, 2018 at 13:48 UTC
82383e6f6cc697d5ffe539d803a183803ef6228a
1 file changed
+110
-20
python.d/megacli.chart.py
+110
-20
@@ -57,6 +57,31 @@ def pd_charts(pds):
57
return order, charts
58
59
60
+def battery_charts(bats):
61
+ order = [
62
+ 'relative_charge',
63
+ 'cycle_count',
64
+ ]
65
+
66
+ def dims(k, bat):
67
+ return [['battery_{0}_{1}'.format(b.id, k), 'adapter {0}'.format(b.id)] for b in bat]
68
+
69
+ charts = {
70
+ 'relative_charge': {
71
+ 'options': [
72
+ None, 'Relative State of Charge', '%', 'battery', 'megacli.relative_charge', 'line'],
73
+ 'lines': dims("relative_charge", bats)
74
+ },
75
+ 'cycle_count': {
76
+ 'options': [
77
+ None, 'Cycle Count', 'cycle count', 'battery', 'megacli.cycle_count', 'line'],
78
+ 'lines': dims("cycle_count", bats)
79
+ },
80
+ }
81
+
82
+ return order, charts
83
+
84
+
85
RE_ADAPTER = re.compile(
86
r'Adapter #([0-9]+) State\s+: ([a-zA-Z]+)'
87
)
@@ -65,6 +90,10 @@ RE_VD = re.compile(
90
r'Slot Number: ([0-9]+) Media Error Count: ([0-9]+) Predictive Failure Count: ([0-9]+)'
91
)
92
93
+RE_BATTERY = re.compile(
94
+ r'BBU Capacity Info for Adapter: ([0-9]+) Relative State of Charge: ([0-9]+) % Cycle Count: ([0-5]+)'
95
+)
96
+
97
98
def find_adapters(d):
99
keys = ("Adapter #", "State")
@@ -78,6 +107,12 @@ def find_pds(d):
107
return [PD(*v) for v in RE_VD.findall(d)]
108
109
110
+def find_batteries(d):
111
+ keys = ('BBU Capacity Info for Adapter', 'Relative State of Charge', 'Cycle Count')
112
+ d = ' '.join(v.strip() for v in d if v.startswith(keys))
113
+ return [Battery(*v) for v in RE_BATTERY.findall(d)]
114
+
115
+
116
class Adapter:
117
def __init__(self, n, state):
118
self.id = n
@@ -102,6 +137,20 @@ class PD:
137
}
138
139
140
+class Battery:
141
+ def __init__(self, adapt_id, rel_charge, cycle_count):
142
+ self.id = adapt_id
143
+ self.rel_charge = rel_charge
144
+ self.cycle_count = cycle_count
145
+
146
+ def data(self):
147
+ return {
148
+ 'battery_{0}_relative_charge'.format(self.id): self.rel_charge,
149
+ 'battery_{0}_cycle_count'.format(self.id): self.cycle_count,
150
+ }
151
+
152
+
153
+# TODO: hardcoded sudo...
154
class Megacli:
155
def __init__(self):
156
self.s = find_binary('sudo')
@@ -123,43 +172,81 @@ class Service(ExecutableService):
172
self.order = list()
173
self.definitions = dict()
174
self.megacli = Megacli()
175
+ self.do_battery = self.configuration.get('do_battery')
176
127
- def check(self):
128
- if not self.megacli:
129
- self.error('can\'t locate "sudo" or "megacli" binary')
130
- return None
131
-
177
+ def check_sudo(self):
178
err = self._get_raw_data(command=self.megacli.sudo_check, stderr=True)
133
-
179
if err:
180
self.error(''.join(err))
181
return False
182
+ return True
183
184
+ def check_disk_info(self):
185
d = self._get_raw_data(command=self.megacli.disk_info)
139
-
186
if not d:
141
- return None
187
+ return False
188
189
ads = find_adapters(d)
190
pds = find_pds(d)
191
192
if not (ads and pds):
193
self.error('failed to parse "{0}" output'.format(' '.join(self.megacli.disk_info)))
194
+ return False
195
+
196
+ o, c = adapter_charts(ads)
197
+ self.order.extend(o)
198
+ self.definitions.update(c)
199
+
200
+ o, c = pd_charts(pds)
201
+ self.order.extend(o)
202
+ self.definitions.update(c)
203
+
204
+ return True
205
+
206
+ def check_battery(self):
207
+ d = self._get_raw_data(command=self.megacli.battery_info)
208
+ if not d:
209
+ return
210
+
211
+ bats = find_batteries(d)
212
+
213
+ if not bats:
214
+ self.error('failed to parse "{0}" output'.format(' '.join(self.megacli.battery_info)))
215
+ return
216
+
217
+ o, c = battery_charts(bats)
218
+ self.order.extend(o)
219
+ self.definitions.update(c)
220
+
221
+ def check(self):
222
+ if not self.megacli:
223
+ self.error('can\'t locate "sudo" or "megacli" binary')
224
return None
225
150
- self.create_charts(ads, pds)
226
+ if not (self.check_sudo() and self.check_disk_info()):
227
+ return False
228
+
229
+ if self.do_battery:
230
+ self.check_battery()
231
+
232
return True
233
234
def get_data(self):
154
- return self.get_adapter_pd_data()
235
+ data = dict()
236
+
237
+ data.update(self.get_adapter_pd_data())
238
+
239
+ if self.do_battery:
240
+ data.update(self.get_battery_data())
241
+
242
+ return data or None
243
244
def get_adapter_pd_data(self):
245
raw = self._get_raw_data(command=self.megacli.disk_info)
246
+ data = dict()
247
248
if not raw:
160
- return None
161
-
162
- data = dict()
249
+ return data
250
251
for a in find_adapters(raw):
252
data.update(a.data())
@@ -169,11 +256,14 @@ class Service(ExecutableService):
256
257
return data
258
172
- def create_charts(self, ads, pds):
173
- o, c = adapter_charts(ads)
174
- self.order.extend(o)
175
- self.definitions.update(c)
259
+ def get_battery_data(self):
260
+ raw = self._get_raw_data(command=self.megacli.battery_info)
261
+ data = dict()
262
177
- o, c = pd_charts(pds)
178
- self.order.extend(o)
179
- self.definitions.update(c)
263
+ if not raw:
264
+ return data
265
+
266
+ for b in find_batteries(raw):
267
+ data.update(b.data())
268
+
269
+ return data