ExecStart är inte ett skal: reparera en VPN-hjälpenhet
ExecStart kör ett program med argument, inte en skallpipeline. Använd en explicit tolk eller ett riktigt skript, verifiera sedan enheten och läs journalen.
Kopiera en fungerande kommandorad till ExecStart, ladda om, och enheten misslyckas eller avslutas tyst eftersom argumenten behandlas som filnamn. Inget är trasigt i systemd. ExecStart är en argumentlista, inte ett skal, så rör, omdirigering och villkor förlorar sin betydelse i samma stund de lämnar terminalen. Bestäm var skalet hör hemma och skriv sedan en enhet som säger exakt vad som ska köras.
Varför röret i ExecStart inte gör något
När ett kommando skrivs i en terminal tolkar skalet det först. Det bygger ett rör, öppnar filer för omdirigering och expanderar variabler innan något program startar. systemd gör inget av detta: det delar ExecStart enligt sina egna regler och kör det resulterande programmet med de argumenten. Därför kommer > som ett bokstavligt argument, och ett | lämnas till programmet i stället för att koppla ihop två processer. Enheten beter sig inte fel; syntaxen menade något annat.
Det är avsiktligt och inte slarv, eftersom förutsägbar argumenthantering är det som gör enheter granskningsbara. Det överraskar bara dem som antar att det finns ett skal.
Skriv en enhet som säger exakt vad som körs
Börja med en liten enhet vars syfte syns i journalen, så att tolkningsproblem hålls åtskilda från tunnelproblem. Den här rapporterar bara versionen av en binär.
[Unit]
Description=Report the installed OpenVPN version
[Service]
Type=oneshot
ExecStart=/usr/sbin/openvpn --version
StandardOutput=journal
StandardError=journalSökvägen är en platshållare, så byt ut den mot binären som faktiskt är installerad. Type=oneshot passar för ett kommando som körs till slutförande, och journalinställningarna lägger dess utdata där du kan läsa dem utan terminal. Det finns medvetet ingen installationssektion, så enheten anropas för hand i stället för att aktiveras vid start. Validera filen innan du startar den, eftersom ett stavfel i ett direktivnamn misslyckas annorlunda än ett stavfel i sökvägen.
systemd-analyze verify /etc/systemd/system/openvpn-version.service
systemctl start openvpn-version.serviceHåll skallogik i ett skript
När en hjälpare verkligen behöver villkorlig logik, lägg den logiken i ett skript och anropa det uttryckligen. Skriptet behöver en tolkrad, körrättighet och utgångskoder som tjänsten kan rapportera. Att starta /bin/sh -c med ett kommando inom citattecken fungerar, men det gömmer citatregler inne i en enhet och gör granskningen svårare. Ett namngivet skript kan testas för hand och bytas ut senare utan att enheten redigeras. Förlita dig inte på den interaktiva användarens skalprofil, eftersom en tjänst startar med sin egen miljö.
Ange WorkingDirectory när relativa sökvägar spelar roll, och skicka miljön via enhetens stödda direktiv i stället för att exportera den i en terminal. Hemligheter hör hemma i skyddade filer eller autentiseringsuppgifter, inte i argumentlistor som journalen kan registrera.
Kontrollera enheten som faktiskt finns
Drop-in-filer ändrar beteende utan att röra filen du minns att du redigerade. Läs vad hanteraren laddade och vad den senaste körningen rapporterade.
systemctl cat vpn-helper.service
journalctl -u vpn-helper.service -n 20 --no-pagerEnhetsutskriften innehåller drop-in-filer i laddningsordning, och det är oftast därifrån en oväntad ExecStart kommer. Ladda om hanteraren efter varje ändring och bekräfta att den nya definitionen är det som systemctl cat skriver ut. Journalen visar den exakta kommandoraden och utgångsstatusen, vilket skiljer ett argumentproblem från en saknad binär eller ett behörighetsfel. Bestäm sedan om hjälparen hör till den befintliga VPN-livscykeln eller bör förbli en manuell diagnos, eftersom en andra bakgrundstunnelprocess skapar en konkurrerande ägare.
En enhet som skriver ut rätt utdata på begäran är en bra första milstolpe. Den är ännu inte en tunnel och bör inte låtsas vara det.