Ово је корак-по-корак водич о томе како да направите једноставан додатак који се може учитати за Zabbix агент 2.
Такође можете користити пример репозиторијума као шаблон или водич за креирање сопствених додатака.
Овај туторијал показује како да креирате нови учитавајући додатак MyIP. Додатак ће имплементирати један кључ ставке, myip, који враћа екстерну IP адресу домаћина на којем ради Zabbix агент 2.
go.mod
у директоријуму додатка да бисте пратили зависности додатка:golang.zabbix.com/sdk
):Замените $LATEST_COMMIT_HASH
са најновијим HEAD
хешем коммита из golang.zabbix.com/sdk
репозиторијума у одговарајућој грани за издање. На пример:
Имајте на уму да верзирање golang.zabbix.com/sdk
тренутно није подржано, али се то може променити у будућности.
Додатне зависности се могу инсталирати по потреби помоћу go get
.
main.go
за изворни код додатка:Сада је почетно подешавање завршено и додатак је спреман за развој.
Модул 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 - дефинише основне методе које сви додаци морају да имплементирају, као што су подешавање имена додатка и руковање временским ограничењима кључа ставке.
Један или више следећих функционалних интерфејса додатка:
Можете сами имплементирати ове интерфејсе или користити подразумеване које пружа Zabbix Go SDK, модификујући их по потреби. Овај туторијал користи подразумеване имплементације.
Сада, увезите пакет додатак и креирајте структуру myIP
која уграђује структуру plugin.Base
:
Структура myIP тренутно задовољава интерфејс Accessor. Метод за имплементацију једног од функционалних интерфејса додатка, Exporter
, биће додат касније у туторијалу.
Your plugin needs the item keys to collect data and provide it to Zabbix server or proxy.
plugin.RegisterMetrics()
function within the run()
function: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
}
To register several item keys, repeat the parameters metric name and description for each metric. For example:
plugin.RegisterMetrics(&impl, "Myip", "metric.one", "Metric one description.", "metric.two", "Metric two description.")
The handler facilitates communication between the agent and the plugin.
run()
function add code to create and set up a handler: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
}
Data collection is done via the Exporter interface, which describes the Export
method:
func Export(
key string, // The item key to collect.
params []string, // Arguments passed to the item key (`myip[arg1, arg2]`).
context ContextProvider // Metadata about the item key data collection.
) (any, error)
import (
"io"
"net/http"
)
Export
method for the myIP
struct:func (p *myIP) Export(
key string, params []string, context plugin.ContextProvider,
) (any, error) {
// The plugin can use different data collection logic based on the `key` parameter.
// This implementation only verifies that the provided `key` is supported.
if key != "myip" {
return nil, errs.Errorf("unknown item key %q", key)
}
// The log will get forwarded to the agent 2 log.
p.Infof(
"received request to handle %q key with %d parameters",
key,
len(params),
)
// Collect the data and return it.
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
}
This should create an executable myip
in the current directory.
echo "Plugins.MyIP.System.Path=$PATH_TO_THE_MYIP_PLUGIN_EXECUTABLE" > /etc/zabbix_agent2.d/plugins.d/myip.conf
Replace $PATH_TO_THE_MYIP_PLUGIN_EXECUTABLE
with the path to the myip
created in step 5.
The plugin name in the configuration parameter name (MyIP in this tutorial) must match the plugin name defined in the plugin.RegisterMetrics() function.
myip
item, run:The output should contain an external IP address of your host and look similar to this:
myip [s|192.0.2.0]
With that, you have created a simple loadable plugin for Zabbix agent 2. Congrats!
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{}
// 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 from the agent is received.
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) {
// The plugin can use different data collection logic based on the `key` parameter.
// This implementation only verifies that the provided `key` is supported.
if key != "myip" {
return nil, errs.Errorf("unknown item key %q", key)
}
// The log will get forwarded to the agent 2 log.
p.Infof(
"received request to handle %q key with %d parameters",
key,
len(params),
)
// Collect the data and return it.
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
}