¿Causar que un script se ejecute después de que la red ha comenzado?

102

Soy relativamente nuevo en systemd y estoy aprendiendo su arquitectura.

En este momento, estoy tratando de descubrir cómo hacer que se ejecute un script de shell personalizado. Este script debe ejecutarse después de que se haya iniciado la capa de red.

Estoy ejecutando Arch, usando systemd y netctl.

Para probar, escribí un script simple que simplemente se ejecuta ip addr list > /tmp/ip.txt. Creé el siguiente archivo de servicio para este script.

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

[Service]
ExecStart=/root/test.script

[Install]
WantedBy=multi-user.target

Luego habilité el script con,

systemctl enable test

Al reiniciar, el script realmente se ejecuta, pero se ejecuta antes de que se inicie la red. En otras palabras, la salida en ip.txtno muestra ninguna dirección IPv4 asignada a la interfaz principal. Cuando inicio sesión, la dirección IPv4 ya se ha asignado y la red está activa.

Supongo que podría alterar el punto en el que se ejecuta el script jugando con el WantedByparámetro, pero no estoy seguro de cómo hacerlo.

¿Podría alguien señalarme en la dirección correcta?

fdmillion
fuente

Respuestas:

126

En dependencias de configuración de red systemd

Es muy fácil afectar el orden de las unidades de systemd. Por otro lado, debe tener cuidado con lo que garantiza una unidad completa.

Configura tu servicio

En los sistemas actuales, ordenar después network.targetsolo garantiza que se ha iniciado el servicio de red, no que haya alguna configuración real. Necesita ordenar después network-online.targety tirar de él para lograrlo.

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

Para la compatibilidad con sistemas más antiguos, es posible que también deba realizar un pedido después de network.target.

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

Eso es para el archivo de la unidad de su servicio y para systemd.

Implementación en versiones actuales de software

Ahora debe asegurarse de que network-online.targetfunciona como se esperaba (o que al menos puede usar network.target).

La versión actual de NetworkManager ofrece lo NetworkManager-wait-online.serviceque obtiene network-online.targety, por lo tanto, su servicio. Este servicio especial garantiza que su servicio esperará hasta que todas las conexiones configuradas para iniciarse se realicen correctamente, fallen o finalicen automáticamente.

La versión actual de systemd-networkd bloquea su servicio hasta que todos los dispositivos estén configurados según lo solicitado. Es más fácil porque actualmente solo admite configuraciones que se aplican en el momento del arranque (más específicamente el tiempo de inicio de `systemd-networkd.service).

En aras de la integridad, el /etc/init.d/networkservicio en Fedora, tal como lo interpretan las versiones actuales de systemd, bloquea network.targety por lo tanto indirectamente bloquea network-online.targety su servicio. Es un ejemplo de una implementación basada en script.

Si su implementación, ya sea basada en daemon o basada en script, se comporta como uno de los servicios de administración de red anteriores, retrasará el inicio de su servicio hasta que la configuración de la red se complete con éxito, falle por una buena razón o se agote el tiempo después de un tiempo razonable marco para completar.

Es posible que desee verificar si netctl funciona de la misma manera y esa información sería una valiosa adición a esta respuesta.

Implementaciones en versiones anteriores de software

No creo que vea una versión suficientemente antigua de systemd donde esto no funcione bien. Pero puede comprobar que al menos network-online.targetexiste y que se ordena después network.target.

Anteriormente, NetworkManager solo garantizaba que se aplicaría al menos una conexión. E incluso para que eso funcione, tendrías que habilitarlo NetworkManager-wait-online.serviceexplícitamente. Esto se ha solucionado durante mucho tiempo en Fedora, pero solo se aplicó recientemente en sentido ascendente.

systemctl enable NetworkManager-wait-online.service

Notas sobre las implementaciones de network.target y network-online.target

Usted no debe necesitar para hacer su software de depender NetworkManager.serviceo NetworkManager-wait-online.serviceni otros servicios específicos. En cambio, todos los servicios de administración de red deben ordenarse antes network.targety opcionalmente network-online.target.

Un servicio de administración de red basado en un script simple debe finalizar la configuración de la red antes de salir y debe ordenarse antes network.targety, por lo tanto, indirectamente antes network-online.target.

[Unit]
Before=network.target

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

Un servicio de administración de red basado en daemon también debe solicitarse antes network.targetaunque no sea muy útil.

[Unit]
Before=network.target

[Service]
Type=simple
ExecStart=...

Un servicio que espera a que finalice el demonio debe solicitarse después del servicio específico y antes network-online.target. Debería usarse Requisiteen el servicio daemon para que falle inmediatamente si no se usa el servicio de administración de red respectivo.

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

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

El paquete debe instalar un enlace simbólico al servicio de espera en el wantsdirectorio para network-online.targetque sea atraído por los servicios que desean esperar la red configurada.

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

Documentación relacionada

Notas finales

Espero que no solo haya ayudado a responder su pregunta en el momento en que la hizo, sino que también haya contribuido a mejorar la situación en las distribuciones ascendentes y Linux, para que ahora pueda dar una mejor respuesta de la que era posible al momento de escribir la original. .

Pavel Šimerda
fuente
¿Se refiere a la opción de conexión automática por "esperar hasta que todas las conexiones configuradas para iniciarse se realicen correctamente"? ¿Puedo aprovechar esto cuando configuro no-auto-default = * pero tengo autoconnect = yes en una de mis conexiones? Y la última pregunta, no entiendo, la opción de espera para el inicio de la página nm-online y manual no ayuda mucho. Gracias por este artículo, muy apreciado!
lzap
Hasta donde yo sé, a nm-online no le importa no-auto-default, solo auto. ¿Tienes alguna pregunta específica? En mi opinión, la página de manual de nm-online establece claramente que con -sella espera a que se intenten todas las conexiones automáticas, es decir, conectadas o fallidas.
Pavel Šimerda
Después de jugar con esta basura durante una hora, encontré la solución: apt-get install sysv-init. :-) La complejidad que systemd agrega como reemplazo de algunos scripts de shell es alucinante.
Alguien
@ Alguien me temo que initscripts no son una respuesta en este caso. Si está utilizando NetworkManager o cualquier otra herramienta de configuración dinámica, initscripts no pueden ordenarse después de una red totalmente configurada. Puede obtener una configuración dinámica limitada usando /etc/init.d/networko similar, pero eso no funciona universalmente.
Pavel Šimerda
@Pavel Šimerda Init se ejecuta en serie, y un script de inicio adecuado no volverá hasta que haya terminado de hacer lo que los scripts posteriores necesitan. Para redes, eso significaría tener todos los adaptadores aplicables listos y listos. A menos que haya sido un momento de suerte, NM se comporta bien dentro de ese contexto. El verdadero problema es, por supuesto, NM reinventar el manejo de la red en lugar de construir sobre estructuras existentes simples y probadas. Las personas de escritorio parecen no tener un concepto de los peligros de la complejidad. ;-)
Alguien
9

Puede usar Afteren la [Unit]sección para definir un servicio que debe iniciarse antes de que comience su servicio. Por ejemplo, si está utilizando NetworkManager, puede hacer que su servicio se inicie después de que se inicie NetworkManager.

[Unit]
Description=test service
After=NetworkManager.service
phoops
fuente
BindsToNo es tan apropiado aquí, ya que el servicio es un evento único y no un servicio persistente (a menos que también incluya una ExecStopfunción para disparar cuando la red deja de funcionar).
Ricitos
eliminadoBindsTo
phoops
Sin BindsToembargo, podría agregar algo para reemplazar , por ejemplo Requires, si solo desea que el servicio se ejecute si lo hace NetworkManager. Afteren realidad no hace eso, solo significa que si NM también se está ejecutando, ejecute esto después. Si NM no se ejecutará, el servicio se ejecutará en un punto arbitrario.
Ricitos
44
After = network.target es mejor que After = NetworkManager.service ya que es más genérico.
Pavel Šimerda
77
Tenga en cuenta que al especificar After=fooserá no hacer que la foounidad se inicia si no se ha iniciado, será solamente decirle systemd cómo ordenar las unidades si están iniciados al mismo tiempo . Usar ambos After=foo, así como Wants=fooo Requires=footendrá el efecto de atraer foosi no se inicia, y también hacer que systemd ordene las unidades correctamente.
Emil Lundberg
8

Si su servicio proporciona un servidor, que puede esperar pasivamente a que alguien se conecte a él, use esto:

[Unit]
After=network.target

Su servicio debe vincularse en la interfaz comodín. Si usa la activación de socket (recomendado), o si es solo local, puede ignorar los destinos de red por completo.

Si su servicio actúa como un cliente, o es de igual a igual, esto es más apropiado:

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

Antes de systemd 213 , network-online.target necesita la solución mencionada por Pavel (debe habilitar manualmente un servicio que esperará a que la red esté activa). A partir de systemd 213 esto se hace por defecto. systemd-networkd-wait-onlineesperará a que se configure al menos una dirección (ya sea enrutable o local de enlace) en una interfaz que no sea de bucle invertido.

Configurar systemd-networkd, NetworkManager o equivalente es una tarea independiente. DHCP (para IPv4) y NDP (para IPv6) tienden a funcionar de forma inmediata, pero debe configurarlos para que su definición precisa de "la red esté activa" es lo que desencadena network-online.target.

Documentación:

Tobu
fuente
Es curioso por qué una nueva respuesta y no solo pequeñas mejoras a la respuesta existente y (con suerte) bien estructurada.
Pavel Šimerda
Los dos primeros enlaces de documentación están actualmente difuntos.
Peter Hansen
¿Por qué usar Requiere en lugar de Deseo?
Karl Morrison
4

Supongo que podría alterar el punto en el que se ejecuta el script jugando con el parámetro WantedBy

Eso tendrá el efecto opuesto de lo que quieres. De man systemd.unit:

WantedBy =, RequiredBy =

[...] Se crea un enlace simbólico en el directorio .wants / o .requires / de cada una de las unidades enumeradas cuando esta unidad se instala mediante systemctl enable. Esto tiene el efecto de que una dependencia del tipo wants = o require = se agrega desde la unidad listada a la unidad actual .

En base a esto, podemos ver que la opción de unidad adecuada es "Desea" o "Requiere"; basado en la descripción de estos, "Requiere" probablemente sea correcto, con la adición de "Después" para garantizar no solo que el servicio de red se ejecute, sino que se ejecute antes de esta unidad.

Ninguna de las opciones de la unidad, AFAIK, puede incluir la estipulación de que un requisito inicial debe haberse completado o alcanzado un cierto punto (la creación de redes es probablemente un servicio demonio), solo que se inicia primero. Con esto en mente, es posible que desee hacer su secuencia de comandos Type=forkingy lanzar un retraso saludable (por ejemplo, 30 segundos), o algún tipo de ciclo de salida al éxito que incluya un retraso, para asegurarse de que primero tenga un contrato de arrendamiento de DHCP.

encerrada dorada
fuente
1
Ni WantedBy ni RequiredBy afectan el pedido.
Pavel Šimerda
1
@ PavelŠimerda: Nadie aquí afirmó que lo hizo. Es por eso que mencioné explícitamente Afterjunto con Requires"para garantizar que no solo se ejecute el servicio de red, sino que se ejecute antes que esta unidad".
Ricitos
1
Sí, Aftertrabaja junto Wantso de Requiresesa manera. Por otro lado, los retrasos explícitos son un mal hábito en las herramientas basadas en la dependencia, especialmente cuando hay una forma explícita de esperar hasta que la red esté configurada según la documentación del sistema, por lo que debo insistir en el voto negativo.
Pavel Šimerda
3

Use Afteren la [Unit]sección para especificar qué debe comenzar antes de su propio servicio. (Esta gran parte de la respuesta anterior es correcta).

Para iniciar su servicio después de que la red esté activa, use el objetivo de red, que debe aplicarse si usa NetworkManager, el sistema conf.d / netctl en Arch o algún otro servicio que systemd conozca.

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

Una breve mirada confirmará que todos los demás servicios en su sistema que dependen de la conectividad de red contienen esta directiva.

También es portátil para cualquier distribución que use systemd. Su archivo de unidad será el mismo para Arch, Fedora, RHEL 7, futuras versiones de Debian ...


Los servicios que inician una conexión de red, como los scripts de Arch o los suyos, deben especificarlo en sus propios archivos de unidad.

[Unit]
Wants=network.target
Before=network.target
Michael Hampton
fuente
No me gusta por completo la Wantsparte porque tiene efectos secundarios en otros paquetes. Mira mi respuesta, por favor.
Pavel Šimerda
Acabo de dar cuenta de que Wantsel network.targetes una buena idea aquí.
Pavel Šimerda
realmente quieres usar network-online.target. ref
Edward Torvalds
1

Quería agregar un punto a este artículo. Actualmente (verano de 2015) en RHEL7 / CentOS 7, network-online.target está configurado incorrectamente antes de que la red IPv6 esté activa, por lo que los demonios que tienen

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

en su definición de servicio que también se vincula explícitamente a las direcciones IPv6, probablemente se iniciará antes de que IPv6 esté en funcionamiento, lo que provocará un error.

Colo Host
fuente
Supongo que este es el caso solo con la configuración automática de IPv6 basada en el núcleo, que de todos modos es defectuosa. Si desea ordenar correctamente después de IPv6, definitivamente debe usar NetworkManager en lugar de /etc/init.d/network. Si tiene el mismo problema incluso con NM, entonces sería una buena razón para presentar una solicitud de función. No he consultado con RHEL / CentOS, puedo ayudarlo con los detalles si está interesado.
Pavel Šimerda
0
[Unit]
After=systemd-networkd.service

funciona para mi.

Zhenxiao Hao
fuente
No estoy seguro si funciona en algunos casos especiales, pero está mal por un par de razones. Uno de ellos es que networkdproporciona su propio servicio / wait-online /. Entrar y ordenar después network-online.targetes la manera correcta de ir con cualquier servicio que lo respalde.
Pavel Šimerda