Archive for the 'Nagios' Category

Reinicio forzado de VMs VMware automáticamente cuando no responden con los “Event handlers” de Nagios

Debido a un bug de Microsoft Windows o VMware, nos surge que determinados PCs virtuales se quedan “congelados”, o bien con un pantallazo azul (BSOD).

Cuando esto ocurre, aparte de quedar inaccesibles, consumen recursos y pueden surgir problemas (usuario no se puede conectar, swapeo del ESX,…)

Lo ideal en este caso sería solucionar el bug (se ha abierto caso a VMware), pero mientras VMware y Microsoft se echan la culpa unos a otros, hemos buscado un “workaround” temporal.

Aprovechando la disponibilidad de la herramienta “Nagios”, se puede aprovechar una de sus múltiples características, llamada “Event Handlers”.

Esta característica permite realizar una acción, cumpliendo ciertas condiciones.

En este caso en particular, se ha procedido de la siguiente manera:

  • Chequeo de conectividad por red (ping) cada 10 minutos
  • Si al 3er intento (pasados 30 minutos), no responde
  • Reinicio forzado de la máquina virtual

Esta operativa necesita la integración de Nagios con la API de VMware, y aprovechando que ambas herramientas utilizan perl, realizarlo en perl.

Para activar los event handlers en Nagios, hay que añadir la siguiente directiva en el fichero /etc/nagios/nagios.cfg:

enable_event_handlers=1
event_handler_timeout=60

Con el segundo paramtero, aumentamos el timeout del script a 60 segundos, puesto que la API de VMware no es todo lo rápida que debería…

Lo primero de todo, es crear la definición del PC a monitorizar en Nagios.

Para ello, creamos el fichero /etc/nagios/hosts/pcs/pcsXXXXX.cfg, cuyo contenido es:

define host{
    use pcs
    host_name HOSTNAME
    alias ALIAS
    address IP
}
define service{
    use pcs-ping-service ; Name of service template to use
    host_name HOSTNAME
    service_description PING
    check_command check_ping!100.0,20%!500.0,60%
    max_check_attempts 4
    event_handler reboot-vm
}

Este fichero indica el nombre e ip del host, así como los servicios (en este caso, un solo servicio, ping), asociados a ese host.

Esta organización de la configuración es propia, puesto que la configuración inicial de nagios, así como los hosts, servicios, etc. en principio se encuentra en /etc/nagios/nagios.cfg, pero debido a la complejidad que esto entraña, se ha dividido en directorios dentro de /etc/nagios.

También es necesario modificar los ficheros de definición (templates), para adaptarlos a la situación: /etc/nagios/templates/hosts_templates.cfg:

define host{
    name pcs
    use generic-host
    check_period workhours
    max_check_attempts 5
    check_command check_dummy!0
    notification_period workhours
    notification_interval 120
    notification_options d,u,r
    contact_groups admins
    register 0 ; DONT REGISTER THIS DEFINITION - ITS NOT A REAL HOST, JUST A TEMPLATE!
}

El chequeo a nivel de host se hace vía ping, sin embargo, en este caso no se ha hecho así, puesto que la monitorización de Nagios funciona de tal manera que si un host no responde (cualquiera que sea el tipo de chequeo que realiza, en este caso ping), no chequea los servicios asociados a ese host, y el event handler de reinicio de la máquina virtual está asociado al servicio, por lo tanto, cuando el PC se quedaba sin red, el event handler no funcionaba, puesto que el chequeo del host fallaba, y no utilizaba el chequeo de servicio.

Por eso, el chequeo del host, utiliza un script “check_dummy”, que no hace nada, siempre da ok, con lo cual, el servicio que provoca el event handler, es un servicio aparte (en este caso ping), solucionando el problema de la dependencia del chequeo de host al chequeo de los servicios. /etc/nagios/templates/services_templates.cfg:

define service{
    name pcs-ping-service
    use local-service
    normal_check_interval 10
    active_checks_enabled 1
    passive_checks_enabled 0
    check_freshness 0
    freshness_threshold 600
    retry_check_interval 10
    max_check_attempts 4
    register 0 ; DONT REGISTER THIS DEFINITION - ITS NOT A REAL SERVICE, JUST A TEMPLATE!
}

Esta es la definición del servicio de chequeo de los pings de los pcs. No es la estándar que utilizamos, porque la estándar es más agresiva (cada minuto, en lugar de cada 10)

NOTA: Los “register 0″ indican que son plantillas, que luego se utilizan en la definición del host y sus servicios.

El comando asociado al event handler se encuentra en /etc/nagios/commands/reboot-vm.cfg, y su contenido es:

define command{
    command_name reboot-vm
    command_line /usr/lib/nagios/plugins/eventhandlers/reboot-vm $HOSTNAME$ $SERVICESTATE$ $SERVICESTATETYPE$ $SERVICEATTEMPT$
}

Normalmente a un event handler, no se le pasa el host, pero en este caso, para hacerlo “genérico”, y que pueda valer para cualquier host (simplificando mucho las cosas…), se le pasa como parametro el nombre del host. El script que trata el event handler es el siguiente:

#!/bin/sh
# # Event handler script for rebooting a VMware virtual machine if it doesn't reply ping
# # Note: This script will only reboot the virtual machine if the ping is
# retried 3 times (in a "soft" state) or if the ping somehow
# manages to fall into a "hard" error state. 

HOSTNAME=$1
URL="URL_VCENTER"
USER="USER_VCENTER"
PASS="PASS_VCENTER"
# # What state is the ping in?
case "$2" in
OK)
    # The ping just came back up, so don't do anything...
    ;;
CRITICAL)
    # Is this a "soft" or a "hard" state?
    case "$3" in
    # We're in a "soft" state, meaning that Nagios is in the middle of retrying the
    # check before it turns into a "hard" state and contacts get notified...
        SOFT)
        # What check attempt are we on? We don't want to restart the virtual machine on the first
        # check, because it may just be a fluke!
        case "$4" in
        # Wait until the check has been tried 3 times before rebooting the virtual machine.
        # If the check fails on the 4th time (after we reboot the vm), the state
        # type will turn to "hard" and contacts will be notified of the problem.
        # Hopefully this will reboot the vm successfully, so the 4th check will
        # result in a "soft" recovery. If that happens no one gets notified because we
        # fixed the problem!
            3) echo -n "Rebooting VM (3rd soft critical state)..."
            # Call the script to reboot the vm
            /usr/lib/nagios/plugins/eventhandlers/resetvm.pl --url $URL --username $USER --password $PASS --vmname $HOSTNAME
            ;;
        esac
        ;;
        # The virtual machine somehow managed to turn into a hard error without getting fixed.
        # It should have been rebooted by the code above, but for some reason it didn't.
        # Let's give it one last try, shall we?
        # Note: Contacts have already been notified of a problem with the virtual machine at this
        # point (unless you disabled notifications for this service)
        HARD)
            echo -n "Rebooting VM..."
            # Call the script to reboot the vm
            /usr/lib/nagios/plugins/eventhandlers/resetvm.pl --url $URL --username $USER --password $PASS --vmname $HOSTNAME
            ;;
        esac
        ;;
esac
exit

La lógica del script es:

  • Si la respuesta del chequeo es OK, no hacer nada
  • Si es CRITICAL (no ha devuelto el ping)
  • Si es SOFT y es la tercera vez del chequeo en SOFT
    • Reiniciar la VM
  • Si es HARD (no debería de llegar aquí nunca, pero…)
    • Reiniciar la VM

El siguiente paso sería procesar esta información y utilizar la API de VMware para resetear la máquina virtual que está causando los problemas… sin embargo, dado que los nombres de las máquinas virtuales no coinciden con el hostname, si no que llevan una descripción asociada en el nombre, hay que tratar esta información antes de mandar la orden (no todo iba a ser fácil ;) )

Por ejemplo, pcsXXXXX, en realidad es “PCSXXXXX – Pruebas piloto YYYY”.

El script de perl que realiza el reinicio es:

#!/usr/bin/perl -w
# VMware and perl related stuff
use strict;
use warnings;
use VMware::VIRuntime;
# Add the vmname parameter to the arguments
my %opts = ( 'vmname' => {
    # String
    type => "=s",
    help => "The name of the virtual machine",
    # Required
    required => 1,
    },
);
# Perl stuff to add the vmname parameter and process themselves
Opts::add_options(%opts);
Opts::parse();
Opts::validate();
# Connect vcenter
Util::connect();
# Add some regexp magic
my $vmname = ".*" . Opts::get_option('vmname') . ".*";
# get the vm objects matching the criteria
my $vm_views = Vim::find_entity_views(view_type => 'VirtualMachine',
    filter => {
        # regexp magic used here
        'config.name' => qr/${vmname}/i,
        # check that the vm is on
        'runtime.powerState' => 'poweredOn'
        }); 

# this loop should be run once, because it should be only one vm...
foreach my $vm(@$vm_views) {
    # print "Name: " . $vm->name . "\n";
    $vm->ResetVM();
}
# Disconnect vcenter
Util::disconnect();

El script está comentado, con lo cual, no debería haber problema en entenderlo ;)

Se ha probado, y funciona correctamente, pero ocurre lo siguiente: Al estar en dominio, hay veces que la máquina virtual levanta el servicio de firewall, impidiendo el ping a la misma, por lo tanto, esto no sería válido… se están evaluando alternativas a esto.

NOTA: Faltan cosas, como integrarlo con las notificaciones, etc.

Post to Twitter Post to Facebook Send Gmail Post to LinkedIn

No Comments »

minWi on octubre 14th 2011 in General, Nagios, VMware

Nagios plugin template

No he encontrado por internet nada, asique he copiado y pegado del libro “Pro Nagios 2.0″. Espero que a alguien le sirva (a mi si :D )
#!/bin/bash
PROGNAME=`basename $0`
PROGPATH=`echo $0 | sed -e 's,[\\/][^\\/][^\\/]*$,,'`

. $PROGPATH/utils.sh

print_usage(){
echo "Usage: $PROGNAME"
}

print_help(){
print_revision $PROGNAME $REVISION
echo ""
print_usage
echo ""
echo "This plugin is a template written in shell script"
echo ""
support
exit 0
}

case "$1" in
--help)
print_help
exit 0
;;
-h)
print_help
exit 0
;;
--version)
print_revision $PROGNAME $REVISION
exit 0
;;
-V)
print_revision $PROGNAME $REVISION
exit 0
;;
*)
testdata=`test -e t1`
status=$?
if test "$1" = "-v" -o "$1" = "--verbose"; then
echo ${testdata}
fi

if test ${status} -eq 1; then
echo "UNKNOWN: The plug-in has failed to function"
exit 3

elif echo ${testdata} | egrep WARNING > /dev/null; then
echo "WARNING: The plug-in returned $status"
exit 1

elif echo ${testdata} | egrep CRITICAL > /dev/null; then
echo "CRITICAL: The plug-in returned $status"
exit 2
else test ${status} -eq 0 ;
echo "OK: The plug-in returned $status"
exit 0
fi
;;
esac

Post to Twitter Post to Facebook Send Gmail Post to LinkedIn

No Comments »

minWi on agosto 17th 2007 in Linux, Nagios

  • RSS
  • Facebook
  • Google+
  • LinkedIn
  • Twitter
  • Picasa
  • Flickr
  • YouTube