DA HAT DOCH WAS GEZUCKT
Nach etlichen Sekunden-Stromausfällen, durchaus auch mal in schneller Folge nacheinander, hatte mich ein 40-minütiger Stromausfall endgültig über die Kante geschubst, und ich wollte meine Rechner mit unterbrechungsfreien Stromversorgungen ausstatten.
Ziel war eine USV-Integration, die:
- Den angeschlossenen Rechner bei Stromausfall zuverlässig herunterfährt.
- Und ihn auch zuverlässig wieder startet.
Utopische Batterielaufzeiten, um irgendwelche Uptimes zu retten, sind bei mir kein Thema, denn alle Systeme, die keine Eingabe einer Passphrase benötigen (also alle bis auf eines), reboote ich wöchentlich aus der Crontab.
First things first: Warum nicht den Marktführer? Warum nicht … APC?
Meine Meinung zu APC ist nicht die beste. Zum einen stört mich enorm, dass APC gefühlt immer noch die exakt selbe Hardware verkauft, sogar original ohne USB, die ich in einem anderen Jahrhundert(!) als Vertriebler im Großhandel verhökert habe. Der apcupsd für Linux scheint seit Ewigkeiten unmaintained, und die Hinweise zu den APC-Hardwaregenerationen bei den Network UPS Tools sind alles andere als ermutigend.
Hardwareauswahl
Der Weg zur richtigen Hardware, die die gewünschte Integration leistet, war steinig und von sehr schweren Pappkartons begleitet.
Für die meisten Anwendungsfälle tut es tatsächlich die wirklich billig-billige 50-Euro-USV von “BlueWalker PowerWalker”, wie sie der kleine Computerladen im Nachbardorf in allen Ausprägungen führt. Der Sinus ist hier allerdings nicht wirklich rund, sondern sehr sehr eckig, so dass er nicht mit jedem PC-Netzteil harmoniert.
Ein Gerät aus der “CSW”-Serie, “Clean Sine Wave” für ca. 150 Euro ebenfalls von “BlueWalker PowerWalker” weigerte sich, das System nach Wiederherstellung der Stromversorgung zuverlässig wieder hoch zu fahren.
Eine “Cyberpower”-USV hatte das beste User-Interface direkt am Panel, zählte die Sekunden der jeweiligen Timings live runter, war aber leider Dead On Arrival mit einem Akku, der wie ein Stein runterfiel, ohne dem angeschlossenen System wenigstens mal 30 Sekunden Zeit zum Runterfahren zu geben.
Nachdem ich einige Wochen Frust geschoben hatte, ging es wieder mit einer PowerWackler weiter, diesmal mit der BlueWalker PowerWalker VI 800 SW. Ein Billiggerät, sieht billig aus, hat ein aus einem Blickwinkel von ca. 0.5 Grad ablesbares LC-Display, und: Funktioniert! Der Sinus ist ulkig windschief, das tut der Funktion aber keinen Abbruch.
Integration
Nach den ersten Tests und der Erkundung der Möglichkeiten, standen meine Wünsche endgültig fest:
- 30 Sekunden nach dem Stromausfall soll das System runterfahren.
- Kommt innerhalb der 30 Sekunden der Strom wieder, soll der Shutdown abgebrochen werden.
- 60 Sekunden nach dem Shutdown soll das System ausgeschaltet werden.
- Kommt während oder nach dem Shutdown der Strom wieder, soll die USV wissen, dass sie das Ding jetzt durchziehen und das System trotzdem aus- und nach einer Wartezeit wieder einschalten soll.
- Ist der Stromausfall beendet, soll das System wieder automatisch eingeschaltet werden.
Mit der richtigen USV ist all das problemlos zu konfigurieren. Leider habe ich mir ärgerlich viel Zeit um die Ohren geschlagen, weil ich immer wieder Fehler auf meinem System in meiner Konfiguration gesucht habe.
NUT-Architektur
Die Network UPS Tools (“NUT”) teilen ihren Stack in 3 1/2 Schichten auf:
- Der NUT-Treiber übernimmt die Kommunikation mit der USV und stellt sie modellunabhängig den nachgeordneten Schichten zur Verfügung.
- Der NUT-Server stellt die Events der USV per TCP bereit, für localhost, oder auch für per Netzwerk angebundene Systeme, die keine lokale USV haben.
- Der NUT-Monitor reagiert auf Events, die er vom Server erhält, hierbei kann der Server entweder lokal laufen, oder über das Netzwerk erreicht werden.
- Der NUT-Scheduler als Teil des NUT-Monitor führt diese Events aus und verfolgt sie im zeitlichen Ablauf.
Ich habe mich überall für Konfigurationen vom Typ “Netserver” entschieden, bei denen aber der NUT-Server hinter einer lokalen Firewall für Verbindungen von außen geblockt ist.
NUT-Treiber
Der NUT-Treiber ist, wenn man einmal akzeptiert hat, dass die USVen alle buggy Firmware haben und man nie bei NUT die Schuld für Fehlfunktionen zu suchen hat, ganz einfach zu konfigurieren. Außer der Auswahl des passenden Subtreibers ist lediglich zu beachten, dass die USV-Firmwares die Timings mal in Sekunden, mal in Minuten und mal gemischt(!) entgegennehmen. Bei manchen darf auch kein ondelay von unter 3 Minuten konfiguriert werden. Was weiß denn ich. Eine /etc/nut/ups.conf:
# /etc/nut/ups.conf für BlueWalker PowerWalker VI 800 SW
maxretry = 3 # Erforderlich
[ups]
driver = blazer_usb # Wahrscheinlichste Alternative: usbhid-ups
port = auto
offdelay = 60 # Zeit bis zum Ausschalten nach Shutdown in Sekunden
ondelay = 3 # Mindestwartezeit bis zum Wiedereinschalten in Minuten
NUT-Server
Der NUT-Server ist etwas unübersichtlich zu konfigurieren, insbesondere bei der Rollenzuweisung im Rahmen seiner Userverwaltung. Die zentrale Konfigurationsdatei /etc/nut/nut.conf ist aber noch äußerst übersichtlich:
# /etc/nut/nut.conf
MODE=netserver
/etc/nut/upsd.conf habe ich inhaltlich leer gelassen (Voreinstellung, alles auskommentiert), hier können für den Netzwerkbetrieb Zertifikate und/oder für den lokalen Betrieb die Bindung auf Localhost konfiguriert werden.
In /etc/nut/upsd.users wird der User angelegt, mit dem sich der NUT-Monitor beim Server anmelden wird. Bei “upsmon master” scheint es sich um eine Art Macro zu handeln, das bestimmte Rechte für den User vorkonfiguriert; die Doku ist nicht allzu verständlich und es ist möglich, dass die expliziten “actions” hier redundant konfiguriert sind. Ansonsten wird hier explizit festgelegt, dass der User “upsmon” mit dem Passwort “xxx” “Instant Commands” an die USV senden darf, dass er mit SET diverse Einstellungen an ihr vornehmen darf, und dass er den FSD, den Forced Shutdown, einleiten darf.
# /etc/nut/upsd.users
[upsmon]
password = xxx
instcmds = ALL
actions = SET
actions = FSD
upsmon master
NUT-Monitor
Der NUT-Monitor ist die Kernkomponente, die tatsächlich den Shutdown des Systems einleiten und/oder abbrechen wird.
Zunächst muss die Kommunikation mit der USV namens “ups” mit dem User “upsmon” etabliert werden. “master” bedeutet, dass die USV hier am System lokal angeschlossen ist, die 1 ist eine Metrik für den Fall, dass mehrere USVen angeschlossen sind. Erhaltene Events werden an den NUT-Scheduler delegiert, und es sollen ausschließlich die Events ONLINE und ONBATT behandelt werden. Hier nur die relevanten zu ändernden Zeilen aus /etc/nut/upsmon.conf:
# /etc/nut/upsmon.conf (excerpt)
MONITOR ups@localhost 1 upsmon xxx master
NOTIFYCMD /sbin/upssched
NOTIFYFLAG ONLINE SYSLOG+WALL+EXEC
NOTIFYFLAG ONBATT SYSLOG+WALL+EXEC
NUT-Scheduler
Dem NUT-Scheduler wird der Pfad zu einem Shellscript übergeben, das den Shutdown des Systems handhaben wird. Die beiden Werte PIPEFN und LOCKFN haben keine Voreinstellungen und müssen sinnvoll belegt werden. Hier die komplette /etc/nut/upssched.conf:
# /etc/nut/upssched.conf
# https://networkupstools.org/docs/user-manual.chunked/ar01s07.html
CMDSCRIPT /usr/local/sbin/upssched-cmd
PIPEFN /run/nut/upssched.pipe
LOCKFN /run/nut/upssched.lock
AT ONBATT * START-TIMER onbatteryshutdown 30
AT ONLINE * CANCEL-TIMER onbatteryshutdown
AT ONBATT * EXECUTE onbattery
AT ONLINE * EXECUTE online
Wenn der Event ONBATT behandelt wird, die USV sich also im Batteriebetrieb befindet:
- Wird ein Timer gestartet, der in 30 Sekunden das CMDSCRIPT mit dem Argument onbatteryshutdown ausführen wird.
- Wird das CMDSCRIPT ausgeführt mit dem Argument onbattery, das die eingeloggten User über den Stromausfall und den in 30 Sekunden bevorstehenden Shutdown informiert.
Wenn der Event ONLINE behandelt wird, die USV sich also nicht mehr im Batteriebetrieb befindet:
- Wird der zuvor gestartete Timer abgebrochen.
- Wird das CMDSCRIPT ausgeführt mit dem Argument online, das die eingeloggten User über den abgebrochenen Shutdown informiert.
CMDSCRIPT /usr/local/sbin/upssched-cmd
Das Herz des Systems ist natürlich in liebevoller Manufakturqualität selbstgescriptet. Der Shutdown selbst wird mit /sbin/upsmon -c fsd bei NUT-Server in Auftrag gegeben, der theoretisch auch noch die Aufgabe hätte, die Shutdowns von per Netzwerk angebundenen Systemen abzuwarten. Bei diesem Forced Shutdown sagt NUT-Server der USV Bescheid, dass der Shutdown jetzt durchgezogen wird und sie nach der im NUT-Treiber konfigurierten offdelay die Stromversorgung auch wirklich aus- und nach Wiederherstellung der Stromversorgung, oder einer Mindestwartezeit, wieder einschalten soll.
#!/usr/bin/env bash
me_path="$(readlink -f "$0")"
case "${1}" in
'onbattery')
/usr/bin/logger -p daemon.warn -t "${me_path}" "UPS on battery."
/usr/bin/wall <<-Here
$(figlet -f small BLACKOUT)
$(figlet -f small BLACKOUT)
+++++ SYSTEM WILL SHUT DOWN IN 30 SECONDS. +++++
Here
;;
'onbatteryshutdown')
/usr/bin/logger -p daemon.crit -t "${me_path}" "UPS on battery, forcing shutdown."
/usr/bin/wall <<-Here
$(figlet -f small BLACKOUT)
$(figlet -f small BLACKOUT)
+++++ SYSTEM IS SHUTTING DOWN N O W. +++++
Here
/sbin/upsmon -c fsd
;;
'online')
/usr/bin/logger -p daemon.warn -t "${me_path}" "UPS no longer on battery."
/usr/bin/wall <<-Here
$(figlet -f small SHUTDOWN)
$(figlet -f small ABORTED)
Power restored. Shutdown aborted. Have a nice day. <3
Here
;;
*)
/usr/bin/logger -p daemon.info -t "${me_path}" "Unrecognized command: ${1}"
echo '?'
;;
esac
Administration/Troubleshooting
Status der USV abfragen:
upsc ups
upsc ups battery.charge
upsc ups ups.status
Unterstützte Kommandos der USV abfragen:
upscmd -u upsmon -p xxx -l ups
Kommando absetzen:
upscmd -u upsmon -p xxx ups <kommando>
upscmd -u upsmon -p xxx ups test.battery.start.quick
upscmd -u upsmon -p xxx ups test.battery.start.deep
Treiber bei der Interaktion mit der USV zuschauen (sollte eigentlich nie erforderlich sein):
/lib/nut/usbhid-ups -DDD -a ups
/lib/nut/usbhid-ups -DDDD -a ups
/lib/nut/usbhid-ups -DDDDD -a ups
Und welche USV ist nun zu empfehlen?
Es gilt leider nur diese eine Empfehlung, die irgendwo auf der NUT-Homepage auftaucht:
Jede, bei deren Kauf man sicher weiß, dass man ein uneingeschränktes Rückgaberecht hat.