Module: check_mk
Branch: master
Commit: ab8068a5a45249acea4b6e619cf70eaab069443d
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=ab8068a5a45249…
Author: Florian Kromer <fk(a)mathias-kettner.de>
Date: Mon Jan 14 09:59:25 2019 +0100
lnx_thermal: Consider all possible trip points
CMK-1506
Change-Id: Idd1c2fdbdd081c9124898e4c9a5c0e3cc734021d
---
checks/lnx_thermal | 120 +++++++++++++--------
.../checks/generictests/datasets/lnx_thermal.py | 30 +++++-
tests/unit/checks/test_lnx_thermal.py | 15 ++-
3 files changed, 112 insertions(+), 53 deletions(-)
diff --git a/checks/lnx_thermal b/checks/lnx_thermal
index 356fecf..f165b68 100644
--- a/checks/lnx_thermal
+++ b/checks/lnx_thermal
@@ -41,57 +41,87 @@ factory_settings["lnx_thermal_default_levels"] = {
}
-@discover
-def inventory_lnx_thermal(line):
- return line[0].replace('thermal_zone', 'Zone ')
-
-
-def check_lnx_thermal(item, params, info):
+def parse_lnx_thermal(info):
+ """
+ Supported format:
+ - Temperature is either the 3rd or 4th element in an info row.
+ - After temperature follows pairwise trip point temperature and trip point type.
+ - Considered trip points are critical, passive, hot.
+ - A known, not considered trip point is active.
+ - In case trip point values are 0 or negative (known default values) they are
ignored.
+ """
+ if not info:
+ return {}
+ parsed = {}
for line in info:
- if line[0].replace('thermal_zone', 'Zone ') == item or\
- line[0].replace('thermal_zone', '') == item:
- # ['thermal_zone0', 'enabled', 'acpitz',
'51000', '90000', 'critical', '79000', 'passive']
-
- # Some devices report an empty value for the 3rd field (type). Trying to fix
those lines.
- # -> thermal_zone1 pkg-temp-0 44000 0 passive 0 passive
- try:
- int(line[2])
- int(line[3])
- line = line[:2] + [''] + line[2:]
- except:
- pass # -> regular line
-
- # convert values from millidegree
- temp = int(line[3]) / 1000.0
-
- # parse trip points
- dev_warn = None
- dev_crit = None
- if len(line) > 4:
- trip_points = dict(zip(line[5::2], [int(x) / 1000.0 for x in
line[4::2]]))
- for tp_name, level in trip_points.iteritems():
- # ignore active cooling device trip points (means enabling a fan or
similar)
- if tp_name == 'active':
- continue
- if level != 0:
- if tp_name in ['hot', 'critical']:
- dev_crit = level
- else:
- dev_warn = level
-
- # If only one relevant trip point is found, use that for both warn and crit
- if (dev_warn is not None) != (dev_crit is not None):
- dev_warn = dev_crit = max(dev_warn, dev_crit)
-
- if dev_warn and dev_crit:
- dev_levels = (dev_warn, dev_crit)
+ zone_identifier = 0
+ temperature_3rd_element_idx = 2
+ temperature_4th_element_idx = 3
+ temperature_factor = 1000.0
+ zone_raw = line[zone_identifier]
+ try:
+ int(line[temperature_3rd_element_idx]) # may raise an exception
+ temperature = int(line[temperature_3rd_element_idx]) / temperature_factor
+ trip_points = dict(zip(line[4::2], [int(x) / temperature_factor for x in
line[3::2]]))
+ except ValueError:
+ temperature = int(line[temperature_4th_element_idx]) / temperature_factor
+ trip_points = dict(zip(line[5::2], [int(x) / temperature_factor for x in
line[4::2]]))
+ zone_formatted = zone_raw.replace('thermal_zone', 'Zone ')
+ parsed[zone_formatted] = {}
+ temperature_and_trip_points = ('temperature', 'passive',
'critical', 'hot')
+ for key in temperature_and_trip_points:
+ parsed[zone_formatted].setdefault(key, None)
+ parsed[zone_formatted]['temperature'] = temperature
+ for tp_name, tp_value in trip_points.items():
+ if tp_name in trip_points and tp_value > 0:
+ parsed[zone_formatted][tp_name] = tp_value
else:
- dev_levels = None
+ # ignore trip point types not supported yet
+ pass
+ return parsed
+
+
+def inventory_lnx_thermal(parsed):
+ for item in parsed.keys():
+ yield item, {}
+
+
+def check_lnx_thermal(item, params, parsed):
+ """
+ - Trip points hot and critical are considered for the device crit level. In case both
trip
+ points are given the lower value is considered for the device crit level.
+ - Trip point passive is considered for the device warn level.
+ - In case both hot and critical trip points are given the lower trip point value
+ is considered for the device crit level.
+ - Trip point temperatures are provided via performance data.
+ """
+ temperature = parsed.get(item).get('temperature')
+ warn_level = parsed.get(item).get('passive')
+ hot_value = parsed.get(item).get('hot')
+ critical_value = parsed.get(item).get('critical')
+
+ if not temperature:
+ return 3, "Item not found or invalid agent data."
+
+ if hot_value and critical_value:
+ crit_level = min(hot_value, critical_value)
+ else:
+ crit_level = hot_value or critical_value
+
+ if not crit_level or not warn_level:
+ crit_level = crit_level or warn_level
+ warn_level = warn_level or crit_level
+
+ if warn_level and crit_level:
+ levels = (warn_level, crit_level)
+ else:
+ levels = None
- return check_temperature(temp, params, "lnx_thermal_%s" % item,
dev_levels=dev_levels)
+ return check_temperature(temperature, params, "lnx_thermal_%s" % item,
dev_levels=levels)
check_info['lnx_thermal'] = {
+ "parse_function": parse_lnx_thermal,
"inventory_function": inventory_lnx_thermal,
"check_function": check_lnx_thermal,
"service_description": "Temperature %s",
diff --git a/tests/unit/checks/generictests/datasets/lnx_thermal.py
b/tests/unit/checks/generictests/datasets/lnx_thermal.py
index a8838ce..cc54922 100644
--- a/tests/unit/checks/generictests/datasets/lnx_thermal.py
+++ b/tests/unit/checks/generictests/datasets/lnx_thermal.py
@@ -2,9 +2,21 @@ checkname = 'lnx_thermal'
info = [['thermal_zone0', 'enabled', 'acpitz', '57000',
'127000', 'critical'],
['thermal_zone1', 'enabled', 'acpitz', '65000',
'100000', 'critical', '95500', 'passive'],
- ['thermal_zone2', 'pkg-temp-0', '44000', '0',
'passive', '0', 'passive']]
+ ['thermal_zone2', 'pkg-temp-0', '44000', '0',
'passive', '0', 'passive'],
+ [
+ 'thermal_zone3', '-', 'TSKN', '48000',
'0', 'passive', '0', 'passive', '127000',
+ 'critical', '87000', 'hot', '77000',
'passive', '127000', 'active'
+ ], ['thermal_zone4', '-', 'INT3400 Thermal',
'20000'],
+ [
+ 'thermal_zone5', '-', 'iwlwifi', '27000',
'-32768000', 'passive', '-32768000',
+ 'passive', '-32768000', 'passive',
'-32768000', 'passive', '-32768000', 'passive',
+ '-32768000', 'passive', '-32768000',
'passive', '-32768000', 'passive'
+ ]]
-discovery = {'': [('Zone 0', {}), ('Zone 1', {}), ('Zone
2', {})]}
+discovery = {
+ '': [('Zone 0', {}), ('Zone 1', {}), ('Zone 2', {}),
('Zone 3', {}), ('Zone 4', {}),
+ ('Zone 5', {})]
+}
checks = {
'': [('Zone 0', {
@@ -18,5 +30,17 @@ checks = {
('Zone 2', {
'device_levels_handling': 'devdefault',
'levels': (70.0, 80.0)
- }, [(0, u'44.0 \xb0C', [('temp', 44.0, 70.0, 80.0, None,
None)])])]
+ }, [(0, u'44.0 \xb0C', [('temp', 44.0, 70.0, 80.0, None,
None)])]),
+ ('Zone 3', {
+ 'device_levels_handling': 'devdefault',
+ 'levels': (70.0, 80.0)
+ }, [(0, u'48.0 \xb0C', [('temp', 48.0, 77.0, 87.0, None,
None)])]),
+ ('Zone 4', {
+ 'device_levels_handling': 'devdefault',
+ 'levels': (70.0, 80.0)
+ }, [(0, u'20.0 \xb0C', [('temp', 20.0, 70.0, 80.0, None,
None)])]),
+ ('Zone 5', {
+ 'device_levels_handling': 'devdefault',
+ 'levels': (70.0, 80.0)
+ }, [(0, u'27.0 \xb0C', [('temp', 27.0, 70.0, 80.0, None,
None)])])]
}
diff --git a/tests/unit/checks/test_lnx_thermal.py
b/tests/unit/checks/test_lnx_thermal.py
index 49497d4..bbbbee9 100644
--- a/tests/unit/checks/test_lnx_thermal.py
+++ b/tests/unit/checks/test_lnx_thermal.py
@@ -1,11 +1,13 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
+
import pytest
+from checktestlib import DiscoveryResult, assertDiscoveryResultsEqual
+
# Mark all tests in this file as check related tests
pytestmark = pytest.mark.checks
-
def splitter(text, split_symbol=None):
return [line.split(split_symbol) for line in text.split("\n")]
@@ -27,9 +29,11 @@ result_discovery = [[('Zone %s' % i, {}) for i in [0, 1, 3,
5]],
@pytest.mark.parametrize("info, result", zip(agent_info, result_discovery))
-def test_parse(check_manager, info, result):
+def test_parse_and_discovery_function(check_manager, info, result):
check = check_manager.get_check("lnx_thermal")
- assert list(check.run_discovery(info)) == result
+ parsed = check.run_parse(info)
+ discovery = DiscoveryResult(check.run_discovery(parsed))
+ assertDiscoveryResultsEqual(check, discovery, DiscoveryResult(result))
result_check = [
@@ -50,7 +54,8 @@ result_check = [
@pytest.mark.parametrize("info, discovered, checked", zip(agent_info,
result_discovery,
result_check))
-def test_parse(check_manager, info, discovered, checked):
+def test_check_functions_perfdata(check_manager, info, discovered, checked):
check = check_manager.get_check("lnx_thermal")
+ parsed = check.run_parse(info)
for (item, params), result in zip(discovered, checked):
- assert check.run_check(item, params, info) == result
+ assert check.run_check(item, {}, parsed) == result