Загружаемые модули

Обзор

Подгружаемые модули предлагают ориентированный на производительность вариант расширения Zabbix.

Функциональность Zabbix можно расширить многими способами, например, с помощью пользовательских параметров, внешних проверок, а также элементов данных Zabbix агента system.run. Они работают очень хорошо, но имеют один большой недостаток, называемый fork(). Zabbix для сбора пользовательских проверок каждый раз должен создавать новый порождённый процесс, что не очень хорошо сказывается на производительности. Обычно это не самая большая проблема, но тем не менее это может быть серьезной проблемой в случае мониторинга встроенных систем, имеющих большое количество наблюдаемых параметров или тяжёлых скриптов со сложной логикой или длительным временем запуска.

Поддержка подгружаемых модулей предлагает пути расширения Zabbix агента, сервера и прокси без ущерба для производительности.

Подгружаемый модуль — в своей основе разделяемая библиотека, которая используется Zabbix демоном и подгружается при старте демона. Библиотека должна содержать определённые функции, чтобы Zabbix процесс мог определить, что файл на самом деле является модулем, который можно загрузить и с ним работать.

Подгружаемые модули имеют много преимуществ. Отличная производительность и возможность реализовать любую логику очень важны, но, возможно, наиболее важное преимущество — возможность разработать, использовать и поделиться Zabbix модулем. Это способствует беспроблемному обслуживанию и помогает вносить новые функции легче и независимо от основной кодовой базы Zabbix.

Лицензирование и распространение модулей в бинарной форме регламентируется лицензией AGPL-3.0 (модули линкуются с Zabbix во время выполнения и используют заголовки Zabbix; в настоящее время весь код Zabbix, начиная с версии 7.0, лицензируется под лицензией AGPL-3.0). Бинарная совместимость не гарантируется Zabbix'ом.

Постоянство API модулей гарантируется в пределах одного цикла выпуска Zabbix LTS (Долгосрочная поддержка). Постоянство Zabbix API не гарантируется (технически имеется возможность вызова внутренних функций Zabbix из модуля, но нет гарантии, что такие модули будут работать).

API модулей

Для того чтобы разделяемая библиотека обрабатывалась как Zabbix модуль, она должна реализовывать и экспортировать несколько функций. На данный момент имеется шесть функций в API модулей Zabbix, только одна из которых обязательна, а остальные пять — не обязательны.

Обязательный интерфейс

Единственной обязательной функцией является zbx_module_api_version():

int zbx_module_api_version(void);

Эта функция должна возвращать версию API, реализованную этим модулем, и для того чтобы модуль был загружен, эта версия должна совпадать с версией API модуля, поддерживаемой Zabbix. Версия API модуля, поддерживаемая Zabbix, — ZBX_MODULE_API_VERSION. Поэтому эта функция должна возвращать именно эту константу. Старая константа ZBX_MODULE_API_VERSION_ONE, ранее использовавшаяся для этой цели, теперь определена как равная ZBX_MODULE_API_VERSION для сохранения совместимости с исходным кодом, однако ее использование не рекомендуется.

Необязательный интерфейс

Необязательными функциями являются zbx_module_init(), zbx_module_item_list(), zbx_module_item_timeout(), zbx_module_history_write_cbs() и zbx_module_uninit():

int zbx_module_init(void);

Эта функция должна выполнить необходимую инициализацию модуля, если она требуется. При успешном выполнении она должна вернуть ZBX_MODULE_OK. В противном случае она должна вернуть ZBX_MODULE_FAIL. В последнем случае Zabbix не запустится.

ZBX_METRIC  *zbx_module_item_list(void);

Эта функция должна возвращать список элементов данных, поддерживаемых модулем. Каждый элемент данных определяется в структуре ZBX_METRIC, см. раздел ниже для подробностей. Список завершается структурой ZBX_METRIC с полем "key", равным NULL.

void    zbx_module_item_timeout(int timeout);

Если модуль экспортирует zbx_module_item_list(), то эта функция используется Zabbix для указания настроек тайм-аута в файле конфигурации Zabbix, которым должны руководствоваться проверки элементов данных, реализованные модулем. Здесь параметр "timeout" задается в секундах.

ZBX_HISTORY_WRITE_CBS   zbx_module_history_write_cbs(void);

Эта функция должна возвращать функции обратного вызова, которые сервер Zabbix будет использовать для экспорта истории различных типов данных. Функции обратного вызова предоставляются в виде полей структуры ZBX_HISTORY_WRITE_CBS; поля могут быть NULL, если модуль не заинтересован в истории определенного типа.

int zbx_module_uninit(void);

Эта функция должна выполнить необходимую деинициализацию, если она требуется, например освобождение выделенных ресурсов, закрытие файловых дескрипторов и т. д.

Все функции вызываются один раз при запуске Zabbix, когда модуль загружается, за исключением zbx_module_uninit(), которая вызывается один раз при завершении работы Zabbix, когда модуль выгружается.

Определение элементов данных

Каждый элемент данных определяется в структуре ZBX_METRIC:

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

Здесь key — это ключ элемента данных (например, "dummy.random"), flags — либо CF_HAVEPARAMS, либо 0 (в зависимости от того, принимает элемент данные параметры или нет), function — это функция C, реализующая элемент данных (например, zbx_module_dummy_random), а test_param — это список параметров, который будет использоваться при запуске агента Zabbix с флагом -p (например, "1,1000", может быть NULL). Пример определения может выглядеть так:

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

Каждая функция, реализующая элемент данных, должна принимать два параметра-указателя: первый типа AGENT_REQUEST, а второй типа 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;
}

Эти функции должны возвращать SYSINFO_RET_OK, если значение элемента данных было успешно получено. В противном случае они должны возвращать SYSINFO_RET_FAIL. См. пример модуля "dummy" ниже, чтобы узнать, как получать информацию из AGENT_REQUEST и как задавать информацию в AGENT_RESULT.

Предоставление callback-функций для экспорта истории

Экспорт истории через модуль больше не поддерживается прокси Zabbix.

Модуль может задавать функции для экспорта данных истории по типам: Numeric (float), Numeric (unsigned), Character, Text и 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;

Каждая из них должна принимать в качестве аргументов массив history из history_num элементов. В зависимости от типа данных истории, которые требуется экспортировать, history представляет собой массив следующих структур соответственно:

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;

Callback-функции будут использоваться процессами синхронизации истории сервера Zabbix в конце процедуры синхронизации истории после записи данных в базу данных Zabbix и сохранения в кэше значений.

В случае внутренней ошибки в модуле экспорта истории рекомендуется реализовать модуль таким образом, чтобы он не блокировал весь мониторинг до восстановления, а вместо этого отбрасывал данные и позволял серверу Zabbix продолжать работу.

Сборка модулей

В настоящее время модули предназначены для сборки внутри дерева исходного кода Zabbix, поскольку API модуля зависит от некоторых структур данных, определенных в заголовочных файлах Zabbix.

Наиболее важный заголовочный файл для загружаемых модулей — include/module.h, который определяет эти структуры данных. Другие необходимые системные заголовочные файлы, которые помогают include/module.h работать корректно, — это stdlib.h и stdint.h.

С учетом этой информации все готово для сборки модуля. Модуль должен включать stdlib.h, stdint.h и module.h, а сценарий сборки должен гарантировать, что эти файлы находятся в пути включения. Подробности см. в примере модуля "dummy" ниже.

Еще один полезный заголовочный файл — include/zbxcommon.h, который определяет функцию zabbix_log(), которую можно использовать для ведения журнала и отладки.

Параметры конфигурации

Агент Zabbix, сервер и прокси поддерживают два параметра для работы с модулями:

  • LoadModulePath - полный путь к расположению загружаемых модулей
  • LoadModule - модуль(и), которые нужно загрузить при запуске. Модули должны находиться в каталоге, указанном в LoadModulePath, либо путь должен предшествовать имени модуля. Если указанный путь является абсолютным (начинается с /), то LoadModulePath игнорируется. Допускается указывать несколько параметров LoadModule.

Например, чтобы расширить агент Zabbix, можно добавить следующие параметры:

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

При запуске агент загрузит модули mariadb.so, apache.so и kernel.so из каталога /usr/local/lib/zabbix/agent, а dummy.so будет загружен из /usr/local/lib/zabbix. Агент не сможет запуститься, если модуль отсутствует, если у него неверные права доступа или если общая библиотека не является модулем Zabbix.

Конфигурация веб-интерфейса

Загружаемые модули поддерживаются агентом Zabbix, сервером и прокси. Поэтому тип элемента данных в веб-интерфейсе Zabbix зависит от того, куда загружен модуль. Если модуль загружен в агент, то тип элемента данных должен быть "Zabbix agent" или "Zabbix agent (active)". Если модуль загружен в сервер или прокси, то тип элемента данных должен быть "Simple check".

Экспорт истории через модули Zabbix не требует какой-либо конфигурации веб-интерфейса. Если модуль успешно загружен сервером и предоставляет функцию zbx_module_history_write_cbs(), которая возвращает как минимум одну ненулевую callback-функцию, то экспорт истории будет включен автоматически.

Модуль dummy

Zabbix включает пример модуля, написанного на языке C. Модуль расположен в 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

Модуль хорошо документирован, его можно использовать как шаблон для собственных модулей.

После выполнения ./configure в корне дерева исходного кода Zabbix, как описано выше, просто выполните make, чтобы собрать 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"

/* переменная хранит настройку тайм-аута для обработки элемента данных */
static int  item_timeout = 0;

/* модуль ДОЛЖЕН определять внутренние функции как static и использовать схему именования, отличную от внутренних */
/* символов Zabbix (zbx_*) и функций API загружаемых модулей (zbx_module_*) во избежание конфликтов               */
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;
}

Модуль экспортирует три новых элемента данных:

  • dummy.ping - всегда возвращает '1'
  • dummy.echo[param1] - возвращает первый параметр как есть, например dummy.echo[ABC] вернет ABC
  • dummy.random[param1, param2] - возвращает случайное число в диапазоне от param1 до param2, например dummy.random[1,1000000]

Ограничения

Поддержка загружаемых модулей реализована только для платформы Unix. Это означает, что она не работает для агентов Windows.

В некоторых случаях модулю может потребоваться считывать параметры конфигурации, связанные с модулем, из zabbix_agentd.conf. В настоящее время это не поддерживается. Если вашему модулю нужно использовать какие-либо параметры конфигурации, вам, вероятно, следует реализовать разбор отдельного файла конфигурации, специфичного для модуля.