25 de Noviembre, 2007

Implementando un watchdog de emergencia

Un watchdog es, como su nombre indica, un perro guardian ;), que en general se encarga de monitorizar un aspecto del sistema para llevar a cabo una acción cuando algo falla. Alguna vez he puesto uno por aquí.

Bueno, es una definición un poco de estar por casa, como lo que voy a explicar ahora: cómo hacer un sencillo watchdog para un servicio, con un shell y herramientas comunes en cualquier entorno Unix.

Ayer un compañero me pidió que le echara una mano con el servidor de un ex-cliente, y como cada vez se puede dedicar menos tiempo a mantener esa máquina, decidimos poner un watchdog para un servicio que había dado problemas ocasionalmente pero no podíamos diagnosticar y corregir.

Vamos a suponer un caso bastante frecuente, en el que el servicio es un solo proceso, que además guarda su PID en un fichero.

Nuestro watchdog haría lo siguiente:

  1. Comprobar que el fichero PID existe: sino existe, eso es seguramente señal de que el servicio está parado.
  2. Verificar que el proceso indicado por ese PID, efectivamente está funcionando: sino encontramos el proceso, suponemos que el servicio ha terminado de forma imprevista (y no ha borrado el fichero, como es habitual).
  3. Si se cumple cualquiera de los puntos anteriores, lanzamos el servicio (borrando el fichero del PID en caso de ser necesario, para evitar que el servicio piense que ya está en marcha).

Es un watchdog muy rudimentario que correríamos desde cron(8) con la frecuencia que creamos conveniente.

Más o menos la implementación que hice ayer fue la siguiente, un poco revisada para publicarlo aquí (claro :D):

#!/bin/sh

# configurable
PIDFILE="/var/run/bogom/bogom.pid"
DAEMON="/usr/local/libexec/bogom"
MAILTO=administrador

# Arranca el servicio y manda un mail al admin
up_and_notice()
{
	$DAEMON
	echo "He arrancado $DAEMON (resultado $?), un saludo :)" \
| mail -s "$0 en `hostname`" $MAILTO
}

# existe el fichero con el PID?
if [ ! -f $PIDFILE ]; then
	up_and_notice
	exit 0
fi

PID=`cat $PIDFILE 2> /dev/null`

# hay efectivamente un PID?
if [ "X" == "X$PID" ]; then
	up_and_notice
	exit 0
fi

ps -p $PID 2> /dev/null 1> /dev/null

# existe el proceso con ese PID?
if [ $? -ne 0 ]; then
	# si no existe, el fichero sobra
	rm $PIDFILE

	up_and_notice
	exit 0
fi

# EOF

En el ejemplo he usado el servicio de bogom (no porque lo necesite, ojo :D), y como bonus se envía un correo al administrador para informar de que se ha levantado otra vez el proceso.

En este caso el watchdog lo tiene que correr root, así que añadiríamos el script en el crontab(5) de ese usuario. Sería muy raro que funcionara tal cual para otros casos, pero como es muy sencillo, seguro que resulta fácil de adaptar.

No me gustan mucho los watchdogs, pero es bueno asumir que todos los programas tienen fallos y a veces causan problemas, y no siempre hay un administrador para ver qué está pasando. En la mayoría de las veces el fallo es anecdótico, y con volver a arrancar: solucionado ;).

Anotación por Juan J. Martínez, clasificada en: hack, unix, scripting.

Los comentarios están cerrados: los comentarios se cierran automáticamente una vez pasados 30 días. Si quieres comentar algo acerca de la anotación, puedes hacerlo por e-mail.

Algunas anotaciones relacionadas: