Wie schreibt man an besten einen Check für eine REST API Abfrage

Das ist witzig. Ich habe gerade vor ein paar Tagen einen Special Agent geschrieben. Der fragt zwar keine REST-Schnittstelle ab, aber was du vorhast, klingt für mich genau danach.

Du brauchst vier Dateien:

  • Ein WATO-Plugin, in dem du die Aufruf-Parameter für den Special Agent festlegen kannst (Username, Passwort, URL)
  • Ein Check-Plugin, das aus diesen WATO-Parametern eine Argumentliste zusammenbaut, mit der dein Special Agent aufgerufen wird.
  • Den Special Agent selbst. Das ist ein beliebiges Skript (oder Binary), das wie ein Agent-Plugin irgendwelche Abfragen macht und dann seine Ausgabe in einer oder mehreren <<<sections>>> nach STDOUT schreibt
  • Das/die eigentliche(n) Check-Plugin(s). Sie unterscheiden sich nicht von anderen Check-Plugins, d.h. sie kriegen die Daten ganz normal in ihre parse/inventory/check-Funktionen reingereicht.

WATO-Plugin
#!/usr/bin/env python3
# -*- mode: Python; encoding: utf-8; indent-offset: 4; autowrap: nil -*-

from cmk.gui.i18n import _
from cmk.gui.valuespec import (
    Dictionary,
    TextAscii,
    PasswordSpec,
)

from cmk.gui.plugins.wato import (
    rulespec_registry,
    HostRulespec,
)

from cmk.gui.plugins.wato.datasource_programs import (
    RulespecGroupDatasourcePrograms,
)

def _valuespec_special_agents_my_rest_api():
    return Dictionary(
        elements=[
            ("uid", TextAscii(title=_("Username"), allow_empty=False)),
            ("pwd", PasswordSpec(title=_("Password"), allow_empty=False, hidden=True)),
            ("url, TextAscii(title=_("URL"), allow_empty=False)),
        ],
        optional_keys=False,
        title=_("REST Parameters"),
    )

rulespec_registry.register(
    HostRulespec(
        group=RulespecGroupDatasourcePrograms,
        name="special_agents:my_rest_api",
        valuespec=_valuespec_special_agents_my_rest_api,
    ))
Check-Plugin für den Aufruf
#!/usr/bin/env python3
# -*- encoding: utf-8; py-indent-offset: 4 -*-

def agent_my_rest_api_arguments(params, hostname, ipaddress):
    args = []
    args.append(params['uid'])
    args.append(params['pwd'])
    args.append(params['url'])
    args.append('--test')
    return args

special_agent_info['my_rest_api'] = agent_my_rest_api_arguments
Special-Agent
#!/usr/bin/env bash

uid=$1;
pwd=$2;
url=$3;
test=$4;

OUTPUT=$(curl -v -X GET -u $uid:$pwd "$url")
do_something_with $OUTPUT;

echo "<<<my_rest_api>>>"
echo $OUTPUT
Check-Plugin(s)

Hier brauchst du nur ein ganz normales Plugin für die Section <<<my_rest_api>>>. Dein Special Agent kann auch mehrere <<<sections>>> schreiben, dann brauchst du halt mehrere Check-Plugins.


Du würdest den Special-Agent natürlich nicht in bash schreiben, sondern z.B. in Python, denn dann kannst du leicht über die zurückgegebene JSON-Struktur iterieren und daraus sowas wie

<<<my_rest_api>>>
network mac=00:0c:82:00:00:06 dhcp=0 addr=192.168.1.1 ...
...

machen. Wichtig ist die Namensgebung der Dateien, denn manche müssen agent_ davor heißen:

  • Check-Plugin: ~/local/share/check_mk/checks/my_rest_api
  • Parameter-Bauer: ~/local/share/check_mk/checks/agent_my_rest_api
  • Special Agent: ~/local/share/check_mk/agents/special/agent_my_rest_api
  • WATO: ~/local/share/check_mk/web/plugins/wato/my_rest_api.py

Ist das ungefähr das, was Du meinst?

Was dann noch fehlt, ist natürlich eine Regel, wonach dein Host nicht per checkmk-Agent sondern mit deiner neuen Datasource (aka Special Agent) abgefragt wird.


EDIT: Ich habe oben geschrieben, der Special Agent soll eine Section <<<my_rest_api>>> ausgeben. Das ist nicht ganz richtig: er kann so viele Sections ausgeben wie er will und die können auch heißen, wie sie wollen (von bereits vergebenen Namen mal abgesehen). Du brauchst dann halt für jede Section ein eigenes “normales” Check-Plugin.

11 Likes