Este es uno de los capítulos del tutorial Trabajando con Systemd. Encontrarás los enlaces a todos los de capítulos, al final de este artículo.
En el capítulo anterior del tutorial viste como podías monitroizar una web con un servicio de Systemd. Pero ¿que sucedería si en lugar de querer monitorizar una única web, quisieras monitorizar varias?¿Tendrías que crear un servicio para cada una de esas páginas web? No, no es necesario, y esto es precisamente lo que voy a abordar en este nuevo episodio del tutorial sobre trabajar con Systemd. Así, podrás utilizar un servicio y varias instancias.
La cuestión es que hace recientemente poco tiempo, tuve que hacer algo similar. Básicamente se trataba de consultar una docena o mas de dispositivos vía REST API, y utilizando un servicio. Me pareció, algo realmente interesante, sencillo a la par que potente, y me dio la idea de publicar este artículo.
Un servicio y varias instancias
El objetivo
Si bien, el capítulo anterior de este tutorial monitorizaba una url utilizando Python, en este caso lo voy a hacer todo con Bash. Bueno, con Bash, y Systemd, claro. En este caso es mucho mas sencillo, que en el artículo anterior. Ahora simplemente se trata de conectarte a la url y comprobar que nos devuelve un 200.
Cuando por la circustancia que sea, se pierda la conectividad, lo que buscamos es que nos avise. Con este propósito, de nuevo, utilizaremos un bot de Telegram que cumplirá a las mil maravillas con esta finalidad. Aunque, sin lugar a dudas, podríamos haber utilizado cualquier otro servicio.
Por otro lado, también enviaremos la información al syslog, para de esta manera tener nuestro proceso, perfectamente monitorizado.
El script
Lo primero es nuestro script en Bash que nos permita monitorizar una sola url. Este script, puede ser tal y como lo que te muestro a continuación,
logger "starting monitor $1"
eval source "$HOME/monitoriza-url.env"
URL=$1
URL=$(systemd-escape -u "$URL")
STATUS="-"
while true
do
ans=$(curl -s -o /dev/null -w "%{http_code}" "$URL")
echo $ans
if [ "$ans" = "200" ] && [ "$STATUS" != "OK" ]
then
STATUS="OK"
MESSAGE="Se ha recuperado la connectividad con ${URL}"
TELEGRAM_URL=https://api.telegram.org/bot${TOKEN}/sendMessage
logger "Status: ${ans} => ${MESSAGE}"
curl -s -X POST ${TELEGRAM_URL} -d chat_id=${CHAT_ID} -d text="${MESSAGE}"
elif [ "$ans" != "200" ] && [ "$STATUS" != "KO" ]
then
STATUS="KO"
MESSAGE="Se ha perdido la connectividad con ${URL}"
TELEGRAM_URL=https://api.telegram.org/bot${TOKEN}/sendMessage
logger "Status: ${ans} => ${MESSAGE}"
curl -s -X POST ${TELEGRAM_URL} -d chat_id=${CHAT_ID} -d text="${MESSAGE}"
fi
sleep $TIMELAPSE
done
Los parámetros que nos hacen falta los guardamos en el archivo monitoriza-url.env
, que estará en nuestro directorio de inicio. Tendrá un aspecto, como el que te muestro a continuación,
TOKEN='----';CHAT_ID='----';TIMELAPSE=300
Evidentemente tienes que sustituir los guiones por el token de tu bot y por el identificador del canal donde te vas a inviar la información.
Indicarte que la ubicación de estos archivos es la siguiente,
monitoriza-url.sh
, el script, lo tienes que poner en~/.local/bin
monitoriza-url.env
, los parámetros, lo tienes que poner en tu inicio, y deberías configurarlo con permisos de solo lectura,400
, para mantenerlo a salvo de miradas indiscretas.
La magia, un servicio y varias instancias
El siguiente paso es crear el servicio. En principio, no tiene mucho misterio, salvo un par de detalles que ahora te comento. Primero el servicio,
[Unit]
Description="Testing instance %i"
PartOf=monitoriza-urls.target
Restart=always
[Service]
Type=simple
ExecStart=/bin/bash %h/.local/bin/monitoriza-url.sh %i
Lo primero que seguro te llama la atención es el %i
. Esto es el nombre de la instancia. Y es que este archivo, en concreto, se llama monitoriza-url@.service
. Una vez creado, lo puedes iniciar de la siguiente forma,
systemctl --user start monitoriza-url@https:--github.com
Antes, recuerda que lo tienes que copiar al directorio ~/.config/systemd/user
y ejecutar systemctl --user daemon-reload
.
Así puedes levantar tantos servicios como quieras. Mucho mas sencillo, práctico e intuitivo.
¿Como se pasa el parámetro y porque tiene ese aspecto?
El nombre de la instancia, es precisamente el valor que hay entre la @
y el .service
. En este ejemplo es https:--github.com
. ¿Y por que tiene ese aspecto? Porque Systemd escapa el texto. Para hacer esto tienes que utilizar la siguiente instrucción,
systemd-escape https://github.com
Claro, que cuando le llega al script esto hay que devolverlo al estado original, para poder utilizarlo, para lo cual tienes que utilizar esta otra instrucción, tal y como lo puedes ver en el propio script de monitorización que te he mostrado anteriormente,
systemd-escape -u https:--github.com
Así queda claro para que se utiliza el %i
, para pasar el nombre de la instancia. Mientras que el %h
, se utiliza para indicar que ahí va el directorio de inicio, el directorio home
. Así todo queda muy ordenado.
Ahora lo siguiente sería, iniciar tantas servicios, utilizando la instrucción anterior, como url quisieras monitorizar. Sin embargo, seguro que te estás preguntando, si no hay una forma de hacerlo de forma más cómoda y práctica. Pues si, la hay.
Iniciando varios servios de forma simultánea
Si lo que quieres es monitorizar varias url de forma simultánea, pero independiente, tienes que crear un nuevo archivo, esta vez con extensión .target
. Este archivo, tendrá el siguiente aspecto,
[Unit]
Description=Check all Urls
Wants=monitoriza-url@https:--www.google.es.service monitoriza-url@https:--es.yahoo.com.service monitoriza-url@https:--duckduckgo.com.service
[Install]
WantedBy=default.target
Como ves, es tremendamente sencillo. Solo necesitas definir el parámetro Wants
, donde indicaras todas las url
que quieres monitorizar separadas por espacio entre ellas.
De nuevo, este archivo lo tienes que copiar al directorio ~/.config/systemd/user
y ejecutar systemctl --user daemon-reload
. Una vez hecho esto, ya puedes iniciar todas tus monitorizaciones de un golpe,
systemctl --user start monitoriza-urls.target
Para distinguir entre uno y otro, además de por la extensión .service
y .target
he querido añadir esa s, por que sea mas descriptivo, pero realmente no es necesario. Lo que hace que todo engrane es el parámetro PartOf=monitoriza-urls.target
del servicio.
Conclusión
Con independencia de que uno está implementado en Python y otro en Bash, ves claramente la diferencia entre un servicio con una sola instancia, tal y como te mostré en el capítulo anterior titulado Vigila una web con un servicio de Systemd y este, en el que has podido crear varias instancias del mismo servicio.
Igualmente, quiero destacar el uso de %i
, pero sobre todo de %h
y $HOME
. De esta forma consigues que todo tenga ruta absoluta, en tanto en cuanto va a estar referido a tu directorio de inicio.
Por supuesto, esto lo vas a poder utilizar, no solo para instancias, sino que también puedes utilizarlo para iniciar varios servicios a partir de un único target
.
Puedes encontrar el código fuente correspondiente a todo lo que has visto aquí en el repositorio de GitHub.
Más información,
Imagen de portada de Ran Berkovich en Unsplash