13 noviembre 2013

Monitorización de base de datos Wordpress desde Nagios




Una de las situaciones que más frustración me hicieron pasar fue, cuando al bajar del estrado en la Campus Party Europa en Londres, uno de los asistentes a mi charla se me acerca y me indica que la web www.securizame.com, daba un error de base de datos. Lo primero que me vino a la cabeza fue: ¿¿¿un SQLi??? Mira que me extraña pero bueno… Así que me conecté a la web y el error era muy distinto:


En general, existen servicios “en la nube” que permiten monitorizar si un servidor web responde o no, o vive o no… de manera que te notifique desde el momento en el que no das servicio correctamente. De hecho, el amigo Jpiera se tomó la molestia voluntariamente, en su momento, de configurar Pingdom para mi web y me suele sorprender por DMs en twitter, diciéndome… "hey ayer estuviste en mantenimiento en la web media hora eh?". Igualmente, en mi sistema de monitorización basado en Nagios, disponía de un check para saber que el servidor web está funcionando correctamente, e igualmente otro check para saber que el servicio Mysqld está levantado y funcionando en la máquina virtual que tiene el servidor mysql.

Si el servidor MySQL se cae, cuando Apache intenta contactar, daría el error que aparece en la imagen anterior. En ese caso, el check del MySQL me avisaría. Sin embargo, el caso que me sucedió en Londres fue diferente. El MySQL estaba correctamente levantado y había bases de datos que estaban correctas. Sin embargo, la que alimentaba el Wordpress de Securízame, había sufrido una corrupción de datos interna. En mi caso, me encontraba fuera, y por seguridad aplicada a mis instalaciones de Wordpress, tengo configurado que la administración de dichos sistemas (el acceso a wp-admin) sólo se pueda hacer desde red interna. Así, me tuve que conectar por VPN y pude reparar el problema manualmente. 

Sin embargo, me prometí intentar encontrar una solución para evitar que esto volviese a pasar. Busqué por internet diferentes plugins para Nagios que interactuasen con Wordpress para su monitorización. Lo único con lo que dí eran scripts que monitorizaban la versión de wordpress y avisaba si existía alguna actualización pendiente, pero no lo que yo necesitaba.

Así, que me puse manos a la obra y escribí un script francamente sencillo, pero que si a alguien le ayuda a monitorizar su instalación y le sirve para detectar este fallo, pues por mí encantado.




Como véis, no puede ser más simple. Directamente en la variable $error_message indicamos el error que queremos detectar, y si lo encuentra pues da error.  La creación del servicio es tan sencilla como check_wordpress!-u http://www.securizame.com






Cuando hay un fallo de BD, aparecería el error y nos notificaría, aunque el check de Mysql estuviera en OK y verde



Según ví que esto ya funcionaba y haciendo varias pruebas pensé… Para esto, tiene que existir alguna forma de hacer que con un check_http, se pueda validar que una expresión regular exista o no. Y efectivamente, así es. El equivalente, en la línea de definición del servicio, a lo que hice sería algo así como:

check_command                   check_http!-p 80 -u http://www.securizame.com -R "Error estableciendo una conexión con la base de datos" --invert-regex

El problema que le veo es que por debajo, la definición del comando, lo asocia a una dirección IP, que se supone que es la del servidor al que le estamos preguntando. Es decir, que por debajo, la llamada que hace Nagios, inyecta un parámetro -I $HOSTADDRESS$ , de manera que sin esto no funciona. Tiene sentido puesto que el  Wordpress que estamos monitorando está albergado en esa dirección IP, que puede servir varios Virtualhosts.

La duda es: ¿Y si tengo varios wordpress que quiero monitorizar en diferentes servidores?

Con mi script no se exige añadir la dirección IP del servidor, y es directamente la máquina con Nagios quien resuelve el dominio que le hayamos especificado con -u, y ya está.

Como digo, una vez hecho, lo mismo me da usar una forma de monitorización que otra. El rendimiento de una u otra solución no me apura puesto que son suficientemente rápidos/lentos como para avisarme, y ambos funcionan.

Pero bueno, como ejercicio, está bien el familiarizarse con el desarrollo de módulos para Nagios. De hecho tengo varias ideas en mente para integrar diversas cosas (incluso domóticas,… Skynet returns) dentro del propio Nagios.

Lo deseable es que, se elija el que se elija, siempre se vea algo como esto:



3 comments :

Agustin dijo...

Hombre, escribir un plugin siempre está bien, pero para este caso con el check_http que viene con los Nagios Plugins debería ser suficiente (https://www.nagios-plugins.org/doc/man/check_http.html)

Algo como:

check_http -H virtualhostFQDN -I virtualhostFQDN -u / -r "Error estableciendo una conexión con la base de datos" --invert-regex



Para cosas más complejas incluso se podría utilizar Jmeter (en plan autentifícate, comprueba que te salgan ciertas cosas tras el login, etc ...)

Lorenzo_Martinez dijo...

Hola Agustín, gracias por tu comentario. Efectivamente es lo que digo al final del post :) Que cuando ya lo tenía hecho (5 minutos) pensé… "oye y con check_http esto no se podrá hacer?"… Como ventaja le veo al mío que si tienes muchos wordpress en diferentes sitios, y quieres ver que "hay servicio", en la definición de un único objeto, lo tienes, en vez de tener que hacer uno por cada wordpress a monitorizar (check_wordpress no pide el Host, sino solamente la URL donde hay un wordpress :D)

Agustin dijo...

Ostras, ¡es verdad! Esto de leer a toda prisa ...

De todas con Nagios puedes definer el check_command, algo como

define command{

command_name check_workpress_cu

command_line /usr/local/nagios/libexec/check_http -H $ARG1$ -I $ARG1$ -u $ARG2$ -r "Error ..." --invert-regex

}

o

define command{

command_name check_workpress

command_line /usr/local/nagios/libexec/check_http -H $ARG1$ -I $ARG1$ -u / -r "Error ..." --invert-regex

}

Con check wordpress asumes que la URL es / y con check_wordpress_cu (cu => custom url) tendrías dos parámetros, así te quedaría algo como:

define service{
use generic-service
host_name www
service_description Wordpress Blog 1
check_command check_wordpress!blog1.securizame.com
notifications_enabled 1
}

define service{
use generic-service
host_name www
service_description Wordpress Blog 2
check_command check_wordpress!blog2.securizame.com
notifications_enabled 1
}

define service{
use generic-service
host_name www
service_description Wordpress Blog 2
check_command check_wordpress_cu!www.securizame.com!/blog/
notifications_enabled 1
}