ExecStart nu este un shell: repararea unei unități ajutătoare VPN
ExecStart rulează un program cu argumente, nu un pipeline de shell. Folosiți un interpretor explicit sau un script real, apoi verificați unitatea și citiți jurnalul.
Copiați o linie de comandă funcțională în ExecStart, reîncărcați, iar unitatea eșuează sau se termină în tăcere, tratând argumentele drept nume de fișiere. Nimic nu este stricat în systemd. ExecStart este o listă de argumente, nu un shell, așa că pipe-urile, redirecționarea și condițiile își pierd sensul în momentul în care părăsesc terminalul. Decideți unde îi este locul shell-ului, apoi scrieți o unitate care spune exact ce trebuie executat.
De ce pipe-ul din ExecStart nu face nimic
Când o comandă este tastată într-un terminal, shell-ul o analizează mai întâi. Construiește un pipe, deschide fișiere pentru redirecționare și extinde variabilele înainte ca vreun program să pornească. systemd nu face nimic din toate acestea: împarte ExecStart după propriile reguli și execută programul rezultat cu acele argumente. De aceea > ajunge ca argument literal, iar un | este predat programului în loc să conecteze două procese. Unitatea nu se comportă greșit; sintaxa însemna altceva.
Este intenționat, nu neglijent, pentru că tratarea previzibilă a argumentelor este cea care face unitățile auditabile. Îi surprinde doar pe cei care presupun că există un shell.
Scrieți o unitate care spune exact ce rulează
Începeți cu o unitate mică al cărei scop este vizibil în jurnal, ca problemele de analiză să rămână separate de cele ale tunelului. Aceasta raportează doar versiunea unui binar.
[Unit]
Description=Report the installed OpenVPN version
[Service]
Type=oneshot
ExecStart=/usr/sbin/openvpn --version
StandardOutput=journal
StandardError=journalCalea este un substituent, așa că înlocuiți-o cu binarul care este într-adevăr instalat. Type=oneshot se potrivește unei comenzi care rulează până la capăt, iar setările jurnalului îi pun rezultatul acolo unde îl puteți citi fără terminal. Nu există în mod deliberat o secțiune de instalare, așa că unitatea este apelată manual în loc să fie activată la pornire. Validați fișierul înainte de a-l porni, pentru că o greșeală de tastare în numele unei directive eșuează diferit de una în cale.
systemd-analyze verify /etc/systemd/system/openvpn-version.service
systemctl start openvpn-version.servicePăstrați logica de shell într-un script
Când un ajutor are într-adevăr nevoie de logică condiționată, puneți acea logică într-un script și apelați-l explicit. Scriptul are nevoie de o linie de interpretor, permisiune de execuție și coduri de ieșire pe care serviciul le poate raporta. Lansarea /bin/sh -c cu o comandă între ghilimele funcționează, dar ascunde regulile de citare în interiorul unității și îngreunează revizuirea. Un script cu nume poate fi testat manual și înlocuit mai târziu fără a edita unitatea. Nu vă bazați pe profilul de shell al utilizatorului interactiv, pentru că un serviciu pornește cu propriul mediu.
Setați WorkingDirectory când căile relative contează, și transmiteți mediul prin directivele acceptate ale unității în loc să îl exportați într-un terminal. Secretele aparțin fișierelor protejate sau acreditărilor, nu listelor de argumente pe care jurnalul le poate înregistra.
Verificați unitatea care există cu adevărat
Fișierele drop-in schimbă comportamentul fără a atinge fișierul despre care vă amintiți că l-ați editat. Citiți ce a încărcat managerul și ce a raportat ultima rulare.
systemctl cat vpn-helper.service
journalctl -u vpn-helper.service -n 20 --no-pagerVidul unității include fișierele drop-in în ordinea încărcării, iar de acolo vine de obicei un ExecStart neașteptat. După orice modificare, reîncărcați managerul și confirmați că noua definiție este ceea ce afișează systemctl cat. Jurnalul arată linia de comandă exactă și starea de ieșire, ceea ce separă o problemă de argumente de un binar lipsă sau de o eroare de permisiuni. Apoi decideți dacă ajutorul aparține ciclului de viață VPN existent sau trebuie să rămână o diagnosticare manuală, pentru că un al doilea proces de tunel în fundal creează un proprietar concurent.
O unitate care afișează rezultatul corect la cerere este un bun prim reper. Nu este încă un tunel și nu ar trebui să pretindă că este.