check-mqtt

A Nagios/Icinga plugin for testing an MQTT broker

Stars
63

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 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 <hostname>] [-P <port>] [-u <username>]
                     [-p <password>] [-m <seconds>] [-e <seconds>]
                     [--sleep <seconds>] [-a <cafile>] [-C <certfile>]
                     [-k <keyfile>] [-n] [-t <topic>] [-s <subscription>] [-r]
                     [-l <payload>] [-j <jsonpath>] [-v <value>]
                     [-o <operator>] [-w <expr>] [-c <expr>] [-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 <hostname>, --host <hostname>
                        mqtt host to connect to (default: 'localhost')
  -P <port>, --port <port>
                        network port to connect to (default: 1883)
  -u <username>, --username <username>
                        MQTT username (default: None)
  -p <password>, --password <password>
                        MQTT password (default: None)
  -m <seconds>, --max-wait <seconds>
                        maximum time to wait for the check (default: 4
                        seconds)
  -e <seconds>, --keepalive <seconds>
                        maximum period in seconds allowed between
                        communications with the broker (default: 60 seconds)
  --sleep <seconds>     main loop sleep period in seconds (default: 0.1
                        seconds)
  -a <cafile>, --cafile <cafile>
                        cafile (default: None)
  -C <certfile>, --certfile <certfile>
                        certfile (default: None)
  -k <keyfile>, --keyfile <keyfile>
                        keyfile (default: None)
  -n, --insecure        suppress TLS verification of server hostname
  -t <topic>, --topic <topic>
                        topic to use for the active check (default:
                        'nagios/test')
  -s <subscription>, --subscription <subscription>
                        topic to use for the passive check (default: 'None')
  -r, --readonly        just read the value of the topic
  -l <payload>, --payload <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>, --jsonpath <jsonpath>
                        if given, payload is interpreted as JSON string and
                        value is extracted using <jsonpath> (default: 'None')
  -v <value>, --value <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 <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 <expr>, --warning <expr>
                        Exit with WARNING status if <expr> is true (default:
                        'None'). <expr> can be any Python expression, use
                        <payload> within expression for current payload value.
  -c <expr>, --critical <expr>
                        Exit with CRITICAL status if <expr> is true (default:
                        'None'). <expr> can be any Python expression, use
                        <payload> 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.

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
}