web-dev-qa-db-fra.com

Faire exécuter un script après le démarrage du réseau?

Je suis relativement nouveau sur systemd et j'apprends son architecture.

En ce moment, j'essaie de comprendre comment provoquer l'exécution d'un script Shell personnalisé. Ce script doit être exécuté après la couche réseau a démarré.

J'exécute Arch, en utilisant systemd ainsi que netctl.

Pour tester, j'ai écrit un script simple qui exécute simplement ip addr list > /tmp/ip.txt. J'ai créé le fichier de service suivant pour ce script.

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

[Service]
ExecStart=/root/test.script

[Install]
WantedBy=multi-user.target

J'ai ensuite activé le script avec,

systemctl enable test

Au redémarrage, le script s'exécute en effet, mais il s'exécute avant le démarrage du réseau. En d'autres termes, la sortie dans ip.txt n'affiche aucune adresse IPv4 attribuée à l'interface principale. Au moment où je me connecte, l'adresse IPv4 a bien été attribuée et le réseau est en place.

Je suppose que je pourrais modifier le point auquel le script s'exécute en jouant avec le paramètre WantedBy, mais je ne sais pas comment faire.

Quelqu'un peut-il m'indiquer la bonne direction?

112
fdmillion

Sur les dépendances de configuration réseau de systemd

Il est très facile d'affecter la commande des unités de systemd. D'un autre côté, vous devez faire attention à ce que garantit une unité terminée.

Configurez votre service

Sur les systèmes actuels, commande après network.target garantit simplement que le service réseau a été démarré, pas qu'il y ait une configuration réelle. Vous devez commander après network-online.target et tirez dessus pour y parvenir.

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

Pour la compatibilité avec les anciens systèmes, vous devrez peut-être également commander après network.target.

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

C'est pour le fichier d'unité de votre service et pour systemd.

Implémentation dans les versions actuelles du logiciel

Vous devez maintenant vous assurer que network-online.target fonctionne comme prévu (ou que vous pouvez au moins utiliser network.target).

La version actuelle de NetworkManager offre le NetworkManager-wait-online.service qui est entraîné par network-online.target et donc par votre service. Ce service spécial garantit que votre service attendra jusqu'à ce que toutes les connexions configurées pour être démarrées réussissent, échouent ou expirent automatiquement.

La version actuelle de systemd-networkd bloque votre service jusqu'à ce que tous les appareils soient configurés comme demandé. Il est plus simple car il ne prend actuellement en charge que les configurations appliquées au démarrage (plus précisément l'heure de démarrage de `systemd-networkd.service).

Par souci d'exhaustivité, le /etc/init.d/network service dans Fedora, tel qu'interprété par les versions actuelles de systemd, bloque network.target et bloque donc indirectement network-online.target et votre service. C'est un exemple d'implémentation basée sur un script.

Si votre implémentation, qu'elle soit basée sur un démon ou sur un script, se comporte comme l'un des services de gestion de réseau ci-dessus, elle retardera le démarrage de votre service jusqu'à ce que la configuration du réseau soit terminée avec succès, échouée pour une bonne raison ou expirée après un délai raisonnable cadre à compléter.

Vous voudrez peut-être vérifier si netctl fonctionne de la même manière et cette information serait un ajout précieux à cette réponse.

Implémentations dans les anciennes versions du logiciel

Je ne pense pas que vous verrez une version suffisamment ancienne de systemd où cela ne fonctionnerait pas bien. Mais vous pouvez vérifier qu'au moins network-online.target existe et qu'il est commandé après network.target.

Auparavant NetworkManager ne garantissait qu'au moins une connexion serait appliquée. Et même pour que cela fonctionne, vous devez activer le NetworkManager-wait-online.service explicitement. Cela a longtemps été corrigé dans Fedora mais n'a été appliqué que récemment en amont.

systemctl enable NetworkManager-wait-online.service

Remarques sur les implémentations network.target et network-online.target

Vous ne devriez jamais avoir besoin de faire dépendre votre logiciel de NetworkManager.service ou NetworkManager-wait-online.service ni aucun autre service spécifique. Au lieu de cela, tous les services de gestion de réseau doivent se commander avant network.target et éventuellement network-online.target.

Un service de gestion de réseau basé sur un script simple doit terminer la configuration du réseau avant de quitter et doit se commander avant network.target et donc indirectement avant network-online.target.

[Unit]
Before=network.target

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

Un service de gestion de réseau basé sur un démon doit également se commander avant network.target même si ce n'est pas très utile.

[Unit]
Before=network.target

[Service]
Type=simple
ExecStart=...

Un service qui attend la fin du démon doit s'ordonner après le service spécifique et avant network-online.target. Il doit utiliser Requisite sur le service démon afin qu'il échoue immédiatement si le service de gestion de réseau respectif n'est pas utilisé.

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

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

Le package doit installer un lien symbolique vers le service en attente dans le répertoire wants pour network-online.target afin qu'il soit attiré par les services qui souhaitent attendre le réseau configuré.

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

Documentation connexe

Notes finales

J'espère que j'ai non seulement aidé à répondre à votre question au moment où vous l'avez posée, mais aussi contribué à améliorer la situation dans les distributions en amont et Linux, afin que je puisse maintenant donner une meilleure réponse que ce qui était possible au moment de la rédaction de l'original .

138
Pavel Šimerda

Vous pouvez utiliser After dans [Unit] section pour définir un service à démarrer avant le démarrage de votre service. Par exemple, si vous utilisez NetworkManager, vous pouvez démarrer votre service après le démarrage de NetworkManager.

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

Si votre service fournit un serveur, qui peut attendre passivement que quelqu'un s'y connecte, utilisez ceci:

[Unit]
After=network.target

Votre service doit se lier sur l'interface générique. S'il utilise l'activation de socket (recommandé), ou s'il est local uniquement, vous pouvez ignorer complètement les cibles réseau.

Si votre service agit en tant que client ou est peer to peer, cela est plus approprié:

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

Avant systemd 21 , network-online.target a besoin de la solution de contournement mentionnée par Pavel (vous devez activer manuellement un service qui attendra que le réseau soit en place). Depuis systemd 213, cela se fait par défaut. systemd-networkd-wait-online attendra qu'au moins une adresse (routable ou link-local) soit configurée sur une interface sans bouclage.

La configuration de systemd-networkd, NetworkManager ou équivalent est une tâche indépendante. DHCP (pour IPv4) et NDP (pour IPv6) ont tendance à fonctionner par défaut, mais vous devez les configurer de sorte que votre définition précise de "le réseau soit en place" soit ce qui déclenche network-online.target.

Documentation:

8
Tobu

Je suppose que je pourrais modifier le point auquel le script s'exécute en jouant avec le paramètre WantedBy

Cela aura l'effet inverse de ce que vous voulez. De man systemd.unit:

WantedBy =, RequiredBy =

[...] Un lien symbolique est créé dans le répertoire .wants/ou .requires/de chacune des unités répertoriées lorsque cette unité est installée par systemctl enable. Cela a pour effet qu'une dépendance de type Wants = ou Requiert = est ajoutée de nité répertoriée à nité actuelle.

Sur cette base, nous pouvons voir que l'option appropriée est "Veut" ou "Requiert"; sur la base de la description de ceux-ci, "Requiert" est probablement correct, avec l'ajout de "Après" pour garantir non seulement que le service réseau soit exécuté, mais qu'il s'exécute avant cette unité.

Aucune des options d'unité, AFAIK, ne peut inclure la stipulation qu'un programme préalable démarré doit avoir terminé, ou atteint un certain point (la mise en réseau est probablement un service démon), seulement qu'il démarre d'abord. Dans cet esprit, vous voudrez peut-être faire votre script Type=forking et ajoutez un délai sain (disons 30 secondes), ou une sorte de boucle de sortie en cas de succès, y compris un délai, pour vous assurer que vous disposez d'un bail DHCP en premier.

4
goldilocks

Utilisez After dans le [Unit] section pour spécifier ce qui doit être démarré avant votre propre service. (Cette partie de la réponse précédente est correcte.)

Pour démarrer votre service une fois le réseau activé, utilisez la cible réseau, qui devrait s'appliquer que vous utilisiez NetworkManager, le système conf.d/netctl dans Arch ou tout autre service dont systemd a connaissance.

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

Un bref aperçu confirmera que chaque service autre de votre système qui repose sur la connectivité réseau contient cette directive.

Il est également portable pour toute distribution utilisant systemd. Votre fichier unitaire sera le même pour Arch, Fedora, RHEL 7, les futures versions de Debian ...


Les services qui démarrent une connexion réseau, tels que les scripts d'Arch ou les vôtres, doivent le spécifier dans leurs propres fichiers d'unité.

[Unit]
Wants=network.target
Before=network.target
3
Michael Hampton

Je voulais ajouter un point à cet article. Actuellement (été 2015) dans RHEL7/CentOS 7, network-online.target n'est pas correctement défini avant la mise en réseau IPv6, donc les démons qui ont

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

dans leur définition de service qui se lient également explicitement aux adresses IPv6 sera probablement démarré avant que IPv6 ne soit opérationnel, ce qui entraînera leur échec.

1
Colo Host
[Unit]
After=systemd-networkd.service

travaille pour moi.

0
Zhenxiao Hao