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?
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.
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.
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.
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
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/
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 .
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
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:
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.
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
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.
[Unit]
After=systemd-networkd.service
travaille pour moi.