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
Nota
Ver información adicional sobre perfdata (Nagios) Ver información adicional sobre plugins (Shinken)
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.
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