CMK version: 2.2.0p6
OS version: Oracle Linux 9.2
Hello, I am trying to monitor a Watchdog device that has external/remote sensors using Check_MK. I have been trying to modify the existing check to allow the external sensors to be detected, and was able to do so, but I’m not able to make all sensors be detected at the same time. Could anyone assist with this?
Here is the original (slightly modified to format the information better for us) check:
#!/usr/bin/env python3
# Copyright (C) 2019 Checkmk GmbH - License: GNU General Public License v2
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
# conditions defined in the file COPYING, which is part of this source code package.
# NOTE: Careful when replacing the *-import below with a more specific import. This can cause
# problems because it might remove variables needed for accessing discovery rulesets.
from cmk.base.check_legacy_includes.temperature import * # pylint: disable=wildcard-import,unused-wildcard-import
# very odd and confusing example outputs:
# version 3.0.0
# .1.3.6.1.4.1.21239.5.1.1.2.0 3.0.0
# .1.3.6.1.4.1.21239.5.1.1.7.0 1
# .1.3.6.1.4.1.21239.5.1.2.1.3.1 Data Center 1
# .1.3.6.1.4.1.21239.5.1.2.1.5.1 1
# .1.3.6.1.4.1.21239.5.1.2.1.4.1 "91 54 06 9D C9 54 06 9D E9 C9 06 9D BD 9B 06 9D "
# .1.3.6.1.4.1.21239.5.1.2.1.6.1 199
# .1.3.6.1.4.1.21239.5.1.2.1.7.1 36
# .1.3.6.1.4.1.21239.5.1.2.1.8.1 44
#
# version 3.2.0
# .1.3.6.1.4.1.21239.5.1.1.2.0 3.2.0
# .1.3.6.1.4.1.21239.5.1.1.7.0 1
# .1.3.6.1.4.1.21239.5.1.2.1.1.1 1
# .1.3.6.1.4.1.21239.5.1.2.1.2.1 41D88039003580C3
# .1.3.6.1.4.1.21239.5.1.2.1.3.1 RSGLDN Watchdog 15
# .1.3.6.1.4.1.21239.5.1.2.1.4.1 1
# .1.3.6.1.4.1.21239.5.1.2.1.5.1 173
# .1.3.6.1.4.1.21239.5.1.2.1.6.1 46
# .1.3.6.1.4.1.21239.5.1.2.1.7.1 56
def _translate_availability(availability):
return {
"0": (2, "Missing"),
"1": (0, "Present"),
"2": (1, "Partially Unavailable"),
}[availability]
def _parse_legacy_line(line, temp_unit):
"""
>>> [i for i in _parse_legacy_line(['1', 'blah', '2CD', '1', '30', '20', '8'], 'C')]
[('general', {'Watchdog 1': {'descr': 'blah', 'availability': (0, 'available')}}), ('temp', {'Temperature 1': ('30', 'C')}), ('humidity', {'Humidity 1': '20'}), ('dew', {'Dew point 1': ('8', 'C')})]
"""
sensor_id = line[0]
yield "general", {
"Sensor %s"
% sensor_id: {"descr": line[1], "availability": _translate_availability(line[3])},
}
yield "temp", {"Temperature %s" % sensor_id: (line[4], temp_unit)}
yield "humidity", {"Humidity %s" % sensor_id: line[5]}
yield "dew", {"Dew point %s" % sensor_id: (line[6], temp_unit)}
def _parse_line(line, temp_unit):
"""
>>> [i for i in _parse_line(['1', 'blah', '1', '30', '20', '8'], 'C')]
[('general', {'Watchdog 1': {'descr': 'blah', 'availability': (0, 'available')}}), ('temp', {'Temperature 1': ('30', 'C')}), ('humidity', {'Humidity 1': '20'}), ('dew', {'Dew point 1': ('8', 'C')})]
"""
sensor_id = line[1]
yield "general", {
"%s Sensor"
% sensor_id: {"descr": line[1], "availability": _translate_availability(line[2])},
}
yield "temp", {"%s Temperature" % sensor_id: (line[3], temp_unit)}
yield "humidity", {"%s Humidity" % sensor_id: line[4]}
yield "dew", {"%s Dew Point" % sensor_id: (line[5], temp_unit)}
def parse_watchdog_sensors(info):
parsed = {}
general, data = info
if not general:
return parsed
temp_unit = {
"1": "C",
"0": "F",
"": "C",
}[general[0][1]]
version = int(general[0][0].replace(".", ""))
if version <= 300:
line_parser = _parse_legacy_line
else:
line_parser = _parse_line
for line in data:
for sensor_type, parsed_line in line_parser(line, temp_unit):
parsed.setdefault(sensor_type, {}).update(parsed_line)
return parsed
# .
# .--general-------------------------------------------------------------.
# | _ |
# | __ _ ___ _ __ ___ _ __ __ _| | |
# | / _` |/ _ \ '_ \ / _ \ '__/ _` | | |
# | | (_| | __/ | | | __/ | | (_| | | |
# | \__, |\___|_| |_|\___|_| \__,_|_| |
# | |___/ |
# +----------------------------------------------------------------------+
# | |
# '----------------------------------------------------------------------'
def inventory_watchdog_sensors(parsed):
for key in parsed.get("general", {}):
yield (key, {})
def check_watchdog_sensors(item, params, parsed):
data = parsed.get("general", {}).get(item)
if not data:
return
descr = data["descr"]
state, state_readable = data["availability"]
yield state, state_readable
if not descr == "":
yield 0, "Location: %s" % descr
check_info["watchdog_sensors"] = {
"parse_function": parse_watchdog_sensors,
"inventory_function": inventory_watchdog_sensors,
"check_function": check_watchdog_sensors,
"service_description": "%s",
"snmp_info": [
(
".1.3.6.1.4.1.21239.5.1.1",
[
"2", # GEIST-V4-MIB::productVersion
"7", # GEIST-V4-MIB::temperatureUnits
],
),
(
".1.3.6.1.4.1.21239.5.1",
[
OID_END,
"2.1.3", # GEIST-V4-MIB::internalName
"2.1.4", # GEIST-V4-MIB::internalLabel but internalAvail if version 3.2.0
"2.1.5", # GEIST-V4-MIB::internalAvail but internalTemp if version 3.2.0
"2.1.6", # GEIST-V4-MIB::internalTemp but internalHumidity if version 3.2.0
"2.1.7", # GEIST-V4-MIB::internalHumidity but internalDewPoint if version 3.2.0
"2.1.8", # GEIST-V4-MIB::internalDewPoint but empty if version 3.2.0
],
),
],
"snmp_scan_function": lambda oid: oid(".1.3.6.1.2.1.1.2.0").startswith(".1.3.6.1.4.1.21239.5.1")
or oid(".1.3.6.1.2.1.1.2.0").startswith(".1.3.6.1.4.1.21239.42.1"), # firmware upgrade
}
# .
# .--temp----------------------------------------------------------------.
# | _ |
# | | |_ ___ _ __ ___ _ __ |
# | | __/ _ \ '_ ` _ \| '_ \ |
# | | || __/ | | | | | |_) | |
# | \__\___|_| |_| |_| .__/ |
# | |_| |
# +----------------------------------------------------------------------+
# | |
# '----------------------------------------------------------------------'
def inventory_watchdog_sensors_temp(parsed):
for key in parsed.get("temp", {}):
yield (key, {})
def check_watchdog_sensors_temp(item, params, parsed):
data = parsed.get("temp", {}).get(item)
if not data:
return None
temperature_str, unit = data
return check_temperature(
float(temperature_str) / 10.0,
params,
"check_watchdog_sensors.%s" % item,
dev_unit=unit.lower(),
)
check_info["watchdog_sensors.temp"] = {
"inventory_function": inventory_watchdog_sensors_temp,
"check_function": check_watchdog_sensors_temp,
"service_description": "%s ",
"has_perfdata": True,
"group": "temperature",
}
# .
# .--humidity------------------------------------------------------------.
# | _ _ _ _ _ |
# | | |__ _ _ _ __ ___ (_) __| (_) |_ _ _ |
# | | '_ \| | | | '_ ` _ \| |/ _` | | __| | | | |
# | | | | | |_| | | | | | | | (_| | | |_| |_| | |
# | |_| |_|\__,_|_| |_| |_|_|\__,_|_|\__|\__, | |
# | |___/ |
# +----------------------------------------------------------------------+
# | |
# '----------------------------------------------------------------------'
factory_settings["watchdog_sensors_humidity_default_levels"] = {
"levels": (50, 55),
"levels_lower": (10, 15),
}
def inventory_watchdog_sensors_humidity(parsed):
for key in parsed.get("humidity", {}):
yield (key, {})
def check_watchdog_sensors_humidity(item, params, parsed):
data = parsed.get("humidity", {}).get(item)
if not data:
return
humidity = int(data)
warn, crit = params["levels"]
warn_lower, crit_lower = params["levels_lower"]
yield 0, "%.1f%%" % humidity, [("humidity", humidity, warn, crit)]
if humidity >= crit:
yield 2, "warn/crit at %s/%s" % (warn, crit)
elif humidity <= crit_lower:
yield 2, "warn/crit at %s/%s" % (warn, crit)
elif humidity >= warn:
yield 1, "warn/crit below %s/%s" % (warn, crit)
elif humidity <= warn_lower:
yield 1, "warn/crit below %s/%s" % (warn, crit)
check_info["watchdog_sensors.humidity"] = {
"inventory_function": inventory_watchdog_sensors_humidity,
"check_function": check_watchdog_sensors_humidity,
"service_description": "%s",
"has_perfdata": True,
"group": "humidity",
"default_levels_variable": "watchdog_sensors_humidity_default_levels",
}
# .
# .--dew-----------------------------------------------------------------.
# | _ |
# | __| | _____ __ |
# | / _` |/ _ \ \ /\ / / |
# | | (_| | __/\ V V / |
# | \__,_|\___| \_/\_/ |
# | |
# +----------------------------------------------------------------------+
# | |
# '----------------------------------------------------------------------'
def inventory_watchdog_sensors_dew(parsed):
for key in parsed.get("dew", {}):
yield (key, {})
def check_watchdog_sensors_dew(item, params, parsed):
data = parsed.get("dew", {}).get(item)
if not data:
return
dew = float(data[0]) / 10.0
unit = data[1]
if unit == "F":
dew = 5.0 / 9.0 * (dew - 32)
yield check_temperature(dew, params, "check_watchdog_sensors.%s" % item)
check_info["watchdog_sensors.dew"] = {
"inventory_function": inventory_watchdog_sensors_dew,
"check_function": check_watchdog_sensors_dew,
"service_description": "%s",
"has_perfdata": True,
"group": "temperature",
}
Here is the modified version that gives results for the external sensors but not the onboard ones (note the different OIDs):
#!/usr/bin/env python3
# Copyright (C) 2019 Checkmk GmbH - License: GNU General Public License v2
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
# conditions defined in the file COPYING, which is part of this source code package.
# NOTE: Careful when replacing the *-import below with a more specific import. This can cause
# problems because it might remove variables needed for accessing discovery rulesets.
from cmk.base.check_legacy_includes.temperature import * # pylint: disable=wildcard-import,unused-wildcard-import
# very odd and confusing example outputs:
# version 3.0.0
# .1.3.6.1.4.1.21239.5.1.1.2.0 3.0.0
# .1.3.6.1.4.1.21239.5.1.1.7.0 1
# .1.3.6.1.4.1.21239.5.1.2.1.3.1 Data Center 1
# .1.3.6.1.4.1.21239.5.1.2.1.5.1 1
# .1.3.6.1.4.1.21239.5.1.2.1.4.1 "91 54 06 9D C9 54 06 9D E9 C9 06 9D BD 9B 06 9D "
# .1.3.6.1.4.1.21239.5.1.2.1.6.1 199
# .1.3.6.1.4.1.21239.5.1.2.1.7.1 36
# .1.3.6.1.4.1.21239.5.1.2.1.8.1 44
#
# version 3.2.0
# .1.3.6.1.4.1.21239.5.1.1.2.0 3.2.0
# .1.3.6.1.4.1.21239.5.1.1.7.0 1
# .1.3.6.1.4.1.21239.5.1.2.1.1.1 1
# .1.3.6.1.4.1.21239.5.1.2.1.2.1 41D88039003580C3
# .1.3.6.1.4.1.21239.5.1.2.1.3.1 RSGLDN Watchdog 15
# .1.3.6.1.4.1.21239.5.1.2.1.4.1 1
# .1.3.6.1.4.1.21239.5.1.2.1.5.1 173
# .1.3.6.1.4.1.21239.5.1.2.1.6.1 46
# .1.3.6.1.4.1.21239.5.1.2.1.7.1 56
def _translate_availability(availability):
return {
"0": (2, "Missing"),
"1": (0, "Present"),
"2": (1, "Partially Unavailable"),
}[availability]
def _parse_legacy_line(line, temp_unit):
"""
>>> [i for i in _parse_legacy_line(['1', 'blah', '2CD', '1', '30', '20', '8'], 'C')]
[('general', {'Watchdog 1': {'descr': 'blah', 'availability': (0, 'available')}}), ('temp', {'Temperature 1': ('30', 'C')}), ('humidity', {'Humidity 1': '20'}), ('dew', {'Dew point 1': ('8', 'C')})]
"""
sensor_id = line[0]
yield "general", {
"Sensor %s"
% sensor_id: {"descr": line[1], "availability": _translate_availability(line[3])},
}
yield "temp", {"Temperature %s" % sensor_id: (line[4], temp_unit)}
# yield "humidity", {"Humidity %s" % sensor_id: line[5]}
# yield "dew", {"Dew point %s" % sensor_id: (line[6], temp_unit)}
def _parse_line(line, temp_unit):
"""
>>> [i for i in _parse_line(['1', 'blah', '1', '30', '20', '8'], 'C')]
[('general', {'Watchdog 1': {'descr': 'blah', 'availability': (0, 'available')}}), ('temp', {'Temperature 1': ('30', 'C')}), ('humidity', {'Humidity 1': '20'}), ('dew', {'Dew point 1': ('8', 'C')})]
"""
sensor_id = line[1]
yield "general", {
"%s Sensor"
% sensor_id: {"descr": line[1], "availability": _translate_availability(line[2])},
}
yield "temp", {"%s Temperature" % sensor_id: (line[3], temp_unit)}
# yield "humidity", {"%s Humidity" % sensor_id: line[4]}
# yield "dew", {"%s Dew Point" % sensor_id: (line[5], temp_unit)}
def parse_watchdog_sensors(info):
parsed = {}
general, data = info
if not general:
return parsed
temp_unit = {
"1": "C",
"0": "F",
"": "C",
}[general[0][1]]
version = int(general[0][0].replace(".", ""))
if version <= 300:
line_parser = _parse_legacy_line
else:
line_parser = _parse_line
for line in data:
for sensor_type, parsed_line in line_parser(line, temp_unit):
parsed.setdefault(sensor_type, {}).update(parsed_line)
return parsed
# .
# .--general-------------------------------------------------------------.
# | _ |
# | __ _ ___ _ __ ___ _ __ __ _| | |
# | / _` |/ _ \ '_ \ / _ \ '__/ _` | | |
# | | (_| | __/ | | | __/ | | (_| | | |
# | \__, |\___|_| |_|\___|_| \__,_|_| |
# | |___/ |
# +----------------------------------------------------------------------+
# | |
# '----------------------------------------------------------------------'
def inventory_watchdog_sensors(parsed):
for key in parsed.get("general", {}):
yield (key, {})
def check_watchdog_sensors(item, params, parsed):
data = parsed.get("general", {}).get(item)
if not data:
return
descr = data["descr"]
state, state_readable = data["availability"]
yield state, state_readable
if not descr == "":
yield 0, "Location: %s" % descr
check_info["watchdog_sensors"] = {
"parse_function": parse_watchdog_sensors,
"inventory_function": inventory_watchdog_sensors,
"check_function": check_watchdog_sensors,
"service_description": "%s",
"snmp_info": [
(
".1.3.6.1.4.1.21239.5.1.1",
[
"2", # GEIST-V4-MIB::productVersion
"7", # GEIST-V4-MIB::temperatureUnits
],
),
(
".1.3.6.1.4.1.21239.5.1",
[
OID_END,
"4.1.3", # GEIST-V4-MIB::tempSensorLabel
"4.1.4", # GEIST-V4-MIB::tempSensorAvail
"4.1.5", # GEIST-V4-MIB::tempSensorTemp
# "4.1.6", # GEIST-V4-MIB::internalTemp but internalHumidity if version 3.2.0
# "4.1.7", # GEIST-V4-MIB::internalHumidity but internalDewPoint if version 3.2.0
# "4.1.8", # GEIST-V4-MIB::internalDewPoint but empty if version 3.2.0
],
),
],
"snmp_scan_function": lambda oid: oid(".1.3.6.1.2.1.1.2.0").startswith(".1.3.6.1.4.1.21239.5.1")
or oid(".1.3.6.1.2.1.1.2.0").startswith(".1.3.6.1.4.1.21239.42.1"), # firmware upgrade
}
# .
# .--temp----------------------------------------------------------------.
# | _ |
# | | |_ ___ _ __ ___ _ __ |
# | | __/ _ \ '_ ` _ \| '_ \ |
# | | || __/ | | | | | |_) | |
# | \__\___|_| |_| |_| .__/ |
# | |_| |
# +----------------------------------------------------------------------+
# | |
# '----------------------------------------------------------------------'
def inventory_watchdog_sensors_temp(parsed):
for key in parsed.get("temp", {}):
yield (key, {})
def check_watchdog_sensors_temp(item, params, parsed):
data = parsed.get("temp", {}).get(item)
if not data:
return None
temperature_str, unit = data
return check_temperature(
float(temperature_str) / 10.0,
params,
"check_watchdog_sensors.%s" % item,
dev_unit=unit.lower(),
)
check_info["watchdog_sensors.temp"] = {
"inventory_function": inventory_watchdog_sensors_temp,
"check_function": check_watchdog_sensors_temp,
"service_description": "%s ",
"has_perfdata": True,
"group": "temperature",
}
# .
# .--humidity------------------------------------------------------------.
# | _ _ _ _ _ |
# | | |__ _ _ _ __ ___ (_) __| (_) |_ _ _ |
# | | '_ \| | | | '_ ` _ \| |/ _` | | __| | | | |
# | | | | | |_| | | | | | | | (_| | | |_| |_| | |
# | |_| |_|\__,_|_| |_| |_|_|\__,_|_|\__|\__, | |
# | |___/ |
# +----------------------------------------------------------------------+
# | |
# '----------------------------------------------------------------------'
factory_settings["watchdog_sensors_humidity_default_levels"] = {
"levels": (50, 55),
"levels_lower": (10, 15),
}
def inventory_watchdog_sensors_humidity(parsed):
for key in parsed.get("humidity", {}):
yield (key, {})
def check_watchdog_sensors_humidity(item, params, parsed):
data = parsed.get("humidity", {}).get(item)
if not data:
return
humidity = int(data)
warn, crit = params["levels"]
warn_lower, crit_lower = params["levels_lower"]
yield 0, "%.1f%%" % humidity, [("humidity", humidity, warn, crit)]
if humidity >= crit:
yield 2, "warn/crit at %s/%s" % (warn, crit)
elif humidity <= crit_lower:
yield 2, "warn/crit at %s/%s" % (warn, crit)
elif humidity >= warn:
yield 1, "warn/crit below %s/%s" % (warn, crit)
elif humidity <= warn_lower:
yield 1, "warn/crit below %s/%s" % (warn, crit)
check_info["watchdog_sensors.humidity"] = {
"inventory_function": inventory_watchdog_sensors_humidity,
"check_function": check_watchdog_sensors_humidity,
"service_description": "%s",
"has_perfdata": True,
"group": "humidity",
"default_levels_variable": "watchdog_sensors_humidity_default_levels",
}
# .
# .--dew-----------------------------------------------------------------.
# | _ |
# | __| | _____ __ |
# | / _` |/ _ \ \ /\ / / |
# | | (_| | __/\ V V / |
# | \__,_|\___| \_/\_/ |
# | |
# +----------------------------------------------------------------------+
# | |
# '----------------------------------------------------------------------'
def inventory_watchdog_sensors_dew(parsed):
for key in parsed.get("dew", {}):
yield (key, {})
def check_watchdog_sensors_dew(item, params, parsed):
data = parsed.get("dew", {}).get(item)
if not data:
return
dew = float(data[0]) / 10.0
unit = data[1]
if unit == "F":
dew = 5.0 / 9.0 * (dew - 32)
yield check_temperature(dew, params, "check_watchdog_sensors.%s" % item)
check_info["watchdog_sensors.dew"] = {
"inventory_function": inventory_watchdog_sensors_dew,
"check_function": check_watchdog_sensors_dew,
"service_description": "%s",
"has_perfdata": True,
"group": "temperature",
}
Any help is much appreciated!