@cryptotaxi247 / netdata-1 / commits / 82383e6f6

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