2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
10 # | Copyright Mathias Kettner 2014 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 # Example output from agent
30 # 3 instances: Ethernetadapter_der_AMD-PCNET-Familie__2_-_Paketplaner-Miniport Ethernetadapter_der_AMD-PCNET-Familie_-_Paketplaner-Miniport MS_TCP_Loopback_interface
31 # -122 43364 1085829 41602 bulk_count
32 # -110 293 4174 932 counter
33 # -244 138 3560 466 counter
34 # -58 155 614 466 counter
35 # 10 100000000 100000000 10000000 rawcount
36 # -246 21219 780491 20801 counter
37 # 14 0 383 466 counter
38 # 16 138 3176 0 counter
42 # -4 22145 305338 20801 counter
43 # 26 0 428 466 counter
44 # 28 155 186 0 counter
48 # <<<winperf_if:sep(44)>>>
49 # Node,MACAddress,Name,NetConnectionID,NetConnectionStatus
50 # WINDOWSXP,08:00:27:8D:47:A4,Ethernetadapter der AMD-PCNET-Familie,LAN-Verbindung,2
51 # WINDOWSXP,,Asynchroner RAS-Adapter,,
52 # WINDOWSXP,08:00:27:8D:47:A4,Paketplaner-Miniport,,
53 # WINDOWSXP,,WAN-Miniport (L2TP),,
54 # WINDOWSXP,50:50:54:50:30:30,WAN-Miniport (PPTP),,
55 # WINDOWSXP,33:50:6F:45:30:30,WAN-Miniport (PPPOE),,
56 # WINDOWSXP,,Parallelanschluss (direkt),,
57 # WINDOWSXP,,WAN-Miniport (IP),,
58 # WINDOWSXP,00:E5:20:52:41:53,Paketplaner-Miniport,,
59 # WINDOWSXP,08:00:27:35:20:4D,Ethernetadapter der AMD-PCNET-Familie,LAN-Verbindung 2,2
60 # WINDOWSXP,08:00:27:35:20:4D,Paketplaner-Miniport,,
62 # Example output for the optional dhcp section. If this plugin is active, any interface for which
63 # dhcp is enabled will warn
65 # Node,Description,DHCPEnabled
66 # WINDOWS,Intel(R) PRO/1000 MT-Desktopadapter,TRUE
67 # WINDOWS,WAN Miniport (IP),FALSE
68 # WINDOWS,Microsoft-ISATAP-Adapter,FALSE
69 # WINDOWS,RAS Async Adapter,FALSE
70 # WINDOWS,Intel(R) PRO/1000 MT-Desktopadapter #2,TRUE
73 def winperf_if_canonize_nic_name(name
):
74 return name
.replace("_", " ").replace(" ", " ").rstrip()
77 def winperf_if_normalize_nic_name(name
, nic_names
):
78 # Intel[R] PRO 1000 MT-Desktopadapter__3 (perf counter)
79 # Intel(R) PRO/1000 MT-Desktopadapter 3 (wmic name)
80 # Intel(R) PRO/1000 MT-Desktopadapter #3 (wmic InterfaceDescription)
82 for from_token
, to_token
in [("/", " "), ("(", "["), (")", "]"), ("#", " ")]:
85 # we do not modify it if this character is in any of the counter names
88 mod_nic_name
= mod_nic_name
.replace(from_token
, to_token
).replace(" ", " ")
92 def parse_winperf_if(info
):
94 timestamp_info
, names_info
, data
= info
[0], info
[1], info
[2:]
95 except (IndexError, ValueError):
96 return None, [], [], [], {}
99 agent_timestamp
= float(timestamp_info
[0])
100 except (IndexError, ValueError):
101 agent_timestamp
= None
103 nic_names
= map(winperf_if_canonize_nic_name
, names_info
[2:])
104 nic_index
= winperf_if_get_nic_index_map(nic_names
)
107 lines
.next() # skip line with timestamp and counter number
108 lines
.next() # skip interface line (already evaluated)
109 nics
= dict([(n
, {}) for n
in nic_names
])
111 # Scan lines with counters
112 is_teaming_line
= False
122 if line
[0] == "[dhcp_start]":
123 line
= lines
.next() # skip start line
124 while line
[0] != "[dhcp_end]":
125 dhcp_lines
.append(line
)
127 line
= lines
.next() # skip end line
129 # Process teaming information
130 if line
[0].startswith("[teaming_start]"):
131 is_teaming_line
= True
132 teaming_headers
= lines
.next()
134 elif line
[0].startswith("[teaming_end]"):
135 is_teaming_line
= False
138 as_dict
= dict(zip(teaming_headers
, [x
.rstrip() for x
in line
]))
139 for guid
in as_dict
["GUID"].split(";"):
140 teaming_info
[guid
] = as_dict
143 counter
= saveint(line
[0])
145 for nr
, value
in enumerate(line
[1:len(nic_names
) + 1]):
146 nics
[nic_names
[nr
]][counter
] = int(value
)
147 # Not an integer: then this must be the line with the additional
148 # information from wmic (which is optional!)
153 if line
[0].startswith("[teaming_start]"):
154 is_teaming_line
= True
155 teaming_headers
= lines
.next()
158 as_dict
= dict(zip(headers
, [x
.strip() for x
in line
]))
160 # Unfortunately teamed interfaces lose their #x index and are no longer
161 # distinguishable with the data from the Win32_NetworkAdapter.
162 # Fortunately this index information is still available in the teaming section
163 # The GUID is used to combine the two datasets
164 guid
= as_dict
.get("GUID")
165 if guid
in teaming_info
:
167 zip(teaming_info
[guid
]["GUID"].split(";"),
168 teaming_info
[guid
]["MemberDescriptions"].split(";")))
169 nic_name
= winperf_if_canonize_nic_name(guid_to_name
[guid
])
170 elif "Name" in as_dict
:
171 nic_name
= winperf_if_canonize_nic_name(as_dict
["Name"])
173 # There seems a bug with some windows configurations
178 # we need to ignore data on interfaces in the optional
179 # wmic section which are marked as non-existing, since
180 # it may happen that there are non-existing interfaces
181 # with the same nic_name as an active one (at least on HP
183 if as_dict
.get("NetConnectionStatus") == "4":
187 if nic_name
in nic_names
:
190 # In the perf counters the nics have strange suffixes, e.g.
191 # Ethernetadapter der AMD-PCNET-Familie 2 - Paketplaner-Miniport, while
192 # in wmic it's only named "Ethernetadapter der AMD-PCNET-Familie 2".
194 mod_nic_name
= winperf_if_normalize_nic_name(nic_name
, nic_names
)
196 if mod_nic_name
not in nic_names
:
198 if n
.startswith(mod_nic_name
+ " "):
199 l
= len(mod_nic_name
)
200 if not (n
[l
:].strip()[0]).isdigit():
206 nic_name
= mod_nic_name
209 # Ignore interfaces that do not have counters
212 nics
[nic_name
].update(as_dict
)
213 except StopIteration:
216 # Now convert the dicts into the format that is needed by if.include
220 nic_names
.sort(reverse
=True)
222 for nic_name
in nic_names
:
224 mac_txt
= nic
.get('MACAddress')
225 bandwidth
= saveint(nic
.get('Speed'))
226 # Some interfaces report several exabyte as bandwidth when down..
227 if bandwidth
> 1024**5:
228 # Greater than petabyte
232 mac
= "".join(chr(int(x
, 16)) for x
in mac_txt
.split(':'))
236 index_info
= str(nic_index
[nic_name
])
237 # Automatically group teamed interfaces
238 if nic
.get("GUID") in teaming_info
:
239 index_info
= (teaming_info
[nic
.get("GUID")]["TeamName"], index_info
)
241 # NetConnectionTable Stuff:
243 # if we have no status, but link information, we assume IF is connected
244 connection_status
= nic
.get('NetConnectionStatus')
245 if not connection_status
:
246 connection_status
= '2'
248 # Windows NetConnectionStatus Table
249 connection_states
= {
250 '0': ('2', 'Disconnected'),
251 '1': ('2', 'Connecting'),
252 '2': ('1', 'Connected'),
253 '3': ('2', 'Disconnecting'),
254 '4': ('2', 'Hardware not present'),
255 '5': ('2', 'Hardware disabled'),
256 '6': ('2', 'Hardware malfunction'),
257 '7': ('7', 'Media disconnected'),
258 '8': ('2', 'Authenticating'),
259 '9': ('2', 'Authentication succeeded'),
260 '10': ('2', 'Authentication failed'),
261 '11': ('2', 'Invalid address'),
262 '12': ('2', 'Credentials required'),
274 ifoperstatus_annotated
= connection_states
[connection_status
]
279 "loopback" in nic_name
.lower() and '24' or '6',
280 bandwidth
or nic
[10], # Bandwidth
281 ifoperstatus_annotated
, # ifOperStatus
282 nic
[-246], # ifInOctets,
285 nic
[16], # non-unicast empfangen
286 nic
[18], # ifInDiscards
287 nic
[20], # ifInErrors
288 nic
[-4], # ifOutOctets (Bytes gesendet)
291 nic
[28], # outnonucast
292 nic
[30], # ifOutDiscards
293 nic
[32], # ifOutErrors
295 nic
.get('NetConnectionID', nic_name
),
299 return agent_timestamp
, converted
, dhcp_lines
, nic_names
, nic_index
302 def winperf_if_get_nic_index_map(nic_names
):
303 return {x
: i
+ 1 for i
, x
in enumerate(nic_names
)}
306 def check_if_dhcp(item
, _no_params
, info
, nic_names
, nic_index
):
308 header
= lines
.next()
311 # wmic is bugged on some windows versions such that we can't use proper csv output, only
312 # visual tables. Those aren't properly split up by the check_mk parser.
313 # Try to fix that mess
315 # assumption 1: header fields contain no spaces
316 num_fields
= len(header
)
317 # assumption 2: only the leftmost field contains spaces
318 lm_field
= " ".join(line
[:(num_fields
- 1) * -1])
320 line
= [lm_field
] + line
[(len(line
) - num_fields
+ 1):]
322 as_dict
= dict(zip(header
, [x
.rstrip() for x
in line
]))
323 name
= winperf_if_normalize_nic_name(as_dict
["Description"], nic_names
)
324 idx
= nic_index
.get(name
)
327 match
= idx
== int(item
)
332 if as_dict
["DHCPEnabled"] == "TRUE":
333 return 1, "dhcp enabled"
334 return 0, "dhcp %s" % as_dict
["DHCPEnabled"]
338 def inventory_winperf_if(parsed
):
339 _agent_timestamp
, perf
, _dhcp
, _nic_names
, _nic_index
= parsed
341 # dhcp info irrelevant to inventory
342 return inventory_if_common(perf
)
345 def check_winperf_if(item
, params
, parsed
):
346 agent_timestamp
, perf
, dhcp
, nic_names
, nic_index
= parsed
348 yield check_if_common(item
, params
, perf
, group_name
="Teaming", timestamp
=agent_timestamp
)
349 yield check_if_dhcp(item
, params
, dhcp
, nic_names
, nic_index
)
352 check_info
["winperf_if"] = {
353 'parse_function': parse_winperf_if
,
354 'inventory_function': inventory_winperf_if
,
355 'check_function': check_winperf_if
,
356 'service_description': 'Interface %s',
357 'has_perfdata': True,
358 'includes': ['if.include'],
360 'default_levels_variable': 'if_default_levels'