Check_MK: Eigener Agent Check

Neben den lokalen Checks gibt es noch Checks die als Plugin im Agenten laufen. Der Unterschied liegt darin das auf dem Host auf dem der Agent läuft keine Bewertung der Informationen stattfindet, diese werden dem Check_MK Monitoring nur als Text zur Verfügung gestellt. Somit basiert ein Agent Plugin aus einem Host Teil (Agent Plugin) und einem Monitoring Server Teil (Check_MK Check).

Alle Dateien des DEMOs als MKP zum Download:

 

Das Agent Plugin

Hierzu ein Beispiel:

Ein Check der die aktuellen offen TCP Listener Ports ausgibt. Die Scriptsprache ist egal, die Datei muss executeable sein.

my_tcp_listener.sh Script in /usr/lib/check_mk_agent/plugins

#!/bin/bash

echo "<<<my_tcp_listener>>>"

netstat -tlpen | sed 1,2d

Im <<<>>> Block wird der Checkname angegeben.

Folgende Ausgabe erzeugt das Plugin:

mmm@home:/home/mmm$ /usr/lib/check_mk_agent/plugins/test.sh
<<<my_tcp_listener>>>
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      0          12608       621/sshd        
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      0          14982       1034/exim4      
tcp        0      0 0.0.0.0:6556            0.0.0.0:*               LISTEN      0          14882       793/xinetd      
tcp        0      0 127.0.0.1:6942          0.0.0.0:*               LISTEN      1000       869419      15640/java      
tcp        0      0 127.0.0.1:5000          0.0.0.0:*               LISTEN      999        13258       1230/apache2    
tcp        0      0 127.0.0.1:63342         0.0.0.0:*               LISTEN      1000       867186      15640/java      
tcp        0      0 0.0.0.0:34607           0.0.0.0:*               LISTEN      105        1941        599/rpc.statd   
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      0          1882        590/rpcbind     
tcp6       0      0 :::22                   :::*                    LISTEN      0          12610       621/sshd        
tcp6       0      0 :::39352                :::*                    LISTEN      105        1945        599/rpc.statd   
tcp6       0      0 ::1:25                  :::*                    LISTEN      0          14983       1034/exim4      
tcp6       0      0 :::111                  :::*                    LISTEN      0          1885        590/rpcbind     
tcp6       0      0 :::80                   :::*                    LISTEN      0          13641       1006/apache2    

Die Ausgabe wird wenn der Agent vom Server abgefragt wird angehängt. Das kann man selbst testen mit einem „telnet <host> 6556“.

In der Check Instanz auf dem Server muss nun noch ein Check geschrieben werden der die Ausgabe des Agenten verarbeiten kann.

Die eigenen Check Plugins auf dem Monitoring Server liegen unter /omd/sites/<sitename>/local/share/check_mk/checks

Beispiel zu my_tcp_listener, die Scriptsprache ist hier zwingend Python:

#!/usr/bin/python

def inventory_my_tcp_listener(info):
  for l in info:
    service_identify = "%s/%s" % (l[0], l[3].split(":")[-1])
    yield service_identify, None

def check_my_tcp_listener(item, params, info):

  proto, port = item.split("/")
  message = (2, "CRIT service not listen")

  for l in info:
    if proto in l[0] and port in l[3].split(":")[-1]:
      message = (0, "OK service listen")

  return message

check_info["my_tcp_listener"] = {
  "inventory_function" :	inventory_my_tcp_listener,
  "check_function" :	check_my_tcp_listener,
  "service_description" : "TCP Listener %s",
}

Die Bestandteile des Check_MK Server Plugins

Inventory Funktion

Die Inventory Funktion dient dazu das WATO neue Services automatisch anlegen kann. Der info Variable wird die Ausgabe des Host Plugins übergeben. Dabei wird jede Zeile in eine Python Liste umgewandelt.

Eine Debugging Ausgabe ist möglich in dem man in die Inventory Funktion direkt ein print info einbaut. Check_MK stellt auch Pretty Print aus Python bereit, das Modul muss nicht importiert werden.

print info:

OMD[test1]:~/local/share/check_mk/checks$ cmk -v -II localhost
Discovering services on localhost:
localhost:
[[u'tcp', u'0', u'0', u'0.0.0.0:22', u'0.0.0.0:*', u'LISTEN', u'0', u'12608', u'621/sshd'], [u'tcp', u'0', u'0', u'127.0.0.1:25', u'0.0.0.0:*', u'LISTEN', u'0', u'14982', u'1034/exim4'], [u'tcp', u'0', u'0', u'0.0.0.0:6556', u'0.0.0.0:*', u'LISTEN', u'0', u'14882', u'793/xinetd'], [u'tcp', u'0', u'0', u'127.0.0.1:6942', u'0.0.0.0:*', u'LISTEN', u'1000', u'869419', u'15640/java'], [u'tcp', u'0', u'0', u'127.0.0.1:5000', u'0.0.0.0:*', u'LISTEN', u'999', u'13258', u'1230/apache2'], [u'tcp', u'0', u'0', u'127.0.0.1:63342', u'0.0.0.0:*', u'LISTEN', u'1000', u'867186', u'15640/java'], [u'tcp', u'0', u'0', u'0.0.0.0:34607', u'0.0.0.0:*', u'LISTEN', u'105', u'1941', u'599/rpc.statd'], [u'tcp', u'0', u'0', u'0.0.0.0:111', u'0.0.0.0:*', u'LISTEN', u'0', u'1882', u'590/rpcbind'], [u'tcp6', u'0', u'0', u':::22', u':::*', u'LISTEN', u'0', u'12610', u'621/sshd'], [u'tcp6', u'0', u'0', u':::39352', u':::*', u'LISTEN', u'105', u'1945', u'599/rpc.statd'], [u'tcp6', u'0', u'0', u'::1:25', u':::*', u'LISTEN', u'0', u'14983', u'1034/exim4'], [u'tcp6', u'0', u'0', u':::111', u':::*', u'LISTEN', u'0', u'1885', u'590/rpcbind'], [u'tcp6', u'0', u'0', u':::80', u':::*', u'LISTEN', u'0', u'13641', u'1006/apache2']]

oder mit pprint.pprint(info)

OMD[test1]:~/local/share/check_mk/checks$ cmk -v -II localhost
Discovering services on localhost:
localhost:
[[u'tcp',
  u'0',
  u'0',
  u'0.0.0.0:22',
  u'0.0.0.0:*',
  u'LISTEN',
  u'0',
  u'12608',
  u'621/sshd'],
 [u'tcp',
  u'0',
  u'0',
  u'127.0.0.1:25',
  u'0.0.0.0:*',
  u'LISTEN',
  u'0',
  u'14982',
  u'1034/exim4'],
 [u'tcp',
  u'0',
  u'0',
  u'0.0.0.0:6556',
  u'0.0.0.0:*',
  u'LISTEN',
  u'0',
  u'14882',
  u'793/xinetd'],
 [u'tcp',
  u'0',
  u'0',
  u'127.0.0.1:6942',
  u'0.0.0.0:*',
  u'LISTEN',
  u'1000',
  u'869419',
  u'15640/java'],
 [u'tcp',
  u'0',
  u'0',
  u'127.0.0.1:5000',
  u'0.0.0.0:*',
  u'LISTEN',
  u'999',
  u'13258',
  u'1230/apache2'],
 [u'tcp',
  u'0',
  u'0',
  u'127.0.0.1:63342',
  u'0.0.0.0:*',
  u'LISTEN',
  u'1000',
  u'867186',
  u'15640/java'],
 [u'tcp',
  u'0',
  u'0',
  u'0.0.0.0:34607',
  u'0.0.0.0:*',
  u'LISTEN',
  u'105',
  u'1941',
  u'599/rpc.statd'],
 [u'tcp',
  u'0',
  u'0',
  u'0.0.0.0:111',
  u'0.0.0.0:*',
  u'LISTEN',
  u'0',
  u'1882',
  u'590/rpcbind'],
 [u'tcp6',
  u'0',
  u'0',
  u':::22',
  u':::*',
  u'LISTEN',
  u'0',
  u'12610',
  u'621/sshd'],
 [u'tcp6',
  u'0',
  u'0',
  u':::39352',
  u':::*',
  u'LISTEN',
  u'105',
  u'1945',
  u'599/rpc.statd'],
 [u'tcp6',
  u'0',
  u'0',
  u'::1:25',
  u':::*',
  u'LISTEN',
  u'0',
  u'14983',
  u'1034/exim4'],
 [u'tcp6',
  u'0',
  u'0',
  u':::111',
  u':::*',
  u'LISTEN',
  u'0',
  u'1885',
  u'590/rpcbind'],
 [u'tcp6',
  u'0',
  u'0',
  u':::80',
  u':::*',
  u'LISTEN',
  u'0',
  u'13641',
  u'1006/apache2']]

Im Beispiel wird jetzt jede Zeile durchgegangen und ein eindeutiger Identifier (Servicename) erzeugt für den Service.

for l in info:
    service_identify = "%s/%s" % (l[0], l[3].split(":")[-1])
    yield service_identify, None

Die Rückgabe der Funktion erfolgt über die Generator Funktion yield und erwartet ein Tuple aus 2 Werten. 1 Wert ist der Servicename, 2 Wert sind Parameter die als Tuple oder Dictionary übergeben werden können. In dem Beispiel haben wir keine Parameter somit übergeben wir ein None.

Hat man seine Inventory Funktion und die check_info Definition in seinem Check komplettiert kann man das auf der Kommandozeile testen:

OMD[test1]:~/local/share/check_mk/checks$ cmk -v -II localhost
Discovering services on localhost:
localhost:
    1 cpu.loads
    1 cpu.threads
    1 df
    1 diskstat
    3 kernel
    1 kernel.util
    1 livestatus_status
    1 lnx_if
    3 local
    1 mem.linux
    1 mkeventd_status
    1 mknotifyd
    1 mounts
    3 mtr
   13 my_tcp_listener
    1 ntp.time
    1 omd_apache
    1 omd_status
    1 tcp_conn_stats
    1 uptime

Die Inventory Funktion hat meine 13 lokalen TCP Ports gefunden und dem Host hinzugefügt. Gespeichert werden diese Informationen an folgendem Ort:

/omd/sites/<sitename>/var/check_mk/autochecks/<hostname>.mk

OMD[test1]:~/var/check_mk/autochecks$ cat localhost.mk 
[
  ('cpu.loads', None, cpuload_default_levels),
  ('cpu.threads', None, threads_default_levels),
  ('df', u'/', {}),
  ('diskstat', u'SUMMARY', diskstat_default_levels),
  ('kernel', u'Context Switches', kernel_default_levels),
  ('kernel', u'Major Page Faults', kernel_default_levels),
  ('kernel', u'Process Creations', kernel_default_levels),
  ('kernel.util', None, {}),
  ('livestatus_status', u'test1', {}),
  ('lnx_if', u'2', {'state': ['1'], 'speed': 1000000000}),
  ('mem.linux', None, {}),
  ('mkeventd_status', u'test1', {}),
  ('mknotifyd', u'test1', {}),
  ('mounts', u'/', [u'data=ordered', u'errors=remount-ro', u'relatime', u'rw']),
  ('my_tcp_listener', u'tcp/111', None),
  ('my_tcp_listener', u'tcp/22', None),
  ('my_tcp_listener', u'tcp/25', None),
  ('my_tcp_listener', u'tcp/34607', None),
  ('my_tcp_listener', u'tcp/5000', None),
  ('my_tcp_listener', u'tcp/63342', None),
  ('my_tcp_listener', u'tcp/6556', None),
  ('my_tcp_listener', u'tcp/6942', None),
  ('my_tcp_listener', u'tcp6/111', None),
  ('my_tcp_listener', u'tcp6/22', None),
  ('my_tcp_listener', u'tcp6/25', None),
  ('my_tcp_listener', u'tcp6/39352', None),
  ('my_tcp_listener', u'tcp6/80', None),
  ('ntp.time', None, {}),
  ('omd_apache', u'test1', None),
  ('omd_status', u'test1', None),
  ('tcp_conn_stats', None, tcp_conn_stats_default_levels),
  ('uptime', None, {}),
]

Check Funktion

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.

Die Check Funktion ist hier stark vereinfacht, grundsätzlich muss man sein item aus der Datenmenge info herraussuchen:

Beispiel aus einem anderen Check:

for line in info:
    if item == line[0]:
        # Hier der Check

Hier für unser Beispiel:

def check_my_tcp_listener(item, params, info):

    proto, port = item.split("/")
    message = (2, "CRIT service not listen")

    for l in info:
        if proto in l[0] and port in l[3].split(":")[-1]:
            message = (0, "OK service listen")

    return message

Als Rückgabe erwartet Check_MK aus 2 bzw. 3 Werten in einem Tuple. 2 Werte wenn keine Performance Daten übergeben werden, 3 wenn Performance Daten dabei sind.

ohne Performance Werte

<STATUS>, <MESSAGE>

mit Performance Werte

<STATUS>, <MESSAGE>, <PERFDATA>

Die Perfomance Werte sind wiederum eine Liste aus Tupeln. Das werde ich in einem anderen Artikel erläutern.

Das check_info Dictionary

Das check_info Dictionary ist ein Verzeichnis das von Check_MK selbst bereitgestellt wird und alle zur Verfügung stehenden Checks beinhaltet.

check_info["my_tcp_listener"] = {
    "inventory_function" :  inventory_my_tcp_listener,
    "check_function" :  check_my_tcp_listener,
    "service_description" : "TCP Listener %s",
}

Der Key muss dem Namen entsprechen welche der Agent für die Sektion z.B. <<<my_tcp_listener>>> verwendet. Im Dictionary werden dann Check_MK die Inventory Funktion und die Check Funktion mitgeteilt. Desweiteren kann man hier den Text definieren welcher für den Service angezeigt wird. Hier wird z.B. für SNMP Checks die OIDs definiert. Mehr dazu in einem anderen Artikel …

Wenn der Check fertig ist muss der Check_MK Core neu geladen werden damit er den Check kennt, das erledigt folgendes Kommando in der OMD Umgebung „cmk -R“

Ob der Check funktioniert kann man mit „cmk -D localhost“ in der OMD Umgebung testen.

OMD[test1]:~/local/share/check_mk/checks$ cmk -v -D localhost

localhost                                                                      
Addresses:              127.0.0.1
Tags:                   /wato/, cmk-agent, ip-v4, ip-v4-only, lan, prod, site:test1, tcp, wato
Host groups:            
Contact groups:         all
Type of agent:          TCP (port: 6556)
Is aggregated:          no
Services:
  checktype         item                           params                                                                                                                                                                                                                                                                                                                                                   description                    groups summarized to groups
  ----------------- ------------------------------ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------ ------ ------------- ------
...
  my_tcp_listener   tcp/111                        None                                                                                                                                                                                                                                                                                                                                                     TCP Listener tcp/111                                      
  my_tcp_listener   tcp/22                         None                                                                                                                                                                                                                                                                                                                                                     TCP Listener tcp/22                                       
  my_tcp_listener   tcp/25                         None                                                                                                                                                                                                                                                                                                                                                     TCP Listener tcp/25                                       
  my_tcp_listener   tcp/34607                      None                                                                                                                                                                                                                                                                                                                                                     TCP Listener tcp/34607                                    
  my_tcp_listener   tcp/5000                       None                                                                                                                                                                                                                                                                                                                                                     TCP Listener tcp/5000                                     
  my_tcp_listener   tcp/63342                      None                                                                                                                                                                                                                                                                                                                                                     TCP Listener tcp/63342                                    
  my_tcp_listener   tcp/6556                       None                                                                                                                                                                                                                                                                                                                                                     TCP Listener tcp/6556                                     
  my_tcp_listener   tcp/6942                       None                                                                                                                                                                                                                                                                                                                                                     TCP Listener tcp/6942                                     
  my_tcp_listener   tcp6/111                       None                                                                                                                                                                                                                                                                                                                                                     TCP Listener tcp6/111                                     
  my_tcp_listener   tcp6/22                        None                                                                                                                                                                                                                                                                                                                                                     TCP Listener tcp6/22                                      
  my_tcp_listener   tcp6/25                        None                                                                                                                                                                                                                                                                                                                                                     TCP Listener tcp6/25                                      
  my_tcp_listener   tcp6/39352                     None                                                                                                                                                                                                                                                                                                                                                     TCP Listener tcp6/39352                                   
  my_tcp_listener   tcp6/80                        None                                                                                                                                                                                                                                                                                                                                                     TCP Listener tcp6/80                                      
....

OMD[test1]:~/local/share/check_mk/checks$ 

Debugging Plugin

Per default werden Exceptions auf der Kommandozeile unterdrückt. Man kann mit –debug die Ausgaben beim „cmk“ Kommando einschalten.

OMD[test1]:~/local/share/check_mk/checks$ cmk -v -II --debug localhost
Discovering services on localhost:
localhost:
Traceback (most recent call last):
  File "/omd/sites/test1/share/check_mk/modules/check_mk.py", line 4838, in <module>
    do_discovery(hostnames, check_types, seen_I == 1)
  File "/omd/sites/test1/share/check_mk/modules/discovery.py", line 80, in do_discovery
    do_discovery_for(hostname, check_types, only_new, use_caches, on_error)
  File "/omd/sites/test1/share/check_mk/modules/discovery.py", line 100, in do_discovery_for
    new_items = discover_services(hostname, check_types, use_caches, do_snmp_scan, on_error)
  File "/omd/sites/test1/share/check_mk/modules/discovery.py", line 718, in discover_services
    return services + discover_services_impl(hostname, check_types, use_caches, on_error, ipaddress)
  File "/omd/sites/test1/share/check_mk/modules/discovery.py", line 733, in discover_services_impl
    use_caches, on_error, use_snmp):
  File "/omd/sites/test1/share/check_mk/modules/discovery.py", line 899, in discover_check_type
    discovered_items = list(discovered_items)
  File "/omd/sites/test1/local/share/check_mk/checks/my_tcp_listener", line 6, in inventory_my_tcp_listener
    yield service_identify, None, xxxx,xxxx,xx
NameError: global name 'xxxx' is not defined

Fertig ???

Im WATO muss man seinen neuen Check auf dem Host noch mit einem einfachen „Tabula Rasa“ inventarisieren.

Jetzt kann man sein Ergebnis auf der Webseite bewundern 🙂

 

Ein Gedanke zu „Check_MK: Eigener Agent Check

  1. Pingback: Check_MK: SNMP based Check – LANbugs

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

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