Tengo un servicio X que necesita conectarse al conector de escucha cuando se inicia. Ese socket de destino es a su vez abierto por otro servicio Y iniciado por systemd.
¿Hay alguna forma de especificar en el archivo de la unidad (o de otra manera) iniciar solo el servicio X después de que el servicio Y haya iniciado y abierto exitosamente el socket de escucha?
Tenga en cuenta que no puedo cambiar el servicio X para volver a intentarlo si falla la conexión inicial. Además, los retrasos fijos tampoco funcionan bien porque el servicio Y tarda distintos tiempos antes de abrir el conector de escucha.
Respuesta1
systemd tiende a funcionar de manera ligeramente diferente. Usted configura systemd para crear y escuchar en el socket, y si alguien como X intenta conectarse, entonces systemd inicia Y para manejar la conexión, pasándole el socket. Entonces X puede comenzar teóricamente antes que Y, pero no importará. Las conexiones posteriores serán manejadas por Y. (También puede configurarlo para que Y se reinicie para cada conexión, pero supongo que ese no es su caso).
Los cambios mínimos en Y son hacer que acepte el socket creado previamente como su descriptor de archivo stdin/stdout, en lugar de realizar la creación/vinculación por sí mismo.
Aquí tienes una configuración de prueba que puedes probar, no como root. Necesitas archivos de 3 unidades.
~/.local/share/systemd/user/mysock.socket
le dice a systemd que cree el socket y cómo transmitirlo:
# create listening socket. on 1st connect run mysock.service
[Socket]
ListenStream=5555
Accept=false
~/.local/share/systemd/user/mysock.service
(que tiene el mismo nombre mysock
) es el servicio que se iniciará si alguien se conecta al socket. Aquí es donde comienzas Y, que he reemplazado por Python.
[Unit]
Description=started from mysock.socket
[Service]
ExecStart=/home/meuh/bin/python/mysock.py
StandardInput=socket
Finalmente, su servicio X tiene una Unidad que dice que requiere el socket. Para X, estoy usando un socat que escribe la fecha en el socket.
~/.local/share/systemd/user/mysockdepend.service
[Unit]
Description=dependent on socket listening
Requires=mysock.socket
[Service]
ExecStart=/usr/bin/socat -U tcp:localhost:5555 exec:/usr/bin/date
Python toma el socket en la entrada estándar, es decir, el descriptor de archivo 0, y lo envuelve en un objeto de socket de Python adecuado, realiza una operación accept()
y puede leerlo/escribirlo:
~/bin/python/mysock.py
#!/usr/bin/python
# started from /home/meuh/.local/share/systemd/user/mysock.service
# with socket on stdin/stdout
import sys, time, socket, subprocess
def debug(msg):
# time.sleep(3)
subprocess.call(["/usr/bin/logger", msg])
debug("start\n")
s = socket.fromfd(sys.stdin.fileno(), socket.AF_INET, socket.SOCK_STREAM)
while True:
conn, addr = s.accept()
conn.send("hello\n")
while True:
try:
data = conn.recv(100)
debug("got "+data+"\n")
if len(data)<=0: break
except:
break
conn.close()
Después de systemctl --user daemon-reload
, deberías poder ejecutar X con
systemctl --user start mysockdepend
y vea en los registros journalctl
que se inició Y y la salida de depuración con la fecha.
Leer acerca deactivación del enchufey2dodel hombre que lo inventó.
Respuesta2
systemd maneja este caso conarchivos de socket.
some-socket.socket
Se crearía un archivo de unidad systemd llamado para representar el socket.
Entonces su Service X
archivo de servicio puede incluir una After=
directiva que haga referencia al socket.
La documentación oficial de systemd sobre archivos de socket debería ser útil.