Mostrando entradas con la etiqueta zabbix. Mostrar todas las entradas
Mostrando entradas con la etiqueta zabbix. Mostrar todas las entradas

Zabbix: Autenticación local y LDAP

Los temas de autenticación de Zabbix son un poco curiosos y en versiones anteriores a la rama 2.x, una vez que se seleccionase el método de autenticación por defecto, todos los usuarios tenía que hacerlo de esta forma. Esto, aunque podía no suponer un problema, cuando menos sí era molesto. Podía darse el caso de que usuarios tuvieran que tener una cuenta dentro de un LDAP para autenticarse en Zabbix, pero que no perteneciesen a la organización.
Por suerte, desde la versión 2.x, esto cambió y ahora, por defecto todos los usuarios emplean el método de autenticación por defecto, excepto que pertenezcan a un grupo especialmente diseñado para realizar una autenticación local.
Dicho de otro formal, vamos a ver cómo realizar una autenticación mediante LDAP para todos los usuarios, dejando una puerta puerta local abierta al usuario Admin, pues la red puede ser que en alguna ocasión nos de malas pasadas. Lógicamente, quien dice usuario Admin, dice cualquier usuario que se desee para autenticación local.
Los pasos a realizar son los siguientes.
  1. Autenticación LDAP configurada y funcionando
    Si nos sabes cómo hacerlo, puedes ver aquí cómo hacerlo.
  2. Crear un grupo de usuarios de autenticación local
    En este caso hemos optado por crear un grupo de usuarios llamado "Local Users" y la parte importante de este proceso es la definición del "Frontend access" o "Acceso al interfaz web", que tenemos que seleccionar entre la opción por defecto (en este caso LDAP) o la opción de autenticación interna.
    La creación de dicho grupo, se muestra en la imagen.
  3. Añadir los usuarios al grupo "Local Users"
    Todos los usuarios que pertenezcan a este grupo tendrán autenticación local, mientras que el resto no. Autenticación local implica que el usuario tendrá una contraseña y ésta, lógicamente, deberá ser segura.
Si no sabías este truco de Zabbix, espero que te sirva de ayuda.
Leer más

Zabbix: Tiempo por defecto en gráficas

Cuando accedemos a una gráfica en Zabbix, el tiempo preconfigurado que muestra es de una hora. Aunque este tiempo luego puede modificarse que queda guardado en el perfil del usuario para que pueda tener otro valores la próxima vez que accedamos a la gráfica, la verdad es que una hora es un poco escaso para saber la tendencia de valores, por ejemplo, en el consumo de red o de RAM.
Este tiempo lo podemos modificar en el fichero includes/defines.inc.php, en la variable ZBX_PERIOD_DEFAULT. Aquí tenemos que poner el número de segundos que deseamos que se muestre por defecto. Es sencillo y podemos hacer que por defecto las gráficas muestren más período. Esta información más útil de cara al usuario pues ya nos da un estado de la tendencia más directo.
define('ZBX_PERIOD_DEFAULT', 14400); //4 horas

La entrada Zabbix: Tiempo por defecto en gráficas la puedes leer en El mundo en bits.
Leer más

Simular conexión de agente Zabbix con zabbix_sender

Ya hacía tiempo que no escribía nada referente a algún truco de Zabbix y hoy ya tocaba. Pues bien, como muchos de vosotros sabréis, Zabbix tiene el comando zabbix_sender que sirve para enviar al servidor el valor de un item que sea de tipo trapper. Trapper es un tipo especial de items en los cuales el servidor Zabbix no pide su valor, sino que alguien debe enviarlos. Alguien que no sea el agente de Zabbix, puesto que estos no se solicitan. Para enviar valores a Zabbix, la forma más sencilla es emplear el propio zabbix_sender.
Hoy lo que nos interesa es ver cómo podemos hacer para que zabbix_sender actualice un valor que sea de tipo "zabbix agent". Como ya dijimos, sólo se puede actualizar valores de tipo trapper. Esto es así por que en el código así está escrito.
La idea es aplicar un pequeño parche al código del zabbix_sender para que éste admita un tipo especial de envío que sea "zabbix agent". Si vemos un poco el código, cada uno de los tipos que admite Zabbix se corresponde con una variable previamente definida. Alterar el código por lo tanto para que se permita el envío de otro tipo de item no "debe ser muy complicado".
El problema está en que los datos que envía el zabbix_sender al llegar al servidor identificados como trapper y el destino es un item de tipo "zabbix agent" son automáticamente truncados. Para evitar este problema, debemos hacer que zabbix_sender envíe la comunicación simulando ser un agente Zabbix.
Os dejo el parche, que podéis descargar desde aquí, y que aplica los cambios necesarios.
Gracias a esta pequeña modificación, podemos ya emplear zabbix_sender para actualizar valores de tipo "zabbix agent", con simplemente añadir en la línea de comandos la opción "-a".
shell> zabbix_sender -h
Zabbix Sender v2.0.6 (revision 35158) (22 April 2013)

usage: zabbix_sender [-Vhv] -a {[-zpsI] -ko | [-zpI] -T -i f -r} [-c f]

Options:
...
Other options:
  -h --help            Give this help
  -V --version         Display version number
  -a --active-agent    Simulate a Zabbix agent in active mode

shell> zabbix_sender -a -s locahost -k system.uname -o "My value"
info from server: "Processed 1 Failed 0 Total 1 Seconds spent 0.000010"
sent: 1; skipped: 0; total: 1
Lógicamente, sentiros libres de modificarlo.
La entrada Simular conexión de agente Zabbix con zabbix_sender la puedes leer en Puppet Linux.
Leer más

Compilar Zabbix-Agent para Windows

El software de monitorización Zabbix es estupendo y ya hablamos de él más veces en este blog. Una de las ventajas más grandes que presenta es que tiene un agente (pequeño código escrito en C) que permite tener "algo" en los equipos para enviar información del estado de los mismos. Quien dice del estado de los mismos, también dice del poder ejecutar comandos remotos, por ejemplos.
Desde la web oficial del proyecto nos ofrecen siempre una versión para sistemas Unix y otra para sistemas Windows y a mayores todo el código fuente. Si nos interesa modificar algo del agente, o simplemente compilar nuestras propias fuentes, hacerlo en sistemas GNU/Linux es muy simple, pero la cosa cambia en entornos Windows.
Hoy vamos a explicar cómo compilar Zabbix para Windows. Para ello partimos de una instalación de Windows 7 sobre la que instalaremos el Windows SDK for Windows 7 (disponible aquí) y también el Visual Studio 2010 Express (disponible para descarga aquí). Cuando tengamos ambos paquetes instalados, simplemente descargamos el código fuente de Zabbix y los extraemos en una carpeta. Para simplificar todo, yo de dejaré en C:\zabbix-2.0.6 (última versión estable a fecha de escribir esta entrada).
  • Versión de 32 bits
    Esta es la versión para la mayoría de los Windows, así que será por la que empecemos. Antes de nada, debemos de establecer las variables de entorno que necesitamos. Para ello ejecutamos,
    msdos> C:\Program Files\Microsoft Visual Studio 10.0\VC\bin\vcvars32.bat
    
    Una vez tengamos ya el entorno listo, simplemente debemos navegar hasta la carpeta que contiene el proyecto y compilarlo. Para ello, todo desde msdos,
    msdos> cd "C:\zabbix-2.0.6\build\win32\project"
    msdos> copy ..\include\config.h ..\..\..\include\
    msdos> nmake Makefile_agent
    msdos> nmake Makefile_get
    msdos> nmake Makefile_sender
    
  • Versión de 64 bits
    Si vamos a la carpeta del proyecto de 64 bits, nos manda a la carpeta de 32, puesto que el código es el mismo. La única diferencia a la hora de compilar este entorno es que debemos de cargar las variables del entorno de 64. Así que,
    msdos> C:\Program Files\Microsoft Visual Studio 10.0\VC\bin\vcvars64.bat
    
    Una vez tengamos esto, el resto de pasos sin idénticos a la versión de 32, por lo que no los vamos a repetir.
Si durante la compilación os salta el siguiente error,
...
zbxconf.c
 rc.exe /d "ZABBIX_AGENT" /d _WINDOWS /d "NDEBUG" /d "_VC80_UPGRADE=0x0600
/l 0x419 /fo"zabbix_agent.res" resource.rc
Microsoft (R) Windows (R) Resource Compiler Version 6.1.7600.16385
Copyright (C) Microsoft Corporation.  All rights reserved.

resource.rc(10) : fatal error RC1015: cannot open include file 'afxres.h'.
NMAKE : fatal error U1077: '"C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\rc.exe"' : código devuelto '0x1'
Stop.
La solución es editar el fichero zabbix-2.0.6/build/win32/project/resource.rc y en la línea 10 cambiar,
...
//
#include "afxres.h"
...
por
...
//
#include "windows.h"
...
Ahora volvemos a compilar y ya todo debería de ir perfectamente. Al finalizar la compilación nos dejará los nuevos binarios en la carpeta bin de la raíz.

La entrada Compilar Zabbix-Agent para Windows la puedes leer en Puppet Linux.
Leer más

Zabbix-API y tiempo de ejecución

En la entrada de hoy voy a comentar una cosa curiosa que me sucedió y a la que le sigo dando vueltas. El software empleado es Zabbix con algunas pequeñas modificaciones que le había aplicado, para tener unos mapas con un poco más de información.
Pongámonos en situación. Zabbix, desde la versión 1.8 trae un API de consulta bastante potente y de la que ya hablamos en otras ocasiones aquí. El propio interfaz gráfico hace uso de ella para obtener sus datos. Especialmente en la versión 2.0 de Zabbix, el uso del API es cada vez más extendido en el frontend. El problema es saber cómo trabajar con un API. No el API de Zabbix, sino cualquier API. ¿Debemos hacer muchas consultas pequeñas? ¿Sólo una y más grande? Mi conclusión, cuando menos para Zabbix, es más óptimo sacar los datos en cuantas menos consultas mejor.
Veamos un ejemplo del fallo.
...
$options = array(
   'nodeids' => get_current_nodeid(true),
   'hostids' => $hostids,
   'output' => array('status'),
   'nopermissions' => true,
   'preservekeys' => true,
   'selectScreens' => API_OUTPUT_COUNT,
);
$hosts = API::Host()->get($options);
foreach ($hosts as $db_element) {
 ...
 if ($db_element['elementtype'] == SYSMAP_ELEMENT_TYPE_HOST) {
  $options = array(
     'hostids' => $db_element["elementid"],
     'output' => array('value', 'description'),
     'nopermissions' => true,
     'filter' => array('value_flags' => null),
     'monitored' => true,
     'skipDependent' => true,
     'only_true' => 1
  );
  $triggers = API::Trigger()->get($options);
  if(count($triggers) > 0) {
   ...
  }
 ...
 }
...
Esta es la parte del código original de Zabbix, en el fichero include/maps.inc.php. Aunque aquí se presenta de forma simplificada, la idea es que se hace una consulta al API (API::Host()) de la que se obtienen los datos de estado de un listado de equipos. Esos equipos son los que pertenecen a un mapa. Después de trabajar con ellos, para un añadido propio, se hace una nueva llamada al API, en la que para cada elemento de tipo HOST se hace una nueva llamada al API de la que se sacan los trigger's que tenga activo el host en cuestión.
Hasta aquí todo correcto y funciona a la perfección. Con un mapa de 10 elementos, por ejemplo, todo es correcto. El problema viene cuando el mapa comienza a tener más de 20 elementos de tipo HOST.  Si el número de elementos (hablando siempre de tipo HOST) es de 7, las llamadas al API será 7, si son 12, 12 y así siempre. Esto es lógico, ¿no?
La lógica también dice que si una llamada tarda en ejecutarse 0.1 segundos, 10 llamadas tardarán 1 segundo. Que yo sepa, el API de Zabbix no hace ningún tipo de filtrado por llamadas excesivas ni nos bloquea por demasiadas peticiones, por lo tanto, lo que me pasó es algo muy curioso.
Si el número de equipos de tipo HOST que tenía en un mapa pasaba de 15, en sacar los datos tardaba entorno a ~20 segundos. Lo normal sería que tardase 2 segundos, podemos asumir incluso 5 segundos, pero si los mapas tenían entorno a 20 equipos, el tiempo no era proporcional al número de llamadas, sino que se disparaba. Esto no entraba dentro de lo esperado, para nada.
Por suerte, la solución fue sencilla y mucho más óptima en cuando a número de llamadas, pero siempre quedará ahí patente el por qué de la tardanza en la ejecución. La base de datos no tenía problema, al servidor web no le subía la carga. Es y quizás seguirá siendo un misterio.

Puede que la informática no siempre sea determinista o que los algoritmos de basen, no siempre sean así.

La entrada Zabbix-API y tiempo de ejecución la puedes leer en Puppet Linux.
Leer más

Zabbix 2.0 API - host.create

Aunque ya hace tiempo que no hablaba acerca de cómo emplear el API de Zabbix, eso no quiere decir que no la estuviese usando, más bien todo el contrario. Durante este tiempo hice numerosas cosas con ella, y la más especial, emplear la versión escrita en Python para interactuar con ella. Puesto que tuve que escribir código en Python, aproveché para recordar y ver cómo evolucionó este lenguaje de programación.
Por si alguien lo necesita, voy a hacer una serie/mini-tutorial acerca de cómo manejar el API de Zabbix (en su versión 2.0), esta vez desde Python.
Lo primero que necesitamos para ello es obtener el código para hablar con el API de Zabbix. Existen varios port's a Pyhton, yo personalmente opté por éste, que es el port a Python de la librería Ruby oficial. Para comenzar a trabajar, lo que necesitamos es crear una carpeta y descargar el código Python necesario (un único fichero). En dicha carpeta también crearemos los script's que vayamos haciendo, para así evitar problemas con las rutas (por simplificar).
shell> mkdir scripts_zabbix
shell> cd scripts_zabbix
shell> wget https://raw.github.com/gescheit/scripts/master/zabbix/zabbix_api.py
Ahora que ya tenemos todo listo, sólo nos queda escribir el pequeño código necesario para crear/actualizar host's en Zabbix. Puesto que deseamos ser ordenados, crearemos un primer fichero de conexión y configuración. Luego un segundo fichero que hará los cálculos y las llamadas. El primer fichero, zabbix_conf.py tendrá el siguiente código.
#!/usr/bin/env python
from zabbix_api import ZabbixAPI

user = 'admin'
password = 'zabbix'
url = 'http://localhost/'
zabbix = ZabbixAPI(server = url)
zabbix.login(user = user, password = password)

templatesList = {
  'windows': '1', # id del template Windows
  'linux': '2',   # id del template Linux
}
soList = {
  'windows': '1', # id del hostgroup Windows
  'linux': '2',   # id del hostgroup Linux
}
Lógicamente, cada uno que adapte la URL, el nombre de usuario y la contraseña a la de su sistema. Acordaros que el usuario que empleéis debe tener acceso a la API. Ahora creamos el segundo fichero, zabbix_host.py que tendrá la siguiente forma,
#!/usr/bin/env python
from zabbix_conf import *
import sys
import getopt
import traceback
import csv
from optparse import OptionParser

use = "Usage: %prog [options]"
parser = OptionParser(usage = use)

parser.add_option("-a", "--add", dest="add", action="store_true", default=False, help="Insert host.")

options, args = parser.parse_args()

if options.add:
  file = csv.reader(open('hosts.list', 'r'), delimiter=' ')
  for index, row in enumerate(file):
    try:
      temporal = {
        "name": row[0].strip(),
        "dns": row[0].strip() + "your_network.net",
        "pais": row[1].strip().upper(),
        "so": row[2].strip()
      }
      groups = [{"groupid": soList[temporal["so"]]}]
      templates = [{"templateid": templatesList[temporal["so"]}]
      profile = {
        "site_country": temporal["pais"],
        "os_full": temporal["so"]
      }
      print str(index + 1) + ":", temporal["name"]
      print "\tGrupos:", groups
      print "\tTemplates:", templates
      print "\tPerfil:", profile

    except:
      print "\tFallo:", data
      continue

    hosts = zabbix.host.get({'filter': {'name': temporal["name"]}, 'output': "extend"})
    if hosts:
      host = {
        'hostid': hosts[0]["hostid"], # línea importante para actualizar
        'host': temporal["name"],
        'groups': groups,
        'templates': templates,
        'inventory': profile,
        'inventory_mode': 0
      }
      r = zabbix.host.update(host);
      if r:
        print "Actualizado correctamente"
      else:
        print "Fallo al actualizar"

    else:
      host = {
        'host': temporal["name"],
        'interfaces': [{'type': 1, 'ip': "0.0.0.0", 'port': 10050, 'useip': 0, 'main': 1, 'dns': temporal["dns"]}],
        'groups': groups,
        'templates': templates,
        'inventory': profile,
        'inventory_mode': 0
      }
      r = zabbix.host.create(host);
      if r:
        print "Añadido correctamente"
      else:
        print "Fallo al crear"
Pues que la idea es automatizar la creación de host's, como podéis observar, al principio del script se lee un fichero, hosts.list, que contiene la siguiente información,
host_1 España Windows
host_2 España Linux
host_3 EE.UU. Linux
Modificar el comportamiento del script no es muy complejo y espero que a alguien le sirva como referencia para comenzar a emplear el API de Zabbix de manera útil.

PD: Recordar que en Python la identación es MUY importante!

La entrada Zabbix 2.0 API - host.create la puedes leer el Puppet Linux.
Leer más

Agregando información extra a los mapas de Zabbix

Aunque lo fuerte de Zabbix no es exactamente el diseño de mapas, sí es cierto que éstos permiten poner de forma visible una gran cantidad de información. Sin mucho esfuerzo podemos crear un mapa con un equipo y que muestre información en tiempo real del mismo. El mapa permite una mejor visualización y la información importante allí mostrada, facilita y de qué forma, saber el estado del mismo. A mayores, si el equipo tiene un fallo, éste también estará presente en el mapa, lo cual ya nos da más información.
Sin embargo, una de las cosas que faltaba en los mapas de Zabbix era que sobre equipos con algún fallo se nos mostrase dicho fallo al pasar por encima con el ratón, por ejemplo. De esta forma los errores se pueden visualizar, pero sólo si nos interesa. En caso contrario no se mostrarán. Con un ejemplo gráfico que se entenderá mejor.

En la parte izquierda tenemos un equipo con información, siempre en tiempo real y con dos errores. La forma de saber cuales son esos errores, tal como está ahí en el mapa es ir a la pestaña trigger's de ese equipo y ver cuales están disparados. Sin embargo, tras la modificación que veremos a continuación, tenemos la imagen de la derecha. En ella se observa un pequeño popup que aparece al pasar el ratón por encima de la imagen y que nos muestra la descripción de los trigger's disparados con el color que le corresponde. Esta información no es molesta, puesto que sólo aparece cuando pasamos el ratón por encima del equipo, sino permanece oculta.
Si te interesa aplicar esta pequeña mejora, simplemente debes de editar el fichero include/maps.inc.php y agregar las siguientes líneas (en negrita) al final de la función getActionMapBySysmap.
...
if (!empty($menus)) {
 $r_area->addAction('onclick', 'javascript: '.$menus);
}

if ($db_element['elementtype'] == SYSMAP_ELEMENT_TYPE_HOST) {
 $options = array(
    'hostids' => $db_element["elementid"],
    'output' => array('value', 'description'),
    'nopermissions' => true,
    'filter' => array('value_flags' => null),
    'monitored' => true,
    'skipDependent' => true,
    'only_true' => 1,
 );
 $triggers = API::Trigger()->get($options);
 if(count($triggers) > 0) {
  $text = "";
  $isTable = false;
  foreach($triggers as $t) {
   if($t["value"] == 1) {
    $isTable = true;
    switch ($t['priority']) {
     case 0: $class="normal"; break;
     case 1: $class="information"; break;
     case 2: $class="warning"; break;
     case 3: $class="average"; break;
     case 4: $class="high"; break;
     case 5: $class="disaster"; break;
     }
    $text .= "<tr><td class='".$class."'>".$t['description']."</td></tr>";
   }
  }
  if($isTable) {
   $text = "<div class='nowrap ui-corner-all ui-widget-header header move'>Triggers</div><table class='tableinfo'>".$text."</table>";
   $r_area->addAction('onmouseover', 'hintBox.HintWraper(event, this, '.zbx_jsvalue($text).', \'\', \'\');');
  }
 }
}
$action_map->addItem($r_area);
...
La idea desarrollada es muy simple. Crear una nueva área oculta con javascript y que ante el evento onmouseover aparezca y contenga la información que no interesa. Lo mismo que el popup que salta al pinchar sobre un equipo y que permite ejecutar comandos, pero con otra información.

La entrada Agregando información extra a los mapas de Zabbix la puedes leer en Puppet Linux.
Leer más

Detalles de Zabbix "more than X minutes"

Hacía ya un tiempo que no hablaba nada de Zabbix y no por que no esté trabajando bastante a menudo con él. Así que hoy os voy a enseñar un pequeño truco que realmente puede resultar muy interesante, especialmente para entornos grandes, donde el número de item's que se están a monitorizar es muy grande.
Como supongo que sí sabréis, desde el interfaz web de Zabbix, en la pestaña Administración/Cola (Administration/Queue) podemos ver el estado de monitorización de los item's. Aunque desde aquí no nos dice nada, sí podemos ver ciertos detalles muy importantes, como la cantidad de item's que hay con un retraso en recepción de datos. Esto, que de base puede parecer una tontería, nos puede resultar a la larga muy útil, por que si tenemos algunos item's que tardan más de 10 minutos, puede ser que el equipo tenga algún fallo, o que el item en cuestión tenga algún fallo.
Zabbix - More than 10 minutes
Lo malo de esta pestaña es que no nos da una información demasiado útil, y aunque podemos tener una vista de detalles, sacar y corregir los fallos en más de 1500 item's, puede ser complicado. Para solucionarlo, os dejo una query para MySQL que os dará los detalles que necesitáis, y así lo podréis intentar solucionar. Siempre que los errores sean realmente errores.
mysql> SELECT 
         h.STATUS AS "status (host)",
         i.hostid AS hostid,
         h.name AS host,
         i.name AS item,
         i.STATUS AS status
       FROM items i
       LEFT JOIN hosts h
         ON h.hostid=i.hostid
       WHERE
           UNIX_TIMESTAMP()-lastclock > delay+(10*60)
         AND
           (h.STATUS = 0 AND i.STATUS = 0);
Por supuesto, si lo que os interesa es sacar el resto de información, donde yo hice la multiplicación (10*60), podéis poner (5*60) y sacareis los detalles de los item's de más de 5 minutos.

La entrada Detalles de Zabbix "more than X minutes" la puedes leer en Puppet Linux.
Leer más

Autenticación LDAP en Zabbix

Si ya tenéis Zabbix integrado en vuestra infraestructura y sois varios los administradores de sistemas que accedéis, así como otra mucha gente que puede potencialmente acceder, la idea de integrarlo con un OpenLDAP/ Microsoft Active Directory es buena. Por varios motivos, pero el principal sin dudarlo es por el control de la contraseña. Tener una password en LDAP y otra para Zabbix no suele ser muy efectivo. De la misma forma que no es efectivo tener una contraseña diferente para cada uno de los servicios que tengáis en la empresa. Si existe un  directorio activo, lo ideal es que todas las aplicaciones se integren contra él. Así que vamos a ver cómo hacer esto desde Zabbix.
Zabbix tiene una peculiaridad a la hora de permitir hacer login contra un LDAP y no es otra que la de que los usuarios tengan que existir en el propio Zabbix. Es decir, lo único que se comprueba contra el directorio activo es la contraseña, mientras que el usuario se comprueba en la base de datos de Zabbix. Si éste existe, entonces se mira si la contraseña es correcta. Dicho este, creamos un nuevo usuario que tenga el mismo nombre que alguno existente en LDAP y le damos permisos de administrador. Si en vuestro LDAP existe el usuario Admin, genial! Se hace directamente.
Pues bien, con el usuario elegido accedemos al interfaz web de Zabbix y vamos a Administración/ Autenticación. Ahí cambiamos el método de autenticación a LDAP y cubrimos los campos, como se muestra a continuación.
Zabbix LDAP authenticacion
Para poder acceder, necesitaremos conocer los datos del árbol LDAP y también tener un usuario al que se le permita consultar la rama. Es aconsejable que ducho usuario sea de sólo lectura ;-)
Una vez todo cubierto, y antes de guardar, realizamos la comprobación de que la contraseña funciona contra el equipo de autenticación remoto. Zabbix nos obliga a este paso antes de cambiar el método de autenticación por seguridad. Si si algo estuviera mal configurado podríamos quedar sin acceso.
Pero, ¿qué significa cada uno de los campos que se nos pide?
Parámetro
Descripción
LDAP-Host
Nombre del servidor LDAP/AD. Por ejemplo: ldap.domain.com
Port
Puerto para las conexiones LDAP.

Por defecto se emplea el puerto 389. En caso de conexiones LDAP seguras, se suele emplear el puerto 636.
Base DN
Ruta base para las búsquedas LDAP.
Search attribute
Atributo para la identificación de las cuentas de usuario.

Por defecto se suele emplear uid para OpenLDAP y sAMAccountName para Active Directory.
Bind DN
Cuenta LDAP para el acceso y búsqueda en el árbol.

El acceso anómino no está permitido!
Bind password
Controseña del usuairo anterior.
Login
Usuario con el que hemos realizado login.

Debe existir en LDAP/AD.
User password
Contraseña para dicho usuario.
Una vez configurado el acceso LDAP correctamente, cada vez que se quiera dar acceso a un nuevo usuario, éste debe de existir en LDAP y también debemos de crearlo como un usuario del sistema Zabbix. Esto es así por los controles que Zabbix realiza para cada usuario, que a fecha de ahora, todavía no se integran en LDAP. Quizás en futuras versiones.
Más información en Zabbix.com

La entrada Autenticación LDAP en Zabbix la puedes leer en Puppet Linux.
Leer más

Zabbix, not browser check

En la versión 2.0 de Zabbix, una de las cosas que más llamó la atención es que comenzaron a eliminar el soporte a ciertos navegadores. Bueno, más que a navegadores, a versiones de navegadores y cuando se accede al frontend Zabbix, comprueba la versión del navegador que se está empleando. En caso de que no esté entre las soportadas, nos redirige a una página para actualizar la versión del navegador. Aunque puede darse el caso de que lo que detecte no sea lo correcto, por ejemplo, si estás empleando IE-10.
Zabbix warning navigation
Zabbix warning
Si no os interesa esta redirección, lo mejor es optar por sacársela y para ello, únicamente hay que editar el fichero js/browsers.js y comentar las últimas líneas, tal que así.
...
/*if (document.cookie.indexOf('browserwarning_ignore') < 0) {
   if (IE6 || IE7) {
      window.location.replace('browserwarning.php');
   }
}*/
Leer más

Zabbix, control de temperatura

La mayoría de los equipos traen sensores de temperatura que son perfectamente accesibles por el kernel. Estos sensores nos marcan la temperatura de determinadas partes del equipo, así como en algunos casos, la temperatura externa de los mismos. Los valores que estos sensores envían los vamos a monitorizar desde Zabbix, para tener controlada la temperatura y actuar en caso de que ésta aumente.
Para hacer uso de los sensores de temperatura, emplearemos el paquete sensord, el cual devuelve las temperaturas de los sensores (si están soportados), y que luego mandaremos directamente a Zabbix.
shell> apt-get install sensord
Tras la instalación del paquete, lo configuramos con sensors-detect, por si no los detectó automáticamente. Luego con el comando sensors ya podemos visualizar lo que nos devuelve.
shell> sensors
i5k_amb-isa-0000
Adapter: ISA adapter
Ch. 0 DIMM 0: +49.5°C  (low  = +105.0°C, high = +124.0°C)  
Ch. 1 DIMM 0: +50.5°C  (low  = +105.0°C, high = +124.0°C)  
Ch. 2 DIMM 0: +48.0°C  (low  = +105.0°C, high = +124.0°C)  
Ch. 3 DIMM 0: +46.0°C  (low  = +105.0°C, high = +124.0°C) 
En mi caso, tengo 4 sensores en el equipos. Lo que representa cada sensor ya depende del equipo. Para saberlo, lo mejor es mirar el manual de la placa. Lo que aquí nos interesa es simplemente sacar esos datos. Sólo para no dar lugar a equivocaciones, ejecutando este mismo comando en otro equipo, la salida es un poco diferente,
shell> sensors
coretemp-isa-0000
Adapter: ISA adapter
Core 0:       +37.0 C  (high = +87.0 C, crit = +97.0 C)
Core 1:       +34.0 C  (high = +87.0 C, crit = +97.0 C)
Core 2:       +35.0 C  (high = +87.0 C, crit = +97.0 C)
Core 3:       +33.0 C  (high = +87.0 C, crit = +97.0 C)
Como podéis observar, la salida depende mucho del fabricante de la placa, por lo que el comando a ejecutar para obtener la temperatura solamente lo tendréis que adaptar.
Para hacerlo editamos el fichero de configuración del agente Zabbix (/etc/zabbix/zabbix_agentd.conf) y creamos una nueva key personalizada, dejándola tal y como así.
UserParameter=system.temp[*], sensors | awk '/^Ch. $1/ {print substr($$5,2,4);}'
En el caso de la segunda salida, sería el mismo comando, pero un poco cambiado,
UserParameter=system.temp[*], sensors | awk '/^Core $1/ {print substr($$3,2,4);}'
Como no sabemos la cantidad de sensores que vamos a tener por equipo, lo mejor es optar por una única key parametrizada. En este caso, $1 será el sensor detectado (0, 1, etc). Por cierto, si ejecutamos el comando en una shell, el valor que nos devuelve es la temperatura actual de ese sensor. En caso de que el resultado no sea como el que sigue, tendréis que adaptar vuestra expresión awk.
shell> sensors  |  awk '/^Ch. 0/ {print substr($5,2,4);}'
49.5
Llegados aquí ya sólo queda configurar los nuevos item's en Zabbix. Tendríamos que configurar un item por cada sensor que nos interese controlar. La configuración es tal como sigue.
New key for temperature control
Lógicamente, también nos interesa tener alertas que nos avisen de que la temperatura ha subido en el equipo más de lo que debiera. Este tipo de alertas sirven para controlar el equipo y a la vez, para controlar la climatización del CPD, por ejemplo. Puesto que los item's son de tipo numérico, la expresión queda muy sencilla. En mi caso por ejemplo, me interesa que si la temperatura de un sensor pasa de 55 °C me alerte. El trigger,
Name: Temperature control fail
Expression: {Template_sensors:system.temp[0].last(0)}>55 |
            {Template_sensors:system.temp[1].last(0)}>55 |
            {Template_sensors:system.temp[2].last(0)}>55 |
            {Template_sensors:system.temp[3].last(0)}>55
Severity: Average
Enabled: True

La entrada Zabbix, control de temperatura la puedes leer en Puppet Linux.
Leer más

Ejecución de comandos remotos en Zabbix

Zabbix es una herramienta de monitorización excelente que permite saber el estado de nuestras máquinas y en función del mismo alertarnos e incluso ejecutar por sí mismo comandos remotos. En caso de que tengamos una máquina con tendencia a que, por ejemplo, Apache, se quede colgado y no responda, podemos hacer que Zabbix ejecute automáticamente cuando esto pasa un restart del servicio. Vamos a ver en este post cómo permitir que Zabbix ejecute comandos en equipos remotos.
Lo primero que necesitamos es editar el fichero de configuración del agente (/etc/zabbix/zabbix_agentd.conf) y habilitar que permita la ejecución de comandos.
EnableRemoteCommands=1
Por defecto, está deshabilitada dicha funcionalidad, así que habilitamos y simplemente hacemos un restart del servicio.
Una vez ya tenemos esto permitido, tenemos que tener en cuenta que en entornos habituales, el agente Zabbix se ejecuta con un usuario sin privilegios (zabbix), por lo tanto no puede hacer todo lo que probablemente queramos. Sí podrá crear un fichero en /tmp, pero no podrá iniciar un servicio, por ejemplo. En este caso, hay dos opciones, ejecutar zabbix-agent como usuario root, lo cual no es aconsejable, o sino incluir en sudo al usuario zabbix con los comandos que nos interese. La segunda opción, más restrictiva, es la mejor de cara a la seguridad.
Entonces, con el paquete sudo instalado, agregamos un nuevo permiso para el usuario zabbix de tal forma que podamos ejecutar lo que nos interese. Siguiendo el ejemplo, reiniciar el servidor Apache. Para ello agregamos la siguiente línea.
zabbix ALL=(ALL) NOPASSWD: service apache2 restart
O en caso de que queramos poder ejecutar todo tipo de comandos sin filtrar, también se podría poner esta línea,
zabbix ALL=NOPASSWD: ALL
Zabbix remote command
Zabbix remote command
Ahora ya tenemos habilitada la ejecución de comandos remotos y también tenemos permisos para hacerlo. Lo único que queda, es establecer la acción que tenga que suceder para ejecutar el comando. Para ello vamos a Configuración/ Acciones y creamos una nueva acción. La parte de Acción y de Condición es la de siempre, como si quisiéramos que nos alertase por e-mail de un error. La parte que cambia es la de operaciones. Concretamente el tipo de operación, que tenemos que ponerlo en "Comando remoto".
En la imagen de la derecha se muestran las partes más esenciales a la hora de configurar una nueva condición para la ejecución del comando. Aunque lo lógico es que un comando se ejecute únicamente cuando hay un fallo en el equipo y no cuando éste se recupera de dicho fallo. Es decir, reiniciaremos el servicio cuando aparezca el "PROBLEM", pero no con el "OK". Puede darse el caso de que tenga que pasar algo de cada vez. En ese caso, simplemente se ejecuta sin condición de estado.
Como podéis observar configurar una acción para que se ejecute un comando remoto no es algo demasiado complicado y lo único a tener en cuenta es la lógica, al igual que para el envío de notificaciones al correo o a jabber.

La entrada Ejecución de comandos remotos en Zabbix la puedes leer en Puppet Linux.
Leer más

Zabbix + MySQL + CONSTRAINT FOREIGN KEY

La mayoría de la gente que usa habitualmente Zabbix sabe el problema que éste tiene con la base de datos. Ya bien sea MySQL o cualquier otro motor. Una de las formas de evitar un acceso tan abusivo a los datos almacenados es dehabilitar el Housekeeping, o dicho de otra forma, deshabilitar el purgado de datos. Si hacemos esto, los datos almacenados en la base de datos nunca se borrarán y para evitar que crezcan sin control, la mejor solución es sin duda emplear un particionado de tablas.
Particionando las tablas conseguimos borrar de forma muy sencilla una gran cantidad de datos (partición == fichero en disco). Puesto que prácticamente todas las tablas dignas de ser particionadas en Zabbix tienen un campo llamado clock, de tipo unixtime, lo que facilita el particionado y el borrado.
En Zabbix 1.8, particionar las tablas y que todo funcionase no conllevaba problema alguno. Sin embargo con el upgrade a la 2.0 la cosa se complica. Si miramos un poco el schema de la base de datos podremos ver cosas como esta,
ALTER TABLE `screens` ADD CONSTRAINT `c_screens_1` FOREIGN KEY (`templateid`)...
ALTER TABLE `media` ADD CONSTRAINT `c_media_1` FOREIGN KEY (`userid`)...
ALTER TABLE `rights` ADD CONSTRAINT `c_rights_2` FOREIGN KEY (`id`)...
...
Estas reglas realizan una restricción de clave foránea, o dicho de forma más comprensible, un campo de una tabla influye directamente en la otra tabla. Por lo tanto, si borramos un valor de una de las tablas, este borrado se tiene que propagar al resto de tablas afectadas.
En la versión 2.0 de Zabbix este tipo de claves han aparecido y lo que en realidad es una facility muy interesante, en entornos de trabajo grandes puede ser un problema. Imaginemos el siguiente escenario en el que tenemos la tabla events está particionado por fecha (semana | mes) y que queremos comenzar a emplear las alertas para determinados eventos. Puesto que la tabla tiene creada la siguiente clave,
ALTER TABLE `alerts` ADD CONSTRAINT `c_alerts_2` FOREIGN KEY (`eventid`) REFERENCES `events` (`eventid`) ON DELETE CASCADE;
Cuando un nuevo evento intenta insertarse en la tabla alerts, tenemos el siguiente fallo,
[Z3005] query failed: [1452] Cannot add or update a child row: a foreign key constraint fails (`tiendas_produccion`.`alerts`, CONSTRAINT `c_alerts_2` FOREIGN KEY (`eventid`) REFERENCES `events` (`eventid`) ON DELETE CASCADE) [insert into alerts (alertid,actionid,eventid,userid,clock,mediatypeid,sendto,subject,message,status,alerttype,esc_step) values (9754,2,327497453,8,1362020524,1,'javier@domain.com','PROBLEM: Zabbix Agent fail','Trigger: Zabbix Agent fail
Trigger status: PROBLEM
Trigger severity: Information
Este fallo realmente es provocado por MySQL, que no soporta las claves "CONSTRAINT FOREIGN KEY" contra tablas particionadas. Si se piensa fríamente, tiene lógica ya que si se borra una partición, el motor de base de datos no puede controlar la clave. Esto pasará con cualquier tabla, pero en lo que nos afecta a nosotros es para Zabbix, en su versión 2.0.
Entonces, ¿cómo lo solucionamos?
Pues bien, como sabemos cual es el problema (la clave foránea) y como tenemos controlado el crecimiento de nuestras tablas con particiones y no nos interesa la funcionalidad que ofrecen estas claves (no las podemos usar), la mejor solución es sin duda, borrar las claves que no se usan. Así que vamos allá!
mysql> ALTER TABLE events DROP FOREIGN KEY c_alerts_2;
ERROR 1506 (HY000): Foreign key clause is not yet supported in conjunction with partitioning
Justamente queremos borrar la clave y nos da un error de que no se puede hacer, justamente por tener la tabla particionada. No pasa nada, no hay nada que root no sea capaz de hacer. Para ello vamos a optar por deshabilitar las claves foráneas,
mysql> SET FOREIGN_KEY_CHECKS = 0;
Query OK, 0 rows affected (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
Y lo volvemos a intentar,
mysql> ALTER TABLE alerts DROP FOREIGN KEY c_alerts_2;
Esta vez ya sin problemas lo pudo ejecutar y las alertas ya comenzarán a funcionar sin problemas en Zabbix.
La entrada Zabbix + MySQL + CONSTRAINT FOREIGN KEY la puedes leer en Puppet Linux.
Leer más

Zabbix, alerts to log

Zabbix trae muchas formas de alertarnos de que un trigger (y por lo tanto algo no esperado) ha pasado. Las más comunes son en envío de mail's o avisar directamente por Jabber. Ya hace tiempo vimos aquí cómo enviar las notificaciones a Twitter. Hoy vamos a explicar cómo poder almacenar dichas alertas en nuestro log de sistema o tratarlas directamente desde syslog. Para lograr esto, emplearemos el comando logger, que se encargará de hacer el envío ordenado al servicio del sistema, que luego será el que se encargue de procesarlo. Una vez el mensaje en syslog, podremos mandarlo a otro servidor, crear cadenas de filtrado especiales, o lo que queramos.
Lo primero es crear el pequeño script que es necesario para procesar las alertas generadas.
#!/bin/bash

/usr/bin/logger -p syslog.notice -t zabbix-alert $2
Como vemos es realmente sencillo. Una simple llamada a logger y le pasamos como parámetro $2, que es el contenido del mensaje generado. En $1 tendremos almacenado la dirección a la que se envía. Yo guardé este script como sendToLog.sh y a continuación le di permisos de ejecución. La carpeta donde almacenar el script está en la variable de configuración AlertScriptsPath y por defecto es /etc/zabbix/alert.d.
Todo lo que nos queda por hacer ahora es configurar la parte del envío de alertas desde Zabbix. Lo primero es crear un nuevo Media types de tipo script.
SendToLog Media Type
Y a continuación agregar éste a un usuario. Si nos interesa que quede registro de todas las alertas, lo agregamos a un usuario con permisos completos, como pudiera ser admin.
Añadir Media Type a usuario
Una vez aceptado, simplemente nos queda por crear una acción que envíe todas las alertas a éste usuario y por éste tipo y es comenzaría a funcionar. El resultado sería similar a éste,
shell> tail -f /var/log/syslog
Feb 9 17:17:22 zabbix zabbix-alert: PROBLEM: server-h not responds
Feb 9 17:24:25 zabbix zabbix-alert: OK: server-f not responds
Feb 9 17:24:58 zabbix zabbix-alert: PROBLEM: server-d, restarted
Feb 9 17:26:00 zabbix zabbix-alert: OK: server-d, restarted
Feb 9 17:28:33 zabbix zabbix-alert: OK: server-f not responds

Nota: En la versión 1.8 de Zabbix es funcionamiento y configuración es el mismo, con la salvedad de que en la creación del Media Type, es necesario indicarle la ruta completa del fichero, no únicamente el fichero de script.
Leer más

Lock wait timeout exceeded in zabbix

Zabbix es un muy buen sistema de monitorización, sin embargo tiene varios problemas ampliamente comentados. Uno de los principales es el empleo intensivo que hace de la base de datos. Por defecto, el servidor Zabbix, así como el interfaz gráfico, realizan un gran número de operaciones contra la base de datos, lo que hace que ésta necesite una gran cantidad de RAM, así como un disco con un muy buen rendimiento. Esto es necesario y se nota especialmente cuando el número de equipos a controlar es alto (más de 5k hosts).
Otro de los problemas que presenta zabbix, bajo mi punto de vista es que no emplea valores autoincrementales. Si miramos las tablas de la base de datos, veremos que todas tienen un id numérico (eventid, historyid, itemid, etc.). Estos valores son numéricos y contiguos, es decir, incrementales, pero sin embargo es el zabbix-server el que se encarga de calcularlos y no los deja en manos del motor de base de datos. Esto es así para ofrecer compatibilidad con SQLite, pero el problema que presenta es todo lo contrario en bases de datos tipo MySQL o Postgress con una carga importante.
Para saber cual es el próximo id a insertar, existe la tabla ids que contiene sobre 40 filas con los ids de cada una de las tablas y es el propio servidor el que calcula el siguiente id y actualiza dicha tabla. Hablando con datos exactos, lanza consultas de este tipo: "update ids set nextid=nextid+1 where nodeid=0 and table_name='events' and field_name='eventid'". Ahora, si la carga del sistema es elevada, cientos o incluso miles de vps (valores por segundo), entonces puede que tengamos en los log's los siguientes mensajes, y además muy abundantes.
...
23966:20120412:234746.094 [Z3005] query failed: [1205] Lock wait timeout exceeded; try restarting transaction [update ids set nextid=nextid+1 where nodeid=0 and table_name='events' and field_name='eventid']
23942:20120412:234750.128 slow query: 50.982490 sec, "update ids set nextid=nextid+1 where nodeid=0 and table_name='events' and field_name='eventid'"
zabbix_server [23942]: ERROR [file:db.c,line:1582] Something impossible has just happened.
...
23969:20120412:234752.153 [Z3005] query failed: [1205] Lock wait timeout exceeded; try restarting transaction [update ids set nextid=nextid+1 where nodeid=0 and table_name='events' and field_name='eventid']
23969:20120412:234752.153 slow query: 50.206625 sec, "update ids set nextid=nextid+1 where nodeid=0 and table_name='events' and field_name='eventid'"
zabbix_server [23969]: ERROR [file:db.c,line:1582] Something impossible has just happened.
El problema, "Lock wait timeout exceeded; try restarting transaction" en realidad no tiene nada que ver con Zabbix, sino que es un fallo de MySQL cuando dos procesos intentan acceder a la misma fila de una tabla y no pueden. Si hay un gran número de eventos a escribir, estos mensajes aparecen con más frecuencia.
Navegando por la red encontré una posible solución, que la verdad es muy sencilla. La solución es pasar la tabla ids de InnoDB a MyISAM ya que resulta que para este tipo de casos la segunda es más rápida que la primera.
mysql> ALTER TABLE ids ENGINE = MyISAM;
Tras realizar este cambio, el número de mensajes como el descrito, sino desaparecen cuando menos sí deberían de descender en frecuencia.
Leer más

Control de sesiones Zimbra desde Zabbix


Zimbra ofrece muy buenas herramientas para extraer, tanto desde el interfaz gráfico como desde línea de comandos, información y estado de toda la actividad. Si deseamos tener un perfecto control de nuestros sistemas, de cuanta más información dispongamos, mejor que mejor. Aunque siempre hay que tener un balanceo entre la información recadada, la procesada y el tiempo de cada una.
Sin embargo, con información fácil de extraer siempre es útil tenerla presente y éste es el caso de las sesiones activas y las cuentas que tiene Zimbra. Con la ejecución de un simple comando, zmsoap -z -t admin DumpSessionsRequest, podemos obtener información interesante del uso de nuestro servidor Zimbra.
shell> zmsoap -z -t admin DumpSessionsRequest
<DumpSessionsResponse activeSessions="21" xmlns="urn:zimbraAdmin">
  <soap activeAccounts="4" activeSessions="8"/>
  <imap activeAccounts="7" activeSessions="13"/>
</DumpSessionsResponse>

Como podemos observar, tenenemos el número de sesiones activas en Zimbra en el momento de la ejecución, por lo que si lo ejecutamos periódicamente podemos obtener unas buenas estadísticas del uso del sistema de correo a lo largo del tiempo, lo que ayudaría a prevenir problemas o a dar respuesta a problemas encontrados. Como de lo que estamos hablando es de monitorización, estamos hablando de Zabbix! En el foro de Zabbix, stefaan dejó un script que hacía lo mismo, así que simplemente lo vamos a adaptar para nuestros intereses y propósitos.
#!/usr/bin/perl

use XML::Simple;
use Data::Dumper;

my $num_args = $#ARGV + 1;
if ($num_args != 1) {
   print "Usage: zabbix_sessions <Accounts|Sessions>\n";
   exit;
} else {
   $parm = $ARGV[0];
   $xml = new XML::Simple;
   $xmldata = `/bin/su -c 'zmsoap -z -t admin DumpSessionsRequest' \
               - zimbra`;
   $data = $xml->XMLin($xmldata);
   if ($parm eq "sessions") {
      if($data->{activeSessions} eq ""){
         print "0";
      } else {
         print $data->{activeSessions};
      }
   }
   
   if ($parm eq "soapaccounts") {
      if($data->{soap}{activeAccounts} eq ""){
         print "0";
      } else {
         print $data->{soap}{activeAccounts};
      }
   }
   
   if ($parm eq "soapsessions") {
      if($data->{soap}{activeSessions} eq ""){
         print "0";
      } else {
         print $data->{soap}{activeSessions};
      }
   }
   
   if ($parm eq "imapaccounts") {
      if($data->{imap}{activeAccounts} eq ""){
         print "0";
      } else {
         print $data->{imap}{activeAccounts};
      }
   }
   
   if ($parm eq "imapsessions") {
      if($data->{imap}{activeSessions} eq ""){
         print "0";
      } else {
         print $data->{imap}{activeSessions};
      }
   }
}
Como siempre, necesitamos darle permisos a dicho script para que el usuario zabbix lo pueda ejecutar y también modificar el fichero de configuración del agente, para crear una nueva key, en este caso zimbra.users.
zabbix ALL= NOPASSWD: /usr/local/bin/zabbix_sessions
Y en el agente, creamos la nueva key,
UserParameter=zimbra.users[*], /usr/bin/sudo /usr/local/bin/zabbix_sessions $1

Los parámetros que acepta son: sessions, soapaccounts, soapsessions, imapaccounts e imapsessions. Ya sólo nos queda crear los item's de monitorización.
Como el valor que se almacena es de tipo numérico, si es necesario crear un trigger para algún valor en concreto será muy simple de hacer.
Leer más

Zabbix trigger report

Supongo que no seré el único que muchas veces está trabajando con Zabbix y necesita tener rápidamente un listado de todos los equipos afectados por un determinado trigger. Recientemente desarrollé un pequeño módulo que se agrega a la pestaña Reports de Zabbix y que ofrece un listado de todos aquellos triggers que están activos y una dirección de correo a la que enviar el listado. Si estás trabajando y alguien te pregunta ¿qué equipos tienen la carga alta? Ahora la respuesta será muy sencilla: "Te lo paso por mail".
Si te interesa lo puedes descargar desde aquí y tras copiarlo a tu directorio raíz con el nombre trigger_report.php ya sólo necesitas editar el fichero include/menu.inc.php y agregar estas líneas dentro del array de reports.
array(
   'url' => 'trigger_report.php',
   'label' => _('Trigger reports'),
   'user_type' => USER_TYPE_SUPER_ADMIN
)
El resultado es el que se muestra en la imagen lateral, en la que sólo salen aquellos trigger's que están activos. A continuación nos pide un mail al que enviar los resultados. Tras darle a enviar, haciendo uso de la API de zabbix, se enviará el listado de los equipos afectados por el trigger que se ha seleccionado.




Leer más

Control de colas de correo desde Zabbix

Hoy vamos a ver cómo podemos controlar las colas de correo de Zimbra (y en general de postfix) desde nuestra herramienta de monitorización.
Antes de comenzar, vamos a hacer una breve introducción a qshape, una utilidad nativa de postfix que permite controlar la antigüedad de los correos. Dicho de otra forma, nos permite saber cuánto tiempo lleva un correo en una cola. Todos sabemos que ne postfix hay 4 colas principales, active, deferred, hold e incoming. Si hacemos uso qshape podremos saber exactamente cuanto correo hay en cada cola. Veamos un ejemplo.
shell> qshape deferred
              T  5 10 20 40 80 160 320 640 1280 1280+
       TOTAL  3  0  0  0  1  0   0   0   0    0     2
    yahoo.es  1  0  0  0  1  0   0   0   0    0     0
 hotmial.com  1  0  0  0  0  0   0   0   0    0     1
    gmail.es  1  0  0  0  0  0   0   0   0    0     1
Como podéis observar, se le pasa como parámetro la cola que nos interesa y nos devuelve la cantidad de mail's que hay en ella. La primera columna representa el nombre del destino, que como se puede observar suelen ser nombres mal escritos. La segunda columna, representada como una T, representa el total de los mail's en cola y el resto de columnas lo mismo pero por minutos.

Para poder graficar y controlar estos valores, primero necesitamos tener un pequeño script que nos los devuelva. Así que aquí os dejo el que yo hice (no muy currado).
#!/usr/bin/perl
#
# Usage: zabbix_qshape <queue> <time>
# <queue>: active, deferred, hold, incoming
# <time>: T (all), 5,10,20,40,80,160,320,640,1280,1280+
# Returns the number of messages in <queue> for <minutes>

use strict;

my $num_args = $#ARGV + 1;
if ($num_args != 2) {
   print "Usage: zabbix_qshape <queue> <time>\n";
   exit;
} else {
   my $queue = @ARGV[0];
   my $time = @ARGV[1];
   my %tindex = ('T' => 2,
      '5' => 3,
      '10' => 4,
      '20' => 5,
      '40' => 6,
      '80' => 7,
     '160' => 8,
     '320' => 9,
     '640' => 10,
    '1280' => 11,
   '1280+' => 12);
   my $index=$tindex{$time};
   if(!$index) {
      print "Usage: zabbix_qshape <queue> <time>\n";
      exit;
   }
   my $command = "sudo /opt/zimbra/postfix/sbin/qshape.pl $queue \
                 | grep TOTAL \
                 | awk {'print \$$index'}";
   my $sal = qx@$command@;
   chomp($sal);
   print "$sal\n";
}
Con este pequeño script al pasarle una cola y un tiempo, nos devuelve el número de mail's que están en dicha cola. De forma más gráfica,
shell> perl /usr/local/bin/zabbix_qshape deferred T
3
Así que ahora sólo queda crear un nuevo item que se encargue de monitorizarlo. Puesto que queda más limpio, soy de los que prefiere emplear el UserParameter del fichero de configuración, creando ahí una nueva key_ que se encargue de controlar esto. Puesto que le vamos a pasar 2 parámetros, vamos a crearla con opciones.
UserParameter=zimbra.queue[*], /usr/local/bin/zabbix_qshape $1 $2
Ahora ya sólo queda crear los items que deseamos monitorizar, tal que así:
Name                    : Zimbra monitor: $1
Type                    : Zabbix agent
Key                     : zimbra.queue[deferred, T]
Type of information     : numeric (unsigned)
Data type               : Decimal
Update interval (in sec): 300
Applications            : Zimbra
De la forma que la hemos creado, tenemos una única key_ a la que le podemos pasar como parámetros la cola y el tiempo y lógicamente, mostrarlos como parte del nombre. En el ejemplo anterior la key_ creada es para la cola deferred. Para monitorizar el resto de colas, las key's a crear serán:
zimbra.queue[active, T]
zimbra.queue[hold, T]
zimbra.queue[incoming, T]
Sólo para terminar, un detalle importante es el empleo de sudo en el comando. Algunos ya os habréis dado cuenta, pero para los que no, simplemente deciros que antes de que esto funcione debemos de añadir la siguiente línea al fichero /etc/sudoers.
zabbix  ALL=NOPASSWD: /opt/zimbra/postfix/sbin/qshape.pl
Como nota adicional decir que el comando qshape de zimbra está localizado bajo /opt/zimbra/bin/qshape, pero como todo el sistema Zimbra está preparado para ser ejecutado con el usuario zimbra. Sin embargo, la instalación de postfix ofrece también dicho comando, localizado /opt/zimbra/postfix/sbin/qshape.pl al que sí le podemos añadir fácilmente permisos con sudo para el usuario zabbix.
Leer más

Zabbix 2.0, problems with MySQL partitions

Si usas Zabbix, especialmente a gran escala o en discos más lentos, sabrás que uno de los principales procesos que más consumen es el de  housekeeping. Este proceso se encarga de "limpiar" los datos que sobran y crear las tendencias de los item's para así poder borrar datos de la base de datos. Con él se pierden datos "brutos" y genera tendencias. Este proceso es muy costoso, pues saca los datos de la tabla history, los procesa y los vuelve a insertar en la tabla trends (a groso modo).
Si lo que deseamos es aumentar en rendimiento, la solución ideal es deshabilitarlo en el fichero de configuración (/etc/zabbix/zabbix_server.conf).
...
### Option: DisableHousekeeping
# If set to 1, disables housekeeping
DisableHousekeeping=1
...
pero esto conlleva un problema que no es otro que el crecimiento de todos los datos de la base de datos. Sin un proceso que borre, los datos estarán ahí para siempre. La solución a este problema es el particionado de las tablas. En vez de dejar el proceso de purgado de datos a un proceso externo, mejor gestionarlo desde el propio MySQL. Para ello, únicamente llega con crear particiones por día/semana/mes (según la carga de datos que tengas) e irlas borrando según los datos ya no te interesen. Así de una forma muy sencilla podrás eliminar todos los datos de todos los host's de un día/semana/mes.
Un día escribiré un post sobre este tema, pero hoy vamos a lo que nos atañe, que no es otra cosa que un problema en la versión 2.0 de Zabbix a la hora de crear las particiones. Generalmente las tablas afectadas de particionado son las de events y las de history* y hasta la versión 2.0 no había ningún problema. En esta nueva versión, al crear las particiones para la tabla events, obtenemos el siguiente error:
mysql> ALTER TABLE events
    -> PARTITION BY RANGE (clock) (
    -> PARTITION p50 VALUES LESS THAN (1355698800),
    -> PARTITION p51 VALUES LESS THAN (1356303600)
    -> );

ERROR 1217 (23000): Cannot delete or update a parent row: a foreign key constraint fails
Sin embargo, dicha tabla si la observáis (SHOW CREATE TABLE events) no presenta ninguna clave foránea, como indica, pero sin embargo no deja crear las particiones que necesitamos.
Ventajas del software libre, podemos observar el schema que Zabbix crea en MySQL y las relaciones que la tabla events tiene, observando que el campo eventid sí es una clave foránea de las tablas alerts y acknowledges.
Para poder particionar las tablas entonces, necesitamos borrarlas.
mysql> ALTER TABLE alerts DROP FOREIGN KEY c_alerts_2;
mysql> ALTER TABLE acknowledges DROP FOREIGN KEY c_acknowledges_2;
Ahora ya se nos permitirá crear las nuevas particiones que nos interesan en la tabla events,
mysql> ALTER TABLE events
    -> PARTITION BY RANGE (clock) (
    -> PARTITION p50 VALUES LESS THAN (1355698800),
    -> PARTITION p51 VALUES LESS THAN (1356303600)
    -> );
Y puesto que nos interesa seguir manteniendo todas las funcionalidades de Zabbix a nivel de base de datos, creamos nuevamente las claves foráneas que anteriormente habíamos borrado.
mysql> ALTER TABLE `alerts` 
    -> ADD CONSTRAINT `c_alerts_2`
    -> FOREIGN KEY (`eventid`)
    -> REFERENCES `events` (`eventid`) ON DELETE CASCADE;

mysql> ALTER TABLE `acknowledges`
    -> ADD CONSTRAINT `c_acknowledges_2`
    -> FOREIGN KEY (`eventid`)
    -> REFERENCES `events` (`eventid`) ON DELETE CASCADE;
Actualización: Quizás antes de volver a crear estas claves te interese leer esto, puesto que a la larga puede traer problemas en el envío de alertas.
Leer más

Formulario de contacto

Nombre

Correo electrónico *

Mensaje *

Últimos comentarios