Fyrtio .ovpn-filer för ett land kommer från en leverantör, och planen verkar självklar: kopiera en slumpmässig på plats och starta sedan tunneln. Skriven som en pipeline inne i ExecStart dör den planen vid uppstart med en statuskod som inte förklarar någonting. Unit-filen är inte ett skript, och rättelsen är antingen att ta in ett skal uttryckligen eller att sluta välja filer helt.

Symtomet: en unit som startar och dör omedelbart

Statusen visar att tjänsten misslyckades på en bråkdel av en sekund, och journalraden namnger ett kommando som inget skal någonsin skulle ha fått. Ingenting om tunneln dyker upp, eftersom tunneln aldrig började.

Att läsa den exakta kommandoraden från journalen är det snabbaste sättet att bekräfta detta. systemd upprepar vad det körde, och strängen visar pipeline-tecknen som bokstavliga argument i stället för som operatorer.

Varför ExecStart inte kan köra en pipeline

systemd delar upp kommandoraden själv, tillämpar sin egen citat- och variabelsubstitution och kör sedan resultatet direkt. Pipes, omdirigering, glob-utvidgning från ett skal och kommandosubstitution är helt enkelt inte en del av den grammatiken. Det är ett designval och inte en utelämning: en unit säger deklarativt vad som ska köras, och skal-logik hör hemma i ett skript som uniten anropar. Båda rättelserna följer av detta, och ingen av dem kräver att uniten får fler rättigheter.

Det förklarar också den missvisande utgångskoden. Det första argumentet behandlas som binären, så en felaktig rad misslyckas innan någon del av din logik körs.

Gör valet i ExecStartPre

Den direkta rättelsen är ett förberedelsesteg som anropar ett skal uttryckligen och håller valet och starten i samma unit, så att ett fel i den ena inte kan lämna den andra att köra ensam.

[Service]
Type=notify
ExecStartPre=/bin/bash -c "ls /etc/openvpn/profiles/au* | shuf -n 1 | xargs -r -I{} cp -f {} /etc/openvpn/%i.conf"
ExecStart=/usr/sbin/openvpn --config /etc/openvpn/%i.conf

Tre detaljer avgör om detta överlever mötet med en riktig maskin. Namngivning är den första fällan: systemd ersätter %i redan vid parsningen av uniten, långt innan bash körs, så specificeraren måste stå utanför enkla citattecken. xargs -r hindrar cp från att köras utan argument när globen inte matchar något. Och ett misslyckat förberedelsesteg stoppar uniten, och det är rätt utfall: att starta med gårdagens konfiguration är sämre än att inte starta. Ett slumpmässigt val som alltid tar samma fil är oftast inte otur. Kontrollera om den kopierade filen skrivs över av en paketuppdatering, eller om globen bara matchar en enda inaktuell post.

Eller låt OpenVPN välja slutpunkten

OpenVPN kan redan hålla flera slutpunkter i en profil och välja slumpmässigt bland dem, vilket tar bort skalet, kopian och skrivåtkomsten helt från uppstartsvägen.

client
remote-random
<connection>
remote au1.example.net 1194 udp
</connection>
<connection>
remote au2.example.net 1194 udp
</connection>

Den här formen håller servervalet inne i filen som leverantören skrev, så en rotation som byter namn på filer bryter inte uniten. Den gör också kandidatlistan granskningsbar, vilket en glob över en katalog aldrig är. Blandningen har fortfarande sin plats när profiler skiljer sig i mer än en slutpunkt: olika certifikat, olika routningsdirektiv, olika chifferpolicy. I så fall är valet mellan hela konfigurationer, och ett skalsteg är det ärliga sättet att uttrycka det.

Läs tillbaka instansen och filen den använde

Bekräfta vilken unit som faktiskt körs innan du felsöker innehållet. Den paketerade metatjänsten och mallen är infrastruktur; unitarna som motsvarar dina filer är instanserna som är uppkallade efter dem.

systemctl list-units 'openvpn*'
systemctl cat [email protected]
journalctl -u openvpn@au -n 30 --no-pager

En instans som ingen minns att man aktiverade leder vanligtvis tillbaka till en vilsegången konfigurationsfil i paketkatalogen. Stäng av den namngivna instansen i stället för mallen, annars tar nästa paketuppgradering tillbaka den. Efter ändringen startar du uniten och läser kommandoraden som journalen rapporterar, och bekräftar sedan konfigurationssökvägen som den faktiskt öppnade. Den enda kontrollen skiljer ett fungerande slumpmässigt val från en tjänst som tyst återanvänder en fil från förra månaden.

Relaterade artiklar