Este é um tutorial passo a passo sobre como criar um plugin carregável simples para o agente Zabbix 2.
Você também pode usar o repositório de exemplo como modelo ou guia para criar seus próprios plugins.
Durante este tutorial, você adicionará um novo plug-in carregável MyIP. O plug-in implementará uma métrica chamada myip, que retorna o endereço IP externo do host em que o Zabbix Agent 2 está sendo executado.
go.mod no diretório do plugin para rastrear as dependências do plugin:golang.zabbix.com/sdk):Substitua $LATEST_COMMIT_HASH pelo hash de commit HEAD mais recente do golang.zabbix.com/sdk repositório na ramificação de lançamento apropriada.
Por exemplo:
Observe que o versionamento golang.zabbix.com/sdk não é suportado atualmente, mas isso pode mudar no futuro.
Dependências adicionais podem ser instaladas conforme necessário usando go get.
main.go vazio para o código-fonte do plugin:Agora a configuração inicial está concluída e o plugin está pronto para desenvolvimento.
O módulo golang.zabbix.com/sdk, instalado na etapa anterior, fornece a estrutura necessária para o desenvolvimento de plugins e garante que todos tenham uma estrutura consistente.
Comece definindo o fluxo de execução principal do plugin. Adicione o seguinte código a main.go:
package main
func main() {
err := run()
if err != nil {
panic(err)
}
}
func run() error {
return nil
}Isso estabelece o fluxo de execução básico para o plugin. A função run conterá posteriormente a lógica central do plugin.
Um plugin do agente Zabbix 2 deve ser representado por uma estrutura que implementa interfaces do pacote golang.zabbix.com/sdk/plugin:
Você pode implementar essas interfaces você mesmo ou usar as interfaces padrão fornecidas pelo Zabbix Go SDK, modificando-as conforme necessário. Este tutorial usa as implementações padrão.
Agora, importe o pacote plugin e crie uma estrutura myIP que incorpore a estrutura plugin.Base:
A estrutura myIP atualmente atende à interface Accessor. Um método para implementar uma das interfaces funcionais do plugin, o Exporter, será adicionado posteriormente neste tutorial.
Seu plugin precisa das chaves de item para coletar dados e fornecê-los ao servidor ou proxy Zabbix.
plugin.RegisterMetrics() dentro da função run():func run() error {
p := &myIP{}
// Registre a chave de item `myip`.
err := plugin.RegisterMetrics(
p,
"MyIP", // Nome do plugin
"myip", // Nome da chave do item
"Retorna o endereço IP do host.", // Descrição da chave do item
)
if err != nil {
return errs.Wrap(err, "falha ao registrar métricas")
}
return nil
}Para registrar várias chaves de item, repita os parâmetros nome da métrica e descrição para cada métrica. Por exemplo:
plugin.RegisterMetrics(&impl, "Myip", "metric.one", "Descrição da métrica um.", "metric.two", "Descrição da métrica dois.")O manipulador facilita a comunicação entre o agente e o plugin.
run() para criar e configurar um manipulador:func run() error {
p := &myIP{}
// Registre a chave de item `myip`.
err := plugin.RegisterMetrics(
p,
"MyIP", // Nome do plugin
"myip", // Nome da chave do item
"Retorna o endereço IP do host.", // Descrição da chave do item
)
if err != nil {
return errs.Wrap(err, "falha ao registrar métricas")
}
// Crie um novo manipulador.
h, err := container.NewHandler("MyIP") // Nome do plugin
if err != nil {
return errs.Wrap(err, "falha ao criar novo manipulador")
}
// Configura o registro para encaminhar logs do plugin para o agente.
// Disponível via p.Logger.Infof, p.Logger.Debugf, etc.
p.Logger = h
// Inicia a execução do plugin.
// Bloqueia até que uma solicitação de término seja recebida do agente.
err = h.Execute()
if err != nil {
return errs.Wrap(err, "falha ao executar o manipulador do plugin")
}
return nil
}A coleta de dados é feita por meio da interface Exporter, que descreve o método Export:
func Export(
key string, // A chave do item a ser coletada.
params []string, // Argumentos passados para a chave do item (`myip[arg1, arg2]`).
context ContextProvider // Metadados sobre a coleta de dados da chave do item.
) (any, error)import(
"io"
"net/http"
)
Export para a estrutura myIP:func (p *myIP) Export(
key string, params []string, context plugin.ContextProvider,
) (any, error) {
// O plugin pode usar diferentes lógicas de coleta de dados com base no parâmetro `key`.
// Esta implementação apenas verifica se a `chave` fornecida é suportada.
if key != "myip" {
return nil, errs.Errorf("chave de item desconhecida %q", key)
}
// O log será encaminhado para o log do agente 2.
p.Infof(
"solicitação recebida para manipular a chave %q com %d parâmetros",
key,
len(params),
)
// Coleta os dados e os retorna.
resp, err := http.Get("https://api.ipify.org")
if err != nil {
return nil, errs.Wrap(err, "falha ao obter o endereço IP")
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errs.Wrap(err, "falha ao ler o corpo da resposta")
}
return string(body), nil
}Isso deve criar um executável myip no diretório atual.
echo "Plugins.MyIP.System.Path=$PATH_TO_THE_MYIP_PLUGIN_EXECUTABLE" > /etc/zabbix_agent2.d/plugins.d/myip.confSubstitua $PATH_TO_THE_MYIP_PLUGIN_EXECUTABLE pelo caminho para o myip criado na etapa 5.
O nome do plugin no parâmetro de configuração name (MyIP neste tutorial) deve corresponder ao nome do plugin definido na função plugin.RegisterMetrics().
myip, execute:A saída deve conter um endereço IP externo do seu host e ser semelhante a este:
myip [s|192.0.2.0]
Com isso, você criou um plugin carregável simples para o agente Zabbix 2. Parabéns!
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{}
// Registra a chave do item `myip`.
err := plugin.RegisterMetrics(
p,
"MyIP", // Nome do plugin
"myip", // Nome da chave do item
"Retorna o endereço IP do host.", // Descrição da chave do item
)
if err != nil {
return errs.Wrap(err, "falha ao registrar métricas")
}
// Cria um novo manipulador.
h, err := container.NewHandler("MyIP") // Nome do plugin
if err != nil {
return errs.Wrap(err, "falha ao criar novo manipulador")
}
// Configura o registro para encaminhar logs do plugin para o agente.
// Disponível via p.Logger.Infof, p.Logger.Debugf, etc.
p.Logger = h
// Inicia a execução do plugin.
// Bloqueia até que uma solicitação de encerramento do agente seja recebida.
err = h.Execute()
if err != nil {
return errs.Wrap(err, "falha ao executar o manipulador do plugin")
}
return nil
}
func (p *myIP) Export(
key string, params []string, context plugin.ContextProvider,
) (any, error) {
// O plugin pode usar uma lógica de coleta de dados diferente com base no parâmetro `key`.
// Esta implementação verifica apenas se a`key` fornecida é suportada.
if key != "myip" {
return nil, errs.Errorf("unknown item key %q", key)
}
// O log será encaminhado para o log do agente 2.
p.Infof(
"received request to handle %q key with %d parameters",
key,
len(params),
)
// Coleta os dados e os retorna.
resp, err := http.Get("https://api.ipify.org")
if err != nil {
return nil, errs.Wrap(err, "falha ao obter o endereço IP")
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errs.Wrap(err, "falha ao ler o corpo da resposta")
}
return string(body), nil
}