Copiate una riga di comando funzionante in ExecStart, ricaricate, e l’unità fallisce o termina in silenzio trattando gli argomenti come nomi di file. Nulla è rotto in systemd. ExecStart è un elenco di argomenti, non una shell, quindi pipe, reindirizzamenti e condizioni perdono senso nel momento in cui lasciano il terminale. Decidete dove deve stare la shell, poi scrivete un’unità che dica esattamente cosa eseguire.

Perché la pipeline in ExecStart non fa nulla

Quando un comando viene digitato in un terminale, la shell lo analizza per prima. Costruisce una pipeline, apre file per il reindirizzamento ed espande le variabili prima che qualsiasi programma parta. systemd non fa nulla di tutto ciò: divide ExecStart secondo le proprie regole ed esegue il programma risultante con quegli argomenti. Un > arriva quindi come argomento letterale, e una | viene passata al programma invece di collegare due processi. L’unità non si comporta male; la sintassi intendeva altro.

È deliberato e non trascurato, perché una gestione prevedibile degli argomenti è ciò che rende le unità verificabili. Sorprende solo chi dà per scontata la presenza di una shell.

Scrivete un’unità che dica esattamente cosa viene eseguito

Cominciate da un’unità piccola il cui scopo sia visibile nel journal, così che i problemi di analisi restino separati da quelli del tunnel. Questa riporta solo la versione di un binario.

[Unit]
Description=Report the installed OpenVPN version

[Service]
Type=oneshot
ExecStart=/usr/sbin/openvpn --version
StandardOutput=journal
StandardError=journal

Il percorso è un segnaposto, quindi sostituitelo con il binario realmente installato. Type=oneshot si adatta a un comando che viene eseguito fino in fondo, e le impostazioni del journal mettono il suo output dove potete leggerlo senza terminale. Non c’è deliberatamente una sezione di installazione, quindi l’unità viene richiamata a mano invece di essere abilitata all’avvio. Validate il file prima di avviarlo, perché un errore di battitura nel nome di una direttiva fallisce diversamente da un errore nel percorso.

systemd-analyze verify /etc/systemd/system/openvpn-version.service
systemctl start openvpn-version.service

Tenete la logica della shell in uno script

Quando un ausiliario ha davvero bisogno di logica condizionale, mettete quella logica in uno script e chiamatelo esplicitamente. Lo script richiede una riga di interprete, il permesso di esecuzione e codici di uscita che il servizio possa riportare. Avviare /bin/sh -c con un comando tra virgolette funziona, ma nasconde le regole di quoting dentro un’unità e rende la revisione più difficile. Uno script con nome può essere provato a mano e sostituito più tardi senza modificare l’unità. Non fate affidamento sul profilo shell dell’utente interattivo, perché un servizio parte con il proprio ambiente.

Impostate WorkingDirectory quando i percorsi relativi contano, e passate l’ambiente tramite le direttive supportate dall’unità invece di esportarlo in un terminale. I segreti appartengono a file protetti o credenziali, non a elenchi di argomenti che il journal può registrare.

Controllate l’unità che esiste davvero

I file drop-in cambiano il comportamento senza toccare il file che ricordate di aver modificato. Leggete cosa ha caricato il gestore e cosa ha riportato l’ultima esecuzione.

systemctl cat vpn-helper.service
journalctl -u vpn-helper.service -n 20 --no-pager

Il dump dell’unità include i file drop-in in ordine di caricamento, ed è da lì che di solito viene un ExecStart inatteso. Dopo ogni modifica ricaricate il gestore e confermate che la nuova definizione sia ciò che stampa systemctl cat. Il journal mostra la riga di comando esatta e lo stato di uscita, il che separa un problema di argomenti da un binario mancante o da un errore di permessi. Poi decidete se l’ausiliario appartiene al ciclo di vita VPN esistente o deve restare una diagnostica manuale, perché un secondo processo tunnel in background crea un proprietario concorrente.

Un’unità che stampa l’output giusto su richiesta è un buon primo traguardo. Non è ancora un tunnel, e non dovrebbe fingere di esserlo.

Articoli correlati