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

Это пошаговое руководство по созданию простого загружаемого плагина для 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.