@cryptotaxi247 / netdata-1 / commits / 17b153700

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)