Mar 29, 2010

Monitorización de VMware ESXi con Zabbix (I)

Uno de las principales desventajas de VMware ESXi es su difícil monitorización.

A través del cliente vSphere podemos hacer un seguimiento de distintos parámetros de la máquina (CPU, memoria, disco, etc.) durante la última hora, situación que generalmente es insuficiente si se necesita mantener registrados dichos valores de cara a la posible resolución de una incidencia. Además a través de dicho cliente, tampoco podemos generar ningún tipo de alerta.

Una de las posibles alternativas que se tienen consiste combinar la herramienta resxtop con uno de los mejores softwares open source existentes para la monitorización de equipos: Zabbix.

La idea va a consistir en lanzar resxtop en modo batch, con el objetivo de recopilar los parámetros que nosotros le indiquemos a través del fichero de configuración de resxtop. Esta operación devolverá como resultado un fichero CSV. La aplicación resxtop será gestionada a través de un script en bash, el cual recibirá como parámetro a través de la línea de órdenes el nombre o dirección IP del VMware ESXi del cual queramos obtener su informe CSV.

A través de Zabbix podremos generar posteriormente un item que tenga asociado este script, y el cual se encargue de obtener el informe CSV de forma periódica.

A continuación y a través de otro script en bash (el cual recibirá como argumentos el nombre o dirección IP del VMware ESXi y el parámetro que se desee obtener - consumo de CPU, memoria libre, etc.), podremos obtener el valor asociado a un argumento concreto. De esta forma y posteriormente en Zabbix, podremos generar varios items que se encarguen de obtener dichos valores utilizando el script.

Para hacer las pruebas vamos a emplear Zabbix 1.8.1 instalado sobre un CentOS 5.4 de 64 bits.

Primero vamos a crear un script en bash denominado resxtop_esxi.sh, el cual reciba por la línea de órdenes el nombre del VMware ESXi (o dirección IP) que se desee monitorizar a través de resxtop (habría que sustituir xxxxxx por la password de root del ESXi).

[root@centos ~]# mkdir -p /etc/zabbix/externalscripts/resxtop_esxi/reports

[root@centos ~]# cd /etc/zabbix/externalscripts

[root@centos externalscripts]# cat resxtop_esxi.sh
#!/bin/bash

PATH_RESXTOP="/etc/zabbix/externalscripts/resxtop_esxi"

if [ "$2" == "" ]; then
echo 1 ; exit 1
fi

mv $PATH_RESXTOP/reports/$2.csv.tmp $PATH_RESXTOP/reports/$2.csv

echo 0
$PATH_RESXTOP/resxtop -b -n 1 -c $PATH_RESXTOP/esxtop4rc --server $2 --username root > $PATH_RESXTOP/reports/$2.csv.tmp << eof
xxxxxx
eof

[root@centos externalscripts]# chmod 700 resxtop_esxi.sh

El script anterior depositará los resultados dentro del directorio reports.

Para instalar resxtop en la máquina CentOS, he descargado la versión de esta aplicación para 64 bits y la he descomprimido directamente dentro del directorio /etc/zabbix/externalscripts/resxtop_esxi. Al intentar instalarla utilizando el script que trae consigo (vmware-install.pl) me ha dado varios problemas, así que he optado por instalarla manualmente.

Éstos son los pasos que he seguido:

[root@centos resxtop_esxi]# tar xvzf VMware-vSphere-CLI-4.0.0-198790.x86_64.tar.gz

[root@centos resxtop_esxi]# mkdir -p /etc/vmware-vcli/

[root@centos resxtop_esxi]# cat /etc/vmware-vcli/locations
answer LIBDIR /usr/lib/vmware-vcli

[root@centos resxtop_esxi]# mkdir -p /usr/lib/vmware-vcli/lib

[root@centos resxtop_esxi]# cp -a vmware-vsphere-cli-distrib/lib/lib64/wrapper-gtk24.sh /usr/lib/vmware-vcli/lib/

[root@centos resxtop_esxi]# cp -ar vmware-vsphere-cli-distrib/lib/bin /usr/lib/vmware-vcli/

[root@centos resxtop_esxi]# cp -ar vmware-vsphere-cli-distrib/lib/lib64 /usr/lib/vmware-vcli/

[root@centos resxtop_esxi]# cp -ar vmware-vsphere-cli-distrib/lib/lib32 /usr/lib/vmware-vcli/

[root@centos resxtop_esxi]# cp -a vmware-vsphere-cli-distrib/bin/resxtop .

[root@centos resxtop_esxi]# rm -rf vmware-vsphere-cli-distrib/

Si tenemos activado SELinux, tendremos que ejecutar las dos siguientes órdenes:

[root@centos resxtop_esxi]# chcon -t textrel_shlib_t '/usr/lib/vmware-vcli/lib32/libvmacore.so.1.0/libvmacore.so.1.0'

[root@centos resxtop_esxi]# semanage fcontext -a -t textrel_shlib_t '/usr/lib/vmware-vcli/lib32/libvmacore.so.1.0/libvmacore.so.1.0'

El fichero de configuración de resxtop tendrá el siguiente contenido:

[root@centos resxtop_esxi]# cat esxtop4rc



AG

DHIJK

5c

De esta forma diremos a resxtop que obtenga los parámetros generales de CPU y memoria (dos primeras líneas en blanco) y los datos concretos para cada una de las unidades de disco e interfaces de red (líneas cuarta y sexta).

Si echamos un vistazo al fichero CSV que crea resxtop, podremos ver que se trata de una tabla con dos filas y múltiples columnas, una por cada uno de los datos registrados.

[root@centos resxtop_esxi]# resxtop -b -n 1 -c esxtop4rc --server esxi.local --username root > esxi.local.csv

[root@centos resxtop_esxi]# cat esxi.local.csv
"(PDH-CSV 4.0) (CET)(0)","\\esxi.local\Memory\Memory Overcommit (1 Minute Avg)","\\esxi.local\Memory\Memory Overcommit (5 Minute Avg)"...
...

[root@centos resxtop_esxi]# cat esxi.local.csv | cut -d',' -f 2
"\\esxi.local\Memory\Memory Overcommit (1 Minute Avg)"
"0.00"

Por lo tanto lo que vamos a hacer será un script en AWK que se encargue de obtener el valor del campo concreto que le indiquemos.

[root@centos resxtop_esxi]# cat parser_resxtop.awk
BEGIN {
FS = "," ; RS = ""
}

{
for (i = 1; i <= NF/2; i++)
if ( index($i, field) != 0 )
{
gsub("\"","",$(i + NF/2))
print $(i + NF/2)
break
}
}

[root@centos resxtop_esxi]# awk -v field="Memory Overcommit (1 Minute Avg)" -f parser_resxtop.awk reports/esxi.local.csv
0.00

Y por último, vamos a hacer un script llamado get_esxi_field.sh que recibirá dos argumentos por la línea de órdenes: el primero será el nombre o dirección IP del ESXi del cual se quiera obtener un cierto parámetro (CPU, memoria, etc.) y el segundo argumento será la cadena de texto que indique dicho argumento (Por ejemplo "Memory Overcommit (1 Minute Avg)").

[root@centos resxtop_esxi]# cd ..

[root@centos externalscripts]# cat get_esxi_field.sh
#!/bin/bash

PATH_SCRIPTS="/etc/zabbix/externalscripts/resxtop_esxi"

if [ "$2" == "" -o "$3" == "" ]; then
echo 1 ; exit 1
fi

echo "$(awk -v field="$3" -f $PATH_SCRIPTS/parser_resxtop.awk $PATH_SCRIPTS/reports/$2.csv)"

[root@centos externalscripts]# chmod +x get_esxi_field.sh

[root@centos externalscripts]# chown -R zabbix:zabbix /etc/zabbix/externalscripts

El árbol de ficheros y directorios de la estructura de monitorización que acabamos de crear quedaría de la siguiente forma:

[root@centos ~]# tree /etc/zabbix/externalscripts
/etc/zabbix/externalscripts
|-- get_esxi_field.sh
|-- resxtop_esxi
| |-- esxtop4rc
| |-- parser_resxtop.awk
| |-- reports
| `-- resxtop
`-- resxtop_esxi.sh

2 directories, 5 files

8 comments:

  1. Qué bueno, esta es una solución muy buena para monitorizar lso ESXi.
    En conjunción con los comandos
    vim-cmd vmsvc/ se puede monitorizar el estado de las máquinas virtuales.

    ReplyDelete
  2. Muy buen tutorial.

    Aún así, parece que hay algún problema.

    El script resxtop_esxi.sh debería ser:
    --------------------
    #!/bin/bash

    PATH_DIR="/etc/zabbix/externalscripts/resxtop_esxi"
    PATH_RESXTOP="/usr/local/bin/"

    if [ "$1" == "" ]; then
    echo 1 ; exit 1
    fi

    $PATH_RESXTOP/resxtop -b -n 1 -c $PATH_DIR/esxtop4rc --server $1 --username root > $PATH_DIR/reports/$1.csv.tmp << eof
    xxxxx
    eof
    mv $PATH_DIR/reports/$1.csv.tmp $PATH_DIR/reports/$1.csv

    echo 0
    --------------------
    El primer parámetro se recoge con $1.

    Y la línea:
    [root@centos resxtop_esxi]# cat resxi.local.csv cut -d',' -f 2

    Debería ser:
    [root@centos resxtop_esxi]# cat esxi.local.csv | cut -d',' -f 2

    ReplyDelete
  3. Hola,

    es con $2 y no con $1, y la razón es porque tú ese script lo vas a lanzar desde Zabbix como un script externo, y al lanzarlo como script externo (External check), Zabbix pasa de forma automática siempre como primer argumento ($1) la dirección IP del equipo donde se ejecuta el script. Por eso tienes que empezar a leer desde $2...

    Puedes ver esto en detalle en otro artículo que escribí:

    http://redes-privadas-virtuales.blogspot.com/2010/03/scripts-externos-en-zabbix.html

    Y con respecto a la tubería (|) que falta en la otra línea, tienes razón, lógicamente hay que ponerla, pero no es que se me haya pasado a mí, sino que el editor de blogger elimina ese carácter y tienes que estar atento cuando vas a publicar un artículo de que siga estando en su sitio.

    Un saludo,

    ReplyDelete
  4. Hola!

    Tengo problemas al hacer la configuración siguiendo los pasos detallados, por ejemplo cuando quiero ver el archivo esxi.local.csv me aparece el siguiente aviso resxtop:command not found.. es como que no se encuentra resxtop he mirado en internet pero no consigo solucionar el problema y ya no se que más hacer, por otro lado, algunos items de la plantilla se mantienen activos y puedo visualizar en lates data los que se mantienen activos, pero todos los valores me dan 0 eso significa que efectivamente estoy monitorizando el ESXI que quería?
    Solicito respuesta.

    GRACIAS y un saludo!

    Buen Blog!

    ReplyDelete
  5. Pues está claro lo que te está pasando, que no has desplegado bien el resxtop. Esta aplicación es la que se encarga de obtener los datos de los ESXi.

    Igual la versión de resxtop que estás utilizando ha variado con respecto a la que utilicé yo y los pasos de instalación reflejados aquí no valen, o igual estás utilizando otro sistema operativo, etc.

    ReplyDelete
  6. Hi Javier,

    Many thanks for this much interesting article! I've been working on it this week in order to implement it on our vSphere Management Assistant VM. Today I found something that could be worth sharing on your blog: as the provided awk parser seemed too slow in my environment, I did some research, looking for a way to optimize it, and found that the use of the RS="" command was kind of a bottleneck. Removing it from the parser and re-writing it accordingly gave me blazing fast execution, see:

    Original parser:
    # time sudo awk -v field="Memory Overcommit (1 Minute Avg)" -f parser_resxtop.awk reports/vipr10.spb.fr.csv
    0.00

    real 0m5.706s
    user 0m5.699s
    sys 0m0.000s

    Re-written one:
    # time sudo awk -v field="Memory Overcommit (1 Minute Avg)" -f parser_resxtop2.awk reports/vipr10.spb.fr.csv
    0.00

    real 0m0.009s
    user 0m0.010s
    sys 0m0.000s

    I also added a second parameter (called identifier) to be able to, for example, easily seek counter value for a particular adapter

    i.e:
    # time sudo awk -v field="Writes/sec" -v identifier="Physical Disk(vmhba2:vmhba2:C0:T0:L101)" -f parser_resxtop2.awk reports/vipr10.spb.fr.csv
    5.18

    real 0m0.011s
    user 0m0.010s
    sys 0m0.000s

    Here is the new parser code, hope this helps:

    BEGIN {
    FS = ","
    i = 0
    }
    {
    if ( i == 0 ){
    #
    # we're reading the first row of the file
    #
    if ( identifier != 0 ){
    #
    # searching the field for a particular identifier (i.e: adapter ID)
    #
    for (i = 1; i <= NF; i++){
    if ( index($i, field) != 0 && index($i, identifier) != 0 )
    {
    break
    }
    }
    }
    else{
    #
    # simple search without identifier provided
    #
    for (i = 1; i <= NF; i++){
    if ( index($i, field) != 0 )
    {
    break
    }
    }
    }
    }
    else{
    #
    # now we can directly read value of the wanted field on second row
    #
    gsub("\"","",$i)
    print $i
    }
    }

    Best regards,

    Xavier.

    ReplyDelete
  7. Great post, much appreciate the time you took to write this

    ReplyDelete