Check_MK: SNMP based Check

Neben der Möglichkeit lokale Scripts per Agent oder Agent Plugins zu verwenden gibt es noch die Option Werte direkt per SNMP von Geräten auszulesen. Bei diesem Beispiel ist auch eine Erweiterung dabei damit in WATO eine Regel erstellt werden kann mit den Parametern für den Check. Performance Werte sind in dem Beispiel ebenfalls integriert.

Die anderen HowTos sind unter Agent Plugin Check und Local Check zu finden.

 

Aufbau eines SNMP Checks

Der SNMP Check besteht genau so wie der Agent based Check aus drei Bestandteilen.

  1. Inventory Funktion
  2. Check Funktion
  3. check_info Directory

Hier ein Beispiel Check dazu, der Check wird abgelegt in ~/local/share/check_mk/checks/:

#!/usr/bin/python

default_mycanon = (500,20000)

def inventory_mycanon(info):

    for i in info:
        idx, frag, pages = i
        yield idx, default_mycanon


def check_mycanon(item, params, info):

    perf=[]

    for i in info:
        idx, frag, pages_s = i

        if idx == item:
            warn, crit = params
            pages = int(pages_s)

    perf = [("pages",pages, warn, crit), ("page_rate",get_rate("page_rate", time.time(), pages), warn, crit)]


    if pages >= crit:
        status = 2
    elif pages >= warn:
        status = 1
    else:
        status = 0

    return status, "%d pages (w:%d/c:%d) %s" % (pages, warn, crit, get_item_state("buh")), perf


check_info["mycanon"] = {
    "inventory_function":   inventory_mycanon,
    "check_function":       check_mycanon,
    "service_description":  "Printer FooBar",
    "snmp_scan_function":   lambda oid: "canon" in oid(".1.3.6.1.2.1.1.1.0").lower(),
    "snmp_info":            ( ".1.3.6.1.4.1.1602.1.11.1.4.1", ["2", "3", "4"]),
    "has_perfdata":         True,
    "group":                "mycanon",
}

Im Gegensatz zu den anderen Checks beginne ich in umgekehrter Reihenfolge mit den einzelnen Bausteinen weil in dem check_info Dictionary definiert ist wo die Inventory Funktion und die Check Funktion ihre Daten her bekommen.

Das check_info Dictionary

check_info["mycanon"] = {
    "inventory_function":   inventory_mycanon,
    "check_function":       check_mycanon,
    "service_description":  "Printer FooBar",
    "snmp_scan_function":   lambda oid: "canon" in oid(".1.3.6.1.2.1.1.1.0").lower(),
    "snmp_info":            ( ".1.3.6.1.4.1.1602.1.11.1.4.1", ["2", "3", "4"]),
    "has_perfdata":         True,
    "group":                "mycanon",
}

Genauso wie bei dem Agent Check muss auch beim SNMP Check die Inventory Funktion und die Check Funktion angegeben werden. Die Service Description ist der Name unter dem später der Check in Check_MK im Host auftaucht.

Die snmp_scan_function wird verwendet um festzustellen ob Check_MK überhaupt auf diesem Gerät tätig wird. Nur wenn der Scan erfolgreich ist wird per SNMP BULK WALK die OIDs die in snmp_info angegeben sind abgerufen.

Bei dem Testgerät handelt es sich um einen Canon Drucker, bei einem SNMP Get auf die OID .1.3.6.1.2.1.1.1.0 gibt er folgenden String zurück „Canon iR C1021 /P“. Die Lambda Funktion überprüft ob in der OID .1.3.6.1.2.1.1.1.0 der String „canon“ vorkommt. Dabei wird die Rückgabe von oid(„.1.3.6.1.2.1.1.1.0“) mit lower() in Lowercase umgewandelt um den Vergleich zu vereinfachen.Hier gibt es noch verschiedene andere Möglichkeiten um zu bestimmen ob der Check zum Gerät passt. Am besten sich dazu die Check_MK eigenen Checks ansehen unter: ~/share/check_mk/checks

In snmp_info werden die OIDs angegeben die Abgerufen werden. Wenn es nur eine OID ist so ist ein Tuple mit OID und den entsprechenden einzelnen Untertabellen anzugeben. Sind es mehrere OIDs sind die Tuples in eine Liste zu verpacken.

"snmp_info":            ( ".1.3.6.1.4.1.1602.1.11.1.4.1", ["2", 
                                                           "3",
                                                           "4"
                        ]),

In dem Beispiel rufen wir jetzt drei Untertabellen der OID .1.3.6.1.4.1.1602.1.11.1.4.1 ab. Diese werden an den Check für die Inventory Funktion und die Check Funktion als verschachtelte Liste übergeben.

Um das zu Testen geben wir die info in der Inventory Funktion mit pprint aus:

def inventory_mycanon(info):
    pprint.pprint(info)

Ausgabe auf der Shell:

OMD[test1]:~/local/share/check_mk/checks$ cmk -v -II printer-canon-c1021
Discovering services on printer-canon-c1021:
printer-canon-c1021:
[[u'101', u'', u'1'],
 [u'102', u'', u'1'],
 [u'104', u'', u'1'],
 [u'108', u'', u'8930'],
 [u'113', u'', u'8930'],
 [u'114', u'', u'2994'],
 [u'123', u'', u'11147'],
 [u'127', u'', u'18618'],
 [u'133', u'', u'7877'],
 [u'148', u'', u'10741'],
 [u'201', u'', u'1459'],
 [u'202', u'', u'1459'],
 [u'222', u'', u'1053'],
 [u'230', u'', u'406'],
 [u'231', u'', u'406'],
 [u'232', u'', u'406']]

In der Liste sind weitere Listen die den Werten aus der SNMP Anfrage entsprechen. Aus der ersten Liste [u’101′, u“, u’1′] ist der 1. Wert aus der 2. Untertabelle, der 2. Wert aus der 3. Untertabelle und der 3. Wert aus der 4. Untertabelle. (siehe oben bei snmp_info)

Inventory Funktion

default_mycanon = (500,20000)

def inventory_mycanon(info):

    for i in info:
        idx, frag, pages = i
        yield idx, default_mycanon

Die Inventory Funktion erkennt neue Services und legt diese in Check_MK an. Der Funktion wird das SNMP BULK WALK Ergebnis übergeben als Liste. (siehe oben) Diese einfache Inventory Funktion legt für jede Subliste einen neuen Service an. Dem yield Generator wird ein Tuple übergeben mit eindeutigem Servicenamen und den Default Parametern für den Check.

Check Funktion

def check_mycanon(item, params, info):

    perf=[]

    for i in info:
        idx, frag, pages_s = i

        if idx == item:
            warn, crit = params
            pages = int(pages_s)

    perf = [("pages",pages, warn, crit), ("page_rate",get_rate("page_rate", time.time(), pages), warn, crit)]


    if pages >= crit:
        status = 2
    elif pages >= warn:
        status = 1
    else:
        status = 0

    return status, "%d pages (w:%d/c:%d)" % (pages, warn, crit), perf

Die Check Funktion beinhaltet die Logik welche überprüft in welchem Zustand sich ein Service befindet (0=OK, 1=WARNING, 2=CRITICAL, 3=UNKNOWN).

Der Check Funktion werden 3 Variablen übergeben: item, params, info

Variable item

Der Variable wird der Servicename übergeben

Variable params

Hier werden die Parameter übergeben die beim Inventory oder durch eine WATO Regel für den Service gesetzt sind.

Variable info

Hier wird die komplette Ausgabe des Agent Check Plugins als Liste übergeben so wie bei der Inventory Funktion.

Schritt 1: Aus info Liste das richtige Item suchen

for i in info:
       idx, frag, pages_s = i

       if idx == item:
           warn, crit = params
           pages = int(pages_s)

Die Liste wird durchgegangen und mit einer IF Anweisung wird verglichen ob es sich um den richtigen Datensatz handelt, wenn True wird das Parameter Tuple in die Variablen warn und vrit gespeichert. Der dritte Wert der Liste ist die Seitenanzahl und die muss noch von einem Unicode String umgewandelt werden zu einem Integer int(pages_s).

Schritt 2: Performance Werte

perf = [("pages",pages, warn, crit), ("page_rate",get_rate("page_rate", time.time(), pages), warn, crit)]

Die Performance Werte werden als Liste übergeben. In der Liste sind wiederum Tupels.

Der Tuple ist wie folgt aufgebaut:

(„<name_des_counters>“, <aktueller_wert>, <warn_wert>, <crit_wert>)

Nettes Feature in Check_MK:

Es gibt die Funktion get_rate welche Werte speichern kann und eine Rate pro Sekunde errechnen kann. Dazu ist eine eindeutige Identifier zu bestimmen und es muss die aktuelle Zeit mitgegeben werden damit Check_MK die Rate berechnen kann. Das gleiche gibt es auch für Average Werte, auch ist es möglich Werte ohne Berechung einfach zu speichern bis zur nächsten Check Ausführung (set_item_state(), get_item_state()).

Schritt 3: Status Logik

Der Status des Checks wird als 0 = OK, 1 = WARNING, 2 = CRITICAL oder 3 = UNKNOWN übergeben.

if pages >= crit:
    status = 2
elif pages >= warn:
    status = 1
else:
    status = 0

Schritt 4: Return oder Yield des Checkergebnisses

return status, "%d pages (w:%d/c:%d)" % (pages, warn, crit), perf

Als letztes wird ein Tuple zusammengebaut das aus 3 Werten besteht:

STATUS, MESSAGE, PERFORMANCEVALUES

Es gibt die Möglichkeit auch das dem yield Generator zu übergeben, statt return wird dann yield verwendet. Check_MK aggregiert dann alle Ergebnisse nacheinander. Dazu kommt in einem anderen Artikel noch weitere Informationen.

WATO Erweiterung für eigene Parameter

Ich habe in unserem Beispiel default Parameter definiert die für jeden Check angelegt werden. Wenn man jetzt für einen Host, Service oder Host/Service die Werte anpassen möchte und es bequem über WATO erledigen will muss man WATO erweitern.

WATO Erweiterungen befinden sich unter ~/lokal/share/check_mk/web/plugins/wato/ und müssen die Dateiendung .py haben. Auch muss zwingend der Apache neu gestartet werden. Das geht auf der OMD Konsole mit „omd restart apache“.

#!/usr/bin/python

register_check_parameters(
    # Category
    "Printers",
    # Group
    "mycanon",
    # Rulename
    "Printer pages max values",
    #Parameter
    Tuple(
        title = "Printer pages max value",
        help = "Define critical and warning values",
        elements = [
            Integer(title="Warn at", unit="pages"),
            Integer(title="Critical at", unit="pages"),
        ]
    ),
    #Item
    TextAscii(
        title = "Item Name",
        help = "Help for the item"
    ),
    #Match
    match_type = "first"
)

Wir haben als default Parameter ein Tuple gespeichert mit 2 Werten, Warn und Crit. Dementsprechend muss unsere WATO Regel ebenfalls ein Tuple mit 2 Werten erzeugen.

Die Funktion register_check_parameters() erzeugt eine neue möglichkeit Regeln zu definieren.

Die Funktion erwartet 6 Parameter:

1 Kategorie – Die Kategorie ist die Rubrik unter der die neue Regel angezeigt wird.

2 Group – Die Gruppe macht die Zuordnung zum Check. Im Check im check_info gibt es hierfür im Dictionary den Key „group“. (siehe oben im Beispiel)

3 Rulename – Der Rulename wird in der Übersicht angezeigt

4 Parameter – Hier werden die Parameter definiert.

5 Item – Es gibt hier 2 Möglichkeiten:

None – Die Regel kann nur für den Host definiert werden und gilt für alle Services die auf die Group matchen.

TextAscii( title = „Item Name“, help = „Help for the item“ ) –  Hier kann ein Servicename definiert werden, die Regel gilt dann nur für einen bestimmten Servicenamen

6 Matchtype – Es gibt 2 Matchtypen:

first – Die erste Regel die Zutrifft wird angewendet.

dict – Eine Kombination aus mehreren Werten ist möglich aus mehreren Regeln. Der Typ ist zwingend wenn der äußere Parametertyp Dictionary ist.

Der Parameter Block

#Parameter
    Tuple(
        title = "Printer pages max value",
        help = "Define critical and warning values",
        elements = [
            Integer(title="Warn at", unit="pages"),
            Integer(title="Critical at", unit="pages"),
        ]
    ),

Das äußere Tuple() ist eine von Check_MK bereitgestellte Funktion, es gibt noch viele weitere (z.B. TextAscii, Integer, Float, ListOf, Dictionary, etc.) Weitere Beispiele findet ihr direkt im Check_MK Code unter ~/share/check_mk/web/plugins/wato/.

Das Tuple() hat in diesem Fall 3 Übergabewerte:

title – Gibt den Titel der Werte an

help – Wenn die Hilfe aktiviert ist (Buch rechts oben in der Ecke) werden die Hilfstexte angezeigt

elements – Sind die Werte die in WATO eingegeben werden können, diese können beliebig oft, entsprechend dem Datenformat, verschachtelt werden. In elements befinden sich unsere 2 Integer() Werte Warn und Crit.

Zu den WATO Erweiterungen wird noch ein gesonderter Artikel folgen den ich hier verlinken werde.

Fertig ??

Jetzt können wir den Check mal Testen, dazu in WATO ein „Tabula Rasa“ für den Host machen, der neue Check sollte dann auftauchen.

Viel Spaß beim Spielen 🙂

 

Schreibe einen Kommentar

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.