Mit Raspberry Pi und Livestatus eine Nagiosampel steuern

20. September 2012 | Von | Kategorie: Monitoring | Availability | StickyBit

Eine schöne Idee den aktuellen Status der verwendeten Systeme, die sowieso durch Nagios überwacht werden, aufzubereiten und auf die eine oder andere Art darzustellen ist eine Nagiosampel. Vor einigen Jahren haben wir unsere eigene Ampel in Betrieb genommen. Da mittlerweile technisch deutlich effizientere Methoden zur Abfrage des Nagios-Stati vorhanden sind war eine Überarbeitung längst überfällig. Als dann mit Fabian Ising ein Praktikant bei uns war hat dieser sich mit der Ampel und deren Ansteuerung genauer beschäftigt.

Im Folgenden wird gezeigt, wie mit Hilfe eines Raspberry Pi über WLAN (hierzu muss ein separater WLAN Stick verwendet werden) der Livestatus-Socket der Nagios-Core abgefragt und entsprechend die Ampel über GPIO Pins geschaltet werden kann. Dieser Artikel basiert auf der Dokumentation von Fabian.

Installation des Raspberry Pi und Einrichten des WLANs

Auf dem Raspberry Pi kommt die speziell angepasste Distribution Raspbian, die wiederum auf Debian Wheezy basiert, zum Einsatz. Für den konkreten Aufbau wurde das Image 2012-08-16-wheezy-raspbian.zip verwendet. Für das Netzwerk ist eine WLAN-Verbindung erforderlich, da die Ampel im Aufenthaltsraum an der Wand hängt und weit und breit kein LAN-Anschluss verfügbar ist. Beim Anschluss des WLAN-Sticks muss beachtet werden, dass der Raspberry Pi genug Strom durch das Netzteil erhält, da die Stromversorgung des USB-WLAN-Stick über das Board erfolgt.

Zunächst wurde geschaut welchen Chipsatz der WLAN-Stick verwendet und die entsprechende Firmware zu installiert.

$ aptitude install zd1211-firmware

Nach dem Aus- und wieder Einstecken des WLAN-Stick sollten Kernelmodule in der Ausgabe von lsmod bzw. der WLAN-Stick selbst in der Ausgabe von dmesg erscheinen. Um sich zu einem WPA verschlüsselten Netzwerk zu verbinden muss das Paket wpasupplicant installiert und die WLAN Konfiguration in /etc/network/interfaces angepasst werden

auto wlan0
iface wlan0 inet dhcp
wpa-ssid "Ampel"
wpa-psk "f1bsc3b0f..."

Nach diesen Anpassungen sollte der Raspberry Pi automatisch eine verschlüsselte WLAN-Verbindung zum Router aufbauen können. Eventuell kann hier ein

$ ifdown wlan0
$ ifup wlan0

den Verbindungsaufbau explizit anstossen.

Die Kommunikation mit dem Livestatus-Socket

Für die Abfrage der benötigten Informationen wurde bisher auf eine Datenbank zurückgegriffen in die der Nagios-Core mit den NDO-Utils alle Check-Ergebnisse geschrieben hat. Da die Datenbank ansonsten nicht weiter benötigt wurde verursachte dies einen überflüssigen administrativen Aufwand und stellt auch einen unnötigen Ressourcenverbrauch dar. Eine deutlich effizientere Variante ist  eine Abfrage mittels Livestatus-Socket, der eine direkte netzwerkbasierte Kommunikation mit dem Nagios-Core-Prozess ermöglicht.

Das verwendete Shell Script testet alle Services und Hosts auf unbearbeitete Warnungen und Fehler. Sollte es unbearbeitete Fehler geben so soll die Ampel rot leuchten. Hierzu wird dem Output-Skript (ioport.sh) eine 1 übergeben. Bei einer unbearbeiteten Warnung soll die orange Lampe aufleuchten, wofür eine 2 übergeben wird. Sollte ein unbearbeiteter unbekannter Fehler vorhanden sein so soll sowohl die rote als auch die orange Lampe aufleuchten, hierzu wird eine 3 übergeben. Sind keine unbearbeiteten Probleme vorhanden, so soll die Ampel grün aufleuchten. Für den letzten Fall wird eine 4 übergeben. Sollte es generelle Probleme bei der Abfrage geben so sollen alle drei Lampen aufleuchten. Hierzu wird an das Output-Skript eine 7 übergeben.

Hier zunächst das eigentliche Bash-Skript zur Abfrage des Nagios-Core über den Livestatus-Socket:

#!/bin/bash
nagiosip="x.x.x.x";
IFS=";"
SUDO="/usr/bin/sudo"
IOPORT="/home/pi/ampel/ioport.sh";
services=$(netcat $nagiosip 6557 < /home/pi/ampel/services);
set -- $services
critical=$1;
warning=$2;
unknown=$3;
# Tritt nur bei fehlender Verbindung auf
if [ "$1" = "" ] || [ "$2" = "" ] || [ "$2" = "" ]
then
#Ampel rot/gelb/gruen
$SUDO $IOPORT 7;
else
host=$(netcat $nagiosip 6557 < /home/pi/ampel/hosts);
IFS=";"
set -- $host
if [ "$1" = "" ] || [ "$2" = "" ] || [ "$2" = "" ]
then
#Ampel rot/gelb/gruen
$SUDO $IOPORT 7;
else
critical=`expr $critical + $1`
warning=`expr $warning + $2`
unknown=`expr $unknown + $3`
if [ $critical -gt 0 ]
then
#Ampel rot, kritisch
$SUDO $IOPORT 1;
elif [ $warning -gt 0 ]
then
#Ampel gelb, Warnung
$SUDO $IOPORT 2
elif [ $unknown -gt 0 ]
then
#Ampel gelb/rot, Unbekannter Fehler
$SUDO $IOPORT 3
elif [ "$warning" = "" ] || [ "$critical" = "" ] || [ "$unknown" = "" ]
then
#Ampel rot/gelb/gruen: Auslesen fehlgeschlagen
$SUDO $IOPORT 7;
else
#Ampel gruen, alles in Ordnung
$SUDO $IOPORT 4;
fi
fi
fi
exit 0

Dieser Skript wird als Cronjob jede Minute ausgeführt und fragt die entsprechenden Daten beim Nagios-Core an. Welche Daten angefragt werden erläutert der folgende Ausschnitte, die als Datei services bei der Verarbeitung des Skriptes eingelesen wird.

GET services
Stats: state = 2
Stats: acknowledged = 0
StatsAnd: 2
Stats: state = 1
Stats: acknowledged = 0
StatsAnd: 2
Stats: state = 3
Stats: acknowledged = 0
StatsAnd: 2

Analog zu den services fragt das Skript auch die hosts über den Livestatus-Socket ab. Hierzu ist lediglich das servives durch hosts zu ersetzen und als Datei mit der Bezeichnung hosts abzuspeichern. Für die Abfrage des Livestatus-Socket wird eine Query Language eingesetzt, die eine logisch Verknüpfung von Abfragen ermöglicht. Eine genauere Erläuterung finden Sie auf den oben verlinkten Seiten zum Livestatus.

Wichtig ist, dass sowohl die services– als auch die hosts-Datei am Ende eine Leerzeile enthalten müssen, da diese Zeile vom Livestatus benötigt wird. Hieran erkennt Livestatus das Ende einer Anfrage und führt diese erst dann aus, andernalls wird der Livestatus die Verbindung einfach zurücksetzen. Es ist außerdem noch zu beachten, dass die IP-Adresse, mit der der Raspberry Pi auf das Nagios zugreift, in der xinetd-Konfiguration des Livestatus Sockets erlaubt sein muss.

Eine Ausgabe auf die Ampel – das Output-Skript

Die Ampel wird mit einer Relaiskarte geschaltet, die  in unser bisherigen Lösung über den Parallel Port eines Laptops gesteuert wurde. Da der Raspberry Pi jedoch über keine parallele Schnittstelle verfügt, werden hierfür die GPIO Pins des Boards verwendet. Diese können relativ einfach als Dateien angesprochen werden:

$ echo "17" > /sys/class/gpio/export
$ echo "out" > /sys/class/gpio/gpio17/direction
$ echo "1" > /sys/class/gpio/gpio17/value

Durch die vorhergehenden Befehle wird zuerst der GPIO Pin 17 (Belegung) zur weiteren Verwendung freigegeben, dann der selbe Pin als Output gesetzt und dann wird der Pin aktiviert, wobei standardmäßig bei aktiviertem Pin ein relativ konstanter Spannungspegel von 3,3V anliegt. Soll eine Pin wieder deaktiviert werden wird einfach

$ echo "0" > /sys/class/gpio/gpio17/value

ausgeführt. Sollen die Pins auch wieder freigegeben werden muss noch

$ echo "17" > /sys/class/gpio/unexport

ausgeführt werden. In unserem Szenario benutzen wir die Pins 17 für die rote, 22 für die orange und 23 für die grüne Ampelleuchte. Damit zur Schonung der Birnen möglichst wenig Schaltvorgänge stattfinden werden immer nur die Lampen ausgeschaltet, die nicht genutzt werden. Das folgende Skript ist das in unserem Falle verwendete Output-Skript ioport.sh:

#!/bin/bash
GPIO="/sys/class/gpio";
if [ ! -L "/sys/class/gpio/gpio17" ]; then
echo "17" > $GPIO/export;
echo "out" > $GPIO/gpio17/direction;
fi
if [ ! -L $GPIO/gpio22 ];
then
echo "22" > $GPIO/export;
echo "out" > $GPIO/gpio22/direction;
fi
if [ ! -L $GPIO/gpio23 ];
then
echo "23" > $GPIO/export;
echo "out" > $GPIO/gpio23/direction;
fi
if [ $1 -eq 1 ]
then
echo "0" > $GPIO/gpio22/value;
echo "0" > $GPIO/gpio23/value;
echo "1" > $GPIO/gpio17/value;
fi
if [ $1 -eq 2 ]
then
echo "0" > $GPIO/gpio17/value;
echo "0" > $GPIO/gpio23/value;
echo "1" > $GPIO/gpio22/value;
fi
if [ $1 -eq 3 ]
then
echo "0" > $GPIO/gpio23/value;
echo "1" > $GPIO/gpio17/value;
echo "1" > $GPIO/gpio22/value;
fi
if [ $1 -eq 4 ]
then
echo "0" > $GPIO/gpio17/value;
echo "0" > $GPIO/gpio22/value;
echo "1" > $GPIO/gpio23/value;
fi
if [ $1 -eq 7 ]
then
echo "1" > $GPIO/gpio17/value;
echo "1" > $GPIO/gpio22/value;
echo "1" > $GPIO/gpio23/value;
fi

Post to Twitter Post to Yahoo Buzz Post to Delicious Post to Digg Post to Facebook Post to Ping.fm Post to Reddit

Tags: | | |

Schreibe einen Kommentar

Fühle dich ermuntert einen Kommentar, Anmerkungen, Hinweise oder deine Ideen zum Thema zu hinterlassen. Wir freuen uns über deine Rückmeldung.