1 Загружаемые модули
Обзор
Загружаемые модули предлагают ориентированный на производительность способ расширения функциональности Zabbix.
Вы можете расширять функциональность Zabbix многими способами, например с помощью пользовательских параметров, внешних проверок и элементов данных агента Zabbix system.run. Все они работают очень хорошо, но имеют один существенный недостаток, а именно fork(). Zabbix должен создавать новый процесс каждый раз, когда обрабатывает пользовательскую метрику, что плохо сказывается на производительности. Обычно это не является большой проблемой, однако может стать серьезной при мониторинге встроенных систем, при большом количестве отслеживаемых параметров или при использовании тяжелых скриптов со сложной логикой либо длительным временем запуска.
Поддержка загружаемых модулей предоставляет способы расширения агента Zabbix, сервера и прокси без ущерба для производительности.
Загружаемый модуль по сути представляет собой разделяемую библиотеку, используемую демоном Zabbix и загружаемую при запуске. Библиотека должна содержать определенные функции, чтобы процесс Zabbix мог определить, что файл действительно является модулем, который можно загрузить и использовать.
Загружаемые модули имеют ряд преимуществ. Очень важны высокая производительность и возможность реализовать любую логику, но, возможно, самым важным преимуществом является возможность разрабатывать, использовать и распространять модули Zabbix. Это способствует беспроблемному сопровождению и помогает проще внедрять новую функциональность независимо от основной кодовой базы Zabbix.
Лицензирование модулей и их распространение в бинарной форме регулируются лицензией AGPL-3.0 (модули динамически связываются с Zabbix во время выполнения и используют заголовочные файлы Zabbix; весь код Zabbix лицензируется по AGPL-3.0 начиная с Zabbix 7.0). Бинарная совместимость со стороны Zabbix не гарантируется.
Стабильность API модулей гарантируется в течение одного цикла релиза Zabbix LTS (Long Term Support). Стабильность API Zabbix не гарантируется (технически из модуля можно вызывать внутренние функции 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);
Эта функция должна возвращать callback-функции, которые сервер Zabbix будет использовать для экспорта истории различных типов данных. Callback-функции предоставляются как поля структуры 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. Подробную информацию о том, как получать данные из AGENT_REQUEST и как задавать данные в AGENT_RESULT, смотрите в примере модуля "dummy" ниже.
Предоставление callback-функций экспорта истории
Экспорт истории через модуль больше не поддерживается Zabbix прокси.
Модуль может определять функции для экспорта данных истории по типам: числовой (float), числовой (unsigned), символьный, текстовый и журнал:
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, а сценарий сборки должен гарантировать, что эти файлы находятся в пути include. Подробности см. в примере модуля "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-функцию, отличную от NULL, то экспорт истории будет включен автоматически.
Тестовый модуль
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: возвращает номер версии интерфейса модуля *
* *
* Return value: ZBX_MODULE_API_VERSION - версия module.h, с которой *
* скомпилирован модуль; чтобы модуль был успешно загружен, *
* Zabbix ДОЛЖЕН быть скомпилирован с той же версией этого *
* заголовочного файла *
* *
******************************************************************************/
int zbx_module_api_version(void)
{
return ZBX_MODULE_API_VERSION;
}
/******************************************************************************
* *
* Function: zbx_module_item_timeout *
* *
* Purpose: установить значение тайм-аута для обработки элементов данных *
* *
* Parameters: timeout - тайм-аут в секундах, 0 - тайм-аут не задан *
* *
******************************************************************************/
void zbx_module_item_timeout(int timeout)
{
item_timeout = timeout;
}
/******************************************************************************
* *
* Function: zbx_module_item_list *
* *
* Purpose: возвращает список ключей элементов данных, поддерживаемых *
* модулем *
* *
* Return value: список ключей элементов данных *
* *
******************************************************************************/
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_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: основная точка входа для обработки элемента данных *
* *
* Parameters: request - структура, содержащая ключ элемента данных и *
* параметры *
* request->key - ключ элемента данных без параметров *
* request->nparam - количество параметров *
* request->params[N-1] - указатели на параметры ключа *
* элемента данных *
* request->types[N-1] - типы параметров ключа элемента данных: *
* REQUEST_PARAMETER_TYPE_UNDEFINED (параметр ключа пуст) *
* REQUEST_PARAMETER_TYPE_ARRAY (массив) *
* REQUEST_PARAMETER_TYPE_STRING (строка в кавычках или без) *
* *
* result - структура, которая будет содержать результат *
* *
* Return value: SYSINFO_RET_FAIL - функция завершилась неудачно, элемент *
* данных будет помечен zabbix как *
* неподдерживаемый *
* SYSINFO_RET_OK - успех *
* *
* Comment: get_rparam(request, N-1) можно использовать для получения *
* указателя на N-й параметр, начиная с 0 (первый параметр). *
* Убедитесь, что он существует, проверив значение request->nparam. *
* Аналогичным образом get_rparam_type(request, N-1) можно *
* использовать для получения типа параметра. *
* *
******************************************************************************/
static int dummy_random(AGENT_REQUEST *request, AGENT_RESULT *result)
{
char *param1, *param2;
int from, to;
if (2 != request->nparam)
{
/* установить необязательное сообщение об ошибке */
SET_MSG_RESULT(result, strdup("Invalid number of parameters."));
return SYSINFO_RET_FAIL;
}
param1 = get_rparam(request, 0);
param2 = get_rparam(request, 1);
/* для простоты строгая проверка параметров и их типов не выполняется */
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: функция вызывается при запуске агента *
* Она должна использоваться для вызова любых процедур *
* инициализации *
* *
* Return value: ZBX_MODULE_OK - успех *
* ZBX_MODULE_FAIL - инициализация модуля завершилась неудачно *
* *
* Comment: модуль не будет загружен в случае ZBX_MODULE_FAIL *
* *
******************************************************************************/
int zbx_module_init(void)
{
/* инициализация для dummy.random */
srand(time(NULL));
return ZBX_MODULE_OK;
}
/******************************************************************************
* *
* Function: zbx_module_uninit *
* *
* Purpose: функция вызывается при остановке агента *
* Она должна использоваться для очистки используемых ресурсов, *
* если таковые имеются *
* *
* Return value: ZBX_MODULE_OK - успех *
* ZBX_MODULE_FAIL - функция завершилась неудачно *
* *
******************************************************************************/
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-функции для сохранения исторических данных типов float, *
* integer, string, text и log соответственно во внешнем хранилище *
* *
* Parameters: history - массив исторических данных *
* history_num - количество элементов в массиве history *
* *
******************************************************************************/
static void dummy_history_float_cb(const ZBX_HISTORY_FLOAT *history, int history_num)
{
int i;
for (i = 0; i < history_num; i++)
{
/* сделать что-либо с 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++)
{
/* сделать что-либо с 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++)
{
/* сделать что-либо с 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++)
{
/* сделать что-либо с 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++)
{
/* сделать что-либо с history[i].itemid, history[i].clock, history[i].ns, history[i].value, ... */
}
}
/******************************************************************************
* *
* Function: zbx_module_history_write_cbs *
* *
* Purpose: возвращает набор функций модуля, которые Zabbix будет вызывать *
* для экспорта различных типов исторических данных *
* *
* Return value: структура с указателями на callback-функции (может быть *
* NULL, если модуль не заинтересован в данных определенных *
* типов) *
* *
******************************************************************************/
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]вернет ABCdummy.random[param1, param2]— возвращает случайное число в диапазоне param1-param2; например,dummy.random[1,1000000]
Ограничения
Поддержка загружаемых модулей реализована только для платформы Unix. Это означает, что она не работает для агентов Windows.
В некоторых случаях модулю может потребоваться чтение связанных с модулем параметров конфигурации из zabbix_agentd.conf. В настоящее время это не поддерживается. Если вашему модулю необходимо использовать какие-либо параметры конфигурации, вам, вероятно, следует реализовать разбор файла конфигурации, специфичного для модуля.