ExecStart ist keine Shell: eine VPN-Hilfsunit reparieren
ExecStart startet ein Programm mit Argumenten, keine Shell-Pipeline. Nutzen Sie einen expliziten Interpreter oder ein echtes Skript, prüfen Sie dann die Unit und lesen Sie das Journal.
Kopieren Sie eine funktionierende Kommandozeile in ExecStart, laden Sie neu, und die Unit schlägt fehl oder endet still, weil die Argumente als Dateinamen behandelt werden. An systemd ist nichts kaputt. ExecStart ist eine Argumentliste, keine Shell, deshalb verlieren Pipes, Umleitung und Bedingungen ihre Bedeutung, sobald sie Ihr Terminal verlassen. Entscheiden Sie, wohin die Shell gehört, und schreiben Sie dann eine Unit, die genau sagt, was ausgeführt werden soll.
Warum die Pipeline in ExecStart nichts bewirkt
Wenn ein Befehl in ein Terminal getippt wird, parst ihn zuerst die Shell. Sie baut eine Pipeline, öffnet Dateien für Umleitungen und expandiert Variablen, bevor irgendein Programm startet. systemd macht nichts davon: Es zerlegt ExecStart nach eigenen Regeln und führt das resultierende Programm mit diesen Argumenten aus. Daher kommt > als wörtliches Argument an, und | wird an das Programm übergeben, statt zwei Prozesse zu verbinden. Die Unit verhält sich nicht falsch; die Syntax meinte etwas anderes.
Das ist Absicht und keine Nachlässigkeit, denn vorhersehbare Argumentbehandlung macht Units prüfbar. Es überrascht nur jene, die eine Shell voraussetzen.
Schreiben Sie eine Unit, die genau sagt, was läuft
Beginnen Sie mit einer kleinen Unit, deren Zweck im Journal sichtbar ist, damit Parsing-Probleme getrennt von Tunnel-Problemen bleiben. Diese meldet nur die Version eines Binärprogramms.
[Unit]
Description=Report the installed OpenVPN version
[Service]
Type=oneshot
ExecStart=/usr/sbin/openvpn --version
StandardOutput=journal
StandardError=journalDer Pfad ist ein Platzhalter, ersetzen Sie ihn also durch das tatsächlich installierte Binärprogramm. Type=oneshot eignet sich für einen Befehl, der bis zum Ende läuft, und die Journal-Einstellungen legen seine Ausgabe dorthin, wo Sie sie ohne Terminal lesen können. Eine Install-Sektion fehlt bewusst, deshalb wird die Unit von Hand aufgerufen statt beim Booten aktiviert. Prüfen Sie die Datei vor dem Start, denn ein Tippfehler im Namen einer Direktive scheitert anders als einer im Pfad.
systemd-analyze verify /etc/systemd/system/openvpn-version.service
systemctl start openvpn-version.serviceHalten Sie Shell-Logik in einem Skript
Wenn ein Helfer wirklich bedingte Logik braucht, legen Sie diese Logik in ein Skript und rufen es ausdrücklich auf. Das Skript braucht eine Interpreterzeile, Ausführungsrechte und Exit-Codes, die der Dienst melden kann. Der Start von /bin/sh -c mit einem gequoteten Befehl funktioniert, verbirgt aber die Quoting-Regeln in einer Unit und erschwert die Prüfung. Ein benanntes Skript lässt sich von Hand testen und später ersetzen, ohne die Unit zu ändern. Verlassen Sie sich nicht auf das Shell-Profil des interaktiven Benutzers, denn ein Dienst startet mit seiner eigenen Umgebung.
Setzen Sie WorkingDirectory, wenn relative Pfade zählen, und reichen Sie die Umgebung über die unterstützten Direktiven der Unit weiter, statt sie in einem Terminal zu exportieren. Geheimnisse gehören in geschützte Dateien oder Credentials, nicht in Argumentlisten, die das Journal aufzeichnen kann.
Prüfen Sie die Unit, die wirklich existiert
Drop-ins ändern das Verhalten, ohne die Datei anzutasten, die Sie bearbeitet zu haben glauben. Lesen Sie, was der Manager geladen hat und was der letzte Lauf gemeldet hat.
systemctl cat vpn-helper.service
journalctl -u vpn-helper.service -n 20 --no-pagerDer Unit-Dump enthält Drop-ins in Ladereihenfolge, und daher kommt meist ein unerwarteter ExecStart. Laden Sie nach jeder Änderung den Manager neu und bestätigen Sie, dass die neue Definition das ist, was systemctl cat ausgibt. Das Journal zeigt die exakte Kommandozeile und den Exit-Status, was ein Argumentproblem von einem fehlenden Binärprogramm oder einem Berechtigungsfehler trennt. Entscheiden Sie dann, ob der Helfer zum bestehenden VPN-Lebenszyklus gehört oder eine manuelle Diagnose bleiben sollte, denn ein zweiter Tunnelprozess im Hintergrund schafft einen konkurrierenden Eigentümer.
Eine Unit, die auf Anforderung die richtige Ausgabe zeigt, ist ein guter erster Meilenstein. Sie ist noch kein Tunnel und sollte nicht so tun, als wäre sie einer.