Module: check_mk
Branch: master
Commit: 7d06b53666f1b6a1fceef21a2260639a45ca9da0
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=7d06b53666f1b6…
Author: Moritz Kiemer <mo(a)mathias-kettner.de>
Date: Tue Apr 23 09:47:21 2019 +0200
7474 check_mk_agent: Cache information for local checks
For local checks running asynchronously the cache age information
is now included in the section header. Services corresponding to
outdated check data will become stale.
CMK-1313
Change-Id: I5dfb7326fc360fa915466f07fc19f7b49f333987
---
.werks/7474 | 13 +++++++++++++
agents/check_mk_agent.aix | 12 ++++++++----
agents/check_mk_agent.freebsd | 12 ++++++++----
agents/check_mk_agent.linux | 12 ++++++++----
agents/check_mk_agent.solaris | 12 ++++++++----
checks/local | 22 ++++++++++++++++++++--
.../checks/generictests/datasets/local_cached.py | 17 +++++++++++++++++
tests/unit/checks/test_local_expired.py | 22 ++++++++++++++++++++++
8 files changed, 104 insertions(+), 18 deletions(-)
diff --git a/.werks/7474 b/.werks/7474
new file mode 100644
index 0000000..9187e40
--- /dev/null
+++ b/.werks/7474
@@ -0,0 +1,13 @@
+Title: check_mk_agent: Cache information for local checks
+Level: 2
+Component: checks
+Compatible: compat
+Edition: cre
+Version: 1.6.0i1
+Date: 1556030292
+Class: feature
+
+For local checks running asynchronously the cache age information
+is now included in the agent output. Services corresponding to
+outdated check data will become stale.
+Previously the user was not able to recognize outdated data in this case.
diff --git a/agents/check_mk_agent.aix b/agents/check_mk_agent.aix
index 9ca0aa5..ba84653 100755
--- a/agents/check_mk_agent.aix
+++ b/agents/check_mk_agent.aix
@@ -124,10 +124,14 @@ function run_cached {
if (( $MTIME < $MAXAGE )) ; then
USE_CACHEFILE=1
fi
- CACHE_INFO=":cached($MTIME,$MAXAGE)"
- # insert the cache info in the section header (^= after '!'),
- # if none is present (^= before '!')
- sed -e
'/^<<<.*\(:cached(\).*>>>/!s/^<<<\([^>]*\)>>>$/<<<\1'$CACHE_INFO'>>>/'
"$CACHEFILE"
+ CACHE_INFO="cached($MTIME,$MAXAGE)"
+ if [[ $NAME == local_* ]]; then
+ sed -e "s/^/$CACHE_INFO /" "$CACHEFILE"
+ else
+ # insert the cache info in the section header (^= after '!'),
+ # if none is present (^= before '!')
+ sed -e
'/^<<<.*\(:cached(\).*>>>/!s/^<<<\([^>]*\)>>>$/<<<\1:'$CACHE_INFO'>>>/'
"$CACHEFILE"
+ fi
fi
if [ -z "$USE_CACHEFILE" -a ! -e "$CACHEFILE.new" ]
then
diff --git a/agents/check_mk_agent.freebsd b/agents/check_mk_agent.freebsd
index f187bbd..849cd19 100755
--- a/agents/check_mk_agent.freebsd
+++ b/agents/check_mk_agent.freebsd
@@ -97,10 +97,14 @@ function run_cached() {
if [ $((NOW - MTIME)) -le $MAXAGE ] ; then local USE_CACHEFILE=1 ; fi
# Output the file in any case, even if it is
# outdated. The new file will not yet be available
- CACHE_INFO=":cached($MTIME,$MAXAGE)"
- # insert the cache info in the section header (^= after '!'),
- # if none is present (^= before '!')
- sed -e
'/^<<<.*\(:cached(\).*>>>/!s/^<<<\([^>]*\)>>>$/<<<\1'$CACHE_INFO'>>>/'
"$CACHEFILE"
+ CACHE_INFO="cached($MTIME,$MAXAGE)"
+ if [[ $NAME == local_* ]]; then
+ sed -e "s/^/$CACHE_INFO /" "$CACHEFILE"
+ else
+ # insert the cache info in the section header (^= after '!'),
+ # if none is present (^= before '!')
+ sed -e
'/^<<<.*\(:cached(\).*>>>/!s/^<<<\([^>]*\)>>>$/<<<\1:'$CACHE_INFO'>>>/'
"$CACHEFILE"
+ fi
fi
# Cache file outdated and new job not yet running? Start it
diff --git a/agents/check_mk_agent.linux b/agents/check_mk_agent.linux
index 90c8c34..5a3e01d 100755
--- a/agents/check_mk_agent.linux
+++ b/agents/check_mk_agent.linux
@@ -290,10 +290,14 @@ function run_cached () {
# all further lines are long output)
sed -e "2s/|/ (Cached: ${AGE}\/${MAXAGE}s)|/" -e t -e "2s/$/
(Cached: ${AGE}\/${MAXAGE}s)/" < "$CACHEFILE"
else
- CACHE_INFO=":cached($MTIME,$MAXAGE)"
- # insert the cache info in the section header (^= after '!'),
- # if none is present (^= before '!')
- sed -e
'/^<<<.*\(:cached(\).*>>>/!s/^<<<\([^>]*\)>>>$/<<<\1'$CACHE_INFO'>>>/'
"$CACHEFILE"
+ CACHE_INFO="cached($MTIME,$MAXAGE)"
+ if [[ $NAME == local_* ]]; then
+ sed -e "s/^/$CACHE_INFO /" "$CACHEFILE"
+ else
+ # insert the cache info in the section header (^= after '!'),
+ # if none is present (^= before '!')
+ sed -e
'/^<<<.*\(:cached(\).*>>>/!s/^<<<\([^>]*\)>>>$/<<<\1:'$CACHE_INFO'>>>/'
"$CACHEFILE"
+ fi
fi
fi
diff --git a/agents/check_mk_agent.solaris b/agents/check_mk_agent.solaris
index 74ebf51..b0c9228 100755
--- a/agents/check_mk_agent.solaris
+++ b/agents/check_mk_agent.solaris
@@ -127,10 +127,14 @@ function run_cached () {
# all further lines are long output)
cat "$CACHEFILE" | sed -e "2s/|/ (Cached:
${AGE}\/${MAXAGE}s)|/" -e t -e "2s/$/ (Cached: ${AGE}\/${MAXAGE}s)/"
else
- CACHE_INFO=":cached($MTIME,$MAXAGE)"
- # insert the cache info in the section header (^= after '!'),
- # if none is present (^= before '!')
- sed -e
'/^<<<.*\(:cached(\).*>>>/!s/^<<<\([^>]*\)>>>$/<<<\1'$CACHE_INFO'>>>/'
"$CACHEFILE"
+ CACHE_INFO="cached($MTIME,$MAXAGE)"
+ if [[ $NAME == local_* ]]; then
+ sed -e "s/^/$CACHE_INFO /" "$CACHEFILE"
+ else
+ # insert the cache info in the section header (^= after '!'),
+ # if none is present (^= before '!')
+ sed -e
'/^<<<.*\(:cached(\).*>>>/!s/^<<<\([^>]*\)>>>$/<<<\1:'$CACHE_INFO'>>>/'
"$CACHEFILE"
+ fi
fi
fi
diff --git a/checks/local b/checks/local
index f6f6ba1..a5c0e7c 100644
--- a/checks/local
+++ b/checks/local
@@ -45,6 +45,16 @@ def float_ignore_uom(value):
return 0.0
+def _parse_cache(line, now):
+ if not line or not line[0].startswith("cached("):
+ return 0, line
+
+ cache_raw, stripped_line = line[0], line[1:]
+ time, maxage = (float(v) for v in cache_raw[7:-1].split(',', 1))
+
+ return max(now - time - maxage, 0), stripped_line
+
+
def _is_valid_line(line):
return len(line) >= 4 or (len(line) == 3 and line[0] == 'P')
@@ -118,11 +128,13 @@ def _parse_perftxt(string):
def parse_local(info):
LocalResult = collections.namedtuple("LocalResult",
- ("node", "item",
"state", "text", "perfdata"))
+ ("node", "expired",
"item", "state", "text", "perfdata"))
+ now = time.time()
parsed = {}
for line in info:
node, stripped_line = line[0], line[1:]
+ expired, stripped_line = _parse_cache(stripped_line, now)
if not _is_valid_line(stripped_line):
parsed.setdefault(None, []).append(LocalResult(node, None, None,
stripped_line))
continue
@@ -136,7 +148,7 @@ def parse_local(info):
if state_msg or perf_msg:
state = 3
text = "%s%sOutput is: %s" % (state_msg, perf_msg, text)
- parsed.setdefault(item, []).append(LocalResult(node, item, state, text,
perfdata))
+ parsed.setdefault(item, []).append(LocalResult(node, expired, item, state, text,
perfdata))
return parsed
@@ -200,8 +212,14 @@ def _calculate_local_worst_state(collected_stats):
def check_local(_no_item, params, data):
collected_stats = {}
for result in data:
+ if result.expired > 0:
+ continue
node_dict = collected_stats.setdefault(result.node, {})
node_dict.setdefault(result.item, _parse_local_line(result))
+ if not collected_stats:
+ most_recent_expirery = min(r.expired for r in data)
+ raise MKCounterWrapped(
+ "Cached data expired %s ago." %
get_age_human_readable(most_recent_expirery))
if params is not None and params.get("outcome_on_cluster",
"worst") == "best":
yield _calculate_local_best_state(collected_stats)
diff --git a/tests/unit/checks/generictests/datasets/local_cached.py
b/tests/unit/checks/generictests/datasets/local_cached.py
new file mode 100644
index 0000000..f7cb085
--- /dev/null
+++ b/tests/unit/checks/generictests/datasets/local_cached.py
@@ -0,0 +1,17 @@
+# yapf: disable
+
+
+checkname = 'local'
+
+freeze_time = "2019-04-23 07:45:00"
+
+info = [
+ ['node_1', 'cached(1556005301,300)', '0',
'Service_FOO', 'V=1', 'This', 'Check', 'is',
'OK'],
+]
+
+
+discovery = {
+ '': [
+ ('Service_FOO', {}),
+ ],
+}
diff --git a/tests/unit/checks/test_local_expired.py
b/tests/unit/checks/test_local_expired.py
new file mode 100644
index 0000000..f967ae7
--- /dev/null
+++ b/tests/unit/checks/test_local_expired.py
@@ -0,0 +1,22 @@
+import pytest # type: ignore
+from cmk_base.check_api import MKCounterWrapped
+from checktestlib import CheckResult
+
+pytestmark = pytest.mark.checks
+
+
+(a)pytest.mark.parametrize('item,info'nfo', [
+ ('Service_FOO', [[
+ 'node_1', 'cached(1556005301,300)', '0',
'Service_FOO', 'V=1', 'This', 'Check', 'is',
+ 'outdated'
+ ]]),
+])
+def test_local_check(check_manager, monkeypatch, item, info):
+ monkeypatch.setattr('time.time', lambda: 1556005721)
+ check = check_manager.get_check('local')
+
+ parsed = check.run_parse(info)
+ assert parsed[item][0].expired == 120.
+
+ with pytest.raises(MKCounterWrapped):
+ CheckResult(check.run_check(item, {}, parsed))