Aktionen

Zabbix sender per Web URL-Aufruf nutzen

Aus znilwiki

Die druckbare Version wird nicht mehr unterstützt und kann Darstellungsfehler aufweisen. Bitte aktualisiere deine Browser-Lesezeichen und verwende stattdessen die Standard-Druckfunktion des Browsers.

Vorwort

In letzter Zeit beschäftige ich mich viel mit den ESP8266 Modulen. Bisher habe ich z.B. einen WLAN-Taster und eine Temperatur/Luftfeuchtigkeits-Messtation gebaut.
Die erfassten Werte (unter anderem der Batteriespannung um zu wissen wann ich nachladen muss) möchte ich natürlich in Zabbix haben.
Nun gibt es zwar schon einige Versuche einen "Zabbix-Agenten" auf dem ESP zu simulieren - aber das ist mir alles viel zu umständlich.

Ich nutze Python und Flask schon eine Weile um darüber meine 32 Relais an einem Raspberry Pi zu bedienen.
Stark vereinfacht erklärt: Flask erstellt einen kleinen Webserver der die aufgerufene URL als Variablen an das Pythonskript übergibt.


Vorbereitung Server

Ich lasse das Python-Skript das den Aufruf entgegen nimmt in diesem Beispiel mit auf dem Zabbix-Server laufen.
Es läuft auf Port 5000 und kommt somit der Zabbix-Webseite auf Port 80/443 nicht in die Quere.
Basis ist bei mir eine Zabbix 4.0.x Server unter Ubuntu 18.04. LTS. Es sollte aber auch genauso auf älteren Systemen laufen.

Meldet euch an eurem Server an und wechselt zum root-Benutzer.
Zunächst prüfen wir ob Python schon installiert ist:

root@zabbix:~# python --version
Python 2.7.15rc1

Was eigentlich der Fall sein sollte. Es gibt auch noch python3 was hier erst einmal egal ist. Das ganze hier läuft sowohl unter Python 2.7 als auch 3.6
Jetzt installieren wir Flask nach

apt install python-flask -y



Skript Stufe 1: Der Test

In Stufe 1 testen wir nun den Zugriff. Dazu erstellen wir unser Skript wie folgt:

mkdir /opt/flask
nano /opt/flask/ZabbixSenderByURL.py

und fügt folgenden Inhalt ein:

#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
from functools import wraps
from flask import Flask, request, Response
app = Flask(__name__)

# Wenn nur die URL ohne Parameter aufgerufen wird
@app.route('/')
def hello():
    return "Start ZabbixSenderByURL! Use /ZabbixServer/Hostname/Item/Value"

# Wenn die URL mit Parametern aufgerufen wird
@app.route('/<zabbixserver>/<zhostname>/<zitem>/<zvalue>')
def ZabbixSender(zabbixserver, zhostname, zitem, zvalue):
    print("/usr/bin/zabbix_sender -z " + zabbixserver + " -s " + zhostname + " -k " + zitem + " -o " + zvalue)
    #os.system("/usr/bin/zabbix_sender -z " + zabbixserver + " -s " + zhostname + " -k " + zitem + " -o " + zvalue  + "  >/dev/null 2>&1")
    return ('OK'), 200

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Das Programm wird uns nun nur den zabbix_sender Aufruf anzeigen, diesen aber noch nicht ausführen.
Achtet darauf das die Einrückung exakt 4 Zeichen betragen!
Wir machen es ausführbar:

chmod +x /opt/flask/ZabbixSenderByURL.py

und starten es:

/opt/flask/ZabbixSenderByURL.py

Ausgabe:

root@zabbix:~# /opt/flask/ZabbixSenderByURL.py
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

Nun rufen wir ein einem Webbrowser die folgende URL auf (IP an euren Server anpassen):

http://10.100.12.15:5000/zabbix.znil.local/Messstation01/znil.esp8266.DHT22.temperature/23

welcher uns dann ein schnödes "OK" zurück gibt.
Die Ausgabe in der Bash sollte nun wie folgt aussehen:

root@zabbix:~# /opt/flask/ZabbixSenderByURL.py
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
/usr/bin/zabbix_sender -z zabbix.znil.local -s Messstation01 -k znil.esp8266.DHT22.temparture -o 23
172.16.103.2 - - [27/Feb/2019 10:03:14] "GET /zabbix.znil.local/Messstation01/znil.esp8266.DHT22.temperature/23 HTTP/1.1" 200 -
172.16.103.2 - - [27/Feb/2019 10:03:14] "GET /favicon.ico HTTP/1.1" 404 -

Das war es schon ... funktioniert. In den letzten beiden Zeilen sehen wir das der Aufruf der URL mit "200" quittiert wurde.
Der Browser wollte dann noch ein favicon.ico haben was wir aber nicht geliefert haben - das ignorieren wir.


Skript Stufe 2: Scharfschalten und als Dienst

Drückt in der Bash STRG + C um den Server wieder zu beenden.
Bearbeitet das Skript noch einmal:

nano /opt/flask/ZabbixSenderByURL.py

und ändert die folgenden 2 Zeilen:

    #print("/usr/bin/zabbix_sender -z " + zabbixserver + " -s " + zhostname + " -k " + zitem + " -o " + zvalue)
    os.system("/usr/bin/zabbix_sender -z " + zabbixserver + " -s " + zhostname + " -k " + zitem + " -o " + zvalue  + "  >/dev/null 2>&1")

Nun wird der Zabbix-Sender ausgeführt wenn die URL aufgerufen wird.
Jetzt richten wir das als Dienst ein:

nano /etc/systemd/system/zabbixsenderbyurl.service

Inhalt:

[Unit]
Description=Zabbix Sender URL Service
After=syslog.target

[Service]
Type=simple
WorkingDirectory=/opt/flask
ExecStart=/opt/flask/ZabbixSenderByURL.py
SyslogIdentifier=zabbixsenderbyurl
StandardOutput=syslog
StandardError=syslog
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

Automatischen Start einschalten:

systemctl enable zabbixsenderbyurl.service

und starten:

systemctl start zabbixsenderbyurl.service



Das Item

Das Item zu dem Beispiel

http://10.100.12.15:5000/zabbix.znil.local/Messstation01/znil.esp8266.DHT22.temperature/23

sieht wie folgt aus:

ClipCapIt-190227-102112.PNG


Wenn wir nun die URL noch einmal aufrufen:

ClipCapIt-190227-102544.PNG



Erklärung

Um mit dem Programm zabbix_sender Daten zu senden nutzen wir folgenden Aufruf:

zabbix_sender -z <zabbixserver> -s <host> -k <item> -o <wert>

zabbix_sender          Das Programm zum Werte senden
-z <zabbixserver>      Name oder IP des Zabbix-Servers oder Zabbix-Proxy, z.B. 127.0.0.1
-s <host>              Name des Host in Zabbix, z.B.  Messstation01
-k <item>              Name des Items das den Wert bekommen soll, z.B. znil.esp8266.DHT22.temperature
-o <wert>              Wert der gesendet werden soll, z.B. 23

Der ganze Aufruf wäre also z.B.

zabbix_sender -z 127.0.0.1 -s Messstation01 -k znil.esp8266.DHT22.temperature -o 23

Den Aufruf verpacken wir nun in einen URL-Aufruf wie wir Ihn in jedem Browser nutzen können:

http://10.100.12.15:5000/zabbix.znil.local/Messstation01/znil.esp8266.DHT22.temperature/23

Das Python-Skript bekommt so die Werte und sendet diese einfach per Zabbix-Sender weiter.


Anpassungen


Port ändern

Das Skript läuft auf Port 5000. Umd as zu ändern müsst Ihr die letzte Zeile im Skript ändern:

app.run(host='0.0.0.0', port=5000)

Und dort die gewünschte Nummer angeben.


URL mit Benutzername + Passwort absichern

Man kann eine "Basic-Authentication" davorschalten - dann poppt beim Aufruf ein Fenster für Benutzername + Passwort auf.
Man kann die Anmeldung aber auch in der URL übergeben - was es einfacher macht.
Ändert das Skript wie folgt ab:

#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
from functools import wraps
from flask import Flask, request, Response
app = Flask(__name__)

# Wenn nur die URL ohne Parameter aufgerufen wird
@app.route('/')
def hello():
    return "Start ZabbixSenderByURL! Use /ZabbixServer/Hostname/Item/Value"

#nur nach Anmeldung, siehe http://flask.pocoo.org/snippets/8/
def check_auth(username, password):
    # This function is called to check if a username /
    # password combination is valid.
    return username == 'zabbix' and password == 'xibbaz'

def authenticate():
    # Sends a 401 response that enables basic auth
    return Response(
    'Could not verify your access level for that URL.\n'
    'You have to login with proper credentials', 401,
    {'WWW-Authenticate': 'Basic realm="Login Required"'})

def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            return authenticate()
        return f(*args, **kwargs)
    return decorated

# Wenn die URL mit Parametern aufgerufen wird
@app.route('/<zabbixserver>/<zhostname>/<zitem>/<zvalue>')
@requires_auth
def ZabbixSender(zabbixserver, zhostname, zitem, zvalue):
    #print("/usr/bin/zabbix_sender -z " + zabbixserver + " -s " + zhostname + " -k " + zitem + " -o " + zvalue)
    os.system("/usr/bin/zabbix_sender -z " + zabbixserver + " -s " + zhostname + " -k " + zitem + " -o " + zvalue  + "  >/dev/null 2>&1")
    return ('OK'), 200

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Den Benutzernamen und das Passwort im Skript müsst Ihr anpassen.
Der Aufruf wäre nun:

http://zabbix:xibbaz@10.100.12.15:5000/zabbix.znil.local/Messstation01/znil.esp8266.DHT22.temperature/23



https nutzen

Immer gleich übertreiben ... im internen Netzwerk nutze ich das nicht. Wer das möchte den verweise ich auf folgende beiden Artikel:



Kommentare

Loading comments...