Module: check_mk
Branch: master
Commit: a36eb3a6c9b9bc107b9eeaf12a1cfa71a3795dd9
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=a36eb3a6c9b9bc…
Author: Tom Baerwinkel <tb(a)mathias-kettner.de>
Date: Tue Sep 4 09:24:47 2018 +0200
6409 FIX wmi.include: don't throw exepctions in the parse function
In previous versions the parse function provided in wmi.include
(used in different WMI checks like e.g. wmi_cpuload) raised
a MKCounterWrapped exception if a WMI timeout occured. This
leads to a crash during the service discovery when a timeout
occurs.
Now the parse function always returns valid data. If a timeout
occurs an empty table is added to the parsed data. The inventory
function can then easily check for empty tables. If on the other
hand the check function tries to access an empty table a
MKCounterWrapped exception is raised.
CMK-868
Change-Id: I22bb9470feb3e4aa9ed47df2c068f4fa78258290
---
.werks/6409 | 20 ++++++++++++++++++++
checks/wmi.include | 41 ++++++++++++++++++++++++++---------------
2 files changed, 46 insertions(+), 15 deletions(-)
diff --git a/.werks/6409 b/.werks/6409
new file mode 100644
index 0000000..cafb750
--- /dev/null
+++ b/.werks/6409
@@ -0,0 +1,20 @@
+Title: wmi.include: don't throw exepctions in the parse function
+Level: 1
+Component: checks
+Compatible: compat
+Edition: cre
+Version: 1.6.0i1
+Date: 1536044950
+Class: fix
+
+In previous versions the parse function provided in wmi.include
+(used in different WMI checks like e.g. wmi_cpuload) raised
+a MKCounterWrapped exception if a WMI timeout occured. This
+leads to a crash during the service discovery when a timeout
+occurs.
+
+Now the parse function always returns valid data. If a timeout
+occurs an empty table is added to the parsed data. The inventory
+function can then easily check for empty tables. If on the other
+hand the check function tries to access an empty table a
+MKCounterWrapped exception is raised.
diff --git a/checks/wmi.include b/checks/wmi.include
index da04cd4..adb8e13 100644
--- a/checks/wmi.include
+++ b/checks/wmi.include
@@ -47,6 +47,12 @@
# '----------------------------------------------------------------------'
+class NullTable(object):
+ """Represents an empty table caused by a WMI
timeout."""
+ def __getattr__(self, name):
+ raise MKCounterWrapped('WMI query timed out')
+
+
class WMITable(object):
"""
Represents a 2-dimensional table of performance metrics.
@@ -168,55 +174,56 @@ class WMITable(object):
def parse_wmi_table(info, key="Name"):
parsed = {}
+ info_iter = iter(info)
try:
# read input line by line. rows with [] start the table name.
# Each table has to start with a header line
- info_iter = iter(info)
line = info_iter.next()
- # Did main section get WMI timeout?
- check_wmi_timeout(line)
-
timestamp, frequency = None, None
if line[0] == "sampletime":
timestamp, frequency = int(line[1]), int(line[2])
line = info_iter.next()
- while line is not None:
- check_wmi_timeout(line)
-
+ while True:
if len(line) == 1 and line[0].startswith("["):
# multi-table input
tablename = regex(r"\[(.*)\]").search(line[0]).group(1)
# Did subsection get WMI timeout?
line = info_iter.next()
- check_wmi_timeout(line)
else:
# single-table input
tablename = ""
+ if is_wmi_timeout(line):
+ parsed[tablename] = NullTable()
+ line = info_iter.next()
+ continue
+
if tablename not in parsed:
parsed[tablename] = WMITable(tablename, line, key, timestamp, frequency)
current = parsed[tablename]
# read table content
line = info_iter.next()
- while line is not None and not line[0].startswith("["):
- check_wmi_timeout(line)
+ while not line[0].startswith("["):
+ if is_wmi_timeout(line):
+ parsed[tablename] = NullTable()
+ line = info_iter.next()
+ continue
current.add_row(line)
line = info_iter.next()
- except StopIteration:
+ except (StopIteration, ValueError):
# regular end of block
pass
return parsed
-def check_wmi_timeout(line):
- if line[0] == "WMItimeout":
- raise MKCounterWrapped("WMI query timed out")
+def is_wmi_timeout(line):
+ return line[0] == "WMItimeout"
#.
@@ -229,6 +236,7 @@ def check_wmi_timeout(line):
# | |
# '----------------------------------------------------------------------'
+
def wmi_filter_global_only(tables, row):
return all(table.get(row, "Name") == "_Global_" for table in
tables.values())
@@ -243,9 +251,11 @@ def wmi_filter_global_only(tables, row):
# | |___/ |
# '----------------------------------------------------------------------'
+
def inventory_wmi_table(tables, **kwargs):
required_tables = kwargs.get('required_tables', tables.keys())
- if not set(required_tables) <= set(tables.keys()):
+ if (not set(required_tables) <= set(tables.keys()) or
+ any(isinstance(table, NullTable) for table in tables.itervalues())):
# if table is missing, nothing gets inventorized. This can
# only happen if required_tables was set
return []
@@ -291,6 +301,7 @@ def inventory_wmi_table(tables, **kwargs):
# | |
# '----------------------------------------------------------------------'
+
# determine time at which a sample was taken
def get_wmi_time(table, row):
timestamp = table.timestamp() or table.get(row, "Timestamp_PerfTime")