1 Moduli caricabili

Panoramica

I moduli caricabili offrono un'opzione orientata alle prestazioni per estendere le funzionalità di Zabbix.

È possibile estendere le funzionalità di Zabbix in molti modi, ad esempio con i parametri utente, i controlli esterni e gli item Zabbix agent system.run. Questi metodi funzionano molto bene, ma presentano un importante svantaggio, vale a dire fork(). Zabbix deve eseguire il fork di un nuovo processo ogni volta che gestisce una metrica utente, e questo non è positivo per le prestazioni. Normalmente non è un grosso problema, tuttavia può diventare una questione seria nel monitoraggio di sistemi embedded, in presenza di un numero elevato di parametri monitorati oppure di script pesanti con logica complessa o tempi di avvio lunghi.

Il supporto dei moduli caricabili offre modi per estendere Zabbix agent, server e proxy senza sacrificare le prestazioni.

Un modulo caricabile è fondamentalmente una libreria condivisa utilizzata dal demone Zabbix e caricata all'avvio. La libreria deve contenere determinate funzioni, in modo che un processo Zabbix possa rilevare che il file è effettivamente un modulo che può caricare e utilizzare.

I moduli caricabili offrono numerosi vantaggi. Le prestazioni elevate e la possibilità di implementare qualsiasi logica sono molto importanti, ma forse il vantaggio più importante è la possibilità di sviluppare, utilizzare e condividere moduli Zabbix. Ciò contribuisce a una manutenzione senza problemi e aiuta a fornire nuove funzionalità più facilmente e indipendentemente dal codice core di Zabbix.

La licenza dei moduli e la distribuzione in forma binaria sono regolate dalla licenza AGPL-3.0 (i moduli si collegano a Zabbix in fase di esecuzione e utilizzano gli header di Zabbix; l'intero codice di Zabbix è concesso in licenza AGPL-3.0 a partire da Zabbix 7.0). La compatibilità binaria non è garantita da Zabbix.

La stabilità della Module API è garantita durante un ciclo di rilascio Zabbix LTS (Long Term Support). La stabilità della Zabbix API non è garantita (tecnicamente è possibile chiamare funzioni interne di Zabbix da un modulo, ma non vi è alcuna garanzia che tali moduli funzionino).

API del modulo

Affinché una libreria condivisa venga trattata come un modulo Zabbix, deve implementare ed esportare diverse funzioni. Attualmente nell'API dei moduli Zabbix sono presenti sei funzioni, di cui solo una è obbligatoria e le altre cinque sono facoltative.

Interfaccia obbligatoria

L'unica funzione obbligatoria è zbx_module_api_version():

int zbx_module_api_version(void);

Questa funzione deve restituire la versione dell'API implementata da questo modulo e, affinché il modulo venga caricato, questa versione deve corrispondere alla versione dell'API del modulo supportata da Zabbix. La versione dell'API del modulo supportata da Zabbix è ZBX_MODULE_API_VERSION. Pertanto, questa funzione deve restituire questa costante. La vecchia costante ZBX_MODULE_API_VERSION_ONE, usata a questo scopo, è ora definita come uguale a ZBX_MODULE_API_VERSION per preservare la compatibilità del codice sorgente, ma il suo utilizzo non è consigliato.

Interfaccia opzionale

Le funzioni opzionali sono zbx_module_init(), zbx_module_item_list(), zbx_module_item_timeout(), zbx_module_history_write_cbs() e zbx_module_uninit():

int zbx_module_init(void);

Questa funzione deve eseguire l'inizializzazione necessaria per il modulo (se presente). In caso di successo, deve restituire ZBX_MODULE_OK. In caso contrario, deve restituire ZBX_MODULE_FAIL. In quest'ultimo caso Zabbix non si avvierà.

ZBX_METRIC  *zbx_module_item_list(void);

Questa funzione deve restituire un elenco di item supportati dal modulo. Ogni item è definito in una struttura ZBX_METRIC; per i dettagli vedere la sezione seguente. L'elenco termina con una struttura ZBX_METRIC il cui campo "key" è NULL.

void    zbx_module_item_timeout(int timeout);

Se il modulo esporta zbx_module_item_list(), allora questa funzione viene utilizzata da Zabbix per specificare le impostazioni di timeout nel file di configurazione di Zabbix che i controlli degli item implementati dal modulo devono rispettare. Qui, il parametro "timeout" è espresso in secondi.

ZBX_HISTORY_WRITE_CBS   zbx_module_history_write_cbs(void);

Questa funzione deve restituire le funzioni di callback che Zabbix server utilizzerà per esportare la cronologia di diversi tipi di dati. Le funzioni di callback sono fornite come campi della struttura ZBX_HISTORY_WRITE_CBS; i campi possono essere NULL se il modulo non è interessato alla cronologia di un determinato tipo.

int zbx_module_uninit(void);

Questa funzione deve eseguire la deinizializzazione necessaria (se presente), ad esempio liberando le risorse allocate, chiudendo i descrittori di file, ecc.

Tutte le funzioni vengono chiamate una volta all'avvio di Zabbix quando il modulo viene caricato, ad eccezione di zbx_module_uninit(), che viene chiamata una volta all'arresto di Zabbix quando il modulo viene scaricato.

Definizione degli item

Ogni item è definito in una struttura ZBX_METRIC:

typedef struct
{
    char        *key;
    unsigned    flags;
    int     (*function)();
    char        *test_param;
}
ZBX_METRIC;

Qui, key è la chiave dell'item (ad esempio, "dummy.random"), flags è CF_HAVEPARAMS oppure 0 (a seconda che l'item accetti parametri o meno), function è una funzione C che implementa l'item (ad esempio, "zbx_module_dummy_random"), e test_param è l'elenco dei parametri da utilizzare quando Zabbix agent viene avviato con il flag "-p" (ad esempio, "1,1000", può essere NULL). Una definizione di esempio può apparire così:

static ZBX_METRIC keys[] =
{
    { "dummy.random", CF_HAVEPARAMS, zbx_module_dummy_random, "1,1000" },
    { NULL }
}

Ogni funzione che implementa un item deve accettare due parametri puntatore, il primo di tipo AGENT_REQUEST e il secondo di 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;
}

Queste funzioni devono restituire SYSINFO_RET_OK se il valore dell'item è stato ottenuto correttamente. In caso contrario, devono restituire SYSINFO_RET_FAIL. Per i dettagli su come ottenere informazioni da AGENT_REQUEST e come impostare informazioni in AGENT_RESULT, vedere l'esempio del modulo "dummy" riportato di seguito.

Fornire callback di esportazione della cronologia

L'esportazione della cronologia tramite modulo non è più supportata da Zabbix proxy.

Il modulo può specificare funzioni per esportare i dati della cronologia per tipo: Numerico (float), Numerico (unsigned), Carattere, Testo e 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;

Ciascuna di esse deve accettare come argomenti l'array "history" di "history_num" elementi. A seconda del tipo di dati della cronologia da esportare, "history" è rispettivamente un array delle seguenti strutture:

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;

Le callback saranno utilizzate dai processi history syncer di Zabbix server al termine della procedura di sincronizzazione della cronologia, dopo che i dati sono stati scritti nel database di Zabbix e salvati nella cache dei valori.

In caso di errore interno nel modulo di esportazione della cronologia, si raccomanda di scrivere il modulo in modo tale che non blocchi l'intero monitoraggio fino al ripristino, ma che invece scarti i dati e consenta a Zabbix server di continuare a funzionare.

Compilazione dei moduli

Attualmente i moduli devono essere compilati all'interno dell'albero dei sorgenti di Zabbix, perché l'API dei moduli dipende da alcune strutture dati definite negli header di Zabbix.

L'header più importante per i moduli caricabili è include/module.h, che definisce queste strutture dati. Altri header di sistema necessari affinché include/module.h funzioni correttamente sono stdlib.h e stdint.h.

Tenendo presenti queste informazioni, tutto è pronto per compilare il modulo. Il modulo deve includere stdlib.h, stdint.h e module.h, e lo script di build deve assicurarsi che questi file siano nel percorso di inclusione. Per i dettagli, vedere l'esempio del modulo "dummy" riportato di seguito.

Un altro header utile è include/zbxcommon.h, che definisce la funzione zabbix_log(), utilizzabile per finalità di logging e debug.

Parametri di configurazione

Zabbix agent, server e proxy supportano due parametri per gestire i moduli:

  • LoadModulePath – percorso completo della posizione dei moduli caricabili
  • LoadModule – modulo/i da caricare all'avvio. I moduli devono trovarsi in una directory specificata da LoadModulePath oppure il percorso deve precedere il nome del modulo. Se il percorso che precede il nome è assoluto (inizia con '/'), allora LoadModulePath viene ignorato. È consentito includere più parametri LoadModule.

Ad esempio, per estendere Zabbix agent potremmo aggiungere i seguenti parametri:

LoadModulePath=/usr/local/lib/zabbix/agent/
LoadModule=mariadb.so
LoadModule=apache.so
LoadModule=kernel.so
LoadModule=/usr/local/lib/zabbix/dummy.so

All'avvio dell'agent verranno caricati i moduli mariadb.so, apache.so e kernel.so dalla directory /usr/local/lib/zabbix/agent, mentre dummy.so verrà caricato da /usr/local/lib/zabbix. L'agent non riuscirà ad avviarsi se manca un modulo, in caso di permessi non corretti oppure se una libreria condivisa non è un modulo Zabbix.

Configurazione del frontend

I moduli caricabili sono supportati da Zabbix agent, server e proxy. Pertanto, il tipo di item nel frontend di Zabbix dipende da dove viene caricato il modulo. Se il modulo viene caricato nell'agent, il tipo di item deve essere "Zabbix agent" oppure "Zabbix agent (active)". Se il modulo viene caricato nel server o nel proxy, il tipo di item deve essere "Simple check".

L'esportazione della history tramite i moduli di Zabbix non richiede alcuna configurazione del frontend. Se il modulo viene caricato correttamente dal server e fornisce la funzione zbx_module_history_write_cbs() che restituisce almeno una funzione di callback non NULL, l'esportazione della history verrà abilitata automaticamente.

Modulo fittizio

Zabbix include un modulo di esempio scritto nel linguaggio C. Il modulo si trova in 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

Il modulo è ben documentato e può essere utilizzato come template per i propri moduli.

Dopo aver eseguito ./configure nella directory radice dell'albero dei sorgenti di Zabbix come descritto sopra, è sufficiente eseguire make per compilare 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;
}

Il modulo esporta tre nuovi item:

  • dummy.ping - restituisce sempre '1'
  • dummy.echo[param1] - restituisce il primo parametro così com'è; per esempio, dummy.echo[ABC] restituirà ABC
  • dummy.random[param1, param2] - restituisce un numero casuale nell'intervallo param1-param2; per esempio, dummy.random[1,1000000]

Limitazioni

Il supporto dei moduli caricabili è implementato solo per la piattaforma Unix. Ciò significa che non funziona per gli agent di Windows.

In alcuni casi un modulo potrebbe dover leggere parametri di configurazione relativi al modulo da zabbix_agentd.conf. Attualmente questo non è supportato. Se hai bisogno che il tuo modulo utilizzi alcuni parametri di configurazione, probabilmente dovresti implementare il parsing di un file di configurazione specifico del modulo.