ExecStart není shell: oprava pomocné jednotky VPN
ExecStart spouští program s argumenty, ne shellovou rouru. Použijte explicitní interpret nebo skutečný skript, potom jednotku ověřte a přečtěte journal.
Zkopírujte fungující příkazový řádek do ExecStart, znovu načtěte a jednotka selže nebo tiše skončí, protože se argumenty považují za názvy souborů. V systemd není nic rozbité. ExecStart je seznam argumentů, ne shell, takže roury, přesměrování a podmínky ztrácejí smysl ve chvíli, kdy opustí váš terminál. Rozhodněte, kam shell patří, a pak napište jednotku, která přesně říká, co se má spustit.
Proč roura v ExecStart nic nedělá
Když se příkaz napíše do terminálu, shell jej nejprve zpracuje. Sestaví rouru, otevře soubory pro přesměrování a rozvine proměnné dřív, než se spustí jakýkoli program. systemd nic z toho nedělá: rozdělí ExecStart podle vlastních pravidel a spustí výsledný program s těmito argumenty. Proto > dorazí jako doslovný argument a | se předá programu místo toho, aby spojil dva procesy. Jednotka se nechová špatně; syntaxe znamenala něco jiného.
Je to záměr, ne nedbalost, protože předvídatelné zacházení s argumenty dělá jednotky auditovatelnými. Překvapí jen ty, kdo předpokládají, že shell je přítomný.
Napište jednotku, která přesně říká, co se spouští
Začněte malou jednotkou, jejíž účel je vidět v journalu, aby problémy s parsováním zůstaly oddělené od problémů s tunelem. Tahle jen hlásí verzi binárky.
[Unit]
Description=Report the installed OpenVPN version
[Service]
Type=oneshot
ExecStart=/usr/sbin/openvpn --version
StandardOutput=journal
StandardError=journalCesta je zástupný text, takže ji nahraďte binárkou, která je skutečně nainstalovaná. Type=oneshot se hodí pro příkaz, který běží do konce, a nastavení journalu umístí jeho výstup tam, kde si ho přečtete bez terminálu. Sekce pro instalaci záměrně chybí, takže se jednotka volá ručně, místo aby se povolila při startu. Ověřte soubor před spuštěním, protože překlep v názvu direktivy selhává jinak než překlep v cestě.
systemd-analyze verify /etc/systemd/system/openvpn-version.service
systemctl start openvpn-version.serviceNechte shellovou logiku ve skriptu
Když pomocník opravdu potřebuje podmíněnou logiku, dejte ji do skriptu a volejte ho explicitně. Skript potřebuje řádek s interpretem, právo spuštění a návratové kódy, které služba umí nahlásit. Spouštění /bin/sh -c s příkazem v uvozovkách funguje, ale skrývá pravidla uvozování uvnitř jednotky a ztěžuje kontrolu. Pojmenovaný skript lze vyzkoušet ručně a později nahradit bez úpravy jednotky. Nespoléhejte na profil shellu interaktivního uživatele, protože služba startuje s vlastním prostředím.
Nastavte WorkingDirectory, když záleží na relativních cestách, a předávejte prostředí podporovanými direktivami jednotky, místo abyste ho exportovali v terminálu. Tajemství patří do chráněných souborů nebo přihlašovacích údajů, ne do seznamů argumentů, které může journal zaznamenat.
Zkontrolujte jednotku, která skutečně existuje
Drop-in soubory mění chování, aniž by se dotkly souboru, který si pamatujete, že jste upravovali. Přečtěte si, co správce načetl a co nahlásil poslední běh.
systemctl cat vpn-helper.service
journalctl -u vpn-helper.service -n 20 --no-pagerVýpis jednotky zahrnuje drop-in soubory v pořadí načítání a právě odtud obvykle pochází neočekávaný ExecStart. Po každé změně znovu načtěte správce a potvrďte, že nová definice je to, co vypisuje systemctl cat. Journal ukazuje přesný příkazový řádek a návratový stav, což odděluje problém s argumenty od chybějící binárky nebo chyby oprávnění. Pak rozhodněte, zda pomocník patří ke stávajícímu životnímu cyklu VPN, nebo má zůstat ruční diagnostikou, protože druhý proces tunelu na pozadí vytváří konkurenčního vlastníka.
Jednotka, která na požádání vypíše správný výstup, je dobrý první milník. Ještě to není tunel a neměla by předstírat, že jím je.