Направите додатак (водач)

Ово је корак-по-корак водич о томе како да направите једноставан додатак који се може учитати за Zabbix агент 2.

Такође можете користити пример репозиторијума као шаблон или водич за креирање сопствених додатака.

Шта ћете креирати

Овај туторијал показује како да креирате нови учитавајући додатак MyIP. Додатак ће имплементирати један кључ ставке, myip, који враћа екстерну IP адресу домаћина на којем се покреће Zabbix агент 2.

Корак 1: Подешавање

  1. Додатак је стандардни Go модул. Почните иницијализацијом датотеке go.mod у директоријуму додатка да бисте пратили зависности додатка:
cd path/to/plugins/myip # Пребаците се на директоријум вашег додатка
       go mod init myip
  1. Инсталирајте обавезну зависност 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.

  1. Направите празну датотеку main.go за изворни код додатка:
touch main.go

Сада је почетно подешавање завршено и додатак је спреман за развој.

Корак 2: Структура додатка

Модул golang.zabbix.com/sdk, инсталиран у претходном кораку, пружа неопходан оквир за развој додатака и осигурава да сви додатци имају конзистентну структуру.

  1. Подесите основни ток извршавања.

Почните дефинисањем главног тока извршавања додатка. Додајте следећи код у main.go:

package main
       
       func main() {
           err := run()
          if err != nil {
            panic(err)
          }
       }
       
       func run() error {
          return nil
       }

Овим се успоставља основни ток извршавања за додатак.Функција run ће касније садржати основну логику додатка.

  1. Истражите интерфејсе додатака.

Додатак Zabbix агента 2 биће представљен структуром која имплементира интерфејсе из пакета golang.zabbix.com/sdk/plugin:

  • Accessor - дефинише основне методе које сви додаци морају да имплементирају, као што су подешавање имена додатка и руковање временским ограничењима кључа ставке.
  • Један или више следећих функционалних интерфејса додатка:
    • Exporter - врши анкету и враћа вредност (или вредности), ништа или грешку; често се користи уз интерфејс Collector.
    • Collector - управља периодичним прикупљањем података.- Runner - дефинише процедуре покретања и гашења додатка.
    • Watcher - омогућава имплементацију независног анкетирања метрика, заобилазећи интерни распоређивач агента; корисно за праћење засновано на замкама или догађајима.
    • Configurator - дефинише како додатак чита и примењује своја подешавања конфигурације.

Можете сами имплементирати ове интерфејсе или користити подразумеване које пружа Zabbix Go SDK, модификујући их по потреби. Овај туторијал користи подразумеване имплементације.

  1. Направите структуру додатка.

Сада увезите пакет додатак и креирајте структуру myIP која уграђује структуру plugin.Base:

import "golang.zabbix.com/sdk/plugin"
       
       type myIP struct {
          plugin.Base
       }

Структура myIP тренутно задовољава интерфејс Accessor. Метод за имплементацију једног од функционалних интерфејса додатка, Exporter, биће додат касније у туторијалу.

Корак 3:

Дефинисање кључева ставкиВаш додатак треба кључеве ставки да би прикупљао податке и пружао их Zabbix серверу или проксију.

  1. Увезите errs пакет за обраду грешака:
import "golang.zabbix.com/sdk/errs"
  1. Региструјте кључеве ставки користећи функцију plugin.RegisterMetrics() унутар функције run():
func run() error {
          p := &myIP{}
       
          // Региструјте `myip` ставку кључа.
          err := plugin.RegisterMetrics(
            p,
            "MyIP",// Назив додатка
            "myip",// Назив кључа ставке
            "Враћа IP адресу хоста.", // Опис кључа ставке
          )
          if err != nil {
            return errs.Wrap(err, "неуспешно регистровање метрика")
          }
       
          return nil
       }

Да бисте регистровали неколико кључева ставки, поновите параметре назив метрике и опис за сваку метрику. На пример:

plugin.RegisterMetrics(&impl, "Myip", "metric.one", "Опис метрике један.", "metric.two", "Опис метрике два.")

Корак 4: Подесите програм за управљање програмом

Руковалац олакшава комуникацију између агента и додатка.

  1. Увезите пакет контејнер:
import "golang.zabbix.com/sdk/plugin/container"
  1. Укључите функцију run() и додајте код за креирање и подешавање руковаоца:
func run() error {
            p := &myIP{}
       
            // Региструјте ставку `myip` key.
            err := plugin.RegisterMetrics(
                   p,
                   "MyIP",// Назив додатка"
                   myip",// Назив кључа ставке"
                   Враћа IP адресу домаћина.", // Опис кључа ставке
          )
            if err != nil {
                   return errs.Wrap(err, "неуспешно регистровање метрике")
            }
       
            // Креирајте нови handler.
            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
       }

Корак 5: Имплементација прикупљања података

Прикупљање података се врши путем интерфејса за извоз, који описује метод Export:

func Export(
            key string,// Кључ ставке који треба прикупити.
            params []string,// Аргументи који се прослеђују кључу ставке (`myip[arg1, arg2]`).
            context ContextProvider // Метаподаци о прикупљању података о кључу ставке.
       ) (any, error)
  1. Увезите потребне пакете за HTTP захтеве и читање одговора:
import (
            "io"
            "net/http"
       )
  1. Имплементирајте метод Export за структуру myIP:
func (p *myIP) Export(
            key string, params []string, context plugin.ContextProvider,
       ) (any, error) {
            // Додатак може да користи различиту логику прикупљања података на основу параметра `key`.
            // Ова имплементација само проверава да ли је дати `key` подржан.
            if key != "myip" {
                   return nil, errs.Errorf("непознати кључ ставке %q", key)
            }
       
            // Лог ће бити прослеђен агенту 2 log.
            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
       }

Корак 6: Направите и конфигуришите додатак

  1. Да бисте направили додатак, покрените:
go mod tidy
       go build

Ово би требало да креира извршну датотеку myip у тренутном директоријуму.

  1. Конфигуришите 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().

  1. Да бисте тестирали додатак и његову ставку myip, покрените:
zabbix_agent2 -c /etc/zabbix_agent2.conf -t myip

Излаз би требало да садржи екстерну IP адресу вашег хоста и да изгледа слично овоме:

myip [s|192.0.2.0]

Овим сте креирали једноставан додатак за 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",   // 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")
            }
       
            // Креирај нови обрађивач
            h, err := container.NewHandler("MyIP") // Plugin name
            if err != nil {
                   return errs.Wrap(err, "failed to create new handler")
            }
            // Подесите евидентирање да бисте прослеђивали логове са додатка агенту.
            // Доступно преко p.Logger.Infof, p.Logger.Debugf, etc.
            p.Logger = h
       
            // Покрените извршавање додатка.
            // Блокира док се не прими захтев за прекид од агента.
            err = h.Execute()
            if err != nil {
                   return errs.Wrap(err, "failed to execute plugin handler")
            }
            return nil
       }
       
       func (p *myIP) Export(
            key string, params []string, context plugin.ContextProvider,
       ) (any, error) {
            // Додатак може да користи различиту логику прикупљања података на основу параметра `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
       }