¿Puedo usar systemd para iniciar y detener un servicio basado en la presencia de un archivo?

9

Mi configuración hasta ahora es:

foo.path

[Path] 
PathExists=/tmp/foo.path

[Install] 
WantedBy=multi.user.target

foo.service

[Unit]
Description=Matt Test
BindsTo=foo.path

[Service]
ExecStart=/bin/sh /home/mpekar/bin/foo.sh 
PIDFile=/run/foo.pid

Esto funciona bien cuando se inicia, pero foo.service no se eliminará cuando se elimine /tmp/foo.path. ¿Hay alguna forma de hacer que systemd haga esto o simplemente no es la herramienta adecuada para el trabajo?

mpr
fuente

Respuestas:

4

Yo intentaría esto. Cree un servicio adicional usando PathChanged:

foo-stop.path

[Path] 
PathChanged=/tmp/foo.path

[Install] 
WantedBy=multi.user.target

Luego crea: foo-stop.service

Haga que su secuencia de comandos "ExecStart" verifique si /tmp/foo.pathse eliminó (ya que PathChanged también podría activarse en otros cambios). Si la ruta se ha eliminado, solicite la secuencia de comandos /bin/systemctl stop foo.

Mark Stosberg
fuente
1
Voy a seguir adelante y aceptar esto hasta el momento en que systemd ofrezca una opción explícita para hacer lo mismo.
mpr
0

Si puede eliminar el proceso vinculado al PIDFile (/run/foo.pid) cuando se elimina /tmp/foo.path (por ejemplo, como acciones dentro del script de apagado del servicio), entonces sí.

Lo logré en un Tomcat que se ejecuta sobre <= RHEL-7.7 con un servicio de bifurcación que incluye una acción ExecStartPost que anota el contenido de la aplicación pidfile (catalina.pid) en la ruta del servicio PIDFile. Un "PathExists" en el archivo .path correspondiente rastrea la aparición en este catalina.pid para enganchar el servicio systemd cuando el usuario (en mi caso, sin privilegios) invoca el script de inicio. Cuando el usuario inicia el apagado, se elimina el archivo pid de la aplicación, el PID (también sin privilegios) muere con gracia y systemd detiene el servicio como consecuencia de la supervisión del sistema pid.

poc.service:

[nouser@nohost system]# cat poc.service
# . . .
[Unit]
After=network.target
After=%p.path
Wants=%p.path
# . . . 
[Service]
Type=forking
Environment="%p_APPLICATION_PID_FILE=/opt/%p/logs/catalina.pid"
PIDFile=/var/run/%p.pid
ExecStart=/bin/sh -c '/path/to/tomcat/control/script/invoked/with/su/hypen start'
ExecStartPost=/bin/sh -c 'cat ${%p_APPLICATION_PID_FILE} > $(systemctl show %n -p PIDFile|cut -f2- -d"=")'
ExecStop=/bin/sh -c '/path/to/tomcat/control/script/invoked/with/su/hypen stop'
# . . .

poc.path:

[nouser@nohost system]# cat poc.path
# . . .
[Path]
PathExists=/opt/%p/logs/catalina.pid
# . . .

De esta manera también me sirvió para las aplicaciones Spring Boot. Pero como nacieron colgados de un proceso bash, tuve que matar inmediatamente ese proceso padre para forzar a PID 1 a ser el padre de la aplicación. De lo contrario, journalctl muestra un mensaje "* .service: proceso de supervisión XXXXX que no es nuestro hijo. Lo más probable es que no nos demos cuenta cuando salga", y al final el servicio systemd no se detiene en la acción de apagado del usuario.

Pere Moltó
fuente