Los módulos cargables ofrecen una opción orientada al rendimiento para ampliar la funcionalidad de Zabbix.
Puede ampliar la funcionalidad de Zabbix de muchas maneras, por ejemplo, con parámetros de usuario, comprobaciones externas, y métricas de agente Zabbix system.run[]
métricas de agente. Estas funcionan muy bien, pero tienen un gran inconveniente, concretamente fork(). Zabbix tiene que bifurcar un nuevo proceso cada vez que maneja una métrica de usuario, lo cual no es bueno para el rendimiento. Normalmente no es un gran problema, sin embargo, podría ser un problema serio al monitorizar sistemas embebidos, tener un gran número de parámetros monitorizados o scripts pesados con lógica compleja o un largo tiempo de inicio.
El soporte de módulos cargables ofrece formas de ampliar el agente, servidor y proxy de Zabbix sin sacrificar el rendimiento.
Un módulo cargable es básicamente una biblioteca compartida utilizada por el demonio de Zabbix y cargada al inicio. La biblioteca debe contener ciertas funciones, de modo que un proceso de Zabbix pueda detectar que el archivo es realmente un módulo que puede cargar y con el que puede trabajar.
Los módulos cargables tienen una serie de beneficios. Un gran rendimiento y la capacidad de implementar cualquier lógica son muy importantes, pero quizás la ventaja más importante es la capacidad de desarrollar, usar y compartir módulos de Zabbix. Esto contribuye a un mantenimiento sin problemas y ayuda a ofrecer nueva funcionalidad de manera más sencilla e independiente del núcleo de Zabbix.
La licencia y distribución de módulos en forma binaria está regulada por la licencia AGPL-3.0 (los módulos se enlazan con Zabbix en tiempo de ejecución y utilizan cabeceras de Zabbix; todo el código de Zabbix está licenciado bajo AGPL-3.0 desde Zabbix 7.0). Zabbix no garantiza la compatibilidad binaria.
La estabilidad de la API de módulos está garantizada durante un ciclo de lanzamiento LTS (Soporte a Largo Plazo) de Zabbix. No se garantiza la estabilidad de la API de Zabbix (técnicamente es posible llamar a funciones internas de Zabbix desde un módulo, pero no hay garantía de que dichos módulos funcionen).
Para que una biblioteca compartida sea tratada como un módulo de Zabbix, debe implementar y exportar varias funciones. Actualmente hay seis funciones en la API de módulos de Zabbix, de las cuales solo una es obligatoria y las otras cinco son opcionales.
La única función obligatoria es zbx_module_api_version():
Esta función debe devolver la versión de la API implementada por este módulo y, para que el módulo se cargue, esta versión debe coincidir con la versión de la API de módulo soportada por Zabbix. La versión de la API de módulo soportada por Zabbix es ZBX_MODULE_API_VERSION. Por lo tanto, esta función debe devolver esta constante. La antigua constante ZBX_MODULE_API_VERSION_ONE utilizada para este propósito ahora está definida como igual a ZBX_MODULE_API_VERSION para preservar la compatibilidad con el código fuente, pero no se recomienda su uso.
Las funciones opcionales son zbx_module_init(), zbx_module_item_list(), zbx_module_item_timeout(), zbx_module_history_write_cbs() y zbx_module_uninit():
Esta función debe realizar la inicialización necesaria para el módulo (si es necesario). Si tiene éxito, debe devolver ZBX_MODULE_OK. De lo contrario, debe devolver ZBX_MODULE_FAIL. En este último caso Zabbix no iniciará.
Esta función debe devolver una lista de métricas soportadas por el módulo. Cada métrica se define en una estructura ZBX_METRIC, consulte la sección siguiente para más detalles. La lista termina con una estructura ZBX_METRIC con el campo "key" en NULL.
Si el módulo exporta zbx_module_item_list() entonces esta función es utilizada por Zabbix para especificar la configuración de timeout en el archivo de configuración de Zabbix que las comprobaciones de métricas implementadas por el módulo deben respetar. Aquí, el parámetro "timeout" está en segundos.
Esta función debe devolver funciones de callback que el servidor Zabbix usará para exportar el historial de diferentes tipos de datos. Las funciones de callback se proporcionan como campos de la estructura ZBX_HISTORY_WRITE_CBS, los campos pueden ser NULL si el módulo no está interesado en el historial de cierto tipo.
Esta función debe realizar la desinicialización necesaria (si la hay) como liberar recursos asignados, cerrar descriptores de archivos, etc.
Todas las funciones se llaman una vez al iniciar Zabbix cuando el módulo es cargado, con la excepción de zbx_module_uninit(), que se llama una vez al apagar Zabbix cuando el módulo es descargado.
Cada métrica se define en una estructura ZBX_METRIC:
Aquí, key es la clave de la métrica (por ejemplo, "dummy.random"), flags es CF_HAVEPARAMS o 0 (dependiendo de si la métrica acepta parámetros o no), function es una función en C que implementa la métrica (por ejemplo, "zbx_module_dummy_random"), y test_param es la lista de parámetros que se utilizará cuando el agente Zabbix se inicie con la opción "-p" (por ejemplo, "1,1000", puede ser NULL). Una definición de ejemplo puede verse así:
static ZBX_METRIC keys[] =
{
{ "dummy.random", CF_HAVEPARAMS, zbx_module_dummy_random, "1,1000" },
{ NULL }
}
Cada función que implementa una métrica debe aceptar dos parámetros puntero, el primero de tipo AGENT_REQUEST y el segundo de tipo AGENT_RESULT:
int zbx_module_dummy_random(AGENT_REQUEST *request, AGENT_RESULT *result)
{
...
SET_UI64_RESULT(result, from + rand() % (to - from + 1));
return SYSINFO_RET_OK;
}
Estas funciones deben devolver SYSINFO_RET_OK, si el valor de la métrica se obtuvo correctamente. De lo contrario, deben devolver SYSINFO_RET_FAIL. Consulte el módulo de ejemplo "dummy" a continuación para obtener detalles sobre cómo obtener información de AGENT_REQUEST y cómo establecer información en AGENT_RESULT.
La exportación de histórico a través de módulo ya no es compatible con el proxy de Zabbix.
El módulo puede especificar funciones para exportar datos de histórico por tipo: Numérico (flotante), Numérico (sin signo), Carácter, Texto y Log:
typedef struct
{
void (*history_float_cb)(const ZBX_HISTORY_FLOAT *history, int history_num);
void (*history_integer_cb)(const ZBX_HISTORY_INTEGER *history, int history_num);
void (*history_string_cb)(const ZBX_HISTORY_STRING *history, int history_num);
void (*history_text_cb)(const ZBX_HISTORY_TEXT *history, int history_num);
void (*history_log_cb)(const ZBX_HISTORY_LOG *history, int history_num);
}
ZBX_HISTORY_WRITE_CBS;
Cada una de ellas debe tomar el array "history" de "history_num" elementos como argumentos. Dependiendo del tipo de datos de histórico a exportar, "history" es un array de las siguientes estructuras, respectivamente:
typedef struct
{
zbx_uint64_t itemid;
int clock;
int ns;
double value;
}
ZBX_HISTORY_FLOAT;
typedef struct
{
zbx_uint64_t itemid;
int clock;
int ns;
zbx_uint64_t value;
}
ZBX_HISTORY_INTEGER;
typedef struct
{
zbx_uint64_t itemid;
int clock;
int ns;
const char *value;
}
ZBX_HISTORY_STRING;
typedef struct
{
zbx_uint64_t itemid;
int clock;
int ns;
const char *value;
}
ZBX_HISTORY_TEXT;
typedef struct
{
zbx_uint64_t itemid;
int clock;
int ns;
const char *value;
const char *source;
int timestamp;
int logeventid;
int severity;
}
ZBX_HISTORY_LOG;
Los callbacks serán utilizados por los procesos history syncer del servidor Zabbix al final del procedimiento de sincronización de histórico después de que los datos se escriban en la base de datos de Zabbix y se guarden en la caché de valores.
En caso de error interno en el módulo de exportación de histórico, se recomienda que el módulo esté escrito de tal manera que no bloquee toda la monitorización hasta que se recupere, sino que descarte los datos y permita que el servidor Zabbix continúe funcionando.
Actualmente, los módulos están pensados para ser compilados dentro del árbol de fuentes de Zabbix, porque la API del módulo depende de algunas estructuras de datos que se definen en los encabezados de Zabbix.
El encabezado más importante para los módulos cargables es include/module.h, que define estas estructuras de datos. Otros encabezados de sistema necesarios que ayudan a que include/module.h funcione correctamente son stdlib.h y stdint.h.
Teniendo en cuenta esta información, todo está listo para que el módulo se compile. El módulo debe incluir stdlib.h, stdint.h y module.h, y el script de compilación debe asegurarse de que estos archivos estén en la ruta de inclusión. Consulte el ejemplo de módulo "dummy" a continuación para más detalles.
Otro encabezado útil es include/zbxcommon.h, que define la función zabbix_log(), que puede utilizarse para fines de registro y depuración.
El agente, servidor y proxy de Zabbix admiten dos parámetros para gestionar módulos:
Por ejemplo, para extender el agente de Zabbix podríamos añadir los siguientes parámetros:
LoadModulePath=/usr/local/lib/zabbix/agent/
LoadModule=mariadb.so
LoadModule=apache.so
LoadModule=kernel.so
LoadModule=/usr/local/lib/zabbix/dummy.so
Al iniciar el agente, cargará los módulos mariadb.so, apache.so y kernel.so desde el directorio /usr/local/lib/zabbix/agent, mientras que dummy.so se cargará desde /usr/local/lib/zabbix. El agente no podrá iniciarse si falta un módulo, en caso de permisos incorrectos o si una biblioteca compartida no es un módulo de Zabbix.
Los módulos cargables son compatibles con el agente, el servidor y el proxy de Zabbix. Por lo tanto, el tipo de métrica en el frontend de Zabbix depende de dónde se cargue el módulo. Si el módulo se carga en el agente, entonces el tipo de métrica debe ser "Agente Zabbix" o "Agente Zabbix (activo)". Si el módulo se carga en el servidor o el proxy, entonces el tipo de métrica debe ser "Comprobación simple".
La exportación de histórico a través de módulos de Zabbix no necesita ninguna configuración en el frontend. Si el módulo se carga correctamente por el servidor y proporciona la función zbx_module_history_write_cbs() que devuelve al menos una función de callback distinta de NULL, entonces la exportación de histórico se habilitará automáticamente.
Zabbix incluye un módulo de ejemplo escrito en lenguaje C. El módulo se encuentra en src/modules/dummy:
alex@alex:~trunk/src/modules/dummy$ ls -l
-rw-rw-r-- 1 alex alex 9019 Apr 24 17:54 dummy.c
-rw-rw-r-- 1 alex alex 67 Apr 24 17:54 Makefile
-rw-rw-r-- 1 alex alex 245 Apr 24 17:54 README
El módulo está bien documentado y puede utilizarse como plantilla para sus propios módulos.
Después de ejecutar ./configure en la raíz del árbol de fuentes de Zabbix como se describió anteriormente, simplemente ejecute make para compilar dummy.so.
/*
** Zabbix
** Copyright (C) 2001-2020 Zabbix SIA
**
** Este programa es software libre; puede redistribuirlo y/o modificarlo
** bajo los términos de la Licencia Pública General de GNU publicada por
** la Free Software Foundation; ya sea la versión 2 de la Licencia, o
** (a su elección) cualquier versión posterior.
**
** Este programa se distribuye con la esperanza de que sea útil,
** pero SIN NINGUNA GARANTÍA; incluso sin la garantía implícita de
** COMERCIABILIDAD o IDONEIDAD PARA UN PROPÓSITO PARTICULAR. Vea la
** Licencia Pública General de GNU para más detalles.
**
** Debería haber recibido una copia de la Licencia Pública General de GNU
** junto con este programa; si no, escriba a la Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdint.h>
#include "module.h"
/* la variable mantiene la configuración de timeout para el procesamiento de métricas */
static int item_timeout = 0;
/* el módulo DEBE definir funciones internas como estáticas y usar un patrón de nombres diferente a los símbolos internos de Zabbix (zbx_*) y a las funciones API de módulos cargables (zbx_module_*) para evitar conflictos */
static int dummy_ping(AGENT_REQUEST *request, AGENT_RESULT *result);
static int dummy_echo(AGENT_REQUEST *request, AGENT_RESULT *result);
static int dummy_random(AGENT_REQUEST *request, AGENT_RESULT *result);
static ZBX_METRIC keys[] =
/* CLAVE BANDERA FUNCIÓN PARÁMETROS DE PRUEBA */
{
{"dummy.ping", 0, dummy_ping, NULL},
{"dummy.echo", CF_HAVEPARAMS, dummy_echo, "a message"},
{"dummy.random", CF_HAVEPARAMS, dummy_random, "1,1000"},
{NULL}
};
/******************************************************************************
* *
* Función: zbx_module_api_version *
* *
* Propósito: devuelve el número de versión de la interfaz del módulo *
* *
* Valor de retorno: ZBX_MODULE_API_VERSION - versión de module.h con la que *
* el módulo está compilado, para cargar el módulo con éxito *
* Zabbix DEBE estar compilado con la misma versión de este *
* archivo de cabecera *
* *
******************************************************************************/
int zbx_module_api_version(void)
{
return ZBX_MODULE_API_VERSION;
}
/******************************************************************************
* *
* Función: zbx_module_item_timeout *
* *
* Propósito: establecer el valor de timeout para el procesamiento de métricas*
* *
* Parámetros: timeout - timeout en segundos, 0 - no se establece timeout *
* *
******************************************************************************/
void zbx_module_item_timeout(int timeout)
{
item_timeout = timeout;
}
/******************************************************************************
* *
* Función: zbx_module_item_list *
* *
* Propósito: devuelve la lista de claves de métricas soportadas por el módulo*
* *
* Valor de retorno: lista de claves de métricas *
* *
******************************************************************************/
ZBX_METRIC *zbx_module_item_list(void)
{
return keys;
}
static int dummy_ping(AGENT_REQUEST *request, AGENT_RESULT *result)
{
SET_UI64_RESULT(result, 1);
return SYSINFO_RET_OK;
}
static int dummy_echo(AGENT_REQUEST *request, AGENT_RESULT *result)
{
char *param;
if (1 != request->nparam)
{
/* establecer mensaje de error opcional */
SET_MSG_RESULT(result, strdup("Número de parámetros inválido."));
return SYSINFO_RET_FAIL;
}
param = get_rparam(request, 0);
SET_STR_RESULT(result, strdup(param));
return SYSINFO_RET_OK;
}
/******************************************************************************
* *
* Función: dummy_random *
* *
* Propósito: punto de entrada principal para el procesamiento de una métrica *
* *
* Parámetros: request - estructura que contiene la clave de la métrica y *
* parámetros *
* request->key - clave de la métrica sin parámetros *
* request->nparam - número de parámetros *
* request->params[N-1] - punteros a los parámetros de la clave *
* request->types[N-1] - tipos de parámetros de la clave: *
* REQUEST_PARAMETER_TYPE_UNDEFINED (parámetro vacío) *
* REQUEST_PARAMETER_TYPE_ARRAY (array) *
* REQUEST_PARAMETER_TYPE_STRING (cadena entrecomillada o no)*
* *
* result - estructura que contendrá el resultado *
* *
* Valor de retorno: SYSINFO_RET_FAIL - la función falló, la métrica será *
* marcada como no soportada por zabbix *
* SYSINFO_RET_OK - éxito *
* *
* Comentario: get_rparam(request, N-1) puede usarse para obtener un puntero *
* al N-ésimo parámetro comenzando desde 0 (primer parámetro). *
* Asegúrese de que existe comprobando el valor de request->nparam. *
* De la misma manera, get_rparam_type(request, N-1) puede usarse *
* para obtener el tipo de parámetro. *
* *
******************************************************************************/
static int dummy_random(AGENT_REQUEST *request, AGENT_RESULT *result)
{
char *param1, *param2;
int from, to;
if (2 != request->nparam)
{
/* establecer mensaje de error opcional */
SET_MSG_RESULT(result, strdup("Número de parámetros inválido."));
return SYSINFO_RET_FAIL;
}
param1 = get_rparam(request, 0);
param2 = get_rparam(request, 1);
/* no hay validación estricta de parámetros y tipos por simplicidad */
from = atoi(param1);
to = atoi(param2);
if (from > to)
{
SET_MSG_RESULT(result, strdup("Rango especificado inválido."));
return SYSINFO_RET_FAIL;
}
SET_UI64_RESULT(result, from + rand() % (to - from + 1));
return SYSINFO_RET_OK;
}
/******************************************************************************
* *
* Función: zbx_module_init *
* *
* Propósito: la función se llama al iniciar el agente *
* Debe usarse para llamar a cualquier rutina de inicialización *
* *
* Valor de retorno: ZBX_MODULE_OK - éxito *
* ZBX_MODULE_FAIL - la inicialización del módulo falló *
* *
* Comentario: el módulo no se cargará en caso de ZBX_MODULE_FAIL *
* *
******************************************************************************/
int zbx_module_init(void)
{
/* inicialización para dummy.random */
srand(time(NULL));
return ZBX_MODULE_OK;
}
/******************************************************************************
* *
* Función: zbx_module_uninit *
* *
* Propósito: la función se llama al apagar el agente *
* Debe usarse para limpiar recursos usados si los hay *
* *
* Valor de retorno: ZBX_MODULE_OK - éxito *
* ZBX_MODULE_FAIL - la función falló *
* *
******************************************************************************/
int zbx_module_uninit(void)
{
return ZBX_MODULE_OK;
}
/******************************************************************************
* *
* Funciones: dummy_history_float_cb *
* dummy_history_integer_cb *
* dummy_history_string_cb *
* dummy_history_text_cb *
* dummy_history_log_cb *
* *
* Propósito: funciones de callback para almacenar datos históricos de tipos *
* float, integer, string, text y log respectivamente en almacenamiento externo *
* *
* Parámetros: history - array de datos históricos *
* history_num - número de elementos en el array history *
* *
******************************************************************************/
static void dummy_history_float_cb(const ZBX_HISTORY_FLOAT *history, int history_num)
{
int i;
for (i = 0; i < history_num; i++)
{
/* hacer algo con history[i].itemid, history[i].clock, history[i].ns, history[i].value, ... */
}
}
static void dummy_history_integer_cb(const ZBX_HISTORY_INTEGER *history, int history_num)
{
int i;
for (i = 0; i < history_num; i++)
{
/* hacer algo con history[i].itemid, history[i].clock, history[i].ns, history[i].value, ... */
}
}
static void dummy_history_string_cb(const ZBX_HISTORY_STRING *history, int history_num)
{
int i;
for (i = 0; i < history_num; i++)
{
/* hacer algo con history[i].itemid, history[i].clock, history[i].ns, history[i].value, ... */
}
}
static void dummy_history_text_cb(const ZBX_HISTORY_TEXT *history, int history_num)
{
int i;
for (i = 0; i < history_num; i++)
{
/* hacer algo con history[i].itemid, history[i].clock, history[i].ns, history[i].value, ... */
}
}
static void dummy_history_log_cb(const ZBX_HISTORY_LOG *history, int history_num)
{
int i;
for (i = 0; i < history_num; i++)
{
/* hacer algo con history[i].itemid, history[i].clock, history[i].ns, history[i].value, ... */
}
}
/******************************************************************************
* *
* Función: zbx_module_history_write_cbs *
* *
* Propósito: devuelve un conjunto de funciones del módulo que Zabbix llamará *
* para exportar diferentes tipos de datos históricos *
* *
* Valor de retorno: estructura con punteros a funciones de callback (puede *
* ser NULL si el módulo no está interesado en datos de ciertos *
* tipos) *
* *
******************************************************************************/
ZBX_HISTORY_WRITE_CBS zbx_module_history_write_cbs(void)
{
static ZBX_HISTORY_WRITE_CBS dummy_callbacks =
{
dummy_history_float_cb,
dummy_history_integer_cb,
dummy_history_string_cb,
dummy_history_text_cb,
dummy_history_log_cb,
};
return dummy_callbacks;
}
El módulo exporta tres nuevas métricas:
dummy.ping
- siempre devuelve '1'dummy.echo[param1]
- devuelve el primer parámetro tal cual, por ejemplo, dummy.echo[ABC]
devolverá ABCdummy.random[param1, param2]
- devuelve un número aleatorio dentro del rango param1-param2, por ejemplo, dummy.random[1,1000000]
El soporte de módulos cargables está implementado solo para la plataforma Unix. Esto significa que no funciona para los agentes de Windows.
En algunos casos, un módulo puede necesitar leer parámetros de configuración relacionados con el módulo desde zabbix_agentd.conf. Actualmente, esto no está soportado. Si necesita que su módulo utilice algunos parámetros de configuración, probablemente debería implementar el análisis de un archivo de configuración específico del módulo.