1 Modules chargeables
Vue d’ensemble
Les modules chargeables offrent une option axée sur les performances pour étendre les fonctionnalités de Zabbix.
Vous pouvez étendre les fonctionnalités de Zabbix de nombreuses façons, par exemple avec les paramètres utilisateur, les vérifications externes et les éléments d’agent Zabbix system.run. Ces méthodes fonctionnent très bien, mais présentent un inconvénient majeur, à savoir fork(). Zabbix doit créer un nouveau processus par fork chaque fois qu’il traite une métrique utilisateur, ce qui n’est pas bon pour les performances. Ce n’est généralement pas un gros problème, mais cela peut devenir un problème sérieux lors de la supervision de systèmes embarqués, lorsqu’un grand nombre de paramètres sont supervisés ou lorsque des scripts lourds avec une logique complexe ou un long temps de démarrage sont utilisés.
La prise en charge des modules chargeables permet d’étendre l’agent, le serveur et le proxy Zabbix sans sacrifier les performances.
Un module chargeable est essentiellement une bibliothèque partagée utilisée par le démon Zabbix et chargée au démarrage. La bibliothèque doit contenir certaines fonctions, afin qu’un processus Zabbix puisse détecter que le fichier est bien un module qu’il peut charger et utiliser.
Les modules chargeables présentent un certain nombre d’avantages. D’excellentes performances et la possibilité d’implémenter n’importe quelle logique sont très importantes, mais l’avantage le plus important est peut-être la possibilité de développer, d’utiliser et de partager des modules Zabbix. Cela contribue à une maintenance sans difficulté et aide à fournir de nouvelles fonctionnalités plus facilement et indépendamment de la base de code principale de Zabbix.
La licence des modules et leur distribution sous forme binaire sont régies par la licence AGPL-3.0 (les modules sont liés à Zabbix à l’exécution et utilisent les en-têtes Zabbix ; l’ensemble du code Zabbix est sous licence AGPL-3.0 depuis Zabbix 7.0). La compatibilité binaire n’est pas garantie par Zabbix.
La stabilité de l’API des modules est garantie pendant un cycle de version LTS (Long Term Support) de Zabbix. La stabilité de l’API Zabbix n’est pas garantie (techniquement, il est possible d’appeler des fonctions internes de Zabbix depuis un module, mais rien ne garantit que de tels modules fonctionneront).
API de module
Pour qu'une bibliothèque partagée soit traitée comme un module Zabbix, elle doit implémenter et exporter plusieurs fonctions. Il existe actuellement six fonctions dans l'API de module Zabbix, dont une seule est obligatoire et les cinq autres sont facultatives.
Interface obligatoire
La seule fonction obligatoire est zbx_module_api_version() :
int zbx_module_api_version(void);
Cette fonction doit renvoyer la version de l’API implémentée par ce module et, pour que le module puisse être chargé, cette version doit correspondre à la version de l’API du module prise en charge par Zabbix. La version de l’API du module prise en charge par Zabbix est ZBX_MODULE_API_VERSION. Cette fonction doit donc renvoyer cette constante. L’ancienne constante ZBX_MODULE_API_VERSION_ONE utilisée à cette fin est désormais définie comme étant égale à ZBX_MODULE_API_VERSION afin de préserver la compatibilité du code source, mais son utilisation n’est pas recommandée.
Interface facultative
Les fonctions facultatives sont zbx_module_init(), zbx_module_item_list(), zbx_module_item_timeout(), zbx_module_history_write_cbs() et zbx_module_uninit() :
int zbx_module_init(void);
Cette fonction doit effectuer l'initialisation nécessaire du module (le cas échéant). En cas de succès, elle doit renvoyer ZBX_MODULE_OK. Sinon, elle doit renvoyer ZBX_MODULE_FAIL. Dans ce dernier cas, Zabbix ne démarrera pas.
ZBX_METRIC *zbx_module_item_list(void);
Cette fonction doit renvoyer une liste des éléments pris en charge par le module. Chaque élément est défini dans une structure ZBX_METRIC ; voir la section ci-dessous pour plus de détails. La liste se termine par une structure ZBX_METRIC dont le champ "key" est défini sur NULL.
void zbx_module_item_timeout(int timeout);
Si le module exporte zbx_module_item_list(), cette fonction est alors utilisée par Zabbix pour spécifier les paramètres de délai d'expiration définis dans le fichier de configuration de Zabbix, que les vérifications d'éléments implémentées par le module doivent respecter. Ici, le paramètre "timeout" est exprimé en secondes.
ZBX_HISTORY_WRITE_CBS zbx_module_history_write_cbs(void);
Cette fonction doit renvoyer les fonctions de rappel que le serveur Zabbix utilisera pour exporter l'historique de différents types de données. Les fonctions de rappel sont fournies sous forme de champs de la structure ZBX_HISTORY_WRITE_CBS ; les champs peuvent être NULL si le module ne s'intéresse pas à l'historique d'un certain type.
int zbx_module_uninit(void);
Cette fonction doit effectuer la désinitialisation nécessaire (le cas échéant), par exemple la libération des ressources allouées, la fermeture des descripteurs de fichiers, etc.
Toutes les fonctions sont appelées une fois au démarrage de Zabbix lorsque le module est chargé, à l'exception de zbx_module_uninit(), qui est appelée une fois à l'arrêt de Zabbix lorsque le module est déchargé.
Définition des éléments
Chaque élément est défini dans une structure ZBX_METRIC :
typedef struct
{
char *key;
unsigned flags;
int (*function)();
char *test_param;
}
ZBX_METRIC;
Ici, key est la clé de l’élément (par ex. « dummy.random »), flags vaut soit CF_HAVEPARAMS, soit 0 (selon que l’élément accepte des paramètres ou non), function est une fonction C qui implémente l’élément (par ex. « zbx_module_dummy_random »), et test_param est la liste des paramètres à utiliser lorsque l’agent Zabbix est démarré avec l’option « -p » (par ex. « 1,1000 », peut être NULL). Un exemple de définition peut ressembler à ceci :
static ZBX_METRIC keys[] =
{
{ "dummy.random", CF_HAVEPARAMS, zbx_module_dummy_random, "1,1000" },
{ NULL }
}
Chaque fonction qui implémente un élément doit accepter deux paramètres pointeurs, le premier de type AGENT_REQUEST et le second de type 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;
}
Ces fonctions doivent renvoyer SYSINFO_RET_OK si la valeur de l’élément a été obtenue avec succès. Sinon, elles doivent renvoyer SYSINFO_RET_FAIL. Voir l’exemple du module « dummy » ci-dessous pour plus de détails sur la manière d’obtenir des informations depuis AGENT_REQUEST et de définir des informations dans AGENT_RESULT.
Fourniture de callbacks d’exportation de l’historique
L’exportation de l’historique via un module n’est plus prise en charge par Zabbix proxy.
Le module peut spécifier des fonctions pour exporter les données d’historique par type : numérique (float), numérique (unsigned), caractère, texte et journal :
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;
Chacune d’elles doit prendre comme arguments le tableau "history" de "history_num" éléments. Selon le type de données d’historique à exporter, "history" est respectivement un tableau des structures suivantes :
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;
Les callbacks seront utilisés par les processus de synchronisation de l’historique du serveur Zabbix à la fin de la procédure de synchronisation de l’historique, après l’écriture des données dans la base de données Zabbix et leur enregistrement dans le cache de valeurs.
En cas d’erreur interne dans le module d’exportation de l’historique, il est recommandé d’écrire le module de manière à ce qu’il ne bloque pas l’ensemble de la supervision jusqu’à son rétablissement, mais qu’il ignore plutôt les données et permette au serveur Zabbix de continuer à fonctionner.
Compilation des modules
Les modules sont actuellement destinés à être compilés à l’intérieur de l’arborescence des sources de Zabbix, car l’API des modules dépend de certaines structures de données définies dans les en-têtes de Zabbix.
L’en-tête le plus important pour les modules chargeables est include/module.h, qui définit ces structures de données. Les autres en-têtes système nécessaires au bon fonctionnement de include/module.h sont stdlib.h et stdint.h.
En gardant ces informations à l’esprit, tout est prêt pour compiler le module. Le module doit inclure stdlib.h, stdint.h et module.h, et le script de compilation doit s’assurer que ces fichiers se trouvent dans le chemin d’inclusion. Voir l’exemple de module « dummy » ci-dessous pour plus de détails.
Un autre en-tête utile est include/zbxcommon.h, qui définit la fonction zabbix_log(), pouvant être utilisée à des fins de journalisation et de débogage.
Paramètres de configuration
Zabbix agent, le serveur et le proxy prennent en charge deux paramètres pour gérer les modules :
- LoadModulePath – chemin complet vers l’emplacement des modules chargeables
- LoadModule – module(s) à charger au démarrage. Les modules doivent être situés dans un répertoire spécifié par LoadModulePath, ou le chemin doit précéder le nom du module. Si le chemin précédent est absolu (commence par '/'), alors LoadModulePath est ignoré. Il est permis d’inclure plusieurs paramètres LoadModule.
Par exemple, pour étendre Zabbix agent, nous pourrions ajouter les paramètres suivants :
LoadModulePath=/usr/local/lib/zabbix/agent/
LoadModule=mariadb.so
LoadModule=apache.so
LoadModule=kernel.so
LoadModule=/usr/local/lib/zabbix/dummy.so
Au démarrage de l’agent, les modules mariadb.so, apache.so et kernel.so seront chargés depuis le répertoire /usr/local/lib/zabbix/agent, tandis que dummy.so sera chargé depuis /usr/local/lib/zabbix. L’agent ne pourra pas démarrer si un module est manquant, en cas de permissions incorrectes ou si une bibliothèque partagée n’est pas un module Zabbix.
Configuration du frontend
Les modules chargeables sont pris en charge par l’agent Zabbix, le serveur et le proxy. Par conséquent, le type d’élément dans le frontend Zabbix dépend de l’endroit où le module est chargé. Si le module est chargé dans l’agent, le type d’élément doit alors être « Agent Zabbix » ou « Agent Zabbix (actif) ». Si le module est chargé dans le serveur ou le proxy, le type d’élément doit alors être « Vérification simple ».
L’export de l’historique via les modules Zabbix ne nécessite aucune configuration du frontend. Si le module est chargé avec succès par le serveur et fournit la fonction zbx_module_history_write_cbs() qui renvoie au moins une fonction de rappel non NULL, alors l’export de l’historique sera activé automatiquement.
Module factice
Zabbix inclut un exemple de module écrit en langage C. Le module se trouve dans 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
Le module est bien documenté et peut être utilisé comme modèle pour vos propres modules.
Après avoir exécuté ./configure à la racine de l’arborescence des sources de Zabbix comme décrit ci-dessus, exécutez simplement make afin de compiler 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"
/* the variable keeps timeout setting for item processing */
static int item_timeout = 0;
/* module SHOULD define internal functions as static and use a naming pattern different from Zabbix internal */
/* symbols (zbx_*) and loadable module API functions (zbx_module_*) to avoid conflicts */
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;
}
Le module exporte trois nouveaux éléments :
dummy.ping- renvoie toujours « 1 »dummy.echo[param1]- renvoie le premier paramètre tel quel ; par exemple,dummy.echo[ABC]renverra ABCdummy.random[param1, param2]- renvoie un nombre aléatoire dans la plage param1-param2 ; par exemple,dummy.random[1,1000000]
Limitations
La prise en charge des modules chargeables est implémentée uniquement pour la plateforme Unix. Cela signifie qu’elle ne fonctionne pas pour les agents Windows.
Dans certains cas, un module peut avoir besoin de lire des paramètres de configuration liés au module depuis zabbix_agentd.conf. Cela n’est actuellement pas pris en charge. Si vous avez besoin que votre module utilise certains paramètres de configuration, vous devriez probablement implémenter l’analyse d’un fichier de configuration spécifique au module.