Far eseguire uno script dopo l'avvio della rete?


102

Sono relativamente nuovo a Systemd e sto imparando la sua architettura.

In questo momento, sto cercando di capire come causare l'esecuzione di uno script di shell personalizzato. Questo script deve essere eseguito dopo l'avvio del livello di rete.

Sto eseguendo Arch, usando systemd e netctl.

Per testare, ho scritto un semplice script che si esegue semplicemente ip addr list > /tmp/ip.txt. Ho creato il seguente file di servizio per questo script.

(/etc/systemd/system/test.service)
[Unit]
Description=test service

[Service]
ExecStart=/root/test.script

[Install]
WantedBy=multi-user.target

Ho quindi abilitato lo script con,

systemctl enable test

Al riavvio, lo script viene effettivamente eseguito, ma viene eseguito prima dell'avvio della rete. In altre parole, l'output in ip.txtnon mostra alcun indirizzo IPv4 assegnato all'interfaccia primaria. Quando accedo, l'indirizzo IPv4 è stato effettivamente assegnato e la rete è attiva.

Immagino che potrei modificare il punto in cui lo script viene eseguito facendo confusione con il WantedByparametro, ma non sono sicuro di come farlo.

Potrebbe qualcuno indicarmi la giusta direzione?

Risposte:


126

Dipendenze dalla configurazione di rete del sistema

È molto facile influenzare l'ordinamento delle unità di systemd. D'altra parte è necessario fare attenzione a ciò che garantisce un'unità completata.

Configura il tuo servizio

Sui sistemi attuali, ordinare dopo network.targetgarantisce solo che il servizio di rete è stato avviato, non che ci sia una configurazione effettiva. È necessario ordinare dopo network-online.targeted estrarlo per raggiungere questo obiettivo.

[Unit]
Wants=network-online.target
After=network-online.target

Per compatibilità con i sistemi più vecchi, potrebbe essere necessario ordinare anche dopo network.target.

[Unit]
Wants=network-online.target
After=network.target network-online.target

Questo è per il file unitario del tuo servizio e per systemd.

Implementazione nelle versioni attuali del software

Ora devi assicurarti che network-online.targetfunzioni come previsto (o che almeno puoi usare network.target).

La versione attuale di NetworkManager offre ciò NetworkManager-wait-online.serviceche viene richiamato da network-online.targete quindi dal tuo servizio. Questo servizio speciale garantisce che il servizio attenderà fino a quando tutte le connessioni configurate per l'avvio avranno esito positivo, non riusciranno o scadranno.

La versione corrente di systemd-networkd blocca il servizio fino a quando tutti i dispositivi sono configurati come richiesto. È più semplice in quanto attualmente supporta solo le configurazioni che vengono applicate al momento dell'avvio (in particolare il tempo di avvio di `systemd-networkd.service).

Per completezza, il /etc/init.d/networkservizio in Fedora, come interpretato dalle attuali versioni di systemd, blocca network.targete quindi blocca indirettamente network-online.targete il vostro servizio. È un esempio di implementazione basata su script.

Se l'implementazione, sia basata su demone o basata su script, si comporta come uno dei servizi di gestione della rete di cui sopra, ritarderà l'avvio del servizio fino a quando la configurazione della rete non viene completata correttamente, non è riuscita per una buona ragione o è scaduta dopo un tempo ragionevole cornice da completare.

Potresti voler controllare se netctl funziona allo stesso modo e che le informazioni sarebbero una preziosa aggiunta a questa risposta.

Implementazioni nelle versioni precedenti del software

Non credo che vedrai una versione sufficientemente vecchia di systemd in cui questo non funzionerebbe bene. Ma puoi controllare che almeno network-online.targetesista e che venga ordinato dopo network.target.

In precedenza NetworkManager garantiva solo l'applicazione di almeno una connessione. E anche perché funzioni, dovresti abilitare NetworkManager-wait-online.serviceesplicitamente. Questo è stato a lungo risolto in Fedora ma è stato applicato solo di recente a monte.

systemctl enable NetworkManager-wait-online.service

Note sulle implementazioni di network.target e network-online.target

Non dovresti mai aver bisogno di far dipendere il tuo software NetworkManager.serviceo di NetworkManager-wait-online.servicealtri servizi specifici. Invece, tutti i servizi di gestione della rete dovrebbero ordinare se stessi prima network.targete opzionalmente network-online.target.

Un semplice servizio di gestione della rete basato su script dovrebbe completare la configurazione della rete prima di uscire e dovrebbe ordinarsi prima network.targete quindi indirettamente prima network-online.target.

[Unit]
Before=network.target

[Service]
Type=oneshot
ExecStart=...
RemainAfterExit=yes

Un servizio di gestione della rete basato su demoni dovrebbe anche ordinarsi prima, network.targetanche se non è molto utile.

[Unit]
Before=network.target

[Service]
Type=simple
ExecStart=...

Un servizio che attende il completamento del demone dovrebbe ordinarsi dopo il servizio specifico e prima network-online.target. Dovrebbe essere utilizzato Requisitesul servizio daemon in modo che fallisca immediatamente se non viene utilizzato il rispettivo servizio di gestione della rete.

[Unit]
Requisite=...
After=...
Before=network-online.target

[Service]
Type=oneshot
ExecStart=...
RemainAfterExit=yes

Il pacchetto dovrebbe installare un collegamento simbolico al servizio di attesa nella wantsdirectory in network-online.targetmodo che venga richiamato dai servizi che desiderano attendere la rete configurata.

ln -s /usr/lib/systemd/system/... /usr/lib/systemd/system/network-online.target.wants/

Documentazione correlata

Note finali

Spero non solo di aver contribuito a rispondere alla tua domanda al momento in cui l'hai fatta, ma anche di aver contribuito a migliorare la situazione nelle distribuzioni upstream e Linux, in modo che ora posso dare una risposta migliore di quanto fosse possibile al momento della stesura di quella originale .


Intendi l'opzione autoconnect per "attendere fino a quando tutte le connessioni configurate per l'avvio abbiano successo automaticamente"? Posso sfruttare questa opzione quando imposto no-auto-default = * ma ho autoconnect = yes su una delle mie connessioni? E l'ultima domanda - non capisco - l'opzione di attesa per l'avvio della pagina di nm-online e manuale non aiuta molto. Grazie per questo commento, molto apprezzato!
lzap,

Per quanto ne so, a nm-online non importa no-auto-default, solo auto. Hai qualche domanda specifica? A mio avviso, la manpage nm-online afferma chiaramente che con -sessa attende che vengano tentati tutti i collegamenti automatici, ovvero connessi o falliti.
Pavel Šimerda,

Dopo aver fatto confusione con questa merda per un'ora, ho trovato la soluzione: apt-get install sysv-init. :-) La complessità che systemd aggiunge in sostituzione di alcuni script della shell è sbalorditiva.
Qualcuno il

@Qualcuno teme che initscripts non sia una risposta in questo caso. Se stai usando NetworkManager o qualsiasi altro strumento di configurazione dinamica, gli initscripts non possono ordinarsi dopo una rete completamente configurata. Puoi ottenere una configurazione dinamica limitata usando /etc/init.d/networko simile ma non funziona universalmente.
Pavel Šimerda,

@Pavel Šimerda Init viene eseguito in serie e uno script init appropriato non tornerà finché non avrà terminato di fare ciò su cui devono fare affidamento gli script successivi. Per il networking ciò significherebbe avere tutti gli adattatori applicabili pronti e pronti. A meno che non sia stato solo un tempismo fortunato, NM si comporta bene in quel contesto. Il vero problema ovviamente è che NM reinventa la gestione della rete invece di basarsi su strutture esistenti semplici e collaudate. Le persone desktop sembrano non avere idea dei pericoli della complessità. ;-)
Qualcuno il

9

È possibile utilizzare Afternella [Unit]sezione per definire un servizio che deve essere avviato prima dell'avvio del servizio. Ad esempio, se si utilizza NetworkManager, è possibile avviare il servizio dopo l'avvio di NetworkManager.

[Unit]
Description=test service
After=NetworkManager.service

BindsTonon è così appropriato in quanto il servizio è un evento unico e non un servizio persistente (a meno che non includa anche una ExecStopfunzione da attivare quando la rete si interrompe).
Riccioli d'oro

rimossoBindsTo
phoops il

È possibile aggiungere qualcosa da sostituire BindsTo, ad esempio Requires, se si desidera eseguire il servizio solo se NetworkManager lo fa. Afterin realtà non lo fa - significa solo che anche NM è in esecuzione, quindi eseguirlo in seguito. Se NM non verrà eseguito, il servizio verrà eseguito in un punto arbitrario.
Riccioli d'oro

4
After = network.target è meglio di After = NetworkManager.service in quanto è più generico.
Pavel Šimerda,

7
Si noti che specificando After=foofarà non causare l' foounità per iniziare, se non è già stato avviato, sarà solo dire systemd come ordinare le unità se sono entrambi iniziato allo stesso tempo . L'uso di entrambi After=foo, così come Wants=fooo Requires=fooavrà l'effetto di fooentrare se non è avviato, e anche fare in modo che il sistema ordini le unità correttamente.
Emil Lundberg,

8

Se il tuo servizio fornisce un server, che può attendere passivamente che qualcuno si colleghi ad esso, usa questo:

[Unit]
After=network.target

Il servizio deve essere associato all'interfaccia con caratteri jolly. Se utilizza l'attivazione socket (consigliata) o se è solo locale, è possibile ignorare completamente le destinazioni di rete.

Se il tuo servizio funge da client o è peer to peer, questo è più appropriato:

[Unit]
After=network-online.target
Requires=network-online.target

Prima di systemd 213 , network-online.target necessita della soluzione alternativa menzionata da Pavel (è necessario abilitare manualmente un servizio che attenderà che la rete sia attiva). A partire da systemd 213 questo è fatto di default. systemd-networkd-wait-onlineattenderà che almeno un indirizzo (instradabile o link-local) sia configurato su un'interfaccia non loopback.

La configurazione di systemd-networkd, NetworkManager o equivalente è un'attività indipendente. DHCP (per IPv4) e NDP (per IPv6) tendono a funzionare immediatamente, ma è necessario configurarli in modo che la definizione precisa di "rete attiva" sia ciò che si innesca network-online.target.

Documentazione:


Solo curioso perché una nuova risposta e non solo piccoli miglioramenti alla risposta esistente e (si spera) ben strutturata.
Pavel Šimerda,

I primi due collegamenti alla documentazione sono attualmente non funzionanti.
Peter Hansen,

Perché usare Richiede invece di Desideri?
Karl Morrison,

4

Immagino di poter modificare il punto in cui lo script viene eseguito facendo confusione con il parametro WantedBy

Ciò avrà l'effetto opposto di quello che vuoi. Da man systemd.unit:

WantedBy =, RequiredBy =

[...] Un collegamento simbolico viene creato nella directory .wants / o .requires / di ciascuna delle unità elencate quando questa unità è installata dall'abilitazione di systemctl. Questo ha l'effetto che una dipendenza di tipo vuol = o = Richiede viene aggiunto dalla unità quotata alla unità corrente .

Sulla base di questo, possiamo vedere l'opzione di unità corretta è "Vuole" o "Richiede"; in base alla descrizione di questi, "Richiede" è probabilmente corretto, con l'aggiunta di "Dopo" per garantire non solo che il servizio di rete sia eseguito, ma che sia eseguito prima di questa unità.

Nessuna delle opzioni di unità, AFAIK, può includere la stipula che un requisito preliminare avviato deve essere completato o raggiunto un certo punto (la rete è probabilmente un servizio daemon), solo che inizia per prima. Con questo in mente, potresti voler creare il tuo script Type=forkinge lanciare un ritardo salutare (diciamo 30 secondi), o una sorta di ciclo di uscita al successo incluso un ritardo, per assicurarti di avere prima un contratto di locazione DHCP.


1
Né WantedBy né RequiredBy influiscono sull'ordinamento.
Pavel Šimerda,

1
@ PavelŠimerda: nessuno qui ha affermato di averlo fatto. L'ordine è il motivo per cui ho esplicitamente menzionato Afterinsieme a Requires"per garantire non solo che il servizio di rete sia eseguito, ma che venga eseguito prima di questa unità".
Riccioli d'oro

1
Sì, Afterfunziona insieme Wantso in Requiresquel modo. D'altra parte, i ritardi espliciti sono una cattiva abitudine negli strumenti basati sulla dipendenza, specialmente quando esiste un modo esplicito di attendere fino a quando la rete non viene configurata specificata dalla documentazione di sistema, quindi devo insistere sul downvote.
Pavel Šimerda,

3

Utilizzare Afternella [Unit]sezione per specificare cosa deve essere avviato prima del proprio servizio. (Gran parte della risposta precedente è corretta.)

Per avviare il servizio dopo che la rete è attiva, utilizzare la destinazione di rete, che dovrebbe applicarsi se si utilizza NetworkManager, il sistema conf.d / netctl in Arch o qualche altro servizio di cui Systemd è a conoscenza.

[Unit]
#.....
After=network.target

Un breve sguardo confermerà che ogni altro servizio sul sistema che si basa sulla connettività di rete contiene questa direttiva.

È anche portatile per qualsiasi distribuzione che utilizza systemd. Il file dell'unità sarà lo stesso per Arch, Fedora, RHEL 7, versioni future di Debian ...


I servizi che avviano una connessione di rete, come gli script di Arch o i tuoi, dovrebbero specificarlo nei propri file di unità.

[Unit]
Wants=network.target
Before=network.target

La parte non mi piace del tutto Wantsperché ha effetti collaterali su altri pacchetti. Guarda la mia risposta, per favore.
Pavel Šimerda,

Appena realizzato che Wantssu network.targetè una buona idea qui.
Pavel Šimerda,

vuoi davvero usare network-online.target. ref
Edward Torvalds,

1

Volevo aggiungere un punto a questo articolo. Attualmente (estate 2015) in RHEL7 / CentOS 7, network-online.target è impostato in modo errato prima che la rete IPv6 sia attiva, quindi i demoni che hanno

Wants=network-online.target
After=network-online.target

nella loro definizione di servizio che si legherà esplicitamente anche agli indirizzi IPv6 verrà probabilmente avviato prima che IPv6 sia attivo e funzionante, causandone il fallimento.


Immagino che questo sia il caso solo con la configurazione automatica IPv6 basata sul kernel che è comunque difettosa. Se si desidera ordinare correttamente dopo IPv6, è necessario utilizzare NetworkManager invece di /etc/init.d/network. Se si riscontra lo stesso problema anche con NM, sarebbe una buona ragione per presentare una richiesta di funzionalità. Non ho verificato con RHEL / CentOS, posso aiutarti con i dettagli se sei interessato.
Pavel Šimerda,

0
[Unit]
After=systemd-networkd.service

per me va bene.


Non sono sicuro che funzioni in alcuni casi speciali, ma è sbagliato per un paio di motivi. Uno di questi è che networkdfornisce il proprio servizio / wait-online /. Accedere e ordinare dopo network-online.targetè il modo giusto di andare con qualsiasi servizio che lo supporti.
Pavel Šimerda,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.