Module: check_mk
Branch: master
Commit: 1b7f4f9768e0119fd2261e07034275bc60d7834e
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=1b7f4f9768e011…
Author: Jukka Aro <ja(a)mathias-kettner.de>
Date: Fri Dec 15 16:17:37 2017 +0100
5416 FIX Prevent MS Exchange checks from crashing upon WMI timeout
Werk #5411 introduced the identification and handling of WMI timeouts.
Some of nested subsections, at least those of MS Exchange, may under
certain circumstances produce an unprecedented order of output lines
suddenly ending in a WMI timeout. This scenario was not expected when
preparing #5411, causing the parsing of some MS Exchange subsections
to fail and the corresponding check to crash.
This fix ensures that a WMI timeout is properly parsed regardless of
where it appears in a subsection output. The corresponding checks no
longer crash but issue a PENDING/UNKNOWN result.
Change-Id: Ic43050a153a1dcb05286564d4a5478934b74fdd4
---
.werks/5416 | 19 +++++++++++++++++++
checks/wmi.include | 19 ++++++++++++-------
2 files changed, 31 insertions(+), 7 deletions(-)
diff --git a/.werks/5416 b/.werks/5416
new file mode 100644
index 0000000..7b579e1
--- /dev/null
+++ b/.werks/5416
@@ -0,0 +1,19 @@
+Title: Prevent MS Exchange checks from crashing upon WMI timeout
+Level: 1
+Component: checks
+Compatible: compat
+Edition: cre
+Version: 1.5.0i2
+Date: 1513609941
+Class: fix
+
+Werk #5411 introduced the identification and handling of WMI timeouts.
+Some of nested subsections, at least those of MS Exchange, may under
+certain circumstances produce an unprecedented order of output lines
+suddenly ending in a WMI timeout. This scenario was not expected when
+preparing #5411, causing the parsing of some MS Exchange subsections
+to fail and the corresponding check to crash.
+
+This fix ensures that a WMI timeout is properly parsed regardless of
+where it appears in a subsection output. The corresponding checks no
+longer crash but issue a PENDING/UNKNOWN result.
diff --git a/checks/wmi.include b/checks/wmi.include
index 5d88176..bdc7703 100644
--- a/checks/wmi.include
+++ b/checks/wmi.include
@@ -147,10 +147,11 @@ def parse_wmi_table(info, key="Name"):
timestamp = int(line[1])
frequency = int(line[2])
line = info_iter.next()
- elif line[0] == "WMItimeout":
- # main section got WMI timeout
- raise MKCounterWrapped("WMI query timed out")
+ else:
+ # Did main section get WMI timeout?
+ check_wmi_timeout(line)
while line is not None:
+ check_wmi_timeout(line)
current = None
if len(line) == 1 and line[0].startswith("["):
# multi-table input
@@ -158,9 +159,8 @@ def parse_wmi_table(info, key="Name"):
res = {}
tablename = regex("\[(.*)\]").search(line[0]).group(1)
line = info_iter.next()
- if line[0] == "WMItimeout":
- # subsection got WMI timeout
- raise MKCounterWrapped("WMI query timed out")
+ # Did subsection get WMI timeout?
+ check_wmi_timeout(line)
if tablename in res:
# known table, append to it
current = res[tablename]
@@ -175,9 +175,9 @@ def parse_wmi_table(info, key="Name"):
# read table content
line = info_iter.next()
while line is not None and not line[0].startswith("["):
+ check_wmi_timeout(line)
current.add_row(line)
line = info_iter.next()
-
except StopIteration:
# regular end of block
pass
@@ -185,6 +185,11 @@ def parse_wmi_table(info, key="Name"):
return res
+def check_wmi_timeout(line):
+ if line[0] == "WMItimeout":
+ raise MKCounterWrapped("WMI query timed out")
+
+
#.
# .--Filters-------------------------------------------------------------.
# | _____ _ _ _ |
Module: check_mk
Branch: master
Commit: 3d1f794bbfe7b027046354dc026616eb7fc3c84d
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=3d1f794bbfe7b0…
Author: Konstantin Büttner <kb(a)mathias-kettner.de>
Date: Mon Dec 18 10:05:44 2017 +0100
Add docstrings
Change-Id: I38d6183d217772a046d4839bd5906035042a40d7
---
tests/checks/checktestlib.py | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/tests/checks/checktestlib.py b/tests/checks/checktestlib.py
index 39a0b98..f7618d1 100644
--- a/tests/checks/checktestlib.py
+++ b/tests/checks/checktestlib.py
@@ -8,6 +8,7 @@ class BasicCheckResult(object):
def __init__(self, status, infotext, perfdata=None):
"""We perform some basic consistency checks during initialization"""
+
assert status in [0,1,2,3]
assert type(infotext) == str
assert "\n" not in infotext
@@ -31,6 +32,13 @@ class BasicCheckResult(object):
self.perfdata = perfdata
def assert_result(self, expected_result):
+ """Assert that a result matches certain criteria
+
+ expected_result is a Dictionary defining the criteria, allowing to not
+ rigidly define every detail about the check result, but only what we
+ really want to test.
+ """
+
if "status" in expected_result:
assert result.status == expected_result["status"]
if "infotext" in expected_result:
@@ -43,6 +51,8 @@ class CompoundCheckResult(object):
"""A check result consisting of multiple subresults, as returned by yield-style checks"""
def __init__(self, result):
+ """Initializes a list of subresults using BasicCheckResult"""
+
self.subresults = []
for subresult in result:
self.subresults.append(BasicCheckResult(*subresult))
Module: check_mk
Branch: master
Commit: 0652c935f9763a654b894de2387c479647535af9
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=0652c935f9763a…
Author: Konstantin Büttner <kb(a)mathias-kettner.de>
Date: Mon Dec 18 12:24:51 2017 +0100
CompoundCheckResult: Provide a way to check for the existence of a matching subresult
Change-Id: I7ea505752c1168da4784375330b38429c13c88ed
---
tests/checks/checktestlib.py | 31 +++++++++++++++++++++++++++++--
tests/checks/test_statgrab_cpu_check.py | 3 ++-
2 files changed, 31 insertions(+), 3 deletions(-)
diff --git a/tests/checks/checktestlib.py b/tests/checks/checktestlib.py
index 221ce7b..d785241 100644
--- a/tests/checks/checktestlib.py
+++ b/tests/checks/checktestlib.py
@@ -42,14 +42,28 @@ class BasicCheckResult(object):
"""Check whether this result's perfdata matches a given value. Exact match."""
return expected_perfdata == self.perfdata
- def assert_result(self, expected_result):
- """Assert that a result matches certain criteria
+ def match(self, expected_result):
+ """Check whether a result matches certain criteria
expected_result is a Dictionary defining the criteria, allowing to not
rigidly define every detail about the check result, but only what we
really want to test. Unset fields mean we don't care.
"""
+ if "status" in expected_result and not match_status(expected_result["status"]):
+ return False
+ if "infotext" in expected_result and not match_infotext(expected_result["infotext"]):
+ return False
+ if "perfdata" in expected_result and not match_perfdata(expected_result["perfdata"]):
+ return False
+ return True
+
+ def assert_result(self, expected_result):
+ """Assert that a result matches certain criteria
+
+ expected_result works as in match_result
+ """
+
if "status" in expected_result:
assert match_status(expected_result["status"])
if "infotext" in expected_result:
@@ -67,3 +81,16 @@ class CompoundCheckResult(object):
self.subresults = []
for subresult in result:
self.subresults.append(BasicCheckResult(*subresult))
+
+ def match_subresult(self, expected_result):
+ """Checks whether a subresult matching certain criteria is contained in this compound result"""
+
+ for subresult in self.subresults:
+ if subresult.match(expected_result):
+ return True
+ return False
+
+ def assert_result(self, expected_result):
+ """Assert that a subresult matching certain criteria is contained in this compound result"""
+
+ assert self.match_subresult(expected_result)
diff --git a/tests/checks/test_statgrab_cpu_check.py b/tests/checks/test_statgrab_cpu_check.py
index 446aa27..ed41637 100644
--- a/tests/checks/test_statgrab_cpu_check.py
+++ b/tests/checks/test_statgrab_cpu_check.py
@@ -21,7 +21,7 @@ pytestmark = pytest.mark.checks
[u'total', u'%d' % int(t*50)],
[u'user', u'%d' % int(t*50)],
[u'vctxsw', u'%d' % int(t*50)]],
- {}, None),
+ {}, {}),
])
def test_statgrab_cpu_check(check_manager, monkeypatch, time_to_info, params, expected_result):
import time
@@ -32,3 +32,4 @@ def test_statgrab_cpu_check(check_manager, monkeypatch, time_to_info, params, ex
pass
monkeypatch.setattr("time.time", lambda: 60)
result = checktestlib.CompoundCheckResult(check.run_check(None, params, time_to_info(60)))
+ result.assert_result(expected_result)
Module: check_mk
Branch: master
Commit: e26a935dca2eccec5e00939352f87d4c3a03ff0d
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=e26a935dca2ecc…
Author: Konstantin Büttner <kb(a)mathias-kettner.de>
Date: Mon Dec 18 11:44:50 2017 +0100
BasicCheckResult: Extract logic for matching status, infotext and perfdata into individual methods
Change-Id: I8840a7679ea43a57974d63c93cb973791060e548
---
tests/checks/checktestlib.py | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/tests/checks/checktestlib.py b/tests/checks/checktestlib.py
index 32cad5d..221ce7b 100644
--- a/tests/checks/checktestlib.py
+++ b/tests/checks/checktestlib.py
@@ -1,4 +1,3 @@
-
class BasicCheckResult(object):
"""A basic check result
@@ -31,20 +30,32 @@ class BasicCheckResult(object):
assert all(type(value) in [int, float, type(None)] for value in entry[2:])
self.perfdata = perfdata
+ def match_status(self, expected_status):
+ """Check if this result's status matches a given value. Exact match."""
+ return self.status == expected_status
+
+ def match_infotext(self, expected_infotext):
+ """Check whether this result's infotext contains a given string. Case-sensitive."""
+ return expected_infotext in self.infotext
+
+ def match_perfdata(self, expected_perfdata):
+ """Check whether this result's perfdata matches a given value. Exact match."""
+ return expected_perfdata == self.perfdata
+
def assert_result(self, expected_result):
"""Assert that a result matches certain criteria
expected_result is a Dictionary defining the criteria, allowing to not
rigidly define every detail about the check result, but only what we
- really want to test.
+ really want to test. Unset fields mean we don't care.
"""
if "status" in expected_result:
- assert result.status == expected_result["status"]
+ assert match_status(expected_result["status"])
if "infotext" in expected_result:
- assert expected_result["infotext"] in result.infotext
+ assert match_infotext(expected_result["infotext"])
if "perfdata" in expected_result:
- assert result.perfdata == expected_result["perfdata"]
+ assert match_perfdata(expected_result["perfdata"])
class CompoundCheckResult(object):