1 Módulos cargables
Descripción general
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 elementos del agent de Zabbix system.run. Estos 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 que no es bueno para el rendimiento. Normalmente no es un gran problema, sin embargo, podría ser un problema grave 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 agent, el server y el 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 ventajas. El 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, utilizar y compartir módulos de Zabbix. Contribuye a un mantenimiento sin problemas y ayuda a ofrecer nuevas funcionalidades más fácilmente e independientemente de la base de código principal de Zabbix.
La licencia de los módulos y su distribución en forma binaria se rige 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 del módulo está garantizada durante un ciclo de lanzamiento de Zabbix LTS (Long Term Support). 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).
API de módulos
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 sólo una es obligatoria y las otras cinco son opcionales.
Interfaz obligatoria
La única función obligatoria es zbx_module_api_version():
int zbx_module_api_version(void);
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 del módulo compatible con Zabbix.
La versión de la API del módulo compatible con Zabbix es ZBX_MODULE_API_VERSION.
Por lo tanto, esta función debe devolver esta constante.
La constante antigua ZBX_MODULE_API_VERSION_ONE, utilizada con 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.
Interfaz opcional
Las funciones opcionales son zbx_module_init(), zbx_module_item_list(), zbx_module_item_timeout(), zbx_module_history_write_cbs() y zbx_module_uninit():
int zbx_module_init(void);
Esta función debe realizar la inicialización necesaria para el módulo, si la hubiera.
Si tiene éxito, debe devolver ZBX_MODULE_OK.
En caso contrario, debe devolver ZBX_MODULE_FAIL.
En este último caso, Zabbix no se iniciará.
ZBX_METRIC *zbx_module_item_list(void);
Esta función debe devolver una lista de items compatibles con el módulo.
Cada item se define en una estructura ZBX_METRIC; consulte la sección siguiente para obtener más detalles.
La lista termina con una estructura ZBX_METRIC cuyo campo "key" es NULL.
void zbx_module_item_timeout(int timeout);
Si el módulo exporta zbx_module_item_list(), entonces Zabbix utiliza esta función para especificar los ajustes de tiempo de espera en el archivo de configuración de Zabbix que deben respetar las comprobaciones de items implementadas por el módulo.
Aquí, el parámetro "timeout" está en segundos.
ZBX_HISTORY_WRITE_CBS zbx_module_history_write_cbs(void);
Esta función debe devolver las funciones de callback que Zabbix server utilizará para exportar el historial de distintos tipos de datos.
Las funciones de callback se proporcionan como campos de la estructura ZBX_HISTORY_WRITE_CBS; los campos pueden ser NULL si al módulo no le interesa el historial de un tipo concreto.
int zbx_module_uninit(void);
Esta función debe realizar la desinicialización necesaria, si la hubiera, como liberar recursos asignados, cerrar descriptores de archivo, etc.
Todas las funciones se llaman una vez al iniciar Zabbix cuando se carga el módulo, con la excepción de zbx_module_uninit(), que se llama una vez al apagar Zabbix cuando se descarga el módulo.
Definición de items
Cada item se define en una estructura ZBX_METRIC:
typedef struct
{
char *key;
unsigned flags;
int (*function)();
char *test_param;
}
ZBX_METRIC;
Aquí, key es la clave del item (por ejemplo, "dummy.random"), flags es CF_HAVEPARAMS o 0 (según si el item acepta parámetros o no), function es una función C que implementa el item (por ejemplo, zbx_module_dummy_random), y test_param es la lista de parámetros que se usará cuando el agent de Zabbix se inicie con la opción -p (por ejemplo, "1,1000", puede ser NULL).
Una definición de ejemplo podría verse así:
static ZBX_METRIC keys[] =
{
{ "dummy.random", CF_HAVEPARAMS, zbx_module_dummy_random, "1,1000" },
{ NULL }
}
Cada función que implementa un item 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 del item se obtuvo correctamente.
De lo contrario, deben devolver SYSINFO_RET_FAIL.
Consulte el ejemplo del módulo "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.
Proporcionar callbacks de exportación de history
La exportación de history mediante módulo ya no es compatible con Zabbix proxy.
El módulo puede especificar funciones para exportar datos de history por tipo: Numeric (float), Numeric (unsigned), Character, Text 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 como argumentos el array history de history_num elementos.
Según el tipo de datos de history que se vaya 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 de Zabbix server al final del procedimiento de sincronización de history, 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 history, se recomienda que el módulo esté escrito de forma que no bloquee toda la monitorización hasta recuperarse, sino que descarte los datos y permita que Zabbix server continúe ejecutándose.
Compilación de módulos
Actualmente, los módulos están pensados para compilarse dentro del árbol de código fuente de Zabbix, porque la API del módulo depende de algunas estructuras de datos que están definidas 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 del sistema necesarios que ayudan a que include/module.h funcione correctamente son stdlib.h y stdint.h.
Con esta información en mente, todo está listo para compilar el módulo.
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 del módulo "dummy" a continuación para obtener 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.
Parámetros de configuración
Zabbix agent, server y proxy admiten dos parámetros para trabajar con módulos:
LoadModulePath- ruta completa a la ubicación de los módulos cargablesLoadModule- módulo(s) que se cargarán al inicio. Los módulos deben estar ubicados en un directorio especificado porLoadModulePatho la ruta debe preceder al nombre del módulo. Si la ruta precedente es absoluta (empieza con/), entoncesLoadModulePathse ignora. Se permite incluir varios parámetros LoadModule.
Por ejemplo, para ampliar Zabbix agent 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 agent, 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.
agent 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.
Configuración del frontend
Los módulos cargables son compatibles con Zabbix agent, server y proxy. Por lo tanto, el tipo de item en el frontend de Zabbix depende de dónde se cargue el módulo. Si el módulo se carga en el agent, entonces el tipo de item debe ser "Zabbix agent" o "Zabbix agent (active)". Si el módulo se carga en server o proxy, entonces el tipo de item debe ser "Simple check".
La exportación del historial a través de módulos de Zabbix no necesita ninguna configuración del frontend.
Si el módulo se carga correctamente en server y proporciona la función zbx_module_history_write_cbs(), que devuelve al menos una función de devolución de llamada no NULL, entonces la exportación del historial se habilitará automáticamente.
Módulo dummy
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 usarse como template para sus propios módulos.
Después de ejecutar ./configure en la raíz del árbol de código fuente de Zabbix, como se describe arriba, solo tiene que ejecutar make para compilar dummy.so.
/*
** Zabbix
** Copyright (C) 2001-2020 Zabbix SIA
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the 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 tiempo de espera para el procesamiento de item */
static int item_timeout = 0;
/* el módulo DEBE definir las funciones internas como static y usar un patrón de nombres diferente de los símbolos */
/* internos de Zabbix (zbx_*) y de las funciones de la 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[] =
/* KEY FLAG FUNCTION TEST PARAMETERS */
{
{"dummy.ping", 0, dummy_ping, NULL},
{"dummy.echo", CF_HAVEPARAMS, dummy_echo, "a message"},
{"dummy.random", CF_HAVEPARAMS, dummy_random, "1,1000"},
{NULL}
};
/******************************************************************************
* *
* Function: zbx_module_api_version *
* *
* Purpose: returns version number of the module interface *
* *
* Return value: ZBX_MODULE_API_VERSION - version of module.h module is *
* compiled with, in order to load module successfully Zabbix *
* MUST be compiled with the same version of this header file *
* *
******************************************************************************/
int zbx_module_api_version(void)
{
return ZBX_MODULE_API_VERSION;
}
/******************************************************************************
* *
* Function: zbx_module_item_timeout *
* *
* Purpose: set timeout value for processing of items *
* *
* Parameters: timeout - timeout in seconds, 0 - no timeout set *
* *
******************************************************************************/
void zbx_module_item_timeout(int timeout)
{
item_timeout = timeout;
}
/******************************************************************************
* *
* Function: zbx_module_item_list *
* *
* Purpose: returns list of item keys supported by the module *
* *
* Return value: list of item keys *
* *
******************************************************************************/
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)
{
/* set optional error message */
SET_MSG_RESULT(result, strdup("Invalid number of parameters."));
return SYSINFO_RET_FAIL;
}
param = get_rparam(request, 0);
SET_STR_RESULT(result, strdup(param));
return SYSINFO_RET_OK;
}
/******************************************************************************
* *
* Function: dummy_random *
* *
* Purpose: a main entry point for processing of an item *
* *
* Parameters: request - structure that contains item key and parameters *
* request->key - item key without parameters *
* request->nparam - number of parameters *
* request->params[N-1] - pointers to item key parameters *
* request->types[N-1] - item key parameters types: *
* REQUEST_PARAMETER_TYPE_UNDEFINED (key parameter is empty) *
* REQUEST_PARAMETER_TYPE_ARRAY (array) *
* REQUEST_PARAMETER_TYPE_STRING (quoted or unquoted string) *
* *
* result - structure that will contain result *
* *
* Return value: SYSINFO_RET_FAIL - function failed, item will be marked *
* as not supported by zabbix *
* SYSINFO_RET_OK - success *
* *
* Comment: get_rparam(request, N-1) can be used to get a pointer to the Nth *
* parameter starting from 0 (first parameter). Make sure it exists *
* by checking value of request->nparam. *
* In the same manner get_rparam_type(request, N-1) can be used to *
* get a parameter type. *
* *
******************************************************************************/
static int dummy_random(AGENT_REQUEST *request, AGENT_RESULT *result)
{
char *param1, *param2;
int from, to;
if (2 != request->nparam)
{
/* set optional error message */
SET_MSG_RESULT(result, strdup("Invalid number of parameters."));
return SYSINFO_RET_FAIL;
}
param1 = get_rparam(request, 0);
param2 = get_rparam(request, 1);
/* there is no strict validation of parameters and types for simplicity sake */
from = atoi(param1);
to = atoi(param2);
if (from > to)
{
SET_MSG_RESULT(result, strdup("Invalid range specified."));
return SYSINFO_RET_FAIL;
}
SET_UI64_RESULT(result, from + rand() % (to - from + 1));
return SYSINFO_RET_OK;
}
/******************************************************************************
* *
* Function: zbx_module_init *
* *
* Purpose: the function is called on agent startup *
* It should be used to call any initialization routines *
* *
* Return value: ZBX_MODULE_OK - success *
* ZBX_MODULE_FAIL - module initialization failed *
* *
* Comment: the module won't be loaded in case of ZBX_MODULE_FAIL *
* *
******************************************************************************/
int zbx_module_init(void)
{
/* initialization for dummy.random */
srand(time(NULL));
return ZBX_MODULE_OK;
}
/******************************************************************************
* *
* Function: zbx_module_uninit *
* *
* Purpose: the function is called on agent shutdown *
* It should be used to cleanup used resources if there are any *
* *
* Return value: ZBX_MODULE_OK - success *
* ZBX_MODULE_FAIL - function failed *
* *
******************************************************************************/
int zbx_module_uninit(void)
{
return ZBX_MODULE_OK;
}
/******************************************************************************
* *
* Functions: dummy_history_float_cb *
* dummy_history_integer_cb *
* dummy_history_string_cb *
* dummy_history_text_cb *
* dummy_history_log_cb *
* *
* Purpose: callback functions for storing historical data of types float, *
* integer, string, text and log respectively in external storage *
* *
* Parameters: history - array of historical data *
* history_num - number of elements in history array *
* *
******************************************************************************/
static void dummy_history_float_cb(const ZBX_HISTORY_FLOAT *history, int history_num)
{
int i;
for (i = 0; i < history_num; i++)
{
/* do something with 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++)
{
/* do something with 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++)
{
/* do something with 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++)
{
/* do something with 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++)
{
/* do something with history[i].itemid, history[i].clock, history[i].ns, history[i].value, ... */
}
}
/******************************************************************************
* *
* Function: zbx_module_history_write_cbs *
* *
* Purpose: returns a set of module functions Zabbix will call to export *
* different types of historical data *
* *
* Return value: structure with callback function pointers (can be NULL if *
* module is not interested in data of certain types) *
* *
******************************************************************************/
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 nuevos items:
dummy.ping- siempre devuelve '1'dummy.echo[param1]- devuelve el primer parámetro tal como está; por ejemplo,dummy.echo[ABC]devolverá ABCdummy.random[param1, param2]- devuelve un número aleatorio dentro del rango de param1-param2; por ejemplo,dummy.random[1,1000000]
Limitaciones
La compatibilidad con módulos cargables está implementada solo para la plataforma Unix. Esto significa que no funciona para los agents 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 no se admite.
Si necesita que su módulo use algunos parámetros de configuración, probablemente debería implementar el análisis de un archivo de configuración específico del módulo.