Checkmk
to checkmk.com
Important

This is a machine translation based on the English version of the article. It might or might not have already been subject to text preparation. If you find errors, please file a GitHub issue that states the paragraph that has to be improved.

1. Introducción

Los complementos de comprobación son módulos de software escritos en Python que se ejecutan en un sitio de Checkmk y que crean y evalúan los servicios en un host.

Checkmk incluye más de 2000 plug-ins de comprobación listos para usar para todo tipo de hardware y software imaginables. El equipo de Checkmk se encarga del mantenimiento de estos plug-ins y cada semana se añaden otros nuevos. Además, en Checkmk Exchange hay más plug-ins aportados por nuestros usuarios.

Y, sin embargo, siempre puede darse el caso de que un dispositivo, una aplicación o simplemente una métrica concreta que te resulte importante aún no esté cubierta por ninguno de estos complementos existentes, quizá simplemente porque se trata de algo desarrollado en tu organización y, por lo tanto, nadie más podría tenerlo. En el artículo sobre la introducción al desarrollo de extensiones para Checkmk, puedes descubrir qué opciones tienes a tu disposición.

Este artículo te muestra cómo desarrollar complementos de comprobación reales para el agente de Checkmk, incluyendo todo lo que ello conlleva. Hay un artículo aparte para los complementos de comprobación basados en SNMP.

Tip

Al desarrollar un complemento de comprobación basado en agente, normalmente necesitas dos complementos: el complemento de agente en el host supervisado, que proporciona los datos, y el complemento de comprobación en el servidor de Checkmk, que evalúa estos datos. Ambos deben escribirse juntos y optimizarse el uno para el otro. Solo así funcionarán sin problemas después.

1.1. La documentación de la API de comprobación

Desde la versión 2.0.0 de Checkmk, existe una API de comprobación de nuevo desarrollo para programar los complementos de comprobación. En la versión 2.4.0 de Checkmk, la API de comprobación V2 es la versión actual. En este artículo, te mostraremos cómo utilizar la API de comprobación versión 2 para la programación de complementos. Puedes encontrar información sobre la migración a la API de comprobación versión 2 al final de este artículo, en el capítulo «Migración».

Puedes acceder a la documentación de la API de Check en cualquier momento a través de la interfaz de usuario de Checkmk: Help > Developer resources > Plug-in API references. En la nueva ventana del navegador, selecciona «Agent based ("Check API") > Version 2» en la barra de navegación de la izquierda:

“Page to access the Check API version 2 documentation.”

Aquí no solo encontrarás la documentación de la API de Check en todas las versiones compatibles, sino también la documentación de todas las demás API relevantes para la creación de complementos de comprobación. En este artículo, no solo utilizamos la API de Check, sino también la API de conjuntos de reglas V1 al crear un conjunto de reglas y la API de gráficos V1 al crear definiciones de métricas.

Tip

Incluso sin tener un sitio Checkmk en funcionamiento, puedes ver una copia de la documentación de la API de complementos en docs.checkmk.com/plugin-api.

1.2. Requisitos previos

Si te interesa programar complementos de comprobación, necesitarás lo siguiente:

  • Conocimientos del lenguaje de programación Python.

  • Experiencia con Checkmk, especialmente en lo que se refiere a agentes y comprobaciones.

  • Práctica en el uso de Linux desde la línea de comandos.

2. Crear un complemento de agente

Si te interesa programar complementos para Checkmk, es muy probable que ya hayas configurado un servidor Checkmk. Si lo has hecho, seguramente también hayas supervisado tu propio servidor Checkmk como un host.

Aquí crearemos un escenario en el que resulta útil que el servidor de Checkmk y el host supervisado sean idénticos. Esto nos permite utilizar consultas Livestatus desde el host para obtener información sobre los grupos de hosts proporcionados por el servidor de Checkmk.

En el ejemplo que describimos, supondremos una organización con varias ubicaciones:

  • Cada una de estas ubicaciones está representada en Checkmk por un grupo de hosts.

  • Cada ubicación tiene su propio equipo de servicio.

Para garantizar que se pueda notificar al equipo de servicio correcto en caso de problemas, cada host debe estar asignado a una ubicación, es decir, también a un grupo de hosts. El objetivo de este ejemplo es configurar una comprobación para garantizar que ningún host se haya olvidado de asignar un grupo de hosts.

Todo el proceso consta de dos pasos:

  1. Leer la información de monitorización del host. De eso trata este capítulo.

  2. Escribir un complemento de comprobación en el sitio de Checkmk que evalúe estos datos. Te lo mostraremos en el próximo capítulo.

Así que, vamos allá…​

2.1. Recuperación y filtrado de información

¡El primer paso antes de escribir cualquier programa de complemento es investigar! Esto significa que hay que averiguar cómo obtener la información que necesitas para la monitorización.

Para el ejemplo elegido, aprovechamos el hecho de que el servidor de Checkmk es también el host. Esto significa que, inicialmente, basta con recuperar los datos de estado a través de Livestatus, es decir, los datos organizados en tablas que Checkmk mantiene sobre los hosts y servicios supervisados en la memoria volátil.

Inicia sesión como usuario del sitio y consulta la información sobre los grupos de hosts con el siguiente comando:

OMD[mysite]:~$ lq "GET hostgroups"
action_url;alias;members;members_with_state;name;notes;notes_url;num_hosts;num_hosts_down;num_hosts_handled_problems;num_hosts_pending;num_hosts_unhandled_problems;num_hosts_unreach;num_hosts_up;num_services;num_services_crit;num_services_handled_problems;num_services_hard_crit;num_services_hard_ok;num_services_hard_unknown;num_services_hard_warn;num_services_ok;num_services_pending;num_services_unhandled_problems;num_services_unknown;num_services_warn;worst_host_state;worst_service_hard_state;worst_service_state
;Hamburg;myhost11,myhost22,myhost33;myhost11|0|1,myhost22|0|1,myhost33|0|1;Hamburg;;;3;0;0;0;0;0;3;123;10;0;10;99;0;14;99;0;24;0;14;0;2;2
;Munich;myhost1,myhost2,myhost3;myhost1|0|1,myhost2|0|1,myhost3|0|1;Munich;;;3;0;0;0;0;0;3;123;10;0;10;99;0;14;99;0;24;0;14;0;2;2
;check_mk;localhost;localhost|0|1;check_mk;;;1;0;0;0;0;0;1;66;0;0;0;4;0;1;4;61;1;0;1;0;1;1
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

La primera línea de la salida contiene los nombres de las columnas de la tabla hostgroups consultada. El punto y coma actúa como separador. Las líneas siguientes contienen el contenido de todas las columnas, también separadas por puntos y comas.

La salida ya resulta relativamente confusa en este pequeño ejemplo y contiene información que no es relevante para nuestro caso. En general, deberías dejar la interpretación de los datos a Checkmk. Sin embargo, filtrar previamente en el host puede reducir el volumen de datos a transferir si no se necesita realmente toda la información. Así que, en este caso, limita la consulta a las columnas relevantes (Columns), a los nombres de los grupos de hosts (name) y a los hosts de esos grupos (members):

OMD[mysite]:~$ lq "GET hostgroups\nColumns: name members"
Hamburg;myhost11,myhost22,myhost33
Munich;myhost1,myhost2,myhost3
check_mk;localhost
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

La interfaz de Livestatus espera recibir todos los comandos y encabezados en líneas separadas. Los saltos de línea necesarios se indican con \n.

En este ejemplo, hay actualmente tres grupos de hosts: dos grupos para las ubicaciones y uno para el grupo check_mk. Este contiene un host llamado localhost.

El grupo de hosts check_mk es una característica especial dentro de los grupos de hosts. No lo has creado tú mismo. Y no puedes añadir activamente un host a este grupo. Entonces, ¿de dónde viene este grupo de hosts? Como por definición cada host en Checkmk debe pertenecer a un grupo, Checkmk asigna por defecto cada host que no asignes específicamente a un grupo al grupo «especial» check_mk. En cuanto hayas asignado un host a uno de tus propios grupos de hosts, Checkmk lo eliminará del grupo check_mk. Tampoco hay forma de reasignar un host al grupo de hosts check_mk.

Precisamente estas propiedades del grupo check_mk se utilizan ahora para nuestro ejemplo: Dado que cada host debe estar asignado a una ubicación, el grupo de hosts check_mk debe estar vacío. Si no está vacío, hay que tomar medidas, es decir, los hosts que contiene deben asignarse a los grupos de hosts y, por lo tanto, a sus ubicaciones correspondientes.

2.2. Incorpora el comando al agente

Hasta ahora, como usuario del sitio, has utilizado el comando lq para mostrar la información. Esto es útil para comprender los datos.

Sin embargo, para recuperar estos datos del servidor Checkmk, el nuevo comando debe formar parte del agente Checkmk en el host supervisado. En teoría, ahora podrías editar directamente el agente Checkmk en el archivo `/usr/bin/check_mk_agent` e incluir esta parte. Este método tendría, sin embargo, la desventaja de que tu nuevo comando volvería a desaparecer cuando se actualice el software del agente, ya que este archivo se sobrescribirá durante la actualización.

Por lo tanto, es mejor crear un complemento de agente. Todo lo que necesitas para ello es un archivo ejecutable que contenga el comando y que se encuentre en el directorio /usr/lib/check_mk_agent/plugins/.

Y hay otra cosa importante: Los datos no se pueden simplemente enviar. Seguirás necesitando un encabezado de sección. Se trata de una línea con un formato especial que contiene el nombre del nuevo complemento de agente. Este encabezado de sección permite a Checkmk reconocer más tarde dónde empiezan los datos del nuevo complemento de agente y dónde terminan los del complemento anterior. Lo más fácil es que el complemento de agente, el encabezado de sección y el complemento de comprobación tengan el mismo nombre, aunque esto no es obligatorio.

Así que, en primer lugar, necesitarás un nombre significativo para tu nuevo complemento de comprobación. Este nombre solo puede contener letras minúsculas (solo a-z, sin diéresis ni acentos), guiones bajos y dígitos, y debe ser único. Evita conflictos de nombres con complementos de comprobación ya existentes. Si tienes curiosidad por saber qué nombres ya existen, en un sitio de Checkmk puedes listarlos en la línea de comandos con cmk -L:

OMD[mysite]:~$ cmk -L
3par_capacity               agent      HPE 3PAR: Capacity
3par_cpgs                   agent      HPE 3PAR: CPGs
3par_cpgs_usage             agent      HPE 3PAR: CPGs Usage
3par_hosts                  agent      HPE 3PAR: Hosts
3par_ports                  agent      HPE 3PAR: Ports
3par_remotecopy             agent      HPE 3PAR: Remote Copy
3par_system                 agent      HPE 3PAR: System
3par_volumes                agent      HPE 3PAR: Volumes
3ware_disks                 agent      3ware ATA RAID Controller: State of Disks
3ware_info                  agent      3ware ATA RAID Controller: General Information
3ware_units                 agent      3ware ATA RAID Controller: State of Units
acme_agent_sessions         snmp       ACME Devices: Agent Sessions
acme_certificates           snmp       ACME Devices: Certificates
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

La salida aquí solo muestra las primeras líneas de una lista muy larga. Al usar prefijos, la asignación de muchos complementos de comprobación ya se puede reconocer fácilmente aquí. Por lo tanto, también se recomienda el uso de prefijos para tus propios complementos de comprobación. Por cierto, la segunda columna muestra cómo obtiene sus datos el complemento de comprobación correspondiente.

Un nombre adecuado para el nuevo complemento de comprobación de nuestro ejemplo es myhostgroups.

Ahora tienes toda la información que necesitas para crear el script del complemento de agente. Crea un nuevo archivo llamado «myhostgroups» como usuario «root» en el directorio «/usr/lib/check_mk_agent/plugins/»:

/usr/lib/check_mk_agent/plugins/myhostgroups
#!/bin/bash

columns="name members"
site="mysite"

echo '<<<myhostgroups:sep(59)>>>'
su - ${site} lq "GET hostgroups\nColumns: ${columns}"
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

¿Qué significa esto exactamente?

La primera línea contiene el «shebang» (una abreviatura de «sharp» y «bang», siendo este último una abreviatura del signo de exclamación), mediante el cual Linux reconoce que debe ejecutar el script con el shell especificado.

Para que el script sea adaptable, a continuación se introducen dos variables:

  • la variable `columns`, que actualmente contiene los nombres de los grupos y los miembros asociados,

  • la variable `site`, que contiene el nombre del sitio de Checkmk.

Usa el comando echo para generar el encabezado de la sección. Como las columnas de la tabla están separadas por un punto y coma, usa la adición sep(59) para especificar que el punto y coma se utiliza como separador de los datos en la salida del agente. El 59 representa el código de carácter ASCII 59, el punto y coma. Sin esta adición, se utilizaría por defecto el carácter de espacio (carácter ASCII 32) como separador.

Para poder utilizar el comando lq, que está disponible para ti como usuario del sitio, en un script ejecutado por el usuario root, antepónle su.

Tip

Es posible que acceder a lq a través de su pueda causar problemas. Como alternativa, como usuario de root, también puedes acceder a Livestatus directamente en el shell con printf o echo -e a través de un socket Unix. El artículo sobre Livestatus explica cómo hacerlo.

Hay otro punto importante una vez que hayas creado el archivo: haz que el archivo sea ejecutable:

root@linux# chmod +x /usr/lib/check_mk_agent/plugins/myhostgroups
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Puedes probar el complemento del agente directamente a mano introduciendo la ruta completa como comando:

root@linux# /usr/lib/check_mk_agent/plugins/myhostgroups
<<<myhostgroups:sep(59)>>>
Hamburg;myhost11,myhost22,myhost33
Munich;myhost1,myhost2,myhost3
check_mk;localhost
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Los grupos de hosts que no contienen ningún host no aparecen aquí.

Tip

Nuestro ejemplo utiliza un script de shell muy sencillo como complemento de agente. En muchos casos, querrás utilizar un lenguaje de scripting o archivos binarios que sean más fáciles de mantener. Se permite cualquier cosa que sea ejecutable en el sistema de destino. Al utilizar Python, hay un pequeño detalle a tener en cuenta: Si no hay un sufijo .py en el nombre del archivo, el «shebang» se evalúa como con todos los demás lenguajes de scripting. Si el sufijo .py está presente, se ignora el shebang y el agente de Checkmk buscará en su lugar el intérprete de Python. También puedes especificar su ruta de archivo absoluta en el archivo de configuración $MK_CONFDIR/python_path.cfg como la variable PYTHON3, que difiere del Python del sistema. Esto resulta útil si un complemento requiere módulos específicos de Python y, por lo tanto, depende de un entorno virtual de Python (venv).

2.3. Prueba del agente

Las pruebas y la resolución de problemas son las tareas más importantes a la hora de crear un complemento de agente que funcione. Lo mejor es proceder en tres pasos:

  1. Prueba el complemento del agente «de forma independiente». Acabas de hacerlo en la sección anterior.

  2. Prueba el agente en su conjunto de forma local.

  3. Recupera el agente del servidor Checkmk.

Probar el agente localmente es muy sencillo. Como usuario «root», ejecuta el comando «check_mk_agent»:

root@linux# check_mk_agent
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

La nueva sección debe aparecer en algún lugar de la salida, que es muy larga. Los complementos del agente son generados por el agente al final del procesamiento.

Puedes desplazarte por la salida añadiendo less (pulsa Spacebar para desplazarte, / para buscar y Q para salir):

root@linux# check_mk_agent | less
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

O puedes buscar en la salida las líneas que te interesen. Por ejemplo, grep con -A tiene una opción para mostrar unas cuantas líneas más después de cada resultado. Esto te permite buscar y mostrar la sección cómodamente:

root@linux# check_mk_agent | grep -A3 '^<<<myhostgroups'
<<<myhostgroups:sep(59)>>>
Hamburg;myhost11,myhost22,myhost33
Munich;myhost1,myhost2,myhost3
check_mk;localhost
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

La tercera y última prueba se realiza directamente desde el sitio de Checkmk. Incluye el host en la monitorización (por ejemplo, como localhost), inicia sesión como usuario del sitio y, a continuación, recupera los datos del agente con cmk -d:

OMD[mysite]:~$ cmk -d localhost | grep -A3 '^<<<myhostgroups'
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Esto debería producir el mismo resultado que el comando anterior.

Si esto funciona, tu agente está listo. ¿Y qué has hecho para ello? Has creado un pequeño script en la ruta /usr/lib/check_mk_agent/plugins/myhostgroups y lo has hecho ejecutable.

Todo lo que viene a continuación solo tiene lugar en el servidor de Checkmk: Allí escribes el complemento de comprobación.

3. Crear un complemento de comprobación sencillo

Preparar el agente es solo la mitad del trabajo. Ahora tienes que enseñarle a Checkmk cómo gestionar la información de la nueva sección del agente, qué servicios debe generar, cuándo deben ir a WARN o CRIT, etc. Puedes hacer todo esto programando un complemento de comprobación con Python.

3.1. Preparación del archivo

Para tus propios complementos de comprobación, encontrarás el directorio base ya preparado en la jerarquía local del directorio del sitio. Se trata de ~/local/lib/python3/cmk_addons/plugins/. El directorio pertenece al usuario del sitio y, por lo tanto, puedes escribir en él.

En este directorio, los complementos se organizan en familias de complementos, cuyos nombres de directorio se pueden definir libremente. Por ejemplo, todos los complementos relacionados con dispositivos Cisco se almacenan en la carpeta cisco, del mismo modo que todos los complementos relacionados con tus grupos de hosts se almacenan en la carpeta myhostgroups. Esta convención permite que todos los complementos que pertenecen a la misma familia compartan código, y se utiliza exactamente de la misma manera por los complementos que se entregan con Checkmk.

En este subdirectorio <plug-in_family>, se crean a continuación otros subdirectorios con nombres predefinidos según sea necesario para las distintas API, por ejemplo, agent_based para la API Check de los complementos de comprobación basados en agentes. A su vez, más adelante introduciremos otros subdirectorios para la API Rulesets y la API Graphing.

Crea los dos subdirectorios para el nuevo complemento de comprobación basado en agente y luego cambia a ellos para trabajar:

OMD[mysite]:~$ mkdir -p ~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based
OMD[mysite]:~$ cd ~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Puedes editar tu complemento de comprobación con cualquier editor de texto instalado en el sistema Linux.

Crea aquí el archivo «myhostgroups.py» para el complemento de comprobación. La convención es que el nombre del archivo refleje el nombre de la sección del agente. Es obligatorio que el archivo termine en «.py», ya que a partir de la versión 2.0.0 de Checkmk los complementos de comprobación son siempre módulos Python reales.

Un marco básico ejecutable (descargar en GitHub), que irás ampliando paso a paso a continuación, tiene este aspecto:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
#!/usr/bin/env python3

from cmk.agent_based.v2 import AgentSection, CheckPlugin, Service, Result, State, Metric, check_levels

def parse_myhostgroups(string_table):
    parsed = {}
    return parsed

def discover_myhostgroups(section):
    yield Service()

def check_myhostgroups(section):
    yield Result(state=State.OK, summary="Everything is fine")

agent_section_myhostgroups = AgentSection(
    name = "myhostgroups",
    parse_function = parse_myhostgroups,
)

check_plugin_myhostgroups = CheckPlugin(
    name = "myhostgroups",
    service_name = "Host group check_mk",
    discovery_function = discover_myhostgroups,
    check_function = check_myhostgroups,
)
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Primero, tienes que importar las funciones y clases necesarias para los complementos de comprobación desde los módulos de Python. Para nuestro ejemplo, solo importaremos lo que sea necesario o pueda resultar útil en el resto de este artículo. Aquí se utiliza `cmk.agent_based.v2` para especificar que se importan los módulos de la API de comprobación V2:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
from cmk.agent_based.v2 import AgentSection, CheckPlugin, Service, Result, State, Metric, check_levels
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

3.2. Escribir la función de análisis

La función de análisis tiene la tarea de «analizar» los datos «sin procesar» del agente, es decir, analizarlos y dividirlos, y poner estos datos en una forma lógicamente estructurada que sea fácil de procesar en todos los pasos posteriores.

Como se muestra en la sección sobre la prueba del agente, la sección proporcionada por el complemento del agente tiene la siguiente estructura:

<<<myhostgroups:sep(59)>>>
Hamburg;myhost11,myhost22,myhost33
Munich;myhost1,myhost2,myhost3
check_mk;localhost

Checkmk ya divide las líneas de la sección proporcionada por el complemento del agente en una lista de líneas basándose en el separador del encabezado de la sección (en el ejemplo, «;»); estas líneas, a su vez, son listas de palabras. Por lo tanto, en Checkmk tienes disponible la siguiente estructura de datos en lugar de los datos sin procesar del complemento del agente:

[
    ['Hamburg', 'myhost11,myhost22,myhost33'],
    ['Munich', 'myhost1,myhost2,myhost3'],
    ['check_mk', 'localhost']
]
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

En la lista interna, el primer elemento contiene el nombre del grupo de hosts y el segundo, los nombres de los hosts que pertenecen al grupo.

Puedes acceder a toda esta información, pero solo a través de su posición en el conjunto de datos. Por lo tanto, siempre tendrías que especificar el número de corchetes y el número de «secuencia» del contenido o contenidos deseados dentro de cada corchete. Con grandes volúmenes de datos, esto se vuelve cada vez más complejo y resulta cada vez más difícil mantener una visión general.

En este punto, una función de análisis sintáctico ofrece claras ventajas gracias a la estructura que crea. Hace que el código sea más fácil de leer, los accesos son más eficientes y es mucho más fácil mantener una visión general. Transforma la estructura de datos proporcionada por Checkmk de tal manera que puedes acceder a cada uno de los valores individuales por su nombre (o clave) a tu antojo, sin tener que depender de buscar repetidamente en la matriz para encontrar lo que buscas:

{
    'Hamburg': {'members': 'myhost11,myhost22,myhost33'},
    'Munich': {'members': 'myhost1,myhost2,myhost3'},
    'check_mk': {'members': 'localhost'}
}
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

La convención es que la función de análisis lleve el nombre de la sección del agente y comience por parse_. Recibe string_table como único argumento. Ten en cuenta que aquí no puedes elegir el argumento: debe llamarse exactamente así.

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
def parse_myhostgroups(string_table):
    # print(string_table)
    parsed = {}
    for line in string_table:
        parsed[line[0]] = {"members": line[1]}
    # print(parsed)
    return parsed
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Con def se especifica en Python que se va a definir una función a continuación. parsed = {} crea el diccionario con la estructura de datos mejorada. En nuestro ejemplo, repasaremos cada línea, elemento por elemento. El grupo de hosts seguido de los miembros del grupo de hosts se extrae de cada línea y se ensambla en una entrada para el diccionario.

A continuación, el diccionario se devuelve con `return parsed`.

Tip

En el ejemplo anterior, encontrarás dos líneas comentadas. Si las descomentas más adelante al probar el complemento de comprobación, los datos antes y después de ejecutar la función de análisis se mostrarán en la línea de comandos. Esto te permite comprobar si la función realmente hace lo que se supone que debe hacer.

3.3. Creación de la sección del agente

Para que todo este procedimiento surta efecto, debes crear la nueva sección de agente con la nueva función de análisis. Esta es la única forma de que Checkmk la reconozca y la tenga en cuenta. Para ello, crea la sección de agente como una instancia de la clase `AgentSection`:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
agent_section_myhostgroups = AgentSection(
    name = "myhostgroups",
    parse_function = parse_myhostgroups,
)
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Aquí es importante que el nombre de la sección coincida exactamente con el encabezado de la sección en la salida del agente. A partir de este momento, cada complemento de comprobación que utilice la sección `myhostgroups` recibirá el valor de retorno de la función `parse`. Por regla general, será el complemento de comprobación del mismo nombre. Pero otros complementos de comprobación también pueden suscribirse a esta sección, como veremos en la extensión del complemento de comprobación.

Por cierto: si quieres saberlo con exactitud, puedes echar un vistazo a la documentación de la API de comprobación en este punto. Allí encontrarás una descripción detallada de esta clase, así como de las clases, funciones y objetos que se utilizarán más adelante en este artículo.

“Check API documentation for the ‘AgentSection’ class.”

3.4. Creación de un complemento de comprobación

Para que Checkmk reconozca que hay un nuevo plugin de comprobación, hay que crearlo. Esto se hace creando una instancia de la clase CheckPlugin.

Siempre debes especificar al menos cuatro cosas:

  1. name: El nombre del complemento de comprobación. La forma más fácil de hacerlo es usar el mismo nombre que tu nueva sección de agente. De esta manera, la comprobación definida más adelante en la función de comprobación sabe automáticamente qué sección debe evaluar.

  2. service_name: El nombre del servicio tal y como debe aparecer en la supervisión.

  3. discovery_function: La función para detectar servicios de este tipo (más sobre esto en un momento).

  4. check_function: La función para realizar la comprobación propiamente dicha (más sobre esto en un momento).

El nombre de la instancia debe empezar por check_plugin_. Entonces queda así:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
check_plugin_myhostgroups = CheckPlugin(
    name = "myhostgroups",
    service_name = "Host group check_mk",
    discovery_function = discover_myhostgroups,
    check_function = check_myhostgroups,
)
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Es mejor que no pruebes esto todavía, ya que primero tienes que escribir las funciones discover_myhostgroups y check_myhostgroups. Estas deben aparecer en el código fuente antes de la sección de creación del agente y del complemento de comprobación, tal y como se ha descrito anteriormente.

Important

Si se utiliza el núcleo de Nagios (siempre en Checkmk Community), no se permiten los siguientes caracteres especiales en el nombre del servicio :
`;~!$%^&*|\'"<>?,()=
Si estos caracteres siguen apareciendo en los nombres de los servicios, simplemente se eliminan en Checkmk.
En las ediciones comerciales con Checkmk Micro Core (CMC), no se permite el punto y coma (; ) en el nombre. El símbolo del dólar ($ ) solo se muestra si se escapa con una barra invertida (\ ).
Lo siguiente se aplica a todas las ediciones: Si aparecen comillas simples en el nombre del servicio, ¡el reconocimiento de servicios no lo encontrará!

3.5. Escribir la función de detección

Una característica especial de Checkmk es el descubrimiento automático de los servicios que se van a supervisar. Para que esto funcione, cada complemento de comprobación debe definir una función que utilice la salida del agente para reconocer si se debe crear un servicio de este tipo o qué servicios de este tipo se deben crear para el host en cuestión.

La función de detección se invoca siempre que se lleva a cabo una detección de servicios para un host. A continuación, decide si se deben crear servicios y cuáles. En el caso estándar, recibe exactamente un argumento con el nombre section. Este contiene los datos de la sección del agente en un formato preparado por la función parse.

Por lo tanto, implementa la siguiente lógica sencilla: si existe la sección del agente myhostgroups, crea también un servicio adecuado. Este aparecerá automáticamente en todos los hosts en los que se haya implementado el complemento del agente.

Para los complementos de comprobación que solo crean un servicio por host, no se necesita más información:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
def discover_myhostgroups(section):
    yield Service()
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

La función de detección debe devolver un objeto del tipo `service` para cada servicio que se vaya a crear utilizando `yield` (no con `return`). En Python, `yield` tiene la misma función que `return`: ambas devuelven un valor a la función que las llama. La diferencia clave es que `yield` recuerda hasta dónde ha llegado la función en el procesamiento de datos. La siguiente llamada continúa después de la última instrucción `yield`, y no vuelve a empezar desde el principio. Esto significa que no solo se lee el primer resultado (como sería el caso con return), sino todos los resultados en secuencia (esta ventaja cobrará relevancia más adelante en nuestro ejemplo con el descubrimiento de servicios).

3.6. Escribir la función de comprobación

Ahora puedes pasar a la función de comprobación propiamente dicha, que utiliza la salida actual del agente para decidir qué estado debe asumir el servicio y puede generar más información.

El objetivo de la función de comprobación es configurar una comprobación que permita verificar si se ha asignado un grupo de hosts a algún host. Para ello, comprueba si el grupo de hosts check_mk contiene hosts. Si es así, el servicio debe recibir el estado CRIT. Si no es así, todo está OK y, por lo tanto, también lo está el estado del servicio.

Aquí está la implementación:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
def check_myhostgroups(section):
    attr = section.get("check_mk")
    hosts = attr["members"] if attr else ""
    if hosts:
        yield Result(state=State.CRIT, summary=f"Default group is not empty; Current member list: {hosts}")
    else:
        yield Result(state=State.OK, summary="Everything is fine")
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Y ahora la explicación: La función `check_myhostgroups()` primero recupera el valor correspondiente a la clave `check_mk` y lo asigna a la variable `attr`. A continuación, la variable `hosts` se vincula al valor de `members` si este existe. Si no hay ningún `members`, `hosts` permanece vacío.

A continuación, se realiza una consulta if para la evaluación real:

  • Si la variable hosts tiene contenido, es decir, si el grupo de hosts check_mk no está vacío, el estado del servicio pasa a CRIT y se muestra un texto informativo. Este texto también contiene una lista de los nombres de todos los hosts que están en el grupo de hosts check_mk. Se usa la cadena F de Python para mostrar el texto con expresiones; se llama así porque la cadena va precedida de la letra f.

  • Si la variable hosts está vacía, es decir, si no hay hosts en el grupo de hosts check_mk, el estado del servicio cambia a OK. En este caso, también se muestra un mensaje adecuado.

Una vez creada la función de comprobación, el complemento de comprobación ya está listo.

El complemento de comprobación y el complemento de agente están disponibles en GitHub.

3.7. Probar y activar el complemento de comprobación

Primero, asegúrate de que tu complemento sea sintácticamente correcto:

OMD[mysite]:~$ cmk-validate-plugins
Agent based plugins loading succeeded, Active checks loading succeeded, Special agents
loading succeeded, Rule specs loading succeeded, Rule specs forms creation succeeded,
Referenced rule specs validation succeeded, Loaded rule specs usage succeeded
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Las pruebas adicionales y la activación del complemento se realizan en la línea de comandos utilizando el comando `cmk`. Primero, prueba la detección de servicios con la opción `-I`. Añadir la opción `v` (para obtener información detallada) generará una salida detallada. La opción `--detect-plugins` restringe la ejecución de comandos a este complemento de comprobación y `localhost` a este host específico:

OMD[mysite]:~$ cmk -vI --detect-plugins=myhostgroups localhost
Discovering services and host labels on: localhost
localhost:
+ FETCHING DATA
No piggyback files for 'localhost'. Skip processing.
Get piggybacked data
+ ANALYSE DISCOVERED HOST LABELS
SUCCESS - Found no new host labels
+ ANALYSE DISCOVERED SERVICES
+ EXECUTING DISCOVERY PLUGINS (1)
  1 myhostgroups
SUCCESS - Found 1 services
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Tal y como estaba previsto, el descubrimiento de servicios reconoce un nuevo servicio en el complemento de comprobación myhostgroups.

Ahora puedes probar la comprobación incluida en el complemento de comprobación:

OMD[mysite]:~$ cmk --detect-plugins=myhostgroups -v localhost
+ FETCHING DATA
No piggyback files for 'localhost'. Skip processing.
Get piggybacked data
Host group check_mk  Default group is not empty; Current member list: localhost
No piggyback files for 'localhost'. Skip processing.
[agent] Success, [piggyback] Success (but no data found for this host), execution time 1.8 sec | execution_time=1.800 user_time=0.030 system_time=0.000 children_user_time=0.000 children_system_time=0.000 cmk_time_agent=1.780
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Al ejecutar la comprobación, se determinará el estado del servicio encontrado anteriormente.

Si todo ha salido como esperabas, puedes activar los cambios. Si no es así, encontrarás información útil en el capítulo sobre resolución de problemas.

Por último, genera una configuración actualizada del núcleo de monitorización y reinícialo:

OMD[mysite]:~$ cmk -R
Generating configuration for core (type nagios)...
Precompiling host checks...OK
Validating Nagios configuration...OK
Restarting monitoring core...OK
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

En la monitorización de Checkmk, ahora encontrarás el nuevo servicio Host group check_mk en el host localhost:

The new service created in the monitoring by the check plug-in.
Dado que el grupo de hostscheck_mk no está vacío, el servicio esCRIT

¡Enhorabuena por haber creado con éxito tu primer complemento de Check!

4. Ampliación del complemento de comprobación

4.1. Trabajos preparatorios

El primer complemento de comprobación, que acabamos de terminar, ahora se va a ampliar paso a paso. Hasta ahora, el complemento del agente solo ha proporcionado información sobre los nombres y los miembros de los grupos de hosts. Para poder evaluar el estado de los hosts y los servicios que se ejecutan en ellos, por ejemplo, se necesitan más datos.

Ampliación del complemento de agente

Primero ampliarás el complemento de agente una vez para recopilar toda la información que se necesitará para ampliar el complemento de comprobación en las siguientes secciones.

Para saber qué información proporciona Checkmk sobre los grupos de hosts, puedes consultar todas las columnas disponibles de la tabla de grupos de hosts con el siguiente comando como usuario del sitio:

OMD[mysite]:~$ lq "GET columns\nFilter: table = hostgroups\nColumns: name"
action_url
alias
members
members_with_state
name
notes
notes_url
num_hosts
...
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

La salida va aún más allá. La tabla tiene casi 30 columnas, y la mayoría de ellas tienen nombres que son significativos. Las siguientes columnas son de interés aquí: Número de hosts por grupo (columna num_hosts), número de hosts en estado «UP» (num_hosts_up), número de servicios de todos los hosts del grupo (num_services) y número de servicios en estado «OK» (num_services_ok).

Ahora solo falta que el agente proporcione estas nuevas columnas. Puedes hacerlo ampliando el complemento del agente creado en el capítulo anterior.

Como usuario root, edita el script del complemento del agente. Dado que el script ya ha puesto los valores configurables en variables, basta con cambiar solo la línea que empieza por columns e introducir las cuatro columnas adicionales que se obtienen allí:

/usr/lib/check_mk_agent/plugins/myhostgroups
#!/bin/bash

columns="name members num_hosts num_hosts_up num_services num_services_ok"
site="mysite"

echo '<<<myhostgroups:sep(59)>>>'
su - ${site} lq "GET hostgroups\nColumns: ${columns}"
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Ejecuta el script para verificarlo:

root@linux# /usr/lib/check_mk_agent/plugins/myhostgroups
<<<myhostgroups:sep(59)>>>
Munich;myhost3,myhost2,myhost1;3;3;180;144
Hamburg;myhost22,myhost33,myhost11;3;2;132;105
check_mk;localhost;1;1;62;45
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Los cuatro nuevos valores —separados por un punto y coma— aparecen ahora al final de cada línea.

Con este cambio, el complemento del agente ahora proporciona datos diferentes a los de antes. En este punto, es importante asegurarse de que, con los datos modificados, el complemento de comprobación siga haciendo lo que se supone que debe hacer.

Ampliando la función de análisis

En un complemento de comprobación, la función de análisis se encarga de convertir los datos proporcionados por el complemento de agente. Al escribir la función de análisis, solo has tenido en cuenta dos columnas de la tabla de grupos de hosts. Ahora se proporcionan seis columnas en lugar de dos. Por lo tanto, la función de análisis debe personalizarse para procesar las cuatro columnas adicionales.

Como usuario del sitio, modifica la función de análisis en el archivo myhostgroups.py, que contiene el complemento de comprobación:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
def parse_myhostgroups(string_table):
    parsed = {}
    column_names = [
        "name",
        "members",
        "num_hosts",
        "num_hosts_up",
        "num_services",
        "num_services_ok",
    ]
    for line in string_table:
        parsed[line[0]] = {}
        for n in range(1, len(column_names)):
            parsed[line[0]][column_names[n]] = line[n]
    return parsed
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Aquí se ha modificado todo lo que hay entre parsed = {} y return parsed. En primer lugar, las columnas que se van a procesar se definen bajo sus nombres como una lista column_names. A continuación, se crea un diccionario en el bucle for generando los pares clave-valor en cada línea a partir del nombre de la columna y el valor leído.

Esta ampliación no es crítica para la función de comprobación existente, ya que la estructura de datos de las dos primeras columnas permanece sin cambios. Solo se añaden columnas adicionales, que (todavía) no se evalúan en la función de comprobación.

Ahora que se pueden procesar los nuevos datos, también los utilizarás.

4.2. Detección de servicios

En el capítulo anterior has creado una comprobación muy sencilla que crea un servicio en un host. Sin embargo, también es muy común que haya varios servicios procedentes de una sola comprobación en un host.

El ejemplo más común de esto es un servicio para un sistema de archivos en un host. El complemento de comprobación llamado «df» crea un servicio por cada sistema de archivos en el host. Para distinguir estos servicios, se incorpora al nombre del servicio el punto de montaje del sistema de archivos (por ejemplo, /var) o la letra de la unidad (por ejemplo, C:). Esto da como resultado un nombre de servicio como Filesystem /var o Filesystem C:. La palabra /var o C: se denomina aquí «elemento». Por lo tanto, también estamos hablando de una comprobación con elementos.

Si quieres crear una comprobación con elementos, debes implementar las siguientes funciones:

  • La función de detección debe generar un servicio para cada una de las entradas que deben supervisarse en el host.

  • Debes incluir el elemento en el nombre del servicio utilizando el marcador de posición %s (por ejemplo, "Filesystem %s").

  • La función de comprobación se llama una vez, por separado para cada elemento, y recibe este como argumento. A partir de los datos del agente, debe extraer los datos relevantes para este elemento.

Para probar esto en la práctica, crearás un servicio independiente para cada grupo de hosts existente.

Dado que el complemento de comprobación myhostgroups creado en el capítulo anterior para comprobar el grupo estándar check_mk debería seguir funcionando, este complemento de comprobación se mantiene tal cual. Para la ampliación, crea el nuevo complemento de comprobación myhostgroups_advanced en el archivo existente myhostgroups.py. — en el primer paso, como antes, creando una instancia de la clase CheckPlugin.

Aquí puedes ver el código antiguo y el nuevo resaltados:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
check_plugin_myhostgroups = CheckPlugin(
    name = "myhostgroups",
    service_name = "Host group check_mk",
    discovery_function = discover_myhostgroups,
    check_function = check_myhostgroups,
)

check_plugin_myhostgroups_advanced = CheckPlugin(
    name = "myhostgroups_advanced",
    sections = [ "myhostgroups" ],
    service_name = "Host group %s",
    discovery_function = discover_myhostgroups_advanced,
    check_function = check_myhostgroups_advanced,
)
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Para que el nuevo complemento de comprobación se pueda distinguir del antiguo, se le asigna un nombre único con myhostgroups_advanced. El parámetro sections determina las secciones de la salida del agente a las que se suscribe el complemento de comprobación. Aquí, se utiliza myhostgroups para especificar que el nuevo complemento de comprobación utiliza los mismos datos que el antiguo: la sección del complemento del agente preparada por la función parse. El nombre del servicio ahora contiene el marcador de posición %s. Checkmk insertará más adelante el nombre del elemento en este punto. En las dos últimas líneas se definen los nombres de la nueva función de descubrimiento y la nueva función de comprobación, que aún hay que escribir.

Primero la función de detección, que ahora tiene la tarea de determinar los elementos que se van a supervisar; esto también se añade a la ya existente:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
def discover_myhostgroups_advanced(section):
    for group in section:
        if group != "check_mk":
            yield Service(item=group)
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Al igual que antes, la función de descubrimiento recibe el argumento section. Los grupos de hosts individuales se recorren en un bucle. Aquí nos interesan todos los grupos de hosts, con la excepción de check_mk, ya que este grupo de hosts especial ya ha sido gestionado por el complemento de comprobación existente myhostgroups. Cada vez que se encuentra un elemento, se devuelve con yield, lo que crea un objeto del tipo Service, que a su vez recibe el nombre del grupo de hosts como elemento.

Si el host se supervisa más tarde, la función de comprobación se llama por separado para cada servicio —y, por lo tanto, para cada elemento. Esto te lleva a la definición de la función de comprobación para el nuevo complemento de comprobación myhostgroups_advanced. La función de comprobación recibe el argumento item además de la sección. La primera línea de la función queda así:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
def check_myhostgroups_advanced(item, section):
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

El algoritmo de la función de comprobación es sencillo: Si el grupo de hosts existe, el servicio se establece en OK y se muestran el número y los nombres de los hosts del grupo. La función completa para esto:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
def check_myhostgroups_advanced(item, section):
    attr = section.get(item)
    if attr:
        yield Result(state=State.OK, summary=f"{attr['num_hosts']} hosts in this group: {attr['members']}")
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

El resultado de la comprobación se entrega devolviendo un objeto de la clase Result a través de yield. Esto requiere los parámetros state y summary. Aquí, state define el estado del servicio (en el ejemplo OK) y summary el texto que se muestra en el Summary del servicio. Esto es meramente informativo y Checkmk no lo evalúa más a fondo. Puedes encontrar más información al respecto en la siguiente sección.

Hasta aquí, todo bien. Pero, ¿qué pasa si no se encuentra el elemento que estás buscando? Esto puede ocurrir si ya se ha creado un servicio para un grupo de hosts en el pasado, pero este grupo de hosts ha desaparecido ahora, ya sea porque el grupo de hosts sigue existiendo en Checkmk pero ya no contiene ningún host, o porque se ha eliminado por completo. En ambos casos, este grupo de hosts ya no estará presente en la salida del agente.

La buena noticia: ¡Checkmk se encarga de esto! Si no se encuentra el elemento buscado, Checkmk genera automáticamente el resultado «UNKNOWN - Item not found in monitoring data» para el servicio. Esto es intencionado y es algo positivo. Si no se encuentra el elemento buscado, simplemente puedes ejecutar Python fuera de la función y dejar que Checkmk haga su trabajo.

Checkmk solo sabe que el elemento que estaba ahí antes ya no está. Checkmk no sabe el motivo de esto, pero tú sí. Por lo tanto, es conveniente no guardarte esa información para ti y detectar esta condición en la función de comprobación para mostrar un mensaje útil.

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
def check_myhostgroups_advanced(item, section):
    attr = section.get(item)
    if not attr:
        yield Result(state=State.CRIT, summary="Group is empty or has been deleted")
        return

    yield Result(state=State.OK, summary=f"{attr['num_hosts']} hosts in this group: {attr['members']}")
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

¿Qué ha cambiado? Ahora se gestiona primero la condición de error. Por lo tanto, comprueba en la rama «if» si el elemento realmente no existe, establece el estado en «CRIT» y sal de la función con «return». En todos los demás casos, devuelve «OK» como antes.

Esto significa que has incorporado la situación de los grupos de hosts que desaparecen en la función de comprobación. En lugar de UNKNOWN, el servicio asociado será ahora CRIT y contendrá información sobre la causa del estado crítico.

Con esto queda completado el nuevo complemento de comprobación como una extensión del antiguo. El complemento de agente ampliado y el archivo ampliado para los complementos de comprobación se pueden encontrar de nuevo en GitHub. Este último contiene el complemento de comprobación simple myhostgroups del capítulo anterior, la función de análisis avanzada y los componentes del nuevo complemento de comprobación myhostgroups_advanced con la creación del complemento de comprobación, la función de detección y la función de comprobación. Ten en cuenta que las funciones siempre deben definirse antes de la creación de complementos de comprobación o secciones de agente para que no haya errores debidos a nombres de funciones no definidos.

Dado que el nuevo complemento de comprobación myhostgroups_advanced ofrece nuevos servicios, debes realizar un descubrimiento de servicios para este complemento de comprobación y activar los cambios para poder ver estos servicios en la supervisión:

The two new services created by the advanced check plug-in in the monitoring.
Dos nuevos servicios en la supervisión:

Proceda tal y como se describe en el capítulo sobre el complemento de comprobación simple. No ejecute los dos primeros comandos para myhostgroups, sino que ejecútelos para el nuevo complemento de comprobación myhostgroups_advanced.

4.3. Resumen y detalles

En la monitorización de Checkmk, cada servicio tiene un estado —OK, WARN, etc.—, así como una línea de texto. Este texto se encuentra en la columna «Summary» —como se puede ver en la captura de pantalla anterior— y, por lo tanto, tiene la función de proporcionar un breve resumen del estado del servicio. La idea es que este texto no supere los 60 caracteres. Esto garantiza una visualización concisa de la tabla sin molestos saltos de línea.

También está el campo «Details», en el que se muestran todos los detalles sobre el estado del servicio, lo que incluye toda la información del resumen. Al hacer clic en el servicio se abre la página del servicio, en la que se pueden ver los dos campos «Summary» y «Details», junto con muchos otros.

Al llamar a yield Result(...), puedes determinar qué información es tan importante que debe mostrarse en el resumen y para cuál basta con que aparezca en los detalles.

En nuestro ejemplo, siempre has utilizado una llamada del siguiente tipo:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
    yield Result(state=State.OK, summary=f"{attr['num_hosts']} hosts in this group: {attr['members']}")
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Esto significa que el texto definido como «summary» siempre aparece en «Summary» —y también en «Details». Por lo tanto, solo debes usar esto para información importante. Si un grupo de hosts contiene muchos hosts, la lista de resumen puede volverse muy larga —más larga que los 60 caracteres recomendados. Si una información es de importancia secundaria, puedes usar «details» para especificar que su texto solo aparezca en los detalles:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
    yield Result(
        state = State.OK,
        summary = f"{attr['num_hosts']} hosts in this group",
        details = f"{attr['num_hosts']} hosts in this group: {attr['members']}",
    )
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

En el ejemplo anterior, la lista de hosts solo se muestra en la vista «Details». La vista «Summary» solo muestra el número de hosts del grupo:

'Summary' and 'Details' shown in the service details.
Contenido diferente para el resumen y los detalles en la supervisión

Además de summary y details, hay un tercer parámetro. Con notice se especifica que un texto para un servicio en OK solo se muestre en los detalles, pero también en el resumen para todos los demás estados. Esto hace que, desde el resumen, quede claro de inmediato por qué el servicio no está OK. El parámetro notice no es especialmente útil si los textos están vinculados permanentemente a los estados, como en nuestro ejemplo hasta ahora.

En resumen, esto significa:

  • El texto total del resumen no debe superar los 60 caracteres para los servicios que son OK.

  • Usa siempre «summary» o «notice» —al menos uno de los dos, pero no ambos.

  • Si es necesario, añade details si el texto de los detalles va a ser una alternativa.

4.4. Varios resultados parciales por servicio

Para evitar que el número de servicios en un host aumente en exceso, a menudo se combinan varios resultados parciales en un solo servicio. Por ejemplo, el servicio Memory en Linux no solo comprueba el uso de la RAM y el espacio de intercambio, sino también la memoria compartida, las tablas de páginas y todo tipo de cosas.

La API Check ofrece una interfaz muy práctica para esto. Una función de comprobación puede simplemente generar un resultado con yield tantas veces como sea necesario. El estado general del servicio se basa entonces en el peor resultado parcial en el orden OKWARNUNKNOWNCRIT.

En el ejemplo, utiliza esta opción para definir dos resultados adicionales para cada servicio de los grupos de hosts, además del resultado existente. Estos evalúan el porcentaje de hosts en el estado UP y de servicios en el estado OK. Utiliza las columnas adicionales de la tabla de grupos de hosts definida previamente en la salida del agente y la función de análisis.

Ahora expande la función de comprobación por etapas, de arriba abajo:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
def check_myhostgroups_advanced(item, section):
    attr = section.get(item)
    if not attr:
        yield Result(state=State.CRIT, summary="Group is empty or has been deleted")
        return

    members = attr["members"]
    num_hosts = int(attr["num_hosts"])
    num_hosts_up = int(attr["num_hosts_up"])
    num_services = int(attr["num_services"])
    num_services_ok = int(attr["num_services_ok"])
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

La rama «if» permanece sin cambios, es decir, los nuevos resultados parciales solo se aplican a los grupos de hosts que también existen. A continuación, defines cinco variables para las columnas de la tabla de grupos de hosts contenida en la sección. Por un lado, esto aumenta la legibilidad y, por otro, puedes convertir las cadenas leídas en números con «int()» para las cuatro columnas que aún se van a utilizar para el cálculo.

El único resultado existente permanece (casi) sin cambios:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
    yield Result(
        state = State.OK,
        summary = f"{num_hosts} hosts in this group",
        details = f"{num_hosts} hosts in this group: {members}",
    )
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Ahora solo el acceso en la «F-String» de Python a la expresión que devuelve el valor es más fácil que antes, ya que attr ya está en las definiciones de variables.

Ahora pasemos al núcleo real de la extensión, la definición de un resultado que implementa la siguiente afirmación: «El servicio del grupo de hosts es WARN cuando el 90 % de los hosts son UP, y CRIT cuando el 80 % de los hosts son UP.» La convención aquí es que la comprobación pasa a WARN o CRIT tan pronto como se alcanza el umbral, y no solo cuando se supera. La API de comprobación proporciona la función auxiliar check_levels para comparar un valor determinado con los valores umbral.

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
    hosts_up_perc = 100.0 * num_hosts_up / num_hosts
    yield from check_levels(
        hosts_up_perc,
        levels_lower = ("fixed", (90.0, 80.0)),
        label = "UP hosts",
        notice_only = True,
    )
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

En la primera línea, se calcula el porcentaje a partir del número total y del número de hosts en estado «UP» y se almacena en la variable «hosts_up_perc». La barra simple (/) ejecuta una división de punto flotante, lo que garantiza que el resultado sea un valor flotante. Esto es útil porque algunas de las funciones que se utilizan más adelante esperan un valor flotante como entrada.

En la segunda línea, el resultado de la función check_levels se devuelve como un objeto del tipo Result, que puedes encontrar en la documentación de la API. Esta función recibe como valores el porcentaje que acabamos de calcular (hosts_up_perc), los dos valores de umbral inferior (levels_lower), una etiqueta que precede a la salida (label) y, por último, notice_only=True.

El último parámetro utiliza el parámetro notice, ya presentado en la sección anterior para el objeto Result(). Con notice_only=True se especifica que el texto del servicio solo se muestra en el Summary si el estado no es OK. Sin embargo, los resultados parciales que dan lugar a un WARN o CRIT serán siempre visibles en el resumen, independientemente del valor de notice_only.

Por último, defines el tercer resultado de la misma manera que el segundo, que evalúa el porcentaje de servicios en estado «OK»:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
    services_ok_perc = 100.0 * num_services_ok / num_services
    yield from check_levels(
        services_ok_perc,
        levels_lower = ("fixed", (90.0, 80.0)),
        label = "OK services",
        notice_only = True,
    )
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Con esto se completa la función de comprobación.

El servicio de un grupo de hosts evalúa ahora tres resultados y muestra el peor estado de entre ellos en la supervisión, como en el siguiente ejemplo:

The summary shows the text for the critical state.
El resumen muestra el texto correspondiente al estado crítico

4.5. Métricas

No siempre, pero a menudo, las comprobaciones tratan con números, y estos números suelen ser valores medidos o calculados. En nuestro ejemplo, el número de hosts en el grupo de hosts (num_hosts) y el número de hosts en estado «UP» (num_hosts_up) son los valores medidos. El porcentaje de hosts en estado «UP» (hosts_up_perc) es un valor calculado a partir de estos valores. Si ese valor se puede mostrar a lo largo de un intervalo de tiempo, también se denomina métrica.

Con su sistema de gráficos integrado, Checkmk cuenta con un componente para almacenar, evaluar y mostrar dichos valores. Esto es completamente independiente del cálculo de los estados OK, WARN y CRIT.

En este ejemplo, definirás los dos valores calculados, hosts_up_perc y services_ok_perc, como métricas. Las métricas serán visibles inmediatamente en la interfaz gráfica de usuario de Checkmk sin que tengas que hacer nada. Se genera automáticamente un gráfico para cada métrica.

Las métricas se determinan mediante la función de comprobación y se devuelven como un resultado adicional. La forma más sencilla es añadir la información de las métricas a la función check_levels() en la llamada.

A modo de recordatorio, aquí tienes las líneas con la llamada a la función `check_levels()` de la sección anterior:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
    yield from check_levels(
        hosts_up_perc,
        levels_lower = ("fixed", (90.0, 80.0)),
        label = "UP hosts",
        notice_only = True,
    )
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Los dos nuevos argumentos para la métrica son metric_name y boundaries:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
    yield from check_levels(
        hosts_up_perc,
        levels_lower = ("fixed", (90.0, 80.0)),
        metric_name = "hosts_up_perc",
        label = "UP hosts",
        boundaries = (0.0, 100.0),
        notice_only = True,
    )
Copiar el contenido del archivo al portapapeles
¡Se ha copiado correctamente el contenido del archivo al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Para que todo sea sencillo y claro, utiliza como nombre de la métrica el nombre de la variable en la que se almacena el porcentaje como valor.

Puedes usar boundaries para proporcionar al sistema de gráficos información sobre el rango de valores posibles. Esto se refiere al valor más pequeño y al más grande posibles. En el caso de un porcentaje, los límites de 0.0 y 100.0 no son demasiado difíciles de determinar. Se permiten tanto números de coma flotante como enteros (que se convierten internamente en números de coma flotante), pero no cadenas de caracteres. Si solo se define un límite del rango de valores, simplemente introduce None para el otro, por ejemplo boundaries = (0.0, None).

Con esta extensión, la función check_levels ahora también devuelve un objeto del tipo Metric a través de yield, además de Result.

Ahora puedes definir la métrica services_ok_perc de la misma manera. Las últimas líneas de la función de comprobación quedarán así:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
    hosts_up_perc = 100.0 * num_hosts_up / num_hosts
    yield from check_levels(
        hosts_up_perc,
        levels_lower = ("fixed", (90.0, 80.0)),
        metric_name = "hosts_up_perc",
        label = "UP hosts",
        boundaries = (0.0, 100.0),
        notice_only = True,
    )
    services_ok_perc = 100.0 * num_services_ok / num_services
    yield from check_levels(
        services_ok_perc,
        levels_lower = ("fixed", (90.0, 80.0)),
        metric_name = "services_ok_perc",
        label = "OK services",
        boundaries = (0.0, 100.0),
        notice_only = True,
    )
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Con la función de comprobación ampliada, ambos gráficos son visibles en la monitorización. En la lista de servicios, el icono de Icon for displaying the graphs for a service. ahora muestra que hay gráficos para el servicio. Si pasas el ratón por encima del icono, los gráficos se mostrarán como vista previa.

The service list with 2 graphs as a preview.
Los nombres de las métricas se utilizan como títulos de los gráficos

En los detalles del servicio encontrarás una vista general de todos los gráficos, incluidas sus leyendas y mucho más.

Pero, ¿qué haces si el valor de la métrica deseada no se ha definido con la función «check_levels()»? Por supuesto, puedes definir una métrica independientemente de una llamada a la función. Para ello se utiliza el objeto «Metric()», que también puedes crear directamente a través de su constructor. La definición alternativa de una métrica para el valor «hosts_up_perc» tiene este aspecto:

    yield Metric(
        name = "hosts_up_perc",
        value = hosts_up_perc,
        levels = (80.0, 90.0),
        boundaries = (0.0, 100.0),
    )
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Los argumentos de Metric() son muy similares a los de la llamada a la función mostrada anteriormente: Son obligatorios los dos primeros argumentos para el nombre de la métrica y el valor. Además, hay dos argumentos opcionales: levels para los valores umbral WARN y CRIT y boundaries para el rango de valores.

Tip

La especificación de levels solo se utiliza aquí como información para mostrar el gráfico. En el gráfico, los valores umbral suelen representarse como líneas amarillas y rojas. La función check_levels, con sus valores umbral especificados, es la encargada de la comprobación real.

Ahora usa la opción de definir no solo los dos valores calculados, sino todos los valores medidos como métricas usando Metric() —en nuestro ejemplo, los cuatro valores medidos de la tabla del grupo de hosts. Limítate a las dos especificaciones obligatorias: el nombre de la métrica y el valor. Las cuatro nuevas líneas completan la ampliación de la función de comprobación para métricas:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
    hosts_up_perc = 100.0 * num_hosts_up / num_hosts
    yield from check_levels(
        hosts_up_perc,
        levels_lower = (90.0, 80.0),
        metric_name = "hosts_up_perc",
        label = "UP hosts",
        boundaries = (0.0, 100.0),
        notice_only = True,
    )
    services_ok_perc = 100.0 * num_services_ok / num_services
    yield from check_levels(
        services_ok_perc,
        levels_lower = (90.0, 80.0),
        metric_name = "services_ok_perc",
        label = "OK services",
        boundaries = (0.0, 100.0),
        notice_only = True,
    )

    yield Metric(name="num_hosts", value=num_hosts)
    yield Metric(name="num_hosts_up", value=num_hosts_up)
    yield Metric(name="num_services", value=num_services)
    yield Metric(name="num_services_ok", value=num_services_ok)
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Esto aumenta el número de gráficos por servicio, pero también te ofrece la opción de combinar varias métricas en un solo gráfico, por ejemplo. Mostramos estas y otras opciones en la sección Personalización de la visualización de métricas más abajo.

En el archivo de ejemplo de GitHub puedes volver a encontrar la función de comprobación completa.

5. Conjuntos de reglas para los parámetros de comprobación

En el complemento de comprobación ampliado «myhostgroups_advanced», habrás generado el estado «WARN» si solo el 90 % de los hosts están «UP», y «CRIT» para el 80 %. En este caso, los números «90» y «80» se definen explícitamente en la función de comprobación o, como dirían los programadores, están «hard-coded». En Checkmk, sin embargo, los usuarios están acostumbrados a poder configurar esos valores umbral y otros parámetros de comprobación mediante reglas. Por ejemplo, si un grupo de hosts solo tiene cuatro miembros, los dos valores umbral del 90 % y el 80 % no encajan muy bien, ya que el porcentaje bajará al 75 % en cuanto falle el primer host y el estado pasará directamente a «CRIT» —sin pasar por el estado intermedio «WARN».

Por lo tanto, ahora hay que modificar el complemento de comprobación para que se pueda configurar a través de la interfaz Setup. Para ello, necesitarás un conjunto de reglas.

Para crear un conjunto de reglas para un complemento de comprobación, sal del desarrollo del complemento y cambia de directorio, archivo y API. Desde Checkmk 2.3.0, la API de conjuntos de reglas te ayuda a crear dichos conjuntos de reglas para los complementos de comprobación. La documentación de la API para conjuntos de reglas se encuentra en tu sitio de Checkmk, en la misma página que la API de comprobación, en Rulesets > Version 1.

5.1. Definición de un nuevo conjunto de reglas

Para crear un nuevo conjunto de reglas, primero crea un nuevo subdirectorio en el directorio de la familia de complementos ~/local/lib/python3/cmk_addons/plugins/myhostgroups/. El nombre rulesets está predefinido para este subdirectorio:

OMD[mysite]:~$ mkdir -p ~/local/lib/python3/cmk_addons/plugins/myhostgroups/rulesets
OMD[mysite]:~$ cd ~/local/lib/python3/cmk_addons/plugins/myhostgroups/rulesets
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

En este directorio, debes crear un archivo para la definición del conjunto de reglas. El nombre del archivo debe basarse en el del complemento de comprobación y, como todos los archivos de complementos, debe tener la extensión py. Para nuestro ejemplo, el nombre de archivo ruleset_myhostgroups.py es adecuado.

Veamos paso a paso la estructura de este archivo. Primero hay algunos comandos de importación:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/rulesets/ruleset_myhostgroups.py
#!/usr/bin/env python3

from cmk.rulesets.v1 import Label, Title
from cmk.rulesets.v1.form_specs import BooleanChoice, DefaultValue, DictElement, Dictionary, Float, LevelDirection, SimpleLevels
from cmk.rulesets.v1.rule_specs import CheckParameters, HostAndItemCondition, Topic
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Primero, se importan las clases para los textos.

La segunda línea realiza una selección de las especificaciones de formulario, es decir, los elementos básicos de la interfaz gráfica de usuario que se utilizan en el conjunto de reglas, por ejemplo, la selección binaria (BooleanChoice), la selección múltiple (Dictionary, DictElement), la definición de valores umbral (SimpleLevel, LevelDirection, DefaultValue) y la introducción de números de coma flotante (Float). Aquí solo solicitas los elementos lógicos del formulario y dejas el diseño de la interfaz gráfica de usuario en manos de Checkmk.

La última línea importa las especificaciones de la regla, que determinan el ámbito de aplicación de la regla en Checkmk, es decir, en este caso la definición de los parámetros de comprobación, la asignación a hosts y elementos, y el almacenamiento bajo un tema. Como tu complemento de comprobación myhostgroups_advanced genera varios servicios, importa aquí HostAndItemCondition. Si tu comprobación no genera un servicio, es decir, no tiene un elemento, importa en su lugar HostCondition.

Ahora vienen las definiciones reales del formulario para introducir los parámetros de comprobación. El usuario debería poder definir por separado los dos valores umbral para WARN y CRIT, tanto para el número de hosts en el estado UP como para el número de servicios en el estado OK:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/rulesets/ruleset_myhostgroups.py
def _parameter_form():
    return Dictionary(
        elements = {
            "hosts_up_lower": DictElement(
                parameter_form = SimpleLevels(
                    title = Title("Lower percentage threshold for host in UP status"),
                    form_spec_template = Float(),
                    level_direction = LevelDirection.LOWER,
                    prefill_fixed_levels = DefaultValue(value=(90.0, 80.0)),
                ),
                required = True,
            ),
            "services_ok_lower": DictElement(
                parameter_form = SimpleLevels(
                    title = Title("Lower percentage threshold for services in OK status"),
                    form_spec_template = Float(),
                    level_direction = LevelDirection.LOWER,
                    prefill_fixed_levels = DefaultValue(value=(90.0, 80.0)),
                ),
                required = True,
            ),
        }
    )
Copiar el contenido del archivo al portapapeles
¡Se ha copiado correctamente el contenido del archivo al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Para ello, crea una función que genere el diccionario. Puedes elegir libremente el nombre de la función; solo es necesario a la hora de crear la regla que viene a continuación. El nombre debe empezar por un guión bajo para que la función no sea visible fuera del módulo.

El `return Dictionary()` es obligatorio. Dentro de él, usa `elements={}` para crear los elementos del diccionario, en el ejemplo `hosts_up_lower` y `services_ok_lower`. El formulario del parámetro `SimpleLevels` se usa para introducir valores de umbral fijos. En el formulario, primero defines el `title` y los números de punto flotante para los valores que se van a introducir (`form_spec_template`). Usa `LevelDirection.LOWER` para especificar que el estado cambiará si los valores caen por debajo de este nivel.

Por último, puedes usar prefill_fixed_levels para proporcionar a los usuarios del conjunto de reglas unos valores en lugar de campos de entrada vacíos. Ten en cuenta que estos valores que se muestran en la interfaz gráfica de usuario no son los valores predeterminados que se configuran más adelante en la creación del complemento de comprobación a través de check_default_parameters. Si quieres mostrar en la interfaz gráfica de usuario los mismos valores predeterminados que se aplican a la función de comprobación, debes mantener los valores consistentes en ambos lugares.

Por último, crea el nuevo conjunto de reglas utilizando los elementos importados y los definidos por ti mismo. Esto se hace creando una nueva instancia de la clase `CheckParameters`. El nombre de esta instancia debe comenzar por `rule_spec_`:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/rulesets/ruleset_myhostgroups.py
rule_spec_myhostgroups = CheckParameters(
    name = "myhostgroups_advanced",
    title = Title("Host group status"),
    topic = Topic.GENERAL,
    parameter_form = _parameter_form,
    condition = HostAndItemCondition(item_title=Title("Host group name")),
)
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Se aplican las siguientes explicaciones:

  • El nombre del conjunto de reglas (name) establece su conexión con los complementos de comprobación. Un complemento de comprobación que quiera usar este conjunto de reglas debe usar este nombre como nombre del complemento de comprobación (check_ruleset_name) cuando se cree. Para poder llevar un control de varios conjuntos de reglas nuevos, es recomendable usar un prefijo en el nombre.

  • title define el título del conjunto de reglas tal y como aparece en la interfaz gráfica de Checkmk.

  • El «topic» determina dónde debe aparecer el conjunto de reglas en el «Setup». Con el valor seleccionado en el ejemplo, encontrarás el conjunto de reglas en «Setup > Services > Service monitoring rules» dentro del cuadro «Various», donde suele estar bien ubicado.

  • Introduce el nombre de la función creada anteriormente como «parameter_form».

  • Si tu comprobación no utiliza un elemento, la condición es «HostCondition» y no «HostAndItemCondition», como en el ejemplo anterior. Con el título «"Host group name"» del elemento, defines la etiqueta en la interfaz gráfica de usuario con la que puedes restringir la regla a determinados grupos de hosts.

5.2. Probar un conjunto de reglas

Una vez que hayas creado el archivo para el conjunto de reglas, deberías comprobar si todo funciona hasta ahora —todavía sin conexión al complemento de comprobación. Al ejecutar cmk-validate-plugins se confirmará que el conjunto de reglas en sí es válido, pero se te advertirá de que aún no tiene ningún efecto.

Para que el conjunto de reglas sea visible, debes reiniciar los procesos de Python que proporcionan la interfaz gráfica de usuario. Esto se hace reiniciando el servidor web Apache:

OMD[mysite]:~$ omd restart apache
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Después de eso, el conjunto de reglas se puede encontrar en Setup en la página mencionada anteriormente. Sin embargo, solo podrás encontrar el valor predeterminado utilizando la función de búsqueda en Setup después de reiniciar Redis:

OMD[mysite]:~$ omd restart redis
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

El conjunto de reglas que acabas de definir tendrá este aspecto en la interfaz gráfica de usuario:

“The newly created rule set in the setup.”

En el cuadro «Conditions», encontrarás el campo de entrada «Host group name» definido a través de «HostAndItemCondition» para restringir la regla a grupos de hosts.

Crea una regla y prueba diferentes valores, tal y como se muestra en la captura de pantalla anterior. Si esto funciona sin errores, ya puedes utilizar los parámetros de comprobación en la función de comprobación.

5.3. Conectar el conjunto de reglas con el complemento de comprobación

El conjunto de reglas recién creado está ahora conectado al complemento de comprobación completado provisionalmente en el capítulo anterior. Para que la regla surta efecto, debes permitir que el complemento de comprobación acepte parámetros de comprobación e indicarle qué regla debe utilizarse. Para ello, añade dos nuevas líneas al archivo del complemento de comprobación al crear el complemento de comprobación myhostgroups_advanced:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
check_plugin_myhostgroups_advanced = CheckPlugin(
    name = "myhostgroups_advanced",
    sections = [ "myhostgroups" ],
    service_name = "Host group %s",
    discovery_function = discover_myhostgroups_advanced,
    check_function = check_myhostgroups_advanced,
    check_default_parameters = {},
    check_ruleset_name = "myhostgroups_advanced",
)
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Con la entrada «check_default_parameters», puedes definir los valores predeterminados que se aplicarán mientras no se haya creado ninguna regla. Al convertir el complemento de comprobación para los parámetros de comprobación, esta línea debe estar presente. En el caso más sencillo, pasa un diccionario vacío {}.

En segundo lugar, introduce check_ruleset_name, es decir, el nombre del conjunto de reglas. De esta forma, Checkmk sabe de qué conjunto de reglas deben determinarse los parámetros.

Ahora Checkmk intentará pasar parámetros a la función de comprobación. Para que esto funcione, debes ampliar la función de comprobación para que espere el argumento params, que se inserta entre item y section:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
def check_myhostgroups_advanced(item, params, section):
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Si estás creando una comprobación sin un elemento, se omite item y params aparece al principio.

Se recomienda encarecidamente que el contenido de la variable params se muestre con un print como primera prueba:

def check_myhostgroups_advanced(item, params, section):
    print(params)
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Cuando se ejecute el complemento de comprobación, las líneas impresas (una por cada servicio) con los valores definidos por una regla tendrán un aspecto similar a este:

OMD[mysite]:~$ cmk --detect-plugins=myhostgroups_advanced -v localhost
Parameters({'hosts_up_lower': ('fixed', (75.0, 60.0)), 'services_ok_lower': ('fixed', (75.0, 60.0))})
Parameters({'hosts_up_lower': ('fixed', (75.0, 60.0)), 'services_ok_lower': ('fixed', (75.0, 60.0))})
Parameters({'hosts_up_lower': ('fixed', (75.0, 60.0)), 'services_ok_lower': ('fixed', (75.0, 60.0))})
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!
Important

Cuando todo esté listo y funcione correctamente, elimina las llamadas a `print`, ya que pueden alterar la comunicación interna dentro de Checkmk. Como alternativa, puedes restringir la salida de información de depuración a una solicitud explícita.

Ahora personaliza aún más tu función de comprobación para que los parámetros pasados surtan efecto. Obtén los dos elementos del diccionario definidos en la regla con el nombre seleccionado allí a partir de los parámetros:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
def check_myhostgroups_advanced(item, params, section):
    hosts_up_lower = params["hosts_up_lower"]
    services_ok_lower = params["services_ok_lower"]
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Más abajo en la función de comprobación, los valores umbral previamente codificados de forma rígida "fixed", (90.0, 80.0) se sustituyen por las variables hosts_up_lower y services_ok_lower:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
    hosts_up_perc = 100.0 * num_hosts_up / num_hosts
    yield from check_levels(
        hosts_up_perc,
        levels_lower = (hosts_up_lower),
        metric_name = "hosts_up_perc",
        label = "UP hosts",
        boundaries = (0.0, 100.0),
        notice_only = True,
    )
    services_ok_perc = 100.0 * num_services_ok / num_services
    yield from check_levels(
        services_ok_perc,
        levels_lower = (services_ok_lower),
        metric_name = "services_ok_perc",
        label = "OK services",
        boundaries = (0.0, 100.0),
        notice_only = True,
    )
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Si se ha configurado una regla, ahora puedes supervisar los grupos de hosts del ejemplo con los valores de umbral establecidos a través de la interfaz gráfica de usuario. Sin embargo, si no se ha definido ninguna regla, esta función de comprobación fallará, ya que los parámetros predeterminados del complemento de comprobación no se habrán rellenado, y el complemento generará un error de «KeyError» al no haber ninguna regla.

No obstante, este problema se puede resolver si se definen los valores predeterminados al crear el complemento de comprobación:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
check_plugin_myhostgroups_advanced = CheckPlugin(
    name = "myhostgroups_advanced",
    sections = [ "myhostgroups" ],
    service_name = "Host group %s",
    discovery_function = discover_myhostgroups_advanced,
    check_function = check_myhostgroups_advanced,
    check_default_parameters = {"hosts_up_lower": ("fixed", (90, 80)), "services_ok_lower": ("fixed", (90, 80))},
    check_ruleset_name = "myhostgroups_advanced",
)
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Siempre debes pasar los valores predeterminados de esta manera (y no interceptar el caso de parámetros faltantes en el complemento de verificación), ya que estos valores predeterminados también se pueden mostrar en la interfaz de Setup. Por ejemplo, en el descubrimiento de servicios de un host, en la página Services of host, en el menú «Display», se encuentra el conmutador «Show check parameters».

Tip

En GitHub puedes encontrar tanto el archivo con el conjunto de reglas como el complemento de comprobación ampliado por dicho conjunto.

5.4. Prueba y activación del complemento de comprobación ampliado

Los cambios realizados en el capítulo anterior afectan tanto al núcleo de monitorización como a la interfaz gráfica de usuario, así como a sus procesos de apoyo. Por lo tanto, después de ejecutar «cmk-validate-plugins», primero debes regenerar la configuración y luego reiniciar el sitio:

OMD[mysite]:~$ cmk -U
OMD[mysite]:~$ omd restart
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!
Reinicio más rápido para expertos

Si conoces a fondo la estructura de procesos de Checkmk y sabes exactamente qué componentes se verán afectados por los cambios en tu complemento, puedes limitar el reinicio a servicios específicos. Para obtener una visión general, consulta el artículo Servicios del sitio.

6. Personalización de la visualización de métricas

En el ejemplo anterior, el complemento de comprobación myhostgroups_advanced generó métricas para todos los valores medidos y calculados. Te hemos mostrado dos formas de hacerlo. En primer lugar, las métricas de los valores calculados se crearon como parte de la función check_levels() con el argumento metric_name, por ejemplo, así:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
    yield from check_levels(
        services_ok_perc,
        levels_lower = ("fixed", (90.0, 80.0)),
        metric_name = "services_ok_perc",
        label = "OK services",
        boundaries = (0.0, 100.0),
        notice_only = True,
    )
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Entonces has generado las métricas medidas directamente con el objeto `Metric()` —para el número de servicios en el estado `OK`, por ejemplo, así:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py
    yield Metric(name="num_services_ok", value=num_services_ok)
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Las métricas se verán inmediatamente en la interfaz gráfica de usuario de Checkmk sin que tengas que hacer nada. Sin embargo, hay algunas restricciones:

  • Las métricas coincidentes no se combinan automáticamente en un gráfico, sino que cada una aparece por separado.

  • La métrica no tendrá un título adecuado, sino que se mostrará el nombre de la variable interna de la métrica.

  • No se utiliza ninguna unidad que permita una representación significativa (por ejemplo, GB en lugar de bytes individuales).

  • Se selecciona un color al azar.

  • El «Perf-O-Meter», es decir, la vista previa gráfica de la métrica en forma de barra, no aparece automáticamente en la lista de servicios (por ejemplo, en la vista que muestra todos los servicios de un host).

Para completar la visualización de tus métricas con estos detalles, necesitarás definiciones de métricas.

Al igual que con los conjuntos de reglas, a partir de Checkmk 2.3.0 también hay una API independiente para métricas, gráficos y Perf-O-Meters con la Graphing API. La documentación de la Graphing API se encuentra en tu sitio de Checkmk en la misma página que la Check API, en Graphing > Version 1.

6.1. Crear nuevas definiciones de métricas

Los procedimientos para crear conjuntos de reglas y definiciones de métricas son muy similares. Primero crea un nuevo subdirectorio con el nombre predeterminado «graphing» en el directorio de tu familia de complementos «~/local/lib/python3/cmk_addons/plugins/myhostgroups/».

OMD[mysite]:~$ mkdir -p ~/local/lib/python3/cmk_addons/plugins/myhostgroups/graphing
OMD[mysite]:~$ cd ~/local/lib/python3/cmk_addons/plugins/myhostgroups/graphing
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

A continuación, crea un archivo de gráficos en este directorio, por ejemplo, graphing_myhostgroups.py.

Primero hay de nuevo algunos comandos de importación:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/graphing/graphing_myhostgroups.py
#!/usr/bin/env python3

from cmk.graphing.v1 import Title
from cmk.graphing.v1.graphs import Graph, MinimalRange
from cmk.graphing.v1.metrics import Color, DecimalNotation, Metric, Unit
from cmk.graphing.v1.perfometers import Closed, FocusRange, Open, Perfometer
Copia el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Para nuestro ejemplo, ahora defines tu propia métrica para el porcentaje de servicios en estado «OK». Esto se hace creando una instancia de la clase `Metric`. El nombre de esta instancia debe empezar por `metric_`

~/local/lib/python3/cmk_addons/plugins/myhostgroups/graphing/graphing_myhostgroups.py
metric_myhostgroups_services_ok_perc = Metric(
    name = "services_ok_perc",
    title = Title("Percentage of services in OK state"),
    unit = Unit(DecimalNotation("%")),
    color = Color.ORANGE,
)
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Aquí tienes la explicación:

  • El nombre de la métrica (en este caso, «services_ok_perc») debe coincidir con lo que devuelve la función de comprobación.

  • title es el título del gráfico de la métrica y sustituye al nombre de la variable interna que se usaba antes.

  • Las unidades disponibles (unit) se pueden encontrar en la documentación de la API; todas terminan en Notation, por ejemplo, DecimalNotation, EngineeringScientificNotation o TimeNotation.

  • Los nombres de colores que se usan en Checkmk para la definición de color se pueden encontrar en GitHub.

Esta definición en el archivo de gráficos garantiza ahora que el título, la unidad y el color de la métrica se muestren correctamente.

Al igual que con la creación de un archivo de conjunto de reglas, primero hay que leer el archivo de gráficos para que el cambio se vea en la interfaz gráfica de usuario. Para ello, reinicia el servidor Apache del sitio:

OMD[mysite]:~$ omd restart apache
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

El gráfico de la métrica tendrá entonces un aspecto similar a este en la interfaz gráfica de Checkmk:

“The new metric definition in the service details.”

6.2. Gráficos con múltiples métricas

Si quieres combinar varias métricas en un solo gráfico (lo cual suele ser muy útil), necesitarás una definición de gráfico que puedas añadir al archivo de gráficos creado en la sección anterior.

En nuestro ejemplo, las dos métricas num_services y num_services_ok se mostrarán en un único gráfico. Las definiciones de métricas para esto se crean de la misma manera que en la sección anterior para services_ok_perc y tienen el siguiente aspecto:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/graphing/graphing_myhostgroups.py
metric_myhostgroups_services = Metric(
    name = "num_services",
    title = Title("Number of services in group"),
    unit = Unit(DecimalNotation("")),
    color = Color.PINK,
)

metric_myhostgroups_services_ok = Metric(
    name = "num_services_ok",
    title = Title("Number of services in OK state"),
    unit = Unit(DecimalNotation("")),
    color = Color.BLUE,
)
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Ahora añade un gráfico que represente estas dos métricas como líneas. Esto se hace mediante una instancia de la clase `Graph`, en la que el nombre de la instancia debe comenzar de nuevo con un prefijo predefinido (graph_):

~/local/lib/python3/cmk_addons/plugins/myhostgroups/graphing/graphing_myhostgroups.py
graph_myhostgroups_combined = Graph(
    name = "services_ok_comparison",
    title = Title("Services in OK state out of total"),
    simple_lines=[ "num_services", "num_services_ok" ],
    minimal_range=MinimalRange(0, 50),
)
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

El parámetro minimal_range describe el rango mínimo que cubre el eje vertical del gráfico, independientemente de los valores reales de la métrica. El eje vertical se ampliará si los valores superan el rango mínimo, pero nunca será más pequeño.

El resultado es el gráfico combinado en la interfaz gráfica de Checkmk:

“The graph shows both metrics in the service details.”

6.3. Métricas en el Perf-O-Meter

¿Te gustaría mostrar un Perf-O-Meter para una métrica en la fila de la lista de servicios? Podría tener este aspecto, por ejemplo:

“The Perf-O-Meter shows the percentage of services in ‘OK’ state.”
El Perf-O-Meter muestra el porcentaje de servicios en estado «OK»

Para crear un Perf-O-Meter de este tipo, necesitarás otra instancia, esta vez de la clase Perfometer, cuyo nombre comienza con el prefijo perfometer_:

~/local/lib/python3/cmk_addons/plugins/myhostgroups/graphing/graphing_myhostgroups.py
perfometer_myhostgroups_advanced = Perfometer(
    name = "myhostgroups_advanced",
    focus_range = FocusRange(Closed(0), Closed(100)),
    segments = [ "services_ok_perc" ],
)
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Los Perf-O-Meters son un poco más complicados que los gráficos, ya que no tienen leyenda. Por lo tanto, es difícil mostrar un rango de valores, especialmente cuando se muestran valores absolutos. Es más fácil mostrar un porcentaje. Este es también el caso del ejemplo anterior:

  • Los nombres de las métricas se introducen en segments; en este ejemplo, el porcentaje de servicios en estado OK.

  • Los límites inferior y superior se introducen en focus_range. Los límites de Closedestán pensados para métricas que solo pueden aceptar valores entre los límites especificados (en este caso, 0 y 100).

Además, en la documentación de la API de gráficos encontrarás opciones aún más sofisticadas para implementar métricas en Perf-O-Meters, por ejemplo, con las clases Bidirectional y Stacked, que permiten mostrar varios Perf-O-Meters en uno solo.

El archivo de gráficos de este capítulo se encuentra en GitHub. Entre otras cosas, este archivo contiene las definiciones de las métricas para los cuatro valores medidos y los dos valores calculados.

7. Formato de los números

Los números suelen aparecer en la vista de «Summary» y en la de «Details» de un servicio. Para que te resulte lo más fácil posible aplicar un formato limpio y correcto, y también para estandarizar la salida de todos los complementos de comprobación, existen funciones auxiliares para mostrar los distintos tipos de unidades. Todas ellas son subfunciones del módulo «render» y, por lo tanto, se invocan con «render.». Por ejemplo, «render.bytes(2000)» da como resultado el texto «1.95 KiB».

Lo que todas estas funciones tienen en común es que su valor se muestra en una unidad denominada canónica o natural. Esto significa que nunca tienes que pensar y que no hay dificultades ni errores al convertir. Por ejemplo, los tiempos siempre se dan en segundos, y los tamaños de discos duros, archivos, etc., siempre se dan en bytes y no en kilobytes, kibibytes, bloques u otras unidades que puedan crear confusión.

Usa estas funciones aunque no te guste mucho cómo se muestran. En cualquier caso, estará estandarizado para el usuario. Es posible que en futuras versiones de Checkmk se pueda cambiar la visualización o incluso que el usuario pueda configurarla, como ya ocurre con la visualización de la temperatura, por ejemplo. Tu plugin de comprobación también se beneficiará de esto.

Antes de poder usar la función «render» en tu plugin de comprobación, también debes importarla:

from cmk.agent_based.v2 import render
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Tras esta descripción detallada de todas las funciones de visualización (funciones de renderizado), encontrarás un resumen en forma de tabla fácil de leer.

7.1. Horas, intervalos de tiempo, frecuencias

Las especificaciones de tiempo absolutas (marcas de tiempo) se formatean con render.date() o render.datetime(). La información siempre se da en tiempo Unix, es decir, en segundos desde el 1 de enero de 1970, 00:00:00 UTC — el inicio de la época Unix. Este es también el formato que usa la función de Python time.time().

La ventaja de esta representación es que es muy fácil de calcular, por ejemplo, para determinar un intervalo de tiempo, cuando se conocen las horas de inicio y fin. La fórmula es simplemente duration = end - start. Estos cálculos funcionan independientemente de la zona horaria, los cambios de horario de verano o los años bisiestos.

render.date() solo muestra la fecha; render.datetime() añade la hora. El resultado se ajusta a la zona horaria actual en la que se encuentra el servidor de Checkmk que está ejecutando la comprobación. Ejemplos:

Llamada Resultado

render.date(0)

1970-01-01

render.datetime(0)

1970-01-01 01:00:00

render.date(1700000000)

2023-11-14

render.datetime(1700000000)

2023-11-14 23:13:20

No te sorprendas de que render.datetime(0) no muestre 00:00 como hora, sino 01:00. Esto se debe a que estamos escribiendo esta Guía del usuario en la zona horaria de Alemania, que está una hora por delante de la hora UTC estándar (al menos durante el horario estándar, ya que el 1 de enero no es horario de verano).

Para intervalos de tiempo (o duraciones) también existe la función render.timespan(). Se le pasa una duración en segundos y la muestra en un formato legible para las personas. Para intervalos de tiempo más largos, se omiten los segundos o los minutos. Si tienes un intervalo de tiempo en un objeto TimeDelta, usa la función total_seconds() para leer el número de segundos como un número de punto flotante.

Llama a Salida

render.timespan(1)

1 second

render.timespan(123)

2 minutes 3 seconds

render.timespan(12345)

3 hours 25 minutes

render.timespan(1234567)

14 days 6 hours

Una frecuencia es, en esencia, el recíproco del tiempo. La unidad canónica es el Hz, que equivale a 1 / s (el recíproco de un segundo). Un ejemplo de su uso es la frecuencia de reloj de una CPU:

Llamada Salida

render.frequency(111222333444)

111 GHz

7.2. Bytes

Cuando se trata de memoria de trabajo, archivos, discos duros, sistemas de archivos y similares, la unidad canónica es el byte. Dado que los ordenadores suelen organizar estas cosas en potencias de dos, por ejemplo en unidades de 512, 1024 o 65 536 bytes, se estableció desde el principio que un kilobyte no es 1000, y por lo tanto mil veces la unidad, sino 1024 (2 elevado a 10) bytes. Es cierto que esto es ilógico, pero resulta muy práctico porque suele dar lugar a números redondos. El legendario Commodore C64 tenía 64 kilobytes de memoria y no 65 536.

Por desgracia, en algún momento a los fabricantes de discos duros se les ocurrió la idea de especificar los tamaños de sus discos en unidades de 1000. Dado que la diferencia entre 1000 y 1024 es del 2,4 % para cada tamaño, y estos se multiplican, un disco de 1 GB (1024 por 1024 por 1024) de repente se convierte en 1,07 GB. Eso se vende mejor.

Esta molesta confusión sigue existiendo hoy en día y sigue dando lugar a errores. Para paliar esto, la Comisión Electrotécnica Internacional (IEC) ha definido nuevos prefijos basados en el sistema binario. Por lo tanto, hoy en día un kilobyte es oficialmente 1000 bytes y un kibibyte es 1024 bytes (2 elevado a 10). Además, se debería decir mebibyte, gibibyte y tebibyte. Las abreviaturas son entonces KiB, MiB, GiB y TiB.

Checkmk cumple con este estándar y te ayuda con una serie de funciones de visualización personalizadas para garantizar que siempre obtengas el resultado correcto. Por ejemplo, existe la función «render.disksize()», especialmente para discos duros y sistemas de archivos, que muestra los resultados en potencias de 1000.

Llama a Salida

render.disksize(1000)

1.00 kB

render.disksize(1024)

1.02 kB

render.disksize(2000000)

2.00 MB

Cuando se trata del tamaño de los archivos, suele ser habitual especificar el tamaño exacto en bytes sin redondear. Esto tiene la ventaja de que puedes ver muy rápidamente si un archivo ha cambiado aunque sea mínimamente o si dos archivos son (probablemente) iguales. Para ello se utiliza la función render.filesize():

Llamada Salida

render.filesize(1000)

1,000 B

render.filesize(1024)

1,024 B

render.filesize(2000000)

2,000,000 B

Si quieres obtener un valor que no sea el tamaño de un disco duro o de un archivo, simplemente usa la función genérica `render.bytes()`. Con esto obtendrás el resultado en las potencias «clásicas» de 1024 según la notación oficial:

Llamada Salida

render.bytes(1000)

1000 B

render.bytes(1024)

1.00 KiB

render.bytes(2000000)

1.91 MiB

7.3. Anchos de banda, velocidades de datos

Los profesionales de redes tienen sus propios términos y formas de expresarse. Y, como siempre, Checkmk se esfuerza por adoptar la forma convencional de comunicarse en cada ámbito. Por eso hay tres funciones de representación diferentes para las velocidades de datos. Lo que todas tienen en común es que las velocidades se expresan en bytes por segundo, ¡aunque la salida real sea en bits!

render.nicspeed() representa la velocidad máxima de una tarjeta de red o de un puerto de conmutador. Como no se trata de valores medidos, no es necesario redondear. Aunque ningún puerto puede enviar bits individuales, los datos se expresan en bits por razones históricas.

Importante: ¡No obstante, aquí también debes indicar bytes por segundo!

Llama a Salida

render.nicspeed(12500000)

100 MBit/s

render.nicspeed(100000000)

800 MBit/s

render.networkbandwidth() está pensada para una velocidad de transmisión realmente medida en la red. El valor de entrada es de nuevo bytes por segundo:

Llamada Salida

render.networkbandwidth(123)

984 Bit/s

render.networkbandwidth(123456)

988 kBit/s

render.networkbandwidth(123456789)

988 MBit/s

Cuando no hay una red de por medio y aún así se muestran velocidades de datos, se suelen usar bytes. El caso más común son las velocidades de E/S de los discos duros. Para esto se usa la función «render.iobandwidth()», que en Checkmk trabaja con potencias de 1000:

Llamada Salida

render.iobandwidth(123)

123 B/s

render.iobandwidth(123456)

123 kB/s

render.iobandwidth(123456789)

123 MB/s

7.4. Porcentajes

La función render.percent() representa un porcentaje, redondeado a dos decimales. Es una excepción respecto a las demás funciones, ya que no pasa el valor natural real —es decir, la relación— sino el porcentaje real. Por ejemplo, si algo está medio lleno, no tienes que pasar 0.5, sino 50.

Como a veces puede ser interesante saber si un valor es casi cero o exactamente cero, los valores se marcan añadiendo el carácter «<» a los valores que son mayores que cero pero menores que el 0,01 %.

Llamada Salida

render.percent(0.004)

<0.01%

render.percent(18.5)

18.50%

render.percent(123)

123.00%

7.5. Resumen

En conclusión, aquí tienes un resumen de todas las funciones de renderizado:

Función Entrada Descripción Ejemplo de salida

date()

Tiempo Unix

Fecha

2023-11-14

datetime()

Tiempo Unix

Fecha y hora

2023-11-14 23:13:20

timespan()

Segundos

Duración / antigüedad

3 hours 25 minutes

frequency()

Hz

Frecuencia (p. ej., velocidad del reloj)

111 GHz

disksize()

Bytes

Tamaño de un disco duro, base 1000

1.234 GB

filesize()

Bytes

Tamaño de un archivo, precisión total

1,334,560 B

bytes()

Bytes

Tamaño, base 1024

23.4 KiB

nicspeed()

Bytes por segundo

Velocidad de la tarjeta de red

100 MBit/s

networkbandwidth()

Bytes por segundo

Velocidad de transmisión

23.50 GBit/s

iobandwidth()

Bytes por segundo

Anchos de banda de E/S

124 MB/s

percent()

Porcentaje

Porcentaje, redondeado de forma significativa

99.997%

8. Resolución de problemas

El manejo correcto de los errores (por desgracia) ocupa gran parte de cualquier trabajo de programación. La buena noticia es que la API Check ya te quita mucho trabajo en el manejo de errores. Por eso, para algunos tipos de errores, es mejor que ni siquiera los manejes tú mismo.

Si Python se encuentra con una situación inesperada, reacciona con lo que se conoce como una excepción. Aquí tienes algunos ejemplos:

  • Conviertes una cadena en un número con `int()`, pero la cadena no contiene ningún número, por ejemplo, `int("foo")`.

  • Usas `bar[4]` para acceder al quinto elemento de `bar`, pero solo tiene cuatro elementos.

  • Estás llamando a una función que no existe.

Para decidir cómo abordar los errores, primero es importante saber el punto exacto del código donde se produce el error. Puedes usar la interfaz gráfica de usuario o la línea de comandos para esto, dependiendo de dónde estés trabajando actualmente.

8.1. Excepciones e informes de fallos en la interfaz gráfica

Si se produce una excepción durante la supervisión o el descubrimiento de servicios en Setup, Summary contiene referencias al informe de fallo que se acaba de crear. Tendrá un aspecto similar a este, por ejemplo:

A service whose check plug-in has crashed.

Al hacer clic en el icono de Icon for a crashed check plug-in., se muestra una página con detalles en la que puedes:

  • puedes ver el archivo en el que se produjo el fallo,

  • recibir toda la información sobre el fallo, como una lista de los errores que se produjeron en el programa (traceback), los valores actuales de las variables locales, la salida del agente y mucho más, y

  • puedes enviarnos el informe (a Checkmk GmbH) como comentario.

El traceback te ayuda, como desarrollador, a decidir si hay un error en el programa (por ejemplo, la llamada a una función inexistente) o si hay datos del agente que no se han podido procesar como se esperaba. En el primer caso, querrás corregir el error; en el segundo, a menudo tiene sentido no hacer nada.

Por supuesto, enviar el informe solo es útil para los complementos de comprobación que forman parte oficialmente de Checkmk. Si pones tus propios complementos a disposición de terceros, puedes pedir a tus usuarios que te envíen los datos.

8.2. Visualización de excepciones en la línea de comandos

Si ejecutas tu plugin de comprobación mediante la línea de comandos, no recibirás ninguna indicación del ID de ningún informe de fallo generado. Solo verás el mensaje de error resumido:

OMD[mysite]:~$ cmk --detect-plugins=myhostgroups_advanced localhost
Error in agent based plugin myhostgroups: invalid syntax (myhostgroups.py, line 11)
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Si añades la opción `--debug` como parámetro de llamada adicional, recibirás el seguimiento de errores del intérprete de Python:

OMD[mysite]:~$ cmk --debug --detect-plugins=myhostgroups_advanced localhost
Traceback (most recent call last):
  File "/omd/sites/mysite/lib/python3/cmk/discover_plugins/_python_plugins.py", line 195, in add_from_module
    module = importer(mod_name, raise_errors=True)
             ^^^^^^^^^^^^^
  File "/omd/sites/mysite/lib/python3/cmk/discover_plugins/_python_plugins.py", line 156, in _import_optionally
    return importlib.import_module(module_name)
           ^^^^^^^^^^^^
  File "/omd/sites/mysite/lib/python3.12/importlib/init.py", line 90, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 995, in exec_module
  File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
  File "/omd/sites/mysite/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py", line 110, in <module>
    agent_section_myhostgroups == AgentSection(
    ^^^^^^^^^^
NameError: name 'agent_section_myhostgroups' is not defined
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Si el error no vuelve a producirse la próxima vez que llames a --debug, por ejemplo, porque hay una nueva salida del agente disponible, también puedes ver los últimos informes de fallos en el sistema de archivos:

OMD[mysite]:~$ ls -lhtr ~/var/check_mk/crashes/check/ | tail -n 5
drwxrwxr-x 2 mysite mysite 4.0K Aug  6 17:56 7b59a49e-540c-11ef-9595-7574c603ce8d/
drwxrwxr-x 2 mysite mysite 4.0K Aug  6 17:56 7c8870c0-540c-11ef-9595-7574c603ce8d/
drwxrwxr-x 2 mysite mysite 4.0K Aug  6 17:56 7cf9626c-540c-11ef-9595-7574c603ce8d/
drwxrwxr-x 2 mysite mysite 4.0K Aug  6 17:56 7d192d68-540c-11ef-9595-7574c603ce8d/
drwxrwxr-x 2 mysite mysite 4.0K Aug  6 17:56 7e2d5ec2-540c-11ef-9595-7574c603ce8d/
Copiar comando(s) al portapapeles
¡Comandos copiados correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Hay dos archivos en cada una de estas carpetas:

  1. crash.info contiene un diccionario de Python con el traceback y mucha más información. A menudo basta con echar un vistazo al archivo con el Pager.

  2. agent_output contiene la salida completa del agente que estaba activa en el momento del fallo.

8.3. Salida de depuración personalizada

En los ejemplos mostrados anteriormente, utilizamos la función `print()` para mostrar el contenido de las variables o la estructura de los objetos para ti como desarrollador. Estas funciones para la salida de depuración deben eliminarse del complemento de comprobación final.

Como alternativa a la eliminación, también puedes hacer que tu salida de depuración solo se muestre cuando se llame al complemento de comprobación desde la consola en modo de depuración. Para ello, importa el objeto de depuración desde la caja de herramientas de Checkmk y, si es necesario, la ayuda de formato `pprint()`. Ahora puedes generar una salida de depuración en función del valor del objeto de depuración:

Tip

El objeto de depuración ha cambiado de ruta entre Checkmk 2.3.0 y 2.4.0. En lugar de la ubicación anterior cmk.utils, ahora se encuentra en cmk.ccc. El código portátil intenta primero importar desde la nueva ruta y, en caso de error, recurre a la antigua.

try:
    from cmk.ccc import debug
except ImportError:
    from cmk.utils import debug

from pprint import pprint

def check_mystuff(section):
    if debug.enabled():
        pprint(section)
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Ten en cuenta que cualquier salida de depuración restante debe usarse con moderación y limitarse a pistas que ayuden a los usuarios posteriores con la depuración. Los errores de usuario obvios y previsibles (por ejemplo, que el contenido de la sección del agente indique que el complemento del agente se ha configurado incorrectamente) deben responderse con el estado UNKNOWN e incluir notas explicativas en el resumen.

8.4. Salida del agente no válida

La pregunta es cómo debes reaccionar si la salida del agente no tiene el formato que esperas, ya sea del agente de Checkmk o recibida a través de SNMP. Supongamos que siempre esperas tres palabras por línea, ¿qué debes hacer si solo recibes dos?

Bueno, si se trata de un comportamiento permitido y conocido por el agente, entonces, por supuesto, debes interceptarlo y trabajar con una distinción de casos. Sin embargo, si en realidad no está permitido, lo mejor es actuar como si la línea siempre constara de tres palabras, por ejemplo, con la siguiente función de análisis:

def parse_foobar(string_table):
    for foo, bar, baz in string_table:
        # ...
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Si hay una línea que no consta exactamente de tres palabras, se genera una excepción y recibes el informe de error tan útil que acabamos de mencionar.

Si accedes a claves de un diccionario que se espera que falten ocasionalmente, por supuesto puede tener sentido reaccionar en consecuencia. Esto se puede hacer configurando el servicio como «CRIT» o «UNKNOWN» y colocando una nota en el resumen sobre la salida del agente que no se puede evaluar. En cualquier caso, es mejor usar la función «get()» del diccionario para esto que capturar la excepción «KeyError». Esto se debe a que «get()» devuelve un objeto de tipo «None» o un sustituto opcional que se pasa como segundo parámetro si la clave no está disponible:

def check_foobar(section):
    foo = section.get("bar")
    if not foo:
        yield Result(state=State.CRIT, summary="Missing key in section: bar")
        return
    # ...
Copiar el contenido del archivo al portapapeles
¡Contenido del archivo copiado correctamente al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

8.5. Elementos que faltan

¿Qué pasa si el agente muestra los datos correctos, pero falta el elemento que se debe comprobar? Como esto, por ejemplo:

def check_foobar(item, section):
    # Try to access the item as key in the section:
    foo = section.get(item)
    if foo:
        yield Result(state=State.OK, summary="Item found in monitoring data")
    # If foo is None, nothing is yielded here
Copiar el contenido del archivo al portapapeles
¡Se ha copiado correctamente el contenido del archivo al portapapeles!
¡Se ha denegado el acceso de escritura al portapapeles!

Si el elemento que buscas no está incluido, el bucle se ejecuta y Python simplemente sale al final de la función sin devolver un resultado a través de yield. ¡Y ese es exactamente el enfoque correcto! Porque Checkmk reconoce que falta el elemento que se debe supervisar y genera el estado correcto y un texto estándar adecuado con UNKNOWN.

8.6. Pruebas con archivos de spool

Si quieres simular salidas concretas del agente, los archivos del directorio spool son muy útiles. Puedes usarlos para probar casos límite que, de otro modo, serían difíciles de recrear. O puedes usar directamente la salida del agente que provocó un informe de fallo para probar cambios en un complemento de comprobación.

Primero desactiva tu complemento de agente habitual, por ejemplo, revocando su autorización de ejecución. A continuación, crea un archivo en el directorio /var/lib/check_mk_agent/spool/ que contenga la sección del agente (o las secciones del agente esperadas) que tu complemento de comprobación espera, incluyendo el encabezado de la sección, y que termine con un salto de línea. La próxima vez que se llame al agente, se transferirá el contenido del archivo de spool en lugar de la salida del complemento de agente.

8.7. Los complementos de comprobación antiguos se vuelven lentos para muchos servicios

Con algunos complementos de comprobación que utilizan elementos, es muy posible que en servidores más grandes se generen varios cientos de servicios. Si no se utiliza una función de análisis separada, esto significa que hay que recorrer toda la lista de cientos de líneas para cada uno de los cientos de elementos. Por lo tanto, el tiempo necesario para la búsqueda aumenta con el cuadrado del número de elementos de la lista, lo que supone decenas de miles de comparaciones para cientos de servicios. Si, por el contrario, la lista anidada se transfiere a un diccionario, el tiempo necesario para buscar un elemento aumenta solo de forma lineal con el tamaño del diccionario.

En la wiki de Python encontrarás un resumen de los costes de búsqueda en diferentes tipos de datos, incluyendo una explicación y la notación O. Usar la función parse reduce la complejidad de la búsqueda de O(n) a O(1).

Dado que las versiones anteriores de este artículo no utilizaban la función parse, deberías identificar esos complementos de comprobación y reescribirlos para que utilicen la función parse.

9. Migración

La API Check V1, introducida en la versión 2.0.0 de Checkmk, fue compatible hasta la versión 2.3.0, pero ya no lo es en la versión actual 2.4.0. Para seguir utilizando tus plugins de comprobación, debes migrarlos a las nuevas API mientras sigas en 2.3.0.

La siguiente información te ayudará con la migración de los complementos de comprobación de la API de comprobación V1 a la V2:

  • La nueva estructura de directorios y la convención de nomenclatura para almacenar los archivos de todas las API de complementos se pueden encontrar en la documentación de la API en la página principal Checkmk’s Plug-in APIs.

  • El resumen de los cambios en la API de comprobación V2 también se puede encontrar en la documentación de la API en Checkmk’s Plug-in APIs > Agent based ('Check API') > Version 2 > New in this version. Allí también encontrarás el enlace a una confirmación de GitHub que migra el complemento de comprobación existente apt a la API de comprobación V2.

  • En GitHub encontrarás scripts en el directorio treasures de Checkmk que te ayudarán a migrar a las nuevas API.

Important

Proporcionamos los archivos del directorio treasures porque pueden ser útiles para nuestra comunidad. Sin embargo, no forman parte del producto Checkmk en sí. Los scripts de treasures quedan excluidos del soporte técnico. Usa estos scripts bajo tu propia responsabilidad.

10. Archivos y directorios

Ruta del archivo Descripción

~/local/lib/python3/cmk_addons/plugins/

Directorio base para guardar los archivos de los complementos.

~/local/lib/python3/cmk_addons/plugins/<plug-in_family>/agent_based/

Ubicación de almacenamiento para los complementos de comprobación escritos según la API de comprobación V2.

~/local/lib/python3/cmk_addons/plugins/<plug-in_family>/rulesets/

Ubicación de almacenamiento para los archivos de conjuntos de reglas creados según la API de conjuntos de reglas.

~/local/lib/python3/cmk_addons/plugins/<plug-in_family>/graphing/

Ubicación de almacenamiento para los archivos de gráficos creados según la API de gráficos.

/usr/lib/check_mk_agent/plugins/

Este directorio se encuentra en un host Linux supervisado. El agente de Checkmk para Linux espera encontrar aquí las extensiones del agente (plug-ins del agente).


Last modified: Wed, 01 Apr 2026 14:11:35 GMT via commit e942b8dca
En esta página