Fucking systemd

Auf meinen Raspberry Pi’s laufen einige Dienste wie ein Q3A-Server. Diese zum Beispiel mit Zabbix zu überwachen ist mir dann doch etwas übertrieben, da diese Dienste entweder rein privat genutzt werden oder ich einfach keine Uptime garantiere.
Trotzdem wäre es dann doch interessant, wenn ich darüber informiert werde, wenn zum Beispiel ein Dienst nicht gestartet werden konnte. Vor allem, wenn man nicht daheim ist. Da ich auf meinem Smartphone auch einen XMPP-Client installiert habe, würde sich eine Lösung mittels XMPP und systemd anbieten.
Um die Nachrichten zu versenden habe ich mir sendxmpp installiert. Unter Arch findet man das Paket im AUR. Um zu testen, ob das Versenden überhaupt funktioniert, habe ich es gleich einmal ausprobiert.
echo 'Hallo Welt' | sendxmpp -t -u fryboyter -j jabjab.de -p 'strenggeheim' empfänger@deshalbfrei.org
Und schon knallt es und ich bekomme die Fehlermeldung “Invalid or unreadable path specified for ssl_ca_path. at /usr/share/perl5/vendor_perl/XML/Stream.pm line 641” vor den Latz geknallt. Dann schauen wir uns die Datei doch mal an. Zeile 641 verrät mir allerdings recht wenig. Allerdings gibt es in besagter Datei die Zeile $self->{SIDS}->{default}->{ssl_ca_path} = ‘’;. An deren Ende habe ich zwischen die beiden ’’ einfach mal /etc/ssl/certs eingetragen.
Nächster Versuch, nächste Fehlermeldung. Error ‘AuthSend’: error: bad-protocol[?]. Na das ist ja mal sehr aussagekräftig. Nach etwas Google-Fu konnte ich das Problem in der Datei /usr/share/perl5/vendor_perl/Net/XMPP/Protocol.pm ausfindig machen. In Zeile 2104 steht return $ self-> AuthSASL (% args);. Diese Zeile kommentieren wir einfach mal mit einem # am Anfang aus. Ich bin mir allerdings nicht sicher, ob das nicht irgendwelche Nebenwirkungen hat.
Und wieder ein neuer Anlauf. Und plötzlich informiert mich mein XMPP-Client, dass ich für empfänger@deshalbfrei.org eine Nachricht erhalten habe. Yeehaa!
Da nun die Benachrichtigungen per XMPP funktionieren, erstellen wir unter /usr/bin ein Shellscript (nennen wir es mal xmpp.sh) mit folgendem Inhalt.
#!/bin/bash
UNIT=$1
UNITSTATUS=$(systemctl status $UNIT)
ALERT=$(echo -e "\u26A0")
echo "$ALERT Unit failed $UNIT $ALERT Status: $UNITSTATUS" | /usr/bin/site_perl/sendxmpp -t -u fryboyter -j jabjab.de -p 'strenggeheim' empfänger@deshalbfrei.org
Nun erstellen wir unter /etc/systemd/system die Service-Datei xmpp@.service mit folgendem Inhalt.
[Unit]
Description=Benachrichtigung mittels XMPP
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/xmpp.sh %I
Zum Schluss editieren wir noch die Service-Dateien der Dienste, die wir überwachen wollen und packen unter dem Bereich [Unit] die Zeile OnFailure=xmpp@%n.service.
Startet nun ein Service nicht erhält man automatisch eine Nachricht per XMPP, die beispielsweise so aussieht.
⚠ Unit failed monitorhell.service ⚠ Status: ● monitorhell.service - Tastaturbeleuchtung automatisch aktivieren
Loaded: loaded (/etc/systemd/system/monitorhell.service; enabled; vendor preset: disabled)
Active: failed (Result: exit-code) since Mon 2017-09-11 16:36:13 CEST; 1min 18s ago
Process: 510 ExecStart=/bin/bashx -c echo 2219 > /sys/class/backlight/intel_backlight/brightness (code=exited, status=203/EXEC)
Main PID: 510 (code=exited, status=203/EXEC)
Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.
Darauf habe ich seit Jahren gewartet. Die Distribution Devuan, welche ohne systemd auskommt, wurde in Version 1.0.0 veröffentlicht und basiert auf Debian Jessie. Endlich hat die laute Minderheit, die systemd nicht leiden kann, ein neues Zuhause.
Versteht mich nicht falsch, systemd ist sicherlich nicht der heilige Gral. Mir ging systemd auch schon auf die Nerven, weil bestimmte Programme beim Herunterfahren des Rechners Probleme gemacht haben und systemd daher mal 90 Sekunden Wartezeit eingelegt hat. Diese lässt sich zwar einstellen, aber so richtig wohl war mir beim Heruntersetzen auf beispielsweise 10 Sekunden nie. Und an manchen Stellen mag systemd auch pauschal nicht das Gelbe vom Ei sein. Aber Sysvinit ist in der heutigen Zeit einfach noch weniger gelb. Alleine das Init-Script von Apache erzeugt bei mir heute noch Albträume.
Aber der Artikel soll jetzt kein Flame in Richtung Sysvinit werden. Genauso wenig wie es ein Hohelied auf systemd sein soll. Ich, als jemand der mit systemd unterm Strich zufrieden ist und der auch durch systemd mehr über den Bootprozess gelernt hat, wünsche Devuan wirklich alles Gute. Ernsthaft. Zum einen, weil es zeigt, dass man in bestimmten Bereichen unter Linux noch die Wahl hat. Und zum anderen, weil dann vielleicht endlich mal das Geflame ohne Belege Richtung systemd weniger wird. Dies bitte nicht mit konstruktiver Kritik an systemd verwechseln. Diese ist, zumindest für mich, weiterhin willkommen. Aber diese “Arguemente” die jahrelang gegen systemd angeführt werden, die man in wenigen Sekunden widerlegen kann, nerven einfach nur.
Heute bekam ich folgende Anfrage (hier abgewandelt, da der genaue Vorgang intern bleiben soll). Wenn in einem Verzeichnis eine Avi-Datei gespeichert wird soll diese automatisch in eine Mkv-Datei (libtheora und libvorbis) umgewandelt und verschoben werden.
Als Erstes habe ich unter /home/video/ das Verzeichnis videos und Verzeichnis videos2 erstellt. Als Nächstes habe ich im gleichen Homeverzeichnis folgendes Shellscript erstellt:
#!/bin/bash
cd /home/video/videos/
for i in *.avi; do
ffmpeg -i "$i" -vcodec libtheora -acodec libvorbis "${i%.*}.mkv"
done
mv *.mkv /home/video/videos2/
rm *.avi
Das Shellscript wechselt erst in das eben erstellte Verzeichnis videos. Dort sucht es nach vorhandenen Dateien mit der Endung .avi und wandelt diese in eine Mkv-Datei mit libtheora und Libvorbis um. Danach werden die Mkv-Dateien in das Verzeichnis videos2 verschoben und die vorhandenen Avi-Datei gelöscht.
Als Nächstes habe ich mir Root-Rechte verschafft und mit diesen unter /etc/systemd/system die Datei convert.service mit folgendem Inhalt angelegt.
[Unit]
Description=Videos in ~/home/video/video automatisch konvertieren
[Service]
Type=oneshot
ExecStart=/home/video/convert.sh
Hier wird im Grunde genommen nur angegeben, dass das eben erstellte Shellscript convert.sh ausgeführt wird.
Im gleichen Verzeichnis habe ich nun noch die Datei convert.path angelegt und mit folgendem Inhalt befüllt.
[Unit]
Description=Startet convert.service wenn eine Datei in /home/video/video$
[Path]
PathModified=/home/video/videos/
[Install]
WantedBy=multi-user.target
Hier ist der Abschnitt Path der wichtige Teil. Sobald im Verzeichnis /home/video/videos etwas geändert wird (wie eben, dass dort eine Avi-Datei abgespeichert wird) wird das in der Service-Datei genannte Shellscript ausgeführt. Anstelle von PathModified gibt es noch PathExists=, PathExistsGlob=, PathChanged=, und DirectoryNotEmpty=. Diese werden unter man systemd.path oder hier online genauer erklärt.
Nun habe ich mittels systemctl start convert.path das ganze einmalig gestartet. Dass es nach einem Testlauf keine Probleme gegeben hat, habe ich diese Automatisierung mittels systemctl enable convert.path scharf geschaltet, sodass der Spaß auch einen Neustart des Systems überlebt.
Manche Services unter systemd haben ziemlich umständliche Bezeichnungen. Systemd-networkd.service oder openvpn@vpn.service zum Beispiel. Um es sich beim Aktivieren, Deaktivieren oder Neustarten etwas einfacher zu machen, kann man hier zu einem Alias greifen. Nehmen wir mal openvpn@vpn.service als Beispiel.
Hier öffnet man einfach die Datei openvpn@vpn.service welche unter /etc/systemd/systemd/multi-user.target.wants/ liegt. Diese sollte wie folgt aussehen.
[Unit]
Description=OpenVPN connection to %i
[Service]
Type=forking
ExecStart=/usr/bin/openvpn --cd /etc/openvpn --config /etc/openvpn/%i.conf --da$
PIDFile=/run/openvpn@%i.pid
[Install]
WantedBy=multi-user.target
Soll der Service auf den Alias vpn1 reagieren, muss man einfach unter [Install] Alias=vpn1.service hinzufügen. Wichtig ist hier, dass der Alias die gleiche Endung hat wie das Original. Also in dem Fall .service. Hier kann man auch mehrere Aliase angeben, welche man in die gleiche Zeile mit einem Lehrschritt getrennt eingibt.
Hat man die Datei nun entsprechend geändert und abgespeichert aktiviert man den Service mittels systemctl enable openvpn@vpn.service. Hiermit wird nun ein Symlink vpn1.service angelegt, welcher auf openvpn@vpn.service verweist. Von nun an kann dieser “Service” anstelle des Originals genutzt werden. Also beispielsweise systemctl status vpn1.service.