Создание плагина (руководство)

Это пошаговое руководство по созданию простого загружаемого плагина для Zabbix агента 2.

Что вы создадите

В ходе этого руководства вы добавите новый загружаемый плагин MyIP. Плагин будет реализовывать 1 метрику под названием myip, которая возвращает внешний IP-адрес хоста, на котором работает Zabbix агент 2.

Часть 1: Написание кода на Go

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

  1. Создайте новую директорию myip в /usr/local/zabbix/go/plugins/.

  2. Создайте файл main.go в директории myip и определите имя вашего Go-пакета.

/usr/local/zabbix/go/plugins/myip/main.go

package main

Оставьте файл открытым, чтобы добавить больше строк, как описано в следующих шагах.

  1. Укажите пакеты для импорта. Эти пакеты поддерживают работу плагина.

/usr/local/zabbix/go/plugins/myip/main.go

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "git.zabbix.com/ap/plugin-support/plugin/container"
    "git.zabbix.com/ap/plugin-support/plugin"
)
  1. Определите структуру плагина. Встроенная структура plugin.Base позволяет получить доступ к стандартной функциональности плагина.

/usr/local/zabbix/go/plugins/myip/main.go

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "git.zabbix.com/ap/plugin-support/plugin/container"
    "git.zabbix.com/ap/plugin-support/plugin"
)

type Plugin struct {
    plugin.Base
}

var impl Plugin
  1. Реализуйте интерфейс плагина Export. Интерфейс Export выполняет опрос и возвращает значение.

/usr/local/zabbix/go/plugins/myip/main.go

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "git.zabbix.com/ap/plugin-support/plugin/container"
    "git.zabbix.com/ap/plugin-support/plugin"
)

type Plugin struct {
    plugin.Base
}

var impl Plugin

func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error)
  1. Добавьте логирование. Сообщения журнала будут отображаться в логах Zabbix agent 2. Вы можете использовать одну из доступных функций логирования для плагинов: Critf(), Errf(), Infof(), Warningf(), Debugf(), Tracef().

/usr/local/zabbix/go/plugins/myip/main.go

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "git.zabbix.com/ap/plugin-support/plugin/container"
    "git.zabbix.com/ap/plugin-support/plugin"
)

type Plugin struct {
    plugin.Base
}

var impl Plugin

func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error){
    p.Infof("received request to handle %s key with %d parameters", key, len(params))
}
  1. Реализуйте основную логику плагина. Эта логика получает ответ от указанного URL, читает его, затем возвращает IP-адрес в качестве ответа и закрывает запрос. В случае ошибки при выполнении GET-запроса или чтении ответа возвращается ошибка.

/usr/local/zabbix/go/plugins/myip/main.go

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "git.zabbix.com/ap/plugin-support/plugin/container"
    "git.zabbix.com/ap/plugin-support/plugin"
)

type Plugin struct {
    plugin.Base
}

var impl Plugin

func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error){
    p.Infof("received request to handle %s key with %d parameters", key, len(params))
    resp, err := http.Get("https://api.ipify.org")
    if err != nil {
        return nil, err
    }

    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    return string(body), nil    
}
  1. Зарегистрируйте метрику. Zabbix agent 2 запускает выполнение функции init() при старте. Эта функция вызовет метод plugin.RegisterMetrics(structure, plugin name, metric name, description), чтобы получить данные плагина.

Описание параметров метода plugin.RegisterMetrics:

  • structure - указатель на реализацию плагина; предоставляет доступ к структуре плагина, включая список доступных интерфейсов плагина (например, &impl).
  • name - имя плагина; должно быть уникальным (например, "Myip").
  • metric name - имя метрики (например, "myip"). Это ключ элемента, используемый для сбора данных из плагина.
  • description - описание метрики; должно начинаться с заглавной буквы и заканчиваться точкой (например, "Возвращает внешний IP-адрес хоста, на котором работает агент.").

Для регистрации нескольких метрик повторите параметры metric name и description для каждой метрики. Например: plugin.RegisterMetrics(&impl, "Myip", "metric.one", "Описание метрики один.", "metric.two", "Описание метрики два.")

/usr/local/zabbix/go/plugins/myip/main.go

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "git.zabbix.com/ap/plugin-support/plugin/container"
    "git.zabbix.com/ap/plugin-support/plugin"
)

type Plugin struct {
    plugin.Base
}

var impl Plugin

func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error){
    p.Infof("received request to handle %s key with %d parameters", key, len(params))
    resp, err := http.Get("https://api.ipify.org")
    if err != nil {
        return nil, err
    }

    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    return string(body), nil    
}

func init() {
    plugin.RegisterMetrics(&impl, "Myip", "myip", "Return the external IP address of the host where agent is running.")
}
  1. Определите функцию main(), которая создаст новый экземпляр обработчика плагина, назначит его для использования логирования плагином, а затем выполнит обработчик плагина.

Определение функции main() является обязательным.

/usr/local/zabbix/go/plugins/myip/main.go

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "git.zabbix.com/ap/plugin-support/plugin/container"
    "git.zabbix.com/ap/plugin-support/plugin"
)

type Plugin struct {
    plugin.Base
}

var impl Plugin

func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error){
    p.Infof("received request to handle %s key with %d parameters", key, len(params))
    resp, err := http.Get("https://api.ipify.org")
    if err != nil {
        return nil, err
    }

    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    return string(body), nil    
}

func init() {
    plugin.RegisterMetrics(&impl, "Myip", "myip", "Return the external IP address of the host where agent is running.")
}

func main() {
    h, err := container.NewHandler(impl.Name())
    if err != nil {
        panic(fmt.Sprintf("failed to create plugin handler %s", err.Error()))
    }
    impl.Logger = &h

    err = h.Execute()
    if err != nil {
        panic(fmt.Sprintf("failed to execute plugin handler %s", err.Error()))
    }
}

Часть 2: Сборка плагина

В этом разделе вы узнаете, как скомпилировать плагин.

  1. Чтобы создать Go-файлы для обработки зависимостей и автоматически загрузить зависимости, выполните этот bash-скрипт из командной строки.
go mod init myip
GOPROXY=direct go get git.zabbix.com/ap/plugin-support/plugin@branchname
go mod tidy
go build

Убедитесь, что указали правильное название ветки, то есть замените branchname (см. строку 2) на одно из следующих:

  • release/* - для стабильной релизной ветки, где "*" — это версия релиза (например, 6.4)
  • master - для ветки master -<хэш коммита> - для конкретной версии коммита (используйте определенный хэш коммита)

Вывод должен быть примерно таким:

go: creating new go.mod: module myip
go: to add module requirements and sums:
    go mod tidy
go: finding module for package git.zabbix.com/ap/plugin-support/plugin/container
go: finding module for package git.zabbix.com/ap/plugin-support/plugin
go: found git.zabbix.com/ap/plugin-support/plugin in git.zabbix.com/ap/plugin-support v0.0.0-20220608100211-35b8bffd7ad0
go: found git.zabbix.com/ap/plugin-support/plugin/container in git.zabbix.com/ap/plugin-support v0.0.0-20220608100211-35b8bffd7ad0
  1. Создайте исполняемый файл myip для загружаемого плагина.

  2. Укажите путь к файлу конфигурации плагина в параметре Plugins.Myip.System.Path файла конфигурации Zabbix agent 2.

Название плагина в параметре конфигурации (в этом руководстве - Myip) должно совпадать с именем плагина, определенным в функции plugin.RegisterMetrics().

echo 'Plugins.Myip.System.Path=/usr/local/zabbix/go/plugins/myip/myip' > /etc/zabbix_agent2.d/plugins.d/myip.conf
  1. Проверьте метрику:
zabbix_agent2 -t myip

Ответ должен содержать внешний IP-адрес вашего узла сети.

В случае ошибки проверьте, есть ли у пользователя zabbix права на доступ к директории /usr/local/zabbix/go/plugins/myip.