it-swarm.com.de

Ein Skript ausführen lassen, nachdem das Netzwerk gestartet wurde?

Ich bin relativ neu in systemd und lerne seine Architektur.

Im Moment versuche ich herauszufinden, wie ein benutzerdefiniertes Shell-Skript ausgeführt werden kann. Dieses Skript muss ausgeführt werden nach Die Netzwerkschicht wurde gestartet.

Ich verwende Arch sowohl mit systemd als auch mit netctl.

Zum Testen habe ich ein einfaches Skript geschrieben, das einfach ip addr list > /tmp/ip.txt Ausführt. Ich habe die folgende Servicedatei für dieses Skript erstellt.

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

[Service]
ExecStart=/root/test.script

[Install]
WantedBy=multi-user.target

Ich habe dann das Skript aktiviert mit,

systemctl enable test

Beim Neustart wird das Skript zwar ausgeführt, jedoch vor dem Start des Netzwerks. Mit anderen Worten, die Ausgabe in ip.txt Zeigt keine IPv4-Adresse an, die der primären Schnittstelle zugewiesen ist. Zum Zeitpunkt der Anmeldung wurde die IPv4-Adresse tatsächlich zugewiesen und das Netzwerk ist aktiv.

Ich schätze, ich könnte den Punkt ändern, an dem das Skript ausgeführt wird, indem ich mit dem Parameter WantedBy herumspiele, aber ich bin mir nicht sicher, wie ich das machen soll.

Könnte mich jemand in die richtige Richtung weisen?

112
fdmillion

Abhängigkeiten von systemd Netzwerkkonfiguration

Es ist sehr einfach, die Reihenfolge der Einheiten von systemd zu beeinflussen. Auf der anderen Seite müssen Sie vorsichtig sein, was eine fertige Einheit garantiert.

Konfigurieren Sie Ihren Service

Auf aktuellen Systemen garantiert die Bestellung nach network.target Nur, dass der Netzwerkdienst gestartet wurde, nicht dass eine tatsächliche Konfiguration vorliegt. Sie müssen nach network-online.target Bestellen und es einziehen, um dies zu erreichen.

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

Aus Gründen der Kompatibilität mit älteren Systemen müssen Sie möglicherweise auch nach network.target bestellen.

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

Das ist für die Unit-Datei Ihres Dienstes und für systemd.

Implementierung in aktuellen Softwareversionen

Jetzt müssen Sie sicherstellen, dass network-online.target Wie erwartet funktioniert (oder dass Sie zumindest network.target Verwenden können).

Die aktuelle Version von NetworkManager bietet den NetworkManager-wait-online.service, Der von network-online.target Und damit von Ihrem Dienst abgerufen wird. Dieser spezielle Dienst stellt sicher, dass Ihr Dienst wartet, bis alle zum Starten konfigurierten Verbindungen automatisch erfolgreich sind, fehlschlagen oder eine Zeitüberschreitung aufweisen.

Die aktuelle Version von systemd-networkd blockiert Ihren Dienst, bis alle Geräte wie angefordert konfiguriert sind. Dies ist einfacher, da derzeit nur Konfigurationen unterstützt werden, die beim Booten angewendet werden (insbesondere die Startzeit von `systemd-networkd.service).

Der Vollständigkeit halber blockiert der Dienst /etc/init.d/network In Fedora, wie er in den aktuellen Versionen von systemd interpretiert wird, network.target Und damit indirekt network-online.target Und Ihren Dienst. Dies ist ein Beispiel für eine skriptbasierte Implementierung.

Wenn sich Ihre Implementierung, ob dämonbasiert oder skriptbasiert, wie einer der oben genannten Netzwerkverwaltungsdienste verhält, verzögert sie den Start Ihres Dienstes, bis die Netzwerkkonfiguration entweder erfolgreich abgeschlossen wurde, aus gutem Grund fehlgeschlagen ist oder nach einer angemessenen Zeit eine Zeitüberschreitung auftritt Rahmen zu vervollständigen.

Vielleicht möchten Sie überprüfen, ob netctl auf die gleiche Weise funktioniert und diese Informationen eine wertvolle Ergänzung zu dieser Antwort darstellen.

Implementierungen in älteren Softwareversionen

Ich glaube nicht, dass Sie eine ausreichend alte Version von systemd sehen werden, bei der dies nicht gut funktionieren würde. Sie können jedoch überprüfen, ob mindestens network-online.target Vorhanden ist und ob es nach network.target Bestellt wird.

Bisher hat NetworkManager nur garantiert, dass mindestens eine Verbindung angewendet wird. Und damit das funktioniert, müssten Sie den NetworkManager-wait-online.service Explizit aktivieren. Dies wurde in Fedora schon lange behoben, aber erst kürzlich vorgelagert angewendet.

systemctl enable NetworkManager-wait-online.service

Hinweise zu Implementierungen von network.target und network-online.target

Sie sollten Ihre Software niemals von NetworkManager.service Oder NetworkManager-wait-online.service Oder anderen spezifischen Diensten abhängig machen müssen. Stattdessen sollten sich alle Netzwerkverwaltungsdienste vor network.target Und optional vor network-online.target Bestellen.

Ein einfacher skriptbasierter Netzwerkverwaltungsdienst sollte die Netzwerkkonfiguration vor dem Beenden abschließen und sich vor network.target Und damit indirekt vor network-online.target Bestellen.

[Unit]
Before=network.target

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

Ein daemonbasierter Netzwerkverwaltungsdienst sollte sich auch vor network.target Bestellen, obwohl dies nicht sehr nützlich ist.

[Unit]
Before=network.target

[Service]
Type=simple
ExecStart=...

Ein Dienst, der darauf wartet, dass der Dämon beendet wird, sollte sich nach dem jeweiligen Dienst und vor network-online.target Bestellen. Es sollte Requisite für den Daemon-Dienst verwenden, damit es sofort fehlschlägt, wenn der jeweilige Netzwerkverwaltungsdienst nicht verwendet wird.

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

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

Das Paket sollte einen Symlink zum wartenden Dienst im Verzeichnis wants für network-online.target Installieren, damit es von Diensten abgerufen wird, die auf das konfigurierte Netzwerk warten möchten.

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

Dazugehörige Dokumentation

Schlussbemerkungen

Ich hoffe, ich habe nicht nur geholfen, Ihre Frage zu dem Zeitpunkt zu beantworten, als Sie sie gestellt haben, sondern auch dazu beigetragen, die Situation in Upstream- und Linux-Distributionen zu verbessern, sodass ich jetzt eine bessere Antwort geben kann, als dies zum Zeitpunkt des Schreibens der ursprünglichen Frage möglich war .

138
Pavel Šimerda

Sie können After im Abschnitt [Unit] Verwenden, um einen Dienst zu definieren, der vor dem Start Ihres Dienstes gestartet werden soll. Wenn Sie beispielsweise NetworkManager verwenden, können Sie Ihren Dienst nach dem Start von NetworkManager starten.

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

Wenn Ihr Dienst einen Server bereitstellt, der passiv darauf warten kann, dass sich jemand mit ihm verbindet, verwenden Sie Folgendes:

[Unit]
After=network.target

Ihr Dienst sollte an die Platzhalterschnittstelle gebunden sein. Wenn die Socket-Aktivierung verwendet wird (empfohlen) oder wenn sie nur lokal ist, können Sie Netzwerkziele vollständig ignorieren.

Wenn Ihr Dienst als Client fungiert oder Peer-to-Peer ist, ist dies angemessener:

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

Vor systemd 21 benötigt network-online.target die erwähnte Problemumgehung Pavel (Sie müssen manuell einen Dienst aktivieren, der darauf wartet, dass das Netzwerk aktiv ist). Ab systemd 213 erfolgt dies standardmäßig. systemd-networkd-wait-online Wartet darauf, dass mindestens eine Adresse (entweder routingfähig oder verbindungslokal) auf einer Nicht-Loopback-Schnittstelle konfiguriert wird.

Das Konfigurieren von systemd-networkd, NetworkManager oder einem gleichwertigen System ist eine unabhängige Aufgabe. DHCP (für IPv4) und NDP (für IPv6) funktionieren normalerweise sofort, aber Sie sollten sie so konfigurieren, dass Ihre genaue Definition von "Das Netzwerk ist aktiv" network-online.target Auslöst.

Dokumentation:

8
Tobu

Ich schätze, ich könnte den Punkt, an dem das Skript ausgeführt wird, ändern, indem ich mit dem WantedBy-Parameter herumspiele

Das hat den gegenteiligen Effekt von dem, was Sie wollen. Von man systemd.unit:

WantedBy =, RequiredBy =

[...] Eine symbolische Verknüpfung wird im Verzeichnis .wants/oder .requires/jeder der aufgelisteten Einheiten erstellt, wenn diese Einheit durch systemctl enable installiert wird. Dies hat zur Folge, dass eine Abhängigkeit vom Typ Wants = oder Requires = hinzugefügt wird von der aufgelistete Einheit zur aktuelle Einheit.

Auf dieser Grundlage können wir sehen, dass die richtige Einheitenoption "Wants" oder "Requires" ist. Basierend auf der Beschreibung dieser ist "Requires" wahrscheinlich korrekt, mit dem Zusatz "After", um sicherzustellen, dass der Netzwerkdienst nicht nur ausgeführt wird, sondern auch vor diesem Gerät ausgeführt wird.

Keine der Einheitenoptionen, AFAIK, kann die Bedingung enthalten, dass eine gestartete Perquisite abgeschlossen sein muss oder einen bestimmten Punkt erreicht hat (Netzwerk ist wahrscheinlich ein Daemon-Dienst), nur dass sie zuerst start. In diesem Sinne möchten Sie möglicherweise Ihr Skript Type=forking und geben Sie eine fehlerhafte Verzögerung (z. B. 30 Sekunden) oder eine Art Exit-on-Success-Schleife einschließlich einer Verzögerung ein, um sicherzustellen, dass Sie zuerst eine DHCP-Lease haben.

4
goldilocks

Verwenden Sie After im [Unit] Abschnitt, um anzugeben, was vor Ihrem eigenen Dienst gestartet werden soll. (So ​​viel von der vorherigen Antwort ist richtig.)

Verwenden Sie zum Starten Ihres Dienstes nach dem Hochfahren des Netzwerks das Netzwerkziel. Dies sollte unabhängig davon gelten, ob Sie NetworkManager, das conf.d/netctl-System in Arch oder einen anderen Dienst verwenden, den systemd kennt.

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

Ein kurzer Blick bestätigt, dass jeder andere Dienst auf Ihrem System, der auf Netzwerkkonnektivität beruht, diese Anweisung enthält.

Es ist auch auf jede Distribution portierbar, die systemd verwendet. Ihre Unit-Datei ist dieselbe für Arch, Fedora, RHEL 7, zukünftige Versionen von Debian ...


Dienste, die starten eine Netzwerkverbindung, wie z. B. Arch's Skripte oder Ihre eigenen, sollten dies in ihren eigenen Einheitendateien angeben.

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

Ich wollte diesem Artikel einen Punkt hinzufügen. Derzeit (Sommer 2015) in RHEL7/CentOS 7 ist network-online.target falsch festgelegt, bevor das IPv6-Netzwerk aktiv ist

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

in ihrer Dienstdefinition, die auch explizit an IPv6-Adressen gebunden ist, werden diese wahrscheinlich gestartet, bevor IPv6 ausgeführt wird, was dazu führt, dass sie fehlschlagen.

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

funktioniert bei mir.

0
Zhenxiao Hao