1 Ladbare Module

Übersicht

Ladbare Module bieten eine leistungsorientierte Möglichkeit, die Funktionalität von Zabbix zu erweitern.

Sie können die Funktionalität von Zabbix auf viele Arten erweitern, zum Beispiel mit Benutzerparametern, externen Prüfungen und Zabbix-Agent-Datenpunkten vom Typ system.run. Diese funktionieren sehr gut, haben jedoch einen wesentlichen Nachteil, nämlich fork(). Zabbix muss jedes Mal einen neuen Prozess forken, wenn es eine Benutzermetrik verarbeitet, was sich negativ auf die Leistung auswirkt. Normalerweise ist das kein großes Problem, kann jedoch zu einem ernsthaften Thema werden, wenn eingebettete Systeme überwacht werden, eine große Anzahl überwachter Parameter vorhanden ist oder umfangreiche Skripte mit komplexer Logik oder langer Startzeit verwendet werden.

Die Unterstützung ladbarer Module bietet Möglichkeiten, den Zabbix-Agent, den Server und den Proxy zu erweitern, ohne dabei Leistung einzubüßen.

Ein ladbares Modul ist im Grunde eine Shared Library, die vom Zabbix-Daemon verwendet und beim Start geladen wird. Die Bibliothek sollte bestimmte Funktionen enthalten, damit ein Zabbix-Prozess erkennen kann, dass die Datei tatsächlich ein Modul ist, das er laden und verwenden kann.

Ladbare Module bieten eine Reihe von Vorteilen. Hohe Leistung und die Möglichkeit, beliebige Logik zu implementieren, sind sehr wichtig, aber der vielleicht wichtigste Vorteil ist die Möglichkeit, Zabbix-Module zu entwickeln, zu verwenden und zu teilen. Dies trägt zu einer problemlosen Wartung bei und hilft dabei, neue Funktionalität einfacher und unabhängig von der Zabbix-Kerncodebasis bereitzustellen.

Die Lizenzierung von Modulen und ihre Distribution in Binärform unterliegen der AGPL-3.0-Lizenz (Module werden zur Laufzeit mit Zabbix gelinkt und verwenden Zabbix-Header; der gesamte Zabbix-Code steht seit Zabbix 7.0 unter der AGPL-3.0-Lizenz). Die Binärkompatibilität wird von Zabbix nicht garantiert.

Die Stabilität der Modul-API wird während eines Zabbix-LTS-Zyklus (Long Term Support) Release garantiert. Die Stabilität der Zabbix-API wird nicht garantiert (technisch ist es möglich, interne Zabbix-Funktionen aus einem Modul heraus aufzurufen, es gibt jedoch keine Garantie, dass solche Module funktionieren).

Modul-API

Damit eine Shared Library als Zabbix-Modul behandelt wird, sollte sie mehrere Funktionen implementieren und exportieren. Derzeit gibt es sechs Funktionen in der Zabbix-Modul-API, von denen nur eine verpflichtend ist und die anderen fünf optional sind.

Obligatorische Schnittstelle

Die einzige obligatorische Funktion ist zbx_module_api_version():

int zbx_module_api_version(void);

Diese Funktion sollte die von diesem Modul implementierte API-Version zurückgeben. Damit das Modul geladen werden kann, muss diese Version mit der von Zabbix unterstützten Modul-API-Version übereinstimmen. Die von Zabbix unterstützte Version der Modul-API ist ZBX_MODULE_API_VERSION. Daher sollte diese Funktion diese Konstante zurückgeben. Die alte Konstante ZBX_MODULE_API_VERSION_ONE, die zu diesem Zweck verwendet wurde, ist jetzt so definiert, dass sie ZBX_MODULE_API_VERSION entspricht, um die Quellkompatibilität zu erhalten, ihre Verwendung wird jedoch nicht empfohlen.

Optionale Schnittstelle

Die optionalen Funktionen sind zbx_module_init(), zbx_module_item_list(), zbx_module_item_timeout(), zbx_module_history_write_cbs() und zbx_module_uninit():

int zbx_module_init(void);

Diese Funktion sollte die erforderliche Initialisierung für das Modul durchführen, falls nötig. Bei Erfolg sollte sie ZBX_MODULE_OK zurückgeben. Andernfalls sollte sie ZBX_MODULE_FAIL zurückgeben. Im letzteren Fall wird Zabbix nicht gestartet.

ZBX_METRIC  *zbx_module_item_list(void);

Diese Funktion sollte eine Liste der vom Modul unterstützten Datenpunkte zurückgeben. Jeder Datenpunkt wird in einer ZBX_METRIC-Struktur definiert; siehe den folgenden Abschnitt für Details. Die Liste wird durch eine ZBX_METRIC-Struktur beendet, deren Feld "key" den Wert NULL hat.

void    zbx_module_item_timeout(int timeout);

Wenn das Modul zbx_module_item_list() exportiert, wird diese Funktion von Zabbix verwendet, um die Timeout-Einstellungen in der Zabbix-Konfigurationsdatei anzugeben, die von den durch das Modul implementierten Datenpunkt-Prüfungen eingehalten werden sollen. Hier ist der Parameter "timeout" in Sekunden angegeben.

ZBX_HISTORY_WRITE_CBS   zbx_module_history_write_cbs(void);

Diese Funktion sollte Callback-Funktionen zurückgeben, die der Zabbix-Server zum Exportieren des Verlaufs verschiedener Datentypen verwendet. Callback-Funktionen werden als Felder der Struktur ZBX_HISTORY_WRITE_CBS bereitgestellt; Felder können NULL sein, wenn das Modul nicht am Verlauf eines bestimmten Typs interessiert ist.

int zbx_module_uninit(void);

Diese Funktion sollte die erforderliche Deinitialisierung durchführen, falls nötig, z. B. das Freigeben zugewiesener Ressourcen, das Schließen von Dateideskriptoren usw.

Alle Funktionen werden beim Start von Zabbix einmal aufgerufen, wenn das Modul geladen wird, mit Ausnahme von zbx_module_uninit(), das beim Herunterfahren von Zabbix einmal aufgerufen wird, wenn das Modul entladen wird.

Definieren von Datenpunkten

Jeder Datenpunkt wird in einer ZBX_METRIC-Struktur definiert:

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

Hier ist key der Datenpunkt-Schlüssel (z. B. "dummy.random"), flags entweder CF_HAVEPARAMS oder 0 (je nachdem, ob der Datenpunkt Parameter akzeptiert oder nicht), function eine C-Funktion, die den Datenpunkt implementiert (z. B. "zbx_module_dummy_random"), und test_param die Parameterliste, die verwendet wird, wenn der Zabbix Agent mit dem Flag "-p" gestartet wird (z. B. "1,1000", kann NULL sein). Eine Beispieldefinition kann wie folgt aussehen:

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

Jede Funktion, die einen Datenpunkt implementiert, sollte zwei Zeigerparameter akzeptieren, der erste vom Typ AGENT_REQUEST und der zweite vom Typ 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;
}

Diese Funktionen sollten SYSINFO_RET_OK zurückgeben, wenn der Datenpunktwert erfolgreich abgerufen wurde. Andernfalls sollten sie SYSINFO_RET_FAIL zurückgeben. Siehe das Beispielmodul "dummy" unten für Details dazu, wie Informationen aus AGENT_REQUEST abgerufen und Informationen in AGENT_RESULT gesetzt werden.

Bereitstellen von Callbacks für den Verlaufsexport

Der Verlaufsexport über ein Modul wird von Zabbix Proxy nicht mehr unterstützt.

Ein Modul kann Funktionen zum Exportieren von Verlaufsdaten nach Typ angeben: Numerisch (float), Numerisch (unsigned), Zeichen, Text und 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;

Jede dieser Funktionen sollte das Array "history" mit "history_num" Elementen als Argumente annehmen. Abhängig vom Typ der zu exportierenden Verlaufsdaten ist "history" jeweils ein Array der folgenden Strukturen:

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;

Die Callbacks werden von den Verlaufssynchronisierungsprozessen des Zabbix Server am Ende des Verlaufssynchronisierungsvorgangs verwendet, nachdem die Daten in die Zabbix-Datenbank geschrieben und im Wertespeicher gespeichert wurden.

Im Fall eines internen Fehlers im Modul für den Verlaufsexport wird empfohlen, das Modul so zu schreiben, dass es nicht die gesamte Überwachung blockiert, bis es sich erholt, sondern stattdessen Daten verwirft und dem Zabbix Server erlaubt, weiterzulaufen.

Module erstellen

Module sind derzeit dafür vorgesehen, innerhalb des Zabbix-Quellcodebaums erstellt zu werden, da die Modul-API von einigen Datenstrukturen abhängt, die in den Zabbix-Headern definiert sind.

Der wichtigste Header für ladbare Module ist include/module.h, der diese Datenstrukturen definiert. Weitere notwendige System-Header, die dafür sorgen, dass include/module.h korrekt funktioniert, sind stdlib.h und stdint.h.

Mit diesen Informationen ist alles für die Erstellung des Moduls vorbereitet. Das Modul sollte stdlib.h, stdint.h und module.h einbinden, und das Build-Skript sollte sicherstellen, dass sich diese Dateien im Include-Pfad befinden. Ein Beispiel finden Sie im untenstehenden „dummy“-Modul.

Ein weiterer nützlicher Header ist include/zbxcommon.h, der die Funktion zabbix_log() definiert, die für Protokollierungs- und Debugging-Zwecke verwendet werden kann.

Konfigurationsparameter

Zabbix Agent, Server und Proxy unterstützen zwei Parameter für den Umgang mit Modulen:

  • LoadModulePath – vollständiger Pfad zum Speicherort ladbarer Module
  • LoadModule – Modul(e), die beim Start geladen werden. Die Module müssen sich in einem durch LoadModulePath angegebenen Verzeichnis befinden, oder dem Modulnamen muss ein Pfad vorangestellt sein. Wenn der vorangestellte Pfad absolut ist (mit '/' beginnt), wird LoadModulePath ignoriert. Es ist zulässig, mehrere LoadModule-Parameter anzugeben.

Um beispielsweise den Zabbix Agent zu erweitern, könnten wir die folgenden Parameter hinzufügen:

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

Beim Start des Agent werden die Module mariadb.so, apache.so und kernel.so aus dem Verzeichnis /usr/local/lib/zabbix/agent geladen, während dummy.so aus /usr/local/lib/zabbix geladen wird. Der Agent kann nicht gestartet werden, wenn ein Modul fehlt, bei fehlerhaften Berechtigungen oder wenn eine Shared Library kein Zabbix-Modul ist.

Frontend-Konfiguration

Ladbare Module werden von Zabbix Agent, Server und Proxy unterstützt. Daher hängt der Datenpunkttyp im Zabbix Frontend davon ab, wo das Modul geladen wird. Wenn das Modul in den Agent geladen wird, sollte der Datenpunkttyp „Zabbix agent“ oder „Zabbix agent (active)“ sein. Wenn das Modul in den Server oder Proxy geladen wird, sollte der Datenpunkttyp „Simple check“ sein.

Der Verlaufsexport über Zabbix-Module benötigt keine Frontend-Konfiguration. Wenn das Modul erfolgreich vom Server geladen wird und die Funktion zbx_module_history_write_cbs() bereitstellt, die mindestens eine Callback-Funktion ungleich NULL zurückgibt, wird der Verlaufsexport automatisch aktiviert.

Dummy-Modul

Zabbix enthält ein Beispielmodul, das in der Programmiersprache C geschrieben ist. Das Modul befindet sich unter 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

Das Modul ist gut dokumentiert und kann als Vorlage für Ihre eigenen Module verwendet werden.

Nachdem ./configure wie oben beschrieben im Stammverzeichnis des Zabbix-Quellbaums ausgeführt wurde, führen Sie einfach make aus, um dummy.so zu erstellen.

/*
** 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;
}

Das Modul exportiert drei neue Datenpunkte:

  • dummy.ping - gibt immer '1' zurück
  • dummy.echo[param1] - gibt den ersten Parameter unverändert zurück; zum Beispiel gibt dummy.echo[ABC] ABC zurück
  • dummy.random[param1, param2] - gibt eine Zufallszahl im Bereich von param1-param2 zurück; zum Beispiel dummy.random[1,1000000]

Einschränkungen

Die Unterstützung für ladbare Module ist nur für die Unix-Plattform implementiert. Das bedeutet, dass sie nicht für Windows-Agenten funktioniert.

In einigen Fällen muss ein Modul möglicherweise modulbezogene Konfigurationsparameter aus zabbix_agentd.conf lesen. Dies wird derzeit nicht unterstützt. Wenn Ihr Modul einige Konfigurationsparameter verwenden soll, sollten Sie wahrscheinlich das Parsen einer modulspezifischen Konfigurationsdatei implementieren.