# check-mqtt A [Nagios]/[Icinga] plugin for checking connectivity to an [MQTT] broker. Or with --readonly monitor an mqtt application. Or for checking the status of MQTT clients maintaining the status on an MQTT broker. This plugin connects to the specified broker and subscribes to a topic. Upon successful subscription, a message is published to said topic, and the plugin expects to receive that payload within `max_wait` seconds. ## Prerequisite This module uses the [paho-mqtt] package. Currently it is not compatible to the latest version of the package (paho-mqtt 2.0.0). Please use `pip install paho-mqtt<2`, or use a virtual environment. This module can use jsonpath-rw. To install, use `$ pip install jsonpath-rw` ## Configuration Configuration can be done via the following command line arguments: ``` usage: check-mqtt.py [-h] [-d|--debug] [-H ] [-P ] [-u ] [-p ] [-m ] [-e ] [--sleep ] [-a ] [-C ] [-k ] [-n] [-t ] [-s ] [-r] [-l ] [-j ] [-v ] [-o ] [-w ] [-c ] [-S] [-V] Nagios/Icinga plugin for checking connectivity or status of MQTT clients on an MQTT broker. optional arguments: -h, --help show this help message and exit -d, --debug enable MQTT logging -H , --host mqtt host to connect to (default: 'localhost') -P , --port network port to connect to (default: 1883) -u , --username MQTT username (default: None) -p , --password MQTT password (default: None) -m , --max-wait maximum time to wait for the check (default: 4 seconds) -e , --keepalive maximum period in seconds allowed between communications with the broker (default: 60 seconds) --sleep main loop sleep period in seconds (default: 0.1 seconds) -a , --cafile cafile (default: None) -C , --certfile certfile (default: None) -k , --keyfile keyfile (default: None) -n, --insecure suppress TLS verification of server hostname -t , --topic topic to use for the active check (default: 'nagios/test') -s , --subscription topic to use for the passive check (default: 'None') -r, --readonly just read the value of the topic -l , --payload payload which will be PUBLISHed (default: PiNG). If it starts with an exclamation mark (!) the output of the command will be used -j , --jsonpath if given, payload is interpreted as JSON string and value is extracted using (default: 'None') -v , --value value to compare against received payload (default: 'PiNG'). If it starts with an exclamation mark (!) the output of the command will be used -o , --operator operator to compare received value with value. Choose from ['eq', 'equal', 'lt', 'lessthan', 'gt', 'greaterthan', 'ct', 'contains'] (default: 'equal'). 'eq' compares Strings, the other convert the arguments to float before compare -w , --warning Exit with WARNING status if is true (default: 'None'). can be any Python expression, use within expression for current payload value. -c , --critical Exit with CRITICAL status if is true (default: 'None'). can be any Python expression, use within expression for current payload value. -S, --short use a shorter string on output -V, --version show program's version number and exit ``` There are no required arguments, defaults are displayed using `--help`. If `--warning` and/or `--critical` is used then possible given `--operator` and `--value` arguments are ignored.
hostname, port, username, password
used to connect to a MQTT broker
cafile certfile keyfile insecure
optional used for an encrypted TLS connection, for details see mosquitto.conf - Certificate based SSL/TLS Support.
max_wait
is the time (integer) we're willing to wait for a SUB to the topic we PUBlish on. If we don't receive the MQTT PUB within this many seconds we exit with _CRITICAL_
keepalive
maximum period in seconds (integer) allowed between communications with the broker. If no other messages are being exchanged, this controls the rate at which the client will send ping messages to the broker
sleep
period in seconds (float) to sleep in main loop - may reduce cpu load if a lot of processes (>100) are running.
topic
topic where the payload will be published when we have received the subscribed message.
payload
payload to publish on topic.
subscription
topic to use for the passive check - read only. If subscription is not given it will be set to topic
readonly
just read on subscription, do not publish any payload on topic
jsonpath
a JSONPath expression refering to a JSON structure (for JSONPath syntax see JSONPath expressions)
value, operator
value to compare against received payload. The comparison is done using one of the listed (see help above) operators. The returned status is OK if the comparison is true, otherwise it will return CRITICAL. If -w (--warning) or -c (--critical) argument is used, value and operator will be ignored.
warning, critical
a warning and/or critical expression. Use the word payload within your formular to refer to the read payload value.
If both are given (warning and critical) the critical expression overrule the warning. <exp> can be any valid pyhton expression inclusive build-in and standard library functions e. g. conversion like str(), float()...
Using one of them a possible --value and/or --operator argument will be ignored.
short
if set it will use a short string layout for returned message
## Examples #### simple ``` ./check-mqtt.py -H localhost -P 1883 -u user -p password -t nagios/test -m 10 OK - message from nagios/test at localhost in 0.00 | response_time=0.10 value=PiNG ``` #### Status check ``` ./check-mqtt.py -H localhost -t devices/mydevice/lastevent -v '!expr `date +%s` - 216000' -r -o greaterthan OK - message from devices/mydevice/lastevent at localhost in 0.05s | response_time=0.05 value=1472626997 ``` #### Ping Pong check ``` ./check-mqtt.py -H localhost -t nagios/ListenForPing -s nagios/PublishPongTo -l ping -v pong OK - message from nagios/PublishPongTo at localhost in 0.05s | response_time=0.05 value=pong ``` #### Jsonpath check ``` ./check-mqtt.py -H localhost -t devices/mydevice/sensor -v '950' -j '$.BME280.Pressure' -r -o greaterthan OK - message from devices/mydevice/sensor at localhost in 0.06s | response_time=0.06 value=1005.0 ``` #### Jsonpath check using range (warning if lower than 4° or higher than 28°, critical if minus or higher than 35°) ``` ./check-mqtt.py -H localhost -t devices/mydevice/sensor -v '950' -j '$.BME280.Temperature' -r --warning 'payload < 4 or payload >28' --critical 'payload < 0 or payload >35' OK - message from devices/mydevice/sensor at localhost in 0.06s | response_time=0.06 value=20.1 ``` ## Nagios Configuration ### command definition ``` define command{ command_name check_mqtt command_line $USER1$/check_mqtt } define command{ command_name check_myapplication command_line $USER1$/check_mqtt -i pong -t mytopic/test/myapplication } ``` ### icinga2 command definition ``` object CheckCommand "check-mqtt" { import "plugin-check-command" command = [ PluginDir + "/check-mqtt.py" ] //constants.conf -> const PluginDir arguments = { "-H" = "$mqtt_host$" "-u" = "$mqtt_user$" "-p" = "$mqtt_password$" "-P" = "$mqtt_port$" "-a" = "$mqtt_cafile$" "-c" = "$mqtt_certfile$" "-k" = "$mqtt_keyfile$" "-t" = "$mqtt_topic$" "-m" = { set_if = "$mqtt_max$" value = "$mqtt_max$" } "-l" = "$mqtt_payload$" "-v" = "$mqtt_value$" "-o" = "$mqtt_operator$" "-r" = { set_if = "$mqtt_readonly$" description = "Don't write." } "-n" = { set_if = "$mqtt_insecure$" description = "suppress TLS hostname check" } } } ``` ### service definition ``` define service{ use local-service host_name localhost service_description mqtt broker check_command check_mqtt notifications_enabled 0 } define service{ use local-service host_name localhost service_description check if myapplication is running check_command check_myapplication notifications_enabled 0 } ``` ### icinga2 host definition ``` object Host "wemos1" { import "generic-host" check_command = "check-mqtt" vars.homie = true vars.lastevent = true vars.mqtt_host = "localhost" # vars.mqtt_port = 1883 # vars.mqtt_user = "user" # vars.mqtt_password = "password" # vars.mqtt_cafile = "cafile" # vars.mqtt_certfile = "certfile" # vars.mqtt_keyfile = "keyfile" vars.mqtt_prefix = "devices/mydevice" vars.mqtt_topic = vars.mqtt_prefix + "/$$online" vars.mqtt_payload = "true" vars.mqtt_value = "true" vars.mqtt_operator = "equal" vars.mqtt_readonly = true vars.os = "Homie" vars.sla = "24x7" } ``` ### icinga2 service definition ``` apply Service "mqtt-health" { import "generic-service" check_command = "check-mqtt" assign where host.vars.mqtt == true ignore where host.vars.no_health_check == true } apply Service "homie-health" { import "generic-service" check_command = "check-mqtt" vars.mqtt_topic = host.vars.mqtt_prefix + "/$$online" vars.mqtt_payload = "true" vars.mqtt_value = "true" vars.mqtt_operator = "equal" vars.mqtt_readonly = true assign where host.vars.homie == true ignore where host.vars.no_health_check == true } apply Service "lastevent-health" { import "generic-service" check_command = "check-mqtt" vars.mqtt_topic = host.vars.mqtt_prefix + "/lastevent" vars.mqtt_payload = "true" vars.mqtt_value = "!expr `date +%s` - 21600" vars.mqtt_operator = "greaterthan" vars.mqtt_readonly = true assign where host.vars.lastevent == true ignore where host.vars.no_health_check == true } ``` [nagios]: http://nagios.org [icinga]: http://icinga.org [mqtt]: http://mqtt.org [paho-mqtt]: https://pypi.org/project/paho-mqtt