English English preferred? This way, please.

Heute habe ich einen coolen neuen Trick gelernt, in dem ich das Item Preprocessing benutzen kann das Zabbix seit der Version 3.4 anbietet. Dies ist kein Zabbix-Blog, aber ich betrachte das als so nützlich — und nicht gerade intuitiv — dass ich das mal eben aufschreiben möchte.

Für alle die es nicht kennen: Zabbix ist ein quelloffenes Monitoring System, der Hersteller nennt es nicht ganz zu unrecht „Enterprise Class“. Ich nutze das nicht nur bei der Arbeit sondern auch zu Hause — nicht nur um das Fleisch in meinem Smoker zu monitoren. :-)

Meiner Meinung nach ist Zabbix wirklich stark bei allem was in Zahlen ausgedrückt werden kann. Es kann auch mit textuellen Informationen umgehen, aber nachdem ich damit ein paar kleinere Schwierigkeiten hatte versuche ich das nach Möglichkeit zu vermeiden. Zustände können in Zabbix auch numerisch dargestellt und als Ganzzahl gespeichert werden, mit dem Value Mapping kann man trotzdem gut lesbare Ausgaben erzeugen.

Heute bin ich an ein Problem gekommen das ich mit meinen üblichen Methoden erst nicht umsetzen konnte. Ein Webservice gibt mir den Status einer Applikation, die ist entweder RUNNING, STOPPING oder STOPPED. Es ist nicht schwer das in einem String-Item zu speichern, und einen Trigger anzulegen der reagiert wenn die Applikation STOPPED ist. In diesem speziellen Fall sollte ich aber einen Trigger bauen der meldet wenn der Dienst länger als eine gewisse Zeit im Status STOPPING ist, daran ist zu erkennen dass es ein Problem beim regulären Anhalten der Applikation gibt. Das war nicht trivial, da die Triggerfunktion str("STOPPING",15m) auch schon zuschlägt wenn mindestens einer der Werte in den letzten 15 Minuten „STOPPING“ war.

Item Preprocessing to the rescue!

Drei Schritte

Drei Schritte

Mit Version 3.4 hat ein Feature namens Item Preprocessing in Zabbix Einzug gehalten. Damit kann ein gemessener Wert auf verschiedene Arten weiterbehandelt werden bevor er gesichert wird. Eine der Methoden ist, durch reguläre Ausdrücke eine Art „Suchen und Ersetzen“ vorzunehmen.

Wie sich rausstellt brauchte ich dazu einen halbwegs komplexen regulären Ausdruck, aber am Ende konnte ich die Zustände des Webservices in einfache Ganzzahlen umwandeln. Bei einer Websuche habe ich etwas über „conditional replacement“ gefunden, und mit diesem großartigen Tester für reguläre Ausdrücke konnte ich diese Schönheit bauen:

Damit kann ich den String den ich mittels JSON Path aus der Ausgabe des Webservices ziehe in zwei weiteren Schritten umwandeln:

  • Erst hänge ich eine Art „Wörterbuch“ an meinen Wert: ich ersetze den kompletten Wert (.*) durch sich selbst, gefolgt von den Ersetzungswerten: \1:STOPPED=0:STOPPING=1:RUNNING=2.
  • Dann ersetze ich den regulären Ausdruck (STOPPED|STOPPING|RUNNING)(?=.*:\1=(\d)) durch den Wert der zweiten Capturing Group \2.

Auf die Weise kann ich mein Item als vorzeichenlose Ganzzahl konfigurieren, da hier nur noch die Zahlen 0, 1 oder 2 abgelegt werden müssen. Und ich kann die übliche Trigger-Funktions-Magie anwenden um zu melden wenn der Wert länger als eine gewisse Zeit bei 1 verbleibt. Ein weiterer Bonus: ich kann im Graphen des Items sehen wann der Webservice nicht im Zustand RUNNING gewesen ist, und wie lange das angehalten hat.

Vorschläge?

Ich bin ziemlich angetan davon, Werte auf diese Weise für die Weiterverarbeitung vorzubereiten. Aber ich bin auch an Meinungen interessiert: gibt es bessere Wege mit diesem Problem umzugehen? Irgendwas offensichtliches das ich übersehen habe?

English English preferred? This way, please.

Grilltemperatur in Zabbix

Grilltemperatur in Zabbix

Leider ist dieses Projekt noch nicht ganz fertig, aber ich berichte trotzdem vom ersten Probelauf. Die Elektronik wollte noch nicht ganz so wie ich wollte, aber man sieht wohin die Reise geht.

Vor knapp zwei Jahren habe ich mal einen Prototypen eines Grillthermometers gebastelt. Den habe ich auch hier vorgestellt, das war wirklich ein ganz krudes Projekt. Seitdem habe ich viel dazu gelernt, und ich will sowas jetzt nochmal in ‚ernsthaft‘ bauen.

Da ich mit dem Ding die Temperatur mehrerer Fleischstücke messen kann war der Name natürlich klar: Multimeater! :-D

Die Hardware

Die Hardware

Basis wird wie bei den letzten Projekten ein ESP8266-Modul, programmiert mit der Arduino-Software. WLAN ist somit vorhanden. Darauf kommt eine Firmware die — ebenfalls wie in mehreren meiner Projekte — auf dem Homie-Framework basiert. Das liefert die Messwerte per MQTT an meinen Broker, von da geht es weiter zu Zabbix. Gemessen wird mit zwei Hochtemperatur-Sensoren die jeweils an einem MAX6675 hängen, sowie vier normalen Einstichthermometern an einem MCP3208.

Sechs Temperaturen? Ja. Der Plan ist, mit zwei Sensoren die Innenraumtemperatur des Grills aufzunehmen. Unter bestimmten Umständen kann die so hoch sein dass die normalen Fleischthermometer das nicht mitmachen würden, also gibt es dafür zwei extra Fühler, jeweils am Ende des Grillraumes (der ist beim Smoker eher länglich, da gibt es tatsächlich ein Temperaturgefälle). Und mit vier Fleischthermometern kann ich die Kerntemperatur von eben bis zu vier Stücken überwachen.

Zabbix ist eigentlich ein Monitoring-System, damit überwacht man eigentlich Serversysteme. Das funktioniert aber nicht nur in großen Rechenzentren, ich erfasse damit zu Hause auch einige… eher ungewöhnliche Daten. ;-)

In diesem Fall habe ich mir damit nur die Temperaturverlaufskurven angesehen, aber wenn ich wirklich mal über Nacht ein Pulled Pork grillen möchte kann Zabbix mich auch aus dem Bett klingeln wenn die Temperaturen nicht so aussehen wie sie sein sollten.

Wie gesagt: das Heute war nur ein Probelauf. Und wie das so ist sind dabei einige Sachen schief gegangen. Ich habe ein Problem mit den Messwerten von den Innenraum-Fühlern gehabt, die waren leider unbrauchbar. Da ich aber eh nur drei Stücke Fleisch hatte konnte ich den vierten Fühler für die Pit-Temperatur benutzen. Der Fühler im Schinkenbraten war erst doof gesteckt, daher sieht die blaue Kurve sehr merkwürdig aus. Und als Krönung hat es zwischenzeitlich heftig geregnet, da der Grill zur Zeit nicht überdacht ist hat es das auch nicht einfacher gemacht.

Alles in allem war das aber schon sehr vielversprechend. Ich bleibe dran, und sobald das Ding wirklich funktioniert stelle ich es natürlich hier vor, mit Schaltplan und Firmware.

Oh, und da die Fragen kommen werden: die technischen Probleme haben dem Grill-Ergebnis keinen Abbruch getan, es hat hervorragend geschmeckt. :-D

Gestern habe ich auf Twitter gelesen dass es im Zabbix-Share ein Modul gibt mit dem man das Monitoring-Tool meiner Wahl — Zabbix — direkt auf einen Arduino zugreifen lassen kann: Zabbuino nennt sich das.

Komischerweise habe ich letzte Woche erst überlegt wieviel Aufwand es wohl sein mag, das Zabbix-Protokoll nachzuimplementieren. Ich bastele zur Zeit wieder mal mit dem WLAN-fähigen Chip ESP8266 herum, den hatte ich hier auch schon erwähnt. Damit lassen sich prima Messwerte einsammeln, und das schreit dann nach Zabbix. Mein erster Ansatz war, Messdaten per HTTP zur Verfügung zu stellen. Die werden dann von einem Skript periodisch abgeholt und per zabbix_send eingespeist. Wesentlich eleganter wäre es natürlich, Zabbix direkt auf den Sensor zugreifen zu lassen…

Es wäre also wirklich mal einen Versuch wert, das Zabbuino-Modul in Verbindung mit einer kleinen ESP8266-Platine zu testen, die kann man auch fuer deutlich unter fünf Euro kaufen. Oder hat das schon jemand ausprobiert?

Da ich das letzte Woche aber noch nicht kannte habe ich schon einen dritten Weg eingeschlagen. Noch viel besser, wie ich finde. Das ist aber eine andere Geschichte, und die soll ein anderes Mal erzählt werden…

Heutzutage fallen an allen möglichen Stellen irgendwelche Daten im JSON-Format an. Und das ist gut so. Trägt nicht so auf wie XML, ist dafür aber flexibler — und vor allem besser definiert — als irgendwelche selbstausgedachten CSV- oder INI-Formate.

Man ist schlecht beraten, zu versuchen dermassen komplexe Formate mit Shell-Tools wie awk, sed oder grep zu Leibe zu rücken. Reguläre Ausdrücke sind eine tolle Sache, aber in dieser Situation fallen die einem früher oder später auf den Fuß. Bislang habe ich meist eine Sprache mit P bemüht: Python, Perl oder zur Not PHP. Die können JSON importieren, danach arbeitet man auf den gewohnten Datenstrukturen. Also auf Arrays und Objekten, und die kann man schön sauber nach dem durchkämmen was man sucht.

Jetzt hat aber ein neues Tool seinen Weg in meinen Werkzeugkasten gefunden: jq. weiterlesen

Krustenbraten im Zabbix

Krustenbraten im Zabbix

Ich schrieb ja schon dass ich mich seit etwas über zwei Wochen intensiv mit dem ESP8266 auseinander setze. Das ist ein WLAN-Modul mit dem man sehr einfach — und vor allem preiswert — eigene Mikrocontroller-Basteleien ins WLAN bekommt.

Gestern lief praktisch ein Proof of Concept für eine der Sachen die ich damit umsetzen möchte: ich habe den Sensor eines elektronischen Fleischthermometers an einen Arduino Nano angeschlossen (ein sogenannter Thermistor, Lady Ada zeigt wie das geht). Zusätzlich den ESP8266 und eine kleine Firmware. Die Firmware hat sich mit meinem WLAN verbunden und alle paar Sekunden die aktuelle Temperatur per HTTP als GET-Parameter an ein kleines Skript geschickt. Dieses Skript hat die Werte jeweils an Zabbix weitergereicht. Mit Zabbix monitore ich hier eigentlich mein ‚Rechenzentrum‘, also meinen Server und die virtuellen Maschinen die darauf laufen.

Wie sich zeigt taugt Zabbix aber auch zur Überwachung eines Krustenbraten. :-D

Der Braten war etwa zweieinhalb Stunden im Grill, bei rund 150°C (in einer nächsten Version will ich auch die Garraumtemperatur überwachen, dann gibt es einen neuen Graphen). Ich hatte einen Trigger gesetzt der bei 75°C Kerntemperatur auslöst. Dem Ergebnis nach würde ich sagen dass ich den beim nächsten Mal eher drei Grad niedriger ansetzen sollte. Oder ich muss das Thermometer nochmal ordentlich kalibrieren. Aber auch wenn er nicht optimal war: geschmeckt hat er. Der WLAN-Krustenbraten. :-)

Das Zabbix-Item

Das Zabbix-Item

Lange Zeit habe ich die Überwachung meines Netzwerkes Nagios anvertraut. Vor einiger Zeit habe ich das durch ein Icinga ersetzt, einfach nur um mal zu sehen inwiefern der Fork besser oder anders ist. Seit einigen Wochen beschäftige ich mich aber aus verschiedenen Gründen mit Zabbix, und das ist auf dem besten Wege sowohl Nagios als auch Icinga zu verbannen. Zabbix kann einfach viel mehr als Nagios/Icinga, und wenn man sich an die Konzepte gewöhnt hat ist es absolut nicht schwieriger zu beherrschen.

Eine der letzten Überwachungen die Nagios und Icinga bei mir gemacht haben, Zabbix aber noch nicht, war der Test auf aktualisierte Softwarepakete. Da die meisten Systeme unter meiner Fuchtel unter Debian laufen ist das nicht allzu schwer. Bislang habe ich regelmäßig durch den Nagios Remote Plugin Executor (NRPE) ein apt-get update && apt-get upgrade ausgeführt und rausgeparst wie viele Pakete aktualisiert würden. Das hat mehrere Nachteile: zum einen sind die Prozesse — gerade bei meiner schmalen Internetanbindung — teilweise recht lange unterwegs, und das führt zu Timeouts. Zum anderen bekommt das Monitoring erst beim nächsten Test mit dass ein System aktualisiert wurde, und da ich meine Kisten nicht unnötig stressen will teste ich nur zweimal täglich. Das bedeutet, dass ein Alarm unter Umständen knapp zwölf Stunden weiter besteht, obwohl die Situation schon bereinigt wurde.

Das geht besser.

Ich vermute dass das auch mit Nagios/Icinga besser ginge, aber ich gestehe dass ich damals nicht die Zeit investiert habe. Für Zabbix habe ich jetzt eine Lösung die mir gut gefällt:

Im nebenstehenden Bild sieht man den Parameter (Zabbix-Sprech: ‚das Item‘) das ich dazu angelegt habe. Das ist in meiner Konfiguration das erste Item vom Typ Zabbix-Trapper, daher stelle ich das hier mal vor. Zabbix-Trapper bedeutet, dass der Parameter nicht aktiv gepollt wird. Zabbix wartet passiv darauf, dass jemand mittels zabbix_sender einen Wert in das System schießt. Das funktioniert natürlich sowohl direkt bei Übergabe an den Zabbix-Server, als auch bei Übergabe an einen Zabbix-Proxy (ja, auch so einen habe ich zu Hause… ;-) ).

Nur wer sagt jetzt beim Zabbix Bescheid ob Pakete zu aktualisieren sind? Keine schlechte Idee ist, regelmäßig ein apt-get update auszuführen, um den Katalog aufzufrischen. Das erledigt Cron gerne, dem könnte man dann auch direkt sagen dass er den aktuellen Wert an Zabbix schicken soll. Das würde aber bedeuten, dass das Problem mit der Verzögerung nach einer Auffrischung des Systems immer noch bestünde. Also habe ich mir Apt mal etwas näher angesehen.

Im Verzeichnis /etc/apt/apt.conf.d/ kann man Hooks ablegen die vor oder nach bestimmten Aktionen des Paketmanagements ausgeführt werden. Bei mir gibt es da jetzt eine Datei namens 99zabbix, die hat einen Inhalt in dieser Form:

APT::Update::Post-Invoke-Success { "zabbix_sender -z zabbix.intern -s $(hostname -s).intern -k debian.updates -o $(apt-get -s upgrade | sed -ne 's/^\([0-9][0-9]*\) .*/\1/p') > /dev/null" };
DPkg::Post-Invoke { "zabbix_sender -z zabbix.intern -s $(hostname -s).intern -k debian.updates -o $(apt-get -s upgrade | sed -ne 's/^\([0-9][0-9]*\) .*/\1/p') > /dev/null" };

Das Kommando ist in beiden Fällen das gleiche. Mit APT::Update::Post-Invoke-Success wird festgelegt was nach einem erfolgreichen apt-get update passieren soll. So bekommt Zabbix nach jedem Update mit ob es etwas neues gibt, unabhängig davon ob Cron das angestossen hat oder ob ich das manuell war. Der Eintrag DPkg::Post-Invoke sagt nach jeder Änderung an den installierten Paketen noch einmal Bescheid wie der Stand der Dinge ist. So wird also nach einem apt-get upgrade der Wert direkt wieder auf 0 zurückgesetzt.

Dazu habe ich folgenden Trigger gebaut:

{Template OS Linux:debian.updates.last(0)}>0

Der meldet bislang nur, wenn der letzte Wert in dem Item debian.updates größer ist als 0. Da muss ich aber noch einmal Hand anlegen, so dass der auch aktiv wird wenn seit einer gewissen Zeit kein aktueller Wert gesetzt wurde. Dann ist davon auszugehen dass der Cron-Job kaputt ist der das apt-get update ausführt, oder dass an der Paketverwaltung grundsätzlich etwas schief läuft. Aber wie das geht muss ich mir noch genauer ansehen…