Check_MK: Inventory erweitern mit SNMP Daten

Check_MK hat seit Version 1.2.5i1 das Feature Inventory an Board. Per Default werden von Systemen CPU, Memory, Harddisks, Softwarepakete und vieles mehr eingesammelt. Die Anleitung dient dazu das Inventory zu erweitern und eigene Informationen per SNMP einzusammeln und per View durchsuchbar zu machen.

Ich habe mittlerweile mehrere eigene Ergänzungen gemacht, darunter CDP Neighbors, Dot1X Authentications, Wireless Accesspoints und Hardware Inventory von Cisco Geräten.

Als Beispiel zeige ich das Cisco Hardware Inventory mit Seriennummern.

Bestandteile für eine Inventory Erweiterung:

  1. Daten sammeln -> Erweiterung für den Inventory Collector unter  ~/local/share/check_mk/inventory/
  2. Daten darstellen -> Erweiterung für die Inventory Views unter ~/local/share/check_mk/web/plugins/views/

1. Daten sammeln

Die Inventory Daten werden innerhalb einer Baumstruktur abgelegt. Man kann für seine eigenen Daten neue Knoten erzeugen. z.B. unter networking das hw_inventory wird im Tree dargestellt als networking.hw_inventory: . Der Doppelpunkt zeigt an das Daten unterhalb des Knotens folgen.

Das Inventory Plugin besteht aus einer Funktion und dem inv_info Directory welches alle Inventory Plugins kennt. In inv_info  im Key snmp_scan_function ist genauso wie bei den Check_MK SNMP Checks angegeben ob Check_MK überhaupt Daten finden wird bei einem SNMP Bulkwalk. snmp_info beinhaltet die OID und alle Untertabellen mit Daten die von Check_MK eingesammelt werden sollen.

Beispiel: ~/local/share/check_mk/inventory/my_hw_inventory.py

#!/usr/bin/python

port = {
0: "-",
1: "other",
2: "unknown",
3: "chassis",
4: "backplane",
5: "container",
6: "powerSupply",
7: "fan",
8: "sensor",
9: "module",
10: "port",
11: "stack",
12: "cpu"

}

def inv_hw_inventory(info, params):
    
    node = inv_tree("networking.hw_inventory:")

    for x in info[0]:
        
        #print x
        
        # If Serial Number is longer than 1 char
        if len(x[10]) >= 1:
        
            fru = "true" if "1" in x[15] else "false"
            
            classx = port[int(x[4])] if len(x[4]) is 1 else port[0]
            
            node.append(
            {
            "index": x[0],
            "description": x[1],
            "vendor_type": x[2],
            "contained_in_id": x[3],
            "class": classx,
            "parent_rel_pos": x[5],
            "name": x[6],
            "hw_rev": x[7],
            "fw_rev": x[8],
            "sw_rev": x[9],
            "serial_number": x[10],
            "manufactor": x[11],
            "model": x[12],
            "alias": x[13],
            "asset_id": x[14],
            "is_fru": fru,
            }
            )
        

inv_info["inv_hw_inventory"] = {
"inv_function": inv_hw_inventory,
"snmp_info": [(".1.3.6.1.2.1.47.1.1.1.1",[OID_END, # entPhysicalIndex
                                        "2", # entPhysicalDescr
                                        "3", # entPhysicalVendorType
                                        "4", # entPhysicalContainedIn
                                        "5", # entPhysicalClass
                                        "6", # entPhysicalParentRelPos
                                        "7", # entPhysicalName
                                        "8", # entPhysicalHardwareRev
                                        "9", # entPhysicalFirmwareRev
                                        "10", # entPhysicalSoftwareRev
                                        "11", # entPhysicalSerialNum                                        
                                        "12", # entPhysicalMfgName
                                        "13", # entPhysicalModelName
                                        "14", # entPhysicalAlias
                                        "15", # entPhysicalAssetID
                                        "16", # entPhysicalIsFRU
                                             ]),
             ],
"snmp_scan_function": lambda oid: oid(".1.3.6.1.2.1.1.2.0").startswith(".1.3.6.1.4.1.9.1"),
}

Mit der inv_tree Funktion wird ein neuer Inventory Baum eröffnet (siehe Code). Alle eingesammelten Informationen werden dann an diesen neuen Baum mit append als Dictionary hinzugefügt.

Die eigene Inventory Funktion kann man testen mit:

OMD[dev1]:~/local/share/check_mk/web/plugins/views$ cmk -v -i testswitch
Doing HW/SW-Inventory for testswitch...inv_hw_inventory snmp_extended_info snmp_os snmp_info ..unchanged..1603 entries..OK

Wenn in der Inventory Funktion ein pprint.pprint(info) eingebaut wird können auch die Rohdaten betrachtet werden.

2. Daten darstellen

Hierfür muss ein View gebaut werden der die Informationen des neuen Inventory Baums darstellt.

Beispiel ~/local/share/check_mk/web/plugins/views/my_inv_hw_inventory.py

#!/usr/bin/python

inventory_displayhints.update({

        ".networking.hw_inventory:"                          : { "title" : _("HW Inventory"), "render" : render_inv_dicttable,  "view" : "invhwi_of_host", "keyorder": 
                                                               ["index","name","description","model","contained_in_id","serial_number","hw_rev","fw_rev","sw_rev","class","manufactor","asset_id","alias","is_fru"] },
        ".networking.hw_inventory:*.index"                   : { "title" : _("Index") },
        ".networking.hw_inventory:*.description"             : { "title" : _("Description") },
        ".networking.hw_inventory:*.contained_in_id"         : { "title" : _("Contained in Index") },
        ".networking.hw_inventory:*.class"                   : { "title" : _("Class") },
        ".networking.hw_inventory:*.name"                    : { "title" : _("Name") },
        ".networking.hw_inventory:*.hw_rev"                  : { "title" : _("HW REV") },
        ".networking.hw_inventory:*.fw_rev"                  : { "title" : _("FW REV") },
        ".networking.hw_inventory:*.sw_rev"                  : { "title" : _("SW REV") },
        ".networking.hw_inventory:*.serial_number"           : { "title" : _("Serial Number") },
        ".networking.hw_inventory:*.manufactor"              : { "title" : _("Manufactor") },
        ".networking.hw_inventory:*.model"                   : { "title" : _("Model") },
        ".networking.hw_inventory:*.alias"                   : { "title" : _("Alias") },
        ".networking.hw_inventory:*.asset_id"                : { "title" : _("Asset ID") },
        ".networking.hw_inventory:*.is_fru"                  : { "title" : _("Is FRU") },
})

declare_invtable_view("invhwi", ".networking.hw_inventory:", _("HW Inventory"), _("HW Inventory"))

Danach sollte man mit „omd restart apache && cmk -v -R“ Check_MK und den Apachen neu starten, damit die neuen Views sichtbar werden. Damit Daten angezeigt werden muss 1 mal das Inventory auf dem Gerät gelaufen sein.

Im Views Menü sollte dann unser neuer View unter Inventory auftauchen:

Man kann sich alle Daten anzeigen lassen oder gezielt nach einzelnen Informationen oder Geräten suchen.

Wenn man im Host View ist kann man über das obere Menü auch direkt zu den Inventory Daten kommen, wurde der Button noch nicht genutzt kann er sichtbar gemacht werden mit dem „…“ Button.

Die Daten werden für den Host als Baumstruktur dargestellt.

Viel Spaß beim Erweitern 😉