Creación de Packs de Monitorización

Un pack de monitorización es un pequeño conjunto de archivos de configuración, chequeos, plantillas o imágenes agrupados dentro de un directorio para realizar una determinada función de monitorización, como por ejemplo, comprobar disponibilidad o servicios de dispositivos (Linux, Windows, Docker…), temperatura de un lugar, luminosidad de un sensor, etcétera.

Se diseñan en forma de packs para poder agrupar aspectos comunes sobre la función de monitorización que realizan. Así se podrán encontrar los archivos relacionados con la configuración o los propios chequeos dentro del mismo sistema de ficheros. Tampoco habrá que buscar información adicional sobre su funcionamiento o las variables que son necesarias de configurar.

Nota

Existen varias comunidades donde se evalúan y desarrollan este tipo de packs:

Estructura básica

Consta de una serie de ficheros agrupados por directorios con una función bien definida. Algunos de los componentes de un pack son opcionales y contribuyen en alguna medida a la funcionalidad de monitorización para la que está diseñada el pack. Esta es la lista de los componentes habituales de un pack:

Discover (opcional): almacena los scripts que se usan en Import Tool para tareas de descubrimiento (interfaces, versión SNMP, QoS…).

Libexec (opcional): almacena los chequeos (scripts) específicos que se utilizan en el pack. Si se utilizan chequeos genéricos no es necesaria su existencia.

Pack: directorio que se copia al core de monitorización para su tratamiento. Tiene la lista de comandos, servicios y plantillas (definición de macros ). También debe contener el fichero .pack asociado.

Templates (opcional): se guardan las definiciones de plantillas RRD para PnP4Nagios. Si el pack no cuenta con este directorio, se utilizarán las plantillas por defecto.

etc/resource.d: almacena el archivo nombre_de_pack.cfg con los resources del pack. Dichos resources son macros que tienen el mismo valor para todos los hosts a monitorizar desde un mismo Wocu.

package.json: archivo que tiene la definición genérica del pack para su uso con herramientas externas.

Un ejemplo de la estructura de directorios comentada:

networkdevice-traffic/
├── discover
│   ├── wocu-discover-community.sh
│   ├── wocu-discover-ifaces.py
│   ├── wocu-discover-snmpversion.py
│   └── wocu-discover-vendor.py
├── libexec
│   ├── wocu_check.py
│   └── wocu-check-traffic.py
├── pack
│   ├── commands.cfg
│   ├── networkdevice-traffic.pack
│   ├── services
│   │   └── traffic.cfg
│   └── templates.cfg
├── package.json
├── templates
│   └── pnp
│          └── wocu-check-traffic.php
└── etc
    └── resource.d
            └── networkdevice-traffic.cfg

A continuación se comentarán en detalle los directorios y ficheros de la estructura anterior (propios del pack networkdevice-traffic). Cabe destacar que los scripts para los chequeos y descubrimiento también deben seguir una serie de reglas para que su funcionamiento sea el deseado (retorno de valor correcto de ejecución y de perfdata).

Fichero package.json

Fichero en formato JSON que se utiliza para el versionado del pack y que provee de información relevante como autor, versión y licencia, así como de las dependencias conocidas para su aplicación.

Otro dato a destacar, es que permite etiquetar este pack para poder realizar operaciones con un visualizador/editor de packs. Este fichero es obligatorio en todos los packs que se realicen.

Ejemplo del fichero de definición package.json:

  {
  "name": "dns",
  "types": ["pack"],
  "version": "0.1",
  "homepage": "http://a3sec.com/monitorizacion/",
  "author": "A3Sec",
"description": "Dnslookup search to obtain the IP address for the given host/domain query.",
  "keywords": [
    "pack",
    "linux",
    "dns"
  ],
  "dependencies": {
    "shinken": ">=2.0.3"
  },
  "license": "AGPL"
  }

Directorio “discover”

En este directorio se van a guardar los diferentes scripts para realizar las operaciones de descubrimiento que se lanzan desde los packs en el Módulo de Configuración.

Hay que tener en cuenta que los scripts de autodescubrimiento sirven para configurar automática y adecuadamente el valor de una determinada macro de un dispositivo (tipo, versión SNMP, etc.). Cada script de descubrimiento devolverá la salida en formato JSON (un array de diccionarios). La estructura de ese JSON variará dependiendo del tipo de macro a completar.

Ejemplos:

Para una macro de tipo string (por ejemplo _DEVICEVENDOR), el JSON que debe devolver un script tendrá el siguiente formato, un array con un diccionario para completar la macro:

[
    {
        ‘vendor’: ‘Cisco’
    }
]

Nótese que el nombre usado en el JSON (vendor) no coincide con el nombre de la macro (_DEVICEVENDOR). No es necesario, el nombre usado en el JSON será el nombre que se mostrará en el interfaz de configuración.

Para macros multivaluadas de tipo table (por ejemplo _IFACES), el JSON que debe devolver un script tendrá el siguiente formato, una array de diccionarios:

[
{
            "admin status": "up",
        "index": "1",
            "max speed in": 0,
        "max speed out": 0,
        "name": "ATM0",
        "oper status": "up",
            "speed": "1MB",
        "type": "adsl",
        "units": "m"
    },
    {
        "admin status": "down",
        "index": "2",
        "max speed in": 0,
        "max speed out": 0,
        "name": "Ethernet0",
        "oper status": "down",
        "speed": "1MB",
        "type": "ethernetCsmacd",
        "units": "m"
    }
]

Las claves de cada diccionario representan las columnas que se mostrarán en el Módulo de Configuración.

Actualmente se han realizado varios scripts de descubrimiento con diversas funciones, entre otros:

  • Descubrimiento de versión SNMP

  • Descubrimiento de comunidad SNMP

  • Descubrimiento de fabricante en dispositivos (Vendor)

  • Descubrimiento de QoS

  • Descubrimiento de interfaces de red

  • Descubrimiento de Access Points Wifi

  • Descubrimiento de procesos

  • Descubrimiento de particiones

  • Descubrimiento de estado HA en clusters

Directorio “libexec”

En esta ruta/directorio se almacenan los propios scripts de monitorización como tal, ficheros escritos en un lenguaje de programación (bash, python, perl …) o bien compilados y listos para ser ejecutados sin necesidad de intérprete.

Son los encargados de realizar los diferentes chequeos que se lanzan desde el fichero de comandos del pack (commands.cfg). No existe un límite numérico para la cantidad de scripts que se pueden almacenar aquí, la limitación reside en que al definir un comando (en el fichero command.cfg) debe existir en las rutas de los chequeos o dentro de este directorio.

Al igual que se comentó previamente en la sección de los scripts de descubrimiento, la sintaxis o el lenguaje utilizado para construir cada script no supone problema alguno, pero en su comportamiento todos ellos deben comportarse de la misma manera, esto es, manejando y devolviendo un conjunto definido de valores de salida/estado.

Son los siguientes:

Valor de retorno del script

Estado

0

OK

1

WARNING

2

CRITICAL

3

UNKNOWN

Adicionalmente al valor de salida, cada uno de los scripts puede devolver (opcionalmente) una cadena de texto, conteniendo un conjunto de valores medibles para procesarlos posteriormente, por ejemplo, realizar su inserción en bases de datos RRD o InfluxDB, usadas para el graficado de las mismas.

En dicha cadena se pueden introducir valores como la carga, CPU, tiempo de respuesta de ping, temperatura del dispositivo, etcétera.

Como mínimo, cualquier chequeo debe devolver una cadena de texto en formato human-readable que nos indicará el estado de los datos que nos interesa medir. Por ejemplo el chequeo de ping check_ping devuelve una cadena como esta:

PING ok - Packet loss = 0%, RTA = 0.80 ms

Si queremos añadir información (perfdata) para postprocesarla, debe ir a continuación de la cadena anterior separada por el pipe “|”, especificando el nombre de las métricas de rendimiento que se deseen medir (percent_packet_loss y rta en el ejemplo):

PING ok - Packet loss = 0%, RTA = 0.80 ms | percent_packet_loss=0  rta=0.80

Plugins

Existe un resumen del fabricante (Shinken) sobre todos los aspectos del desarrollo de plugins. Se pueden consultar en este siguiente enlace.

Adicionalmente se pueden encontrar multitud de chequeos y scripts que se podrían adaptar como packs en lugares oficiales o no:

Directorio pack

Este directorio es necesario en todos los packs de WOCU-Monitoring. Contiene la definición del propio pack, así como de las plantillas (de dispositivos y servicios). También la definición de los servicios y de los comandos asociados a ellos.

Debe tenerse especial cuidado en completar esta parte de forma correcta, ya que cualquier error de sintaxis en dichos ficheros provoca una salida error del motor de monitorización (al hacer WOCU-Check). Si se detiene el aplicativo no se podrá volver a arrancar hasta corregir estos problemas de sintaxis.

Se describen a continuación todos los componentes de dicho directorio:

Fichero “commands.cfg”

Fichero en el que se definen las equivalencias de nombres de comandos que se usarán en el pack, con el script real al que se llama. Pueden incluirse múltiples definiciones.

Dentro de este fichero se hace uso intensivo de las diferentes macros definidas para el dispositivo o el servicio.

Se define un command con la siguiente estructura:

# Wocu CPU load wrapper
define command {
command_line $PLUGINSDIR$/wocu-check-cpu.py -H $HOSTADDRESS$ -C $_HOSTSNMPCOMMUNITY$ -V $_HOSTDEVICEVENDOR$ -s $_HOSTSNMPVERSION$ -w $_HOSTCPU_WARNING_THRESHOLD$ -c $_HOSTCPU_CRITICAL_THRESHOLD$
command_name    wocu-check-cpu
}

Como puede observarse, debe definirse por una parte el nombre del comando (command_name), y por otra, la llamada al script real del sistema de ficheros (command_line). También se le pasan todo tipo de macros, tanto estándares (ADDRESS) como definidas por el usuario (_SNMPVERSION).

Para usar cualquier tipo de macro es obligatorio encerrarlas entre símbolos de dólar ($). Para usar las macros de “Host” es necesario anteponer un prefijo al nombre de la macro (HOST):

  • Estándar: $HOSTADDRESS$

  • Definida por el usuario: $_HOSTSNMPVERSION$

Para el caso de las macros de servicios, la sintaxis es similar pero anteponiendo el prefijo SERVICE al nombre de la macro que se quiera utilizar, del tipo que sea.

Fichero “templates.cfg”

Fichero en el que se definen los dispositivos y servicios asociados al pack. Este será el nombre que se asociará a cada dispositivo al especificarle este pack dentro del Módulo de Configuración.

Dentro de estas definiciones se incluyen en la parte del dispositivo las posibles macros definidas por el usuario (recuerda que comienzan por guión bajo), así como el valor personalizado de los atributos del dispositivo o servicio.

Se puede encontrar una lista detallada de los atributos de ambos en estos enlaces:

Nota

Es muy importante que en la definición de servicios y dispositivos ambos incluyan la parte de register 0, para que esta definición sea genérica y no aplicada a un dispositivo en concreto. Si no se añade esta opción en ambas definiciones, no funcionará correctamente la asignación del dispositivo ni de los servicios, al dispositivo en cuestión que se esté configurando.

Ejemplo:

define host{
name           ssh
_SSHPORT       22
register       0
}
define service{
name                 ssh-service
use                  generic-service
check_interval       10
retry_interval       2
max_check_attempts   2
register             0
}

Recomendación

El servicio que se define aquí se utiliza principalmente para dar los valores de tiempos por defecto al pack, esto es, cada cuánto tiempo se realiza, cada cuánto tiempo se reintenta y el número de veces que se reintenta. La parte específica se puede sobreescribir dentro de los ficheros del directorio services.

Fichero “discovery.cfg”

Fichero que se utiliza para la operación de autodescubrimiento en Shinken (discovery.cfg). Son reglas para completar la información de un dispositivo añadiéndole nuevos servicios en base a las reglas de descubrimiento.

Estas reglas pueden definirse bajo ciertos criterios, como: puertos abiertos, dispositivos en estado UP, etcétera.

Un posible ejemplo para el pack de HTTP:

define discoveryrule {
    discoveryrule_name   Http
    creation_type        host
    openports            ^80$
    +use                 http
}

Más información en: descubrimiento simple o avanzado.

Importante

Esta parte se va a convertir en opcional en la nueva versión y tendrá que ser activada como módulo.

Ficheros “services.cfg”

Ficheros para la definición de los servicios más específicos del pack, que se asociarán de forma directa al dispositivo que estemos configurando en el Módulo de Configuración.

Se pueden definir todos dentro de un único fichero, pero por convenio, se crea un fichero por cada uno de los servicios a asignar. De esta forma, aplicando un único pack se pueden añadir varios chequeos al dispositivo. Por ejemplo, aplicando el pack de linux-ssh se añadirán dentro de su directorio services los chequeos de CPU, Memoria, Carga, Discos, Ficheros… Todos ellos tendrán una definición del servicio en este directorio con el nombre que corresponda: cpu.cfg, memory.cfg

A continuación, dos ejemplos del pack citado previamente:

define service{
service_description  CPU Stats
use                  linux-ssh-service
host_name            linux-ssh
check_command        check_ssh_linux_cpu_stats
register             0
}
define service{
service_description Memory
use                 linux-ssh-service
host_name           linux-ssh
check_command       check_ssh_linux_memory
register            0
}

Al igual que se ha comentado previamente, existe la necesidad de incluir la opción de register 0 en la definición de los servicios.

En la opción de service_description se establecerá el nombre del servicio que se mostrará en las diferentes consolas de monitorización. Es importante que el valor de service_description sea único para cada servicio y pack, así se evitará errores de duplicidad de servicios y gráficas RRD (ya que este campo se usa para la construcción de ambos elementos).

En la opción de use hay que especificar el servicio genérico que se creó dentro del fichero templates.cfg, y en la opción de host_name el del dispositivo genérico de ese mismo fichero.

El valor de check_command será el de un comando definido dentro del fichero commands.cfg al que haremos referencia, pudiendo pasarle parámetros (con el formato de VALUE_N) como se muestra a continuación.

Un caso particular de servicios, es cuando se trate de iterar sobre una macro de tipo lista. En estos casos, es deseable la creación de un servicio por cada valor que tengamos en dicha lista, por ejemplo, monitorizar el tráfico de todos los interfaces que estén en esta lista, o bien monitorizar las clases de servicio de los dispositivos de red. Para ello, se utiliza una construcción especial en la que se itera sobre una macro de este tipo: duplicate foreach.

Recordemos el valor de la macro por defecto:

_QOS_CLASSES             dummy$(Example_Class)$

Y un ejemplo ya configurado:

_QOS_CLASSES B_IN$(ClaseBronce_i)$,B_OUT$(Clase_Bronce_o)$

define service {
    service_description     QOS_$KEY$
    use                     generic-service
    host_name               qos-cisco
    check_command           check_qos_cisco!$VALUE1$
    duplicate_foreach       _QOS_CLASSES
    register                0
}

De esta manera se creará un nuevo servicio para cada valor de la macro de tipo lista. Como valor de clave ($KEY) se usa el primario de la macro (B_IN y B_OUT) y se le pasaría como parámetro al comando (definido previamente en el archivo commands.cfg) el primer valor de la lista de valores que tenga la macro, en este caso: Clase_Bronce_i y Clase_Bronce_o.

Al ser un servicio genérico también deben llevar la opción de register 0.

Fichero .pack

Este es uno de los ficheros más importantes de todo el pack. Es un fichero también en formato JSON en el que se describe todo el pack. Nos provee del nombre del pack, así como de su ruta para la instalación.

Permite la definición de hashes personalizadas para que se puedan utilizar en la herramienta de gestión de configuraciones Import Tool. Un ejemplo claro de ello es la definición de un “coste” asociado a cada pack, cuyo uso debe ser capturado y gestionado en el Módulo de Configuración.

Adicionalmente, hay que configurar todas las macros que van ser utilizadas en el pack, indicando el tipo al que pertenecen, así como de una breve descripción de su uso. Para hacerlo, hay que definir un hash en el que se relaciona el nombre de la macro con 2 valores:

  • Description: una cadena de texto explicando su función.

  • Type: tipo definido de la macro. Valores permitidos:

    • string

    • integer

    • percent

    • table

    • 3 comma-separated integer

    • 6 comma-separated integer

    • doublepercent

    • float

    • floatpercent

    • ip_address_v4

Además, para cada macro se pueden definir estos campos opcionales:

  • Protected: para enmascarar contraseñas, etc. en el en el Módulo de Configuración.

  • Puede tomar los valores true o false.

  • Choices: para que aparezca un desplegable con las opciones. Se indican respetando el siguiente formato: "choices": ["ip", "hostname"]

  • Required: para indicar que es una macro obligatoria. El Módulo de Configuración no dejará guardar cambios si no se rellena esta macro.

  • Unique: para que se compruebe que no hay varias macros con el mismo valor que esta. Puede tomar los valores “1” o “0”.

Ejemplo de fichero .pack:

{
"name":"qos-cisco",
"description":"This plugin checks for the QOS status configured on Cisco routers",
"path":"qos-cisco/",
"cost":"5",
"macros":{
        "_SNMPCOMMUNITY": {
        "description": "SNMP community to use in the check",
        "type": "string"
        },
        "_QOS_WARNING_THRESHOLD": {
        "description": "QOS warning limits",
        "type": "string"
        },
        "_QOS_CRITICAL_THRESHOLD": {
        "description": "QOS critical limits",
        "type": "string"
        },

"_QOS_CLASSES": {
            "description": "QOS classes(cisco)",
            "type": "table",
            "table_fields": [{
                "Display Name": {
                    "help": "Name appearing in the service: QOS_<Display Name>",
                    "type": "str"
                }},
                {"QOS Name": {
                    "help": "QOS snmp class name (configured on remote device)",
                    "type": "str"
                }}
            ],
        "discover_script": "wocu-discover-qos.py -H $HOSTADDRESS$ -C $_SNMPCOMMUNITY$"
        }
        }
}

Las macros que se definen con valores simples como integer, string o percent admiten un único valor que más tarde será presentado adecuadamente en el Módulo de Configuración.

Sin embargo, las macros de tipo tabla, representadas como table, pueden contener un número indefinido de campos, que más tarde serán representados como columnas. Para manejar estos campos, se definirne un array con sus valores, manteniendo la misma estructura de tipo JSON. En él, se definirán por cada campo: su tipo y un campo adicional para mostrar la ayuda al usuario mediante un icono azul.

../../_images/5_121_aggregator_packs_configuration_detail_0-60.png

Para definir un script de descubrimiento asociado a una macro (de cualquier tipo, tabla o valor) se debe hacer dentro de la sección de definición de dicha macro, utilizando la clave discover-script y como valor el path completo del script con los parámetros requeridos.

{
    "name": "networkdevice-cpu",
    "description": "Network device cpu checks",
    "path": "networkdevice-cpu",
    "cost": "4",
    "macros": {
        [...]
        "_SNMPVERSION": {
            "type": "string",
            "description": "Device SNMP versions supported are: 1 and 2c",
    "discover_script": "wocu-discover-snmpversion.py -H $HOSTADDRESS$ -C $_SNMPCOMMUNITY$"
        },
        "_DEVICEVENDOR": {
            "type": "string",
            "description": "Device vendor",
    "discover_script": "wocu-discover-vendor.py -H $HOSTADDRESS$ -C $_SNMPCOMMUNITY$"
        },
        [...]

Lista de macros en el fichero de definición (templates.cfg):

define host {
    name                     qos-cisco
    use                      generic-host
    _SNMPCOMMUNITY           $SNMPCOMMUNITYREAD$
    _QOS_CLASSES             dummy$(Example_Class)$
    _QOS_WARNING_THRESHOLD   10
    _QOS_CRITICAL_THRESHOLD  20
    register                 0
}

Como se puede observar en el fichero ejemplo .pack, es necesario definir obligatoriamente los siguientes entradas:

  • Name: nombre del pack.

  • Description: breve descripción del funcionamiento del pack.

  • Path: relativo sobre el que se instalará (por defecto mismo que name)

  • Macros: lista de macros definidas en el archivo de plantillas (templates.cfg)

Adicionalmente se pueden crear campos personalizados en claves, por ejemplo el coste:

[...]
"cost": "3",

Directorio “templates”

En este directorio se almacenan (dentro de la ruta pnp/), las plantillas asociadas a los ficheros de scripts alojados dentro de la ruta <packname>/libexec/ (ver capítulo anterior sobre este tema).

Ficheros de plantilla (.php)

Se utilizan para modificar la visualización de los valores almacenados dentro de las bases de datos de gráficas RRD en las consolas de monitorización.

Esta funcionalidad la recoge PnP4Nagios. Trae incorporadas multitud de plantillas por defecto para la mayoría de los chequeos habituales (nagiosplugins).

Todos los chequeos de servicios que no tengan una plantilla con la que corresponderse, no podrán dibujar de forma correcta los valores almacenados en las bases de datos RRD.

La sintaxis que elige PnP4Nagios para la representación de los datos es a través de ficheros escritos en PHP.

Se pueden consultar ejemplos de plantillas asociadas a chequeos y de la sintaxis utilizada en los siguiente enlaces:

Directorio “etc/resource.d”

En este directorio se guarda el fichero de configuración con los resources a utilizar en el pack.

Para evitar tener que configurar las mismas macros y valores en todos los dispositivos de un mismo WOCU-Monitoring que usen el mismo pack, se pueden definir dichas macros como resources en el fichero /etc/resource.d/nombre_del_pack.cfg.

A la hora de desplegar el pack en los distintos WOCU-Monitoring, se copiará el archivo .cfg a la ruta de Shinken adecuada para que las macros estén disponibles.

Ejemplo:

En el pack log-occurrences, se ha definido el fichero etc/resource.d/log-occurrences.cfg con el siguiente contenido:

$ELASTICSEARCH_CLUSTER_IP$="127.0.0.1"
$ELASTICSEARCH_CLUSTER_PORT$=9200

Una vez desplegado el pack, se deberá editar el fichero log-occurrences.cfg para configurar la IP y el puerto correcto de ElasticSearch para el caso concreto.

Cambio del intervalo de chequeos en packs

En los packs se define un servicio genérico, normalmente con el nombre del pack seguido del sufijo -service en el que se especifican los valores por defecto de los intervalos de los chequeos. Aunque de forma más específica se puede cambiar el comportamiento de alguno de los servicios definidos dentro del directorio services.

Ejemplo de definición de un dispositivo y servicio en el fichero templates.cf del pack SSH:

define host{
name           ssh
_SSHPORT       22
register       0
}
define service{
name                 ssh-service
use                  generic-service
check_interval       10
retry_interval       2
max_check_attempts   2
register             0
}

Ejemplo con el pack SSH, definiendo los tiempos de un servicio del pack en el fichero services/custom_ssh.cfg:

define custom_ssh_service{
host_name            ssh
use                  ssh-service
check_interval       5
retry_interval       1
max_check_attempts   2
register             0
}

Instalación y distribución

Para su instalación habría que poner el directorio raíz del pack dentro de la estructura del core de monitorización, concretamente dentro del directorio destinado para los pack: packs_wocu.

Para poder comprobar si la sintaxis que se ha utilizado en el pack es correcta, se puede realizar una comprobación a través de la línea de comandos.

wocu-check

Sin embargo, para la comprobación del funcionamiento hay que habilitar el pack y revisar su funcionamiento contra un dispositivo real.

En los logs de WOCU-Monitoring se puede observar si hay errores de sintaxis o incongruencias entre el fichero templates.cfg y el fichero .pack.

La parte de distribución se realiza con la herramienta de distribución de configuraciones Salt, responsable de mantener la versión más actualizada de los plugins.

networkdevice-traffic/
├── discover
│   ├── wocu-discover-community.sh
│   ├── wocu-discover-ifaces.py
│   ├── wocu-discover-snmpversion.py
│   └── wocu-discover-vendor.py
├── libexec
│   ├── wocu_check.py
│   └── wocu-check-traffic.py
├── pack
│   ├── commands.cfg
│   ├── networkdevice-traffic.pack
│   ├── services
│   │   └── traffic.cfg
│   └── templates.cfg
├── package.json
├── templates
│   └── pnp
│          └── wocu-check-traffic.php
└── etc
    └── resource.d
            └── networkdevice-traffic.cfg

Este es uno de los ficheros más importantes. Es un fichero también en formato JSON en el que se describe todo el pack. Indica el nombre del pack, así como de la ruta para la instalación.

linux-nrpe/
├── commands.cfg
├── linux-nrpe.pack
├── linux.png
├── services
│   ├── disks.cfg
│   ├── load.cfg
│   ├── procs.cfg
│   ├── swap.cfg
│   └── users.cfg
└── templates.cfg