Создание плагина (руководство)
Это пошаговое руководство по созданию простого загружаемого плагина для Zabbix Agent 2.
Вы также можете использовать репозиторий примеров в качестве шаблона или руководства для создания собственных плагинов.
Что вы создадите
В этом руководстве показано, как создать новый загружаемый плагин MyIP. Плагин будет реализовывать один ключ элемента, myip, который возвращает внешний IP-адрес хоста, на котором запущен Zabbix агент 2.
Шаг 1: Настройка
- Плагин — это стандартный модуль Go.
Начните с инициализации файла go.mod в каталоге плагина для отслеживания зависимостей плагина:
cd path/to/plugins/myip # Перейдите в каталог вашего плагина
go mod init myip
- Установите обязательную зависимость Zabbix Go SDK (
golang.zabbix.com/sdk):
go get golang.zabbix.com/sdk@$LATEST_COMMIT_HASH
Замените $LATEST_COMMIT_HASH на последний хеш коммита HEAD из golang.zabbix.com/sdk репозитория в соответствующей ветке релиза.
Например:
go get golang.zabbix.com/sdk@af85407
Обратите внимание, что версионирование golang.zabbix.com/sdk в настоящее время не поддерживается, но это может измениться в будущем.
При необходимости дополнительные зависимости можно установить с помощью go get.
- Создайте пустой файл
main.goдля исходного кода плагина:
touch main.go
Теперь начальная настройка завершена, и плагин готов к разработке.
Шаг 2: Структура плагина
Модуль golang.zabbix.com/sdk, установленный на предыдущем шаге, предоставляет необходимую основу для разработки плагинов и обеспечивает единообразную структуру всех плагинов.
- Настройте базовый поток выполнения.
Начните с определения основного потока выполнения плагина. Добавьте следующий код в main.go:
package main
func main() {
err := run()
if err != nil {
panic(err)
}
}
func run() error {
return nil
}
Это задает базовый поток выполнения для плагина. Функция run позже будет содержать основную логику плагина.
- Изучите интерфейсы плагина.
Плагин агента Zabbix 2 должен быть представлен структурой, которая реализует интерфейсы из пакета golang.zabbix.com/sdk/plugin:
- Accessor - определяет основные методы, которые должны реализовывать все плагины, например задание имени плагина и обработку тайм-аутов ключей элементов данных.
- Один или несколько из следующих функциональных интерфейсов плагина:
- Exporter - выполняет опрос и возвращает значение (или значения), ничего или ошибку; часто используется вместе с интерфейсом Collector.
- Collector - управляет периодическим сбором данных.
- Runner - определяет процедуры запуска и завершения работы плагина.
- Watcher - позволяет реализовать независимый опрос метрик, обходя внутренний планировщик агента; полезно для мониторинга на основе ловушек или событий.
- Configurator - определяет, как плагин читает и применяет свои параметры конфигурации.
Вы можете реализовать эти интерфейсы самостоятельно или использовать стандартные, предоставляемые Zabbix Go SDK, при необходимости изменяя их. В этом руководстве используются стандартные реализации.
- Создайте структуру плагина.
Теперь импортируйте пакет plugin и создайте структуру myIP, которая включает структуру plugin.Base:
import "golang.zabbix.com/sdk/plugin"
type myIP struct {
plugin.Base
}
Структура myIP в настоящее время удовлетворяет интерфейсу Accessor.
Метод для реализации одного из функциональных интерфейсов плагина, Exporter, будет добавлен позже в руководстве.
Шаг 3: Определите ключи элементов данных
Вашему плагину нужны ключи элементов данных, чтобы собирать данные и передавать их серверу Zabbix или прокси.
- Импортируйте пакет errs для обработки ошибок:
import "golang.zabbix.com/sdk/errs"
- Зарегистрируйте ключи элементов данных с помощью функции
plugin.RegisterMetrics()внутри функцииrun():
func run() error {
p := &myIP{}
// Register the `myip` item key.
err := plugin.RegisterMetrics(
p,
"MyIP", // Plugin name
"myip", // Item key name
"Returns the host's IP address.", // Item key description
)
if err != nil {
return errs.Wrap(err, "failed to register metrics")
}
return nil
}
Чтобы зарегистрировать несколько ключей элементов данных, повторите параметры metric name и description для каждой метрики. Например:
plugin.RegisterMetrics(&impl, "Myip", "metric.one", "Metric one description.", "metric.two", "Metric two description.")
Шаг 4: Настройка обработчика
Обработчик обеспечивает связь между агентом и плагином.
- Импортируйте пакет container:
import "golang.zabbix.com/sdk/plugin/container"
- Внутри функции
run()добавьте код для создания и настройки обработчика:
func run() error {
p := &myIP{}
// Register the `myip` item key.
err := plugin.RegisterMetrics(
p,
"MyIP", // Plugin name
"myip", // Item key name
"Returns the host's IP address.", // Item key description
)
if err != nil {
return errs.Wrap(err, "failed to register metrics")
}
// Create a new handler.
h, err := container.NewHandler("MyIP") // Plugin name
if err != nil {
return errs.Wrap(err, "failed to create new handler")
}
// Setup logging to forward logs from the plugin to the agent.
// Available via p.Logger.Infof, p.Logger.Debugf, etc.
p.Logger = h
// Start plugin execution.
// Blocks until a termination request is received from the agent.
err = h.Execute()
if err != nil {
return errs.Wrap(err, "failed to execute plugin handler")
}
return nil
}
Шаг 5: Реализация сбора данных
Сбор данных выполняется через интерфейс Exporter, который описывает метод Export:
func Export(
key string, // Ключ элемента данных для сбора.
params []string, // Аргументы, передаваемые ключу элемента данных (`myip[arg1, arg2]`).
context ContextProvider // Метаданные о сборе данных по ключу элемента данных.
) (any, error)
- Импортируйте необходимые пакеты для HTTP-запросов и чтения ответа:
import (
"io"
"net/http"
)
- Реализуйте метод
Exportдля структурыmyIP:
func (p *myIP) Export(
key string, params []string, context plugin.ContextProvider,
) (any, error) {
// Плагин может использовать разную логику сбора данных в зависимости от параметра `key`.
// Эта реализация только проверяет, что переданный `key` поддерживается.
if key != "myip" {
return nil, errs.Errorf("unknown item key %q", key)
}
// Журнал будет перенаправлен в журнал агента 2.
p.Infof(
"received request to handle %q key with %d parameters",
key,
len(params),
)
// Соберите данные и верните их.
resp, err := http.Get("https://api.ipify.org")
if err != nil {
return nil, errs.Wrap(err, "failed to get IP address")
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errs.Wrap(err, "failed to read response body")
}
return string(body), nil
}
Шаг 6: Сборка и настройка плагина
- Чтобы собрать плагин, выполните:
go mod tidy
go build
Это должно создать исполняемый файл myip в текущем каталоге.
- Настройте агент Zabbix 2 для использования плагина:
echo "Plugins.MyIP.System.Path=$PATH_TO_THE_MYIP_PLUGIN_EXECUTABLE" > /etc/zabbix_agent2.d/plugins.d/myip.conf
Замените $PATH_TO_THE_MYIP_PLUGIN_EXECUTABLE на путь к myip, созданному на шаге 5.
Имя плагина в имени параметра конфигурации (MyIP в этом руководстве) должно совпадать с именем плагина, определенным в функции plugin.RegisterMetrics().
- Чтобы протестировать плагин и его элемент данных
myip, выполните:
zabbix_agent2 -c /etc/zabbix_agent2.conf -t myip
Вывод должен содержать внешний IP-адрес вашего узла сети и выглядеть примерно так:
myip [s|192.0.2.1]
На этом вы создали простой загружаемый плагин для агента Zabbix 2. Поздравляем!
Полный исходный код
package main
import (
"io"
"net/http"
"golang.zabbix.com/sdk/errs"
"golang.zabbix.com/sdk/plugin"
"golang.zabbix.com/sdk/plugin/container"
)
var _ plugin.Exporter = (*myIP)(nil)
type myIP struct {
plugin.Base
}
func main() {
err := run()
if err != nil {
panic(err)
}
}
func run() error {
p := &myIP{}
// Зарегистрируйте ключ элемента данных `myip`.
err := plugin.RegisterMetrics(
p,
"MyIP", // Имя плагина
"myip", // Имя ключа элемента данных
"Возвращает IP-адрес узла сети.", // Описание ключа элемента данных
)
if err != nil {
return errs.Wrap(err, "не удалось зарегистрировать метрики")
}
// Создайте новый обработчик.
h, err := container.NewHandler("MyIP") // Имя плагина
if err != nil {
return errs.Wrap(err, "не удалось создать новый обработчик")
}
// Настройте журналирование для перенаправления журналов из плагина в агент.
// Доступно через p.Logger.Infof, p.Logger.Debugf и т. д.
p.Logger = h
// Запустите выполнение плагина.
// Блокируется до получения запроса на завершение от агента.
err = h.Execute()
if err != nil {
return errs.Wrap(err, "не удалось выполнить обработчик плагина")
}
return nil
}
func (p *myIP) Export(
key string, params []string, context plugin.ContextProvider,
) (any, error) {
// Плагин может использовать разную логику сбора данных в зависимости от параметра `key`.
// Эта реализация только проверяет, что указанный `key` поддерживается.
if key != "myip" {
return nil, errs.Errorf("unknown item key %q", key)
}
// Журнал будет перенаправлен в журнал агента 2.
p.Infof(
"получен запрос на обработку ключа %q с %d параметрами",
key,
len(params),
)
// Соберите данные и верните их.
resp, err := http.Get("https://api.ipify.org")
if err != nil {
return nil, errs.Wrap(err, "не удалось получить IP-адрес")
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errs.Wrap(err, "не удалось прочитать тело ответа")
}
return string(body), nil
}