Cleanup config.nodes_of
[check_mk.git] / checks / brocade_optical
blobb73dc071a099b66a4c2f47b6c15df7e75688bd4f
1 #!/usr/bin/python
2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
9 # | |
10 # | Copyright Mathias Kettner 2016 mk@mathias-kettner.de |
11 # +------------------------------------------------------------------+
13 # This file is part of Check_MK.
14 # The official homepage is at http://mathias-kettner.de/check_mk.
16 # check_mk is free software; you can redistribute it and/or modify it
17 # under the terms of the GNU General Public License as published by
18 # the Free Software Foundation in version 2. check_mk is distributed
19 # in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
20 # out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
21 # PARTICULAR PURPOSE. See the GNU General Public License for more de-
22 # tails. You should have received a copy of the GNU General Public
23 # License along with GNU Make; see the file COPYING. If not, write
24 # to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 # Boston, MA 02110-1301 USA.
27 # .1.3.6.1.4.1.1991.1.1.3.3.6.1.1.1 41.4960 C: Normal
28 # .1.3.6.1.4.1.1991.1.1.3.3.6.1.1.2 50.9531 C: Normal
29 # .1.3.6.1.4.1.1991.1.1.3.3.6.1.1.65 49.8007 C: Normal
31 # .1.3.6.1.4.1.1991.1.1.3.3.6.1.2.1 007.9643 dBm: Normal
32 # .1.3.6.1.4.1.1991.1.1.3.3.6.1.2.2 007.5898 dBm: Normal
33 # .1.3.6.1.4.1.1991.1.1.3.3.6.1.2.65 006.9644 dBm: Normal
35 # .1.3.6.1.4.1.1991.1.1.3.3.6.1.3.1 000.6744 dBm: Normal
36 # .1.3.6.1.4.1.1991.1.1.3.3.6.1.3.2 -023.0102 dBm: Low-Alarm
37 # .1.3.6.1.4.1.1991.1.1.3.3.6.1.3.65 -015.6863 dBm: Low-Alarm
40 # .1.3.6.1.4.1.1991.1.1.3.3.9.1.1.1 100GBASE-LR4 CFP2
41 # .1.3.6.1.4.1.1991.1.1.3.3.9.1.1.2 100GBASE-LR4 CFP2
42 # .1.3.6.1.4.1.1991.1.1.3.3.9.1.1.65 100GBASE-LR4 CFP2
44 # .1.3.6.1.4.1.1991.1.1.3.3.9.1.4.1 12-1234567-01
45 # .1.3.6.1.4.1.1991.1.1.3.3.9.1.4.2 12-1234567-01
46 # .1.3.6.1.4.1.1991.1.1.3.3.9.1.4.65 12-1234567-01
48 # .1.3.6.1.4.1.1991.1.1.3.3.9.1.5.1 XXX00000X00X00X
49 # .1.3.6.1.4.1.1991.1.1.3.3.9.1.5.2 XXX000000000XX0
50 # .1.3.6.1.4.1.1991.1.1.3.3.9.1.5.65 XXX0000000000X
53 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.2.1.1 41.5000 C: Normal
54 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.2.1.2 41.4960 C: Normal
55 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.2.1.3 41.4921 C: Normal
56 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.2.1.4 41.5039 C: Normal
57 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.2.2.1 50.9687 C: Normal
58 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.2.2.2 50.9843 C: Normal
59 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.2.2.3 50.9570 C: Normal
60 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.2.2.4 50.9570 C: Normal
61 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.2.65.1 49.7539 C: Normal
62 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.2.65.2 49.7734 C: Normal
63 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.2.65.3 49.7578 C: Normal
64 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.2.65.4 49.7851 C: Normal
66 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.3.1.1 001.9072 dBm: Normal
67 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.3.1.2 002.5098 dBm: Normal
68 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.3.1.3 001.3392 dBm: Normal
69 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.3.1.4 001.9473 dBm: Normal
70 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.3.2.1 001.5615 dBm: Normal
71 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.3.2.2 001.4924 dBm: Normal
72 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.3.2.3 001.6840 dBm: Normal
73 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.3.2.4 001.5421 dBm: Normal
74 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.3.65.1 000.0543 dBm: Normal
75 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.3.65.2 000.6069 dBm: Normal
76 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.3.65.3 001.6307 dBm: Normal
77 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.3.65.4 001.3152 dBm: Normal
79 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.4.1.1 -004.9935 dBm: Normal
80 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.4.1.2 -005.4030 dBm: Normal
81 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.4.1.3 -005.3017 dBm: Normal
82 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.4.1.4 -005.6479 dBm: Normal
83 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.4.2.1 -026.0205 dBm: Low-Alarm
84 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.4.2.2 -214.3647 dBm: Low-Alarm
85 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.4.2.3 -214.3647 dBm: Low-Alarm
86 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.4.2.4 -024.9485 dBm: Low-Alarm
87 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.4.65.1 -021.4266 dBm: Low-Alarm
88 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.4.65.2 -020.3621 dBm: Low-Alarm
89 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.4.65.3 -022.4412 dBm: Low-Alarm
90 # .1.3.6.1.4.1.1991.1.1.3.3.10.1.4.65.4 -021.8045 dBm: Low-Alarm
92 OPER_STATUS_MAP = {
93 '1': 'up',
94 '2': 'down',
95 '3': 'testing',
96 '4': 'unknown',
97 '5': 'dormant',
98 '6': 'not present',
99 '7': 'lower layer down',
100 '8': 'degraded',
101 '9': 'admin down',
105 def parse_brocade_optical(info):
106 def parse_value(value_string):
107 if value_string == 'N/A' or value_string.lower() == "not supported":
108 return None, None
109 try:
110 val, _unit, status = value_string.split()
111 return float(val), status
112 except ValueError:
113 return None, None
115 if_info, if_data, if_ids, lanes = info
116 parsed = {}
118 for temp, tx_light, rx_light, if_id in if_data:
119 parsed.setdefault(
120 if_id, {
121 'temp': parse_value(temp),
122 'tx_light': parse_value(tx_light),
123 'rx_light': parse_value(rx_light),
126 for if_id, if_descr, if_type, if_operstatus in if_info:
127 if if_id in parsed:
128 parsed[if_id].update({
129 'port_type': if_type,
130 'description': if_descr,
131 'operational_status': if_operstatus
134 # add informational values
135 for media_type, part, serial, if_id in if_ids:
136 if if_id in parsed:
137 parsed[if_id].update({'type': media_type, 'part': part, 'serial': serial})
139 # add per-lane data
140 for temp, tx_light, rx_light, lane in lanes:
141 if_id, lane = lane.split('.')
142 if if_id in parsed:
143 parsed[if_id].setdefault('lanes', {})\
144 .setdefault(int(lane), {
145 'temp': parse_value(temp),
146 'tx_light': parse_value(tx_light),
147 'rx_light': parse_value(rx_light),
149 return parsed
152 def inventory_brocade_optical(parsed):
153 settings = host_extra_conf_merged(host_name(), inventory_if_rules)
154 porttypes = set(settings.get('porttypes', if_inventory_porttypes))
155 portstates = settings.get('portstates', if_inventory_portstates)
156 match_desc = settings.get('match_desc')
158 if parsed:
159 pad_width = max([int(len(key)) for key in parsed.keys()])
160 else:
161 pad_width = 0
163 def port_match(name, what):
164 if what is None:
165 return True
166 for r in what:
167 if regex(r).match(name):
168 return True
169 return False
171 for key, entry in parsed.iteritems():
172 if (entry['port_type'] in porttypes and entry['operational_status'] in portstates and
173 port_match(entry['description'], match_desc)):
174 # if pad_width == 0 then "0" * -X == ""
175 yield "0" * (pad_width - len(key)) + key, {}
178 def check_brocade_optical(item, params, parsed):
179 def nagios_state(entry, key):
180 reading = entry[key]
181 if reading[0] is None:
182 return 3
183 elif params.get(key, False):
184 state = reading[1].lower()
185 if state == "normal":
186 return 0
187 if state.endswith("warn"):
188 return 1
189 return 2
190 return 0
192 def infotext(reading, title, unit):
193 if reading[0] < -214748.0:
194 reading_text = "off"
195 else:
196 reading_text = "%.1f %s" % (reading[0], unit)
197 return "%s %s (%s)" % (title, reading_text, reading[1])
199 item = item.lstrip('0')
201 if item in parsed:
202 iface = parsed[item]
204 add_info = []
205 if 'serial' in iface:
206 add_info.append('S/N %s' % iface['serial'])
207 if 'part' in iface:
208 add_info.append('P/N %s' % iface['part'])
210 oper_status = iface['operational_status']
211 oper_status_readable = OPER_STATUS_MAP.get(oper_status, 'unknown[%s]' % oper_status)
212 if add_info:
213 yield 0, '[%s] Operational %s' % (", ".join(add_info), oper_status_readable)
214 else:
215 yield 0, 'Operational %s' % oper_status_readable
217 if 'temp' in iface:
218 yield check_temperature(
219 iface['temp'][0],
220 params,
221 "brocade_optical_%s" % item,
222 dev_status=nagios_state(iface, 'temp'))
224 if 'tx_light' in iface and iface['tx_light'][0] is not None:
225 yield nagios_state(iface, 'tx_light'), infotext(iface['tx_light'], "TX Light", "dBm"),\
226 [("tx_light", iface['tx_light'][0])]
228 if 'rx_light' in iface and iface['rx_light'][0] is not None:
229 yield nagios_state(iface, 'rx_light'), infotext(iface['rx_light'], "RX Light", "dBm"),\
230 [("rx_light", iface['rx_light'][0])]
232 if 'lanes' in iface and params.get('lanes', False):
233 for num, lane in iface['lanes'].iteritems():
234 state, text, perf = check_temperature(
235 lane['temp'][0],
236 params,
237 "brocade_optical_lane%d_%s" % (num, item),
238 dev_status=nagios_state(lane, 'temp'))
239 perf = [("port_%s_%d" % (perf[0][0], num), perf[0][1])]
240 if state in [1, 2]:
241 yield state, "Temperature (Lane %d) %s" % (num, text), perf
242 else:
243 yield state, None, perf
245 state = nagios_state(lane, 'tx_light')
246 if state in [1, 2]:
247 yield state,\
248 infotext(iface['tx_light'], "TX Light (Lane %d)" % num, "dBm"),\
249 [("tx_light_%d" % num, lane['tx_light'][0])]
250 else:
251 yield state, None, [("tx_light_%d" % num, lane['tx_light'][0])]
253 state = nagios_state(lane, 'rx_light')
254 if state in [1, 2]:
255 yield state,\
256 infotext(iface['rx_light'], "RX Light (Lane %d)" % num, "dBm"),\
257 [("rx_light_%d" % num, lane['rx_light'][0])]
258 else:
259 yield state, None, [("rx_light_%d" % num, lane['rx_light'][0])]
262 check_info['brocade_optical'] = {
263 'parse_function': parse_brocade_optical,
264 'check_function': check_brocade_optical,
265 'inventory_function': inventory_brocade_optical,
266 'service_description': "Interface %s Optical",
267 'snmp_info': [
269 ".1.3.6.1.2.1.2.2.1",
271 1, # ifIndex
272 2, # ifDescr
273 3, # ifType
274 8, # ifOperStatus
277 ".1.3.6.1.4.1.1991.1.1.3.3.6.1",
279 1, # temperature
280 2, # TX light level
281 3, # RX light level
282 OID_END
285 ".1.3.6.1.4.1.1991.1.1.3.3.9.1",
287 1, # media type
288 4, # part number
289 5, # serial number
290 OID_END
293 ".1.3.6.1.4.1.1991.1.1.3.3.10.1",
295 2, # lane temperature
296 3, # lane TX light level
297 4, # lane RX light level
298 OID_END
301 'snmp_scan_function': lambda oid: oid(".1.3.6.1.2.1.1.2.0").startswith(".1.3.6.1.4.1.1991.1."),
302 'has_perfdata': True,
303 'group': "brocade_optical",
304 'includes': ["temperature.include", "if.include"],