Este es un tutorial paso a paso sobre cómo crear un plugin cargable simple para el agente Zabbix 2.
También puede utilizar el repositorio de ejemplo como plantilla o guía para crear sus propios plugins.
Este tutorial demuestra cómo crear un nuevo plugin cargable MyIP. El plugin implementará una única clave de métrica, myip, que devuelve la dirección IP externa del equipo donde se está ejecutando el agente Zabbix 2.
go.mod
en el directorio del plugin para rastrear las dependencias del plugin:golang.zabbix.com/sdk
):Reemplace $LATEST_COMMIT_HASH
con el último hash de commit HEAD
del repositorio de golang.zabbix.com/sdk
en la rama de lanzamiento correspondiente. Por ejemplo:
Tenga en cuenta que actualmente no se admite la gestión de versiones de golang.zabbix.com/sdk
, pero esto puede cambiar en el futuro.
Las dependencias adicionales se pueden instalar según sea necesario usando go get
.
main.go
para el código fuente del plugin:Ahora la configuración inicial está completa y el plugin está listo para el desarrollo.
El módulo golang.zabbix.com/sdk
, instalado en el paso anterior, proporciona el marco necesario para el desarrollo de plugins y garantiza que todos los plugins tengan una estructura coherente.
Comience definiendo el flujo principal de ejecución del plugin. Añada el siguiente código a main.go
:
package main
func main() {
err := run()
if err != nil {
panic(err)
}
}
func run() error {
return nil
}
Esto establece el flujo básico de ejecución para el plugin. La función run contendrá más adelante la lógica principal del plugin.
Un plugin de Zabbix agent 2 debe estar representado por una estructura que implemente interfaces del paquete golang.zabbix.com/sdk/plugin
:
Puede implementar estas interfaces usted mismo o utilizar las predeterminadas proporcionadas por el Zabbix Go SDK, modificándolas según sea necesario. Este tutorial utiliza las implementaciones predeterminadas.
Ahora, importe el paquete plugin y cree una estructura myIP
que incluya la estructura plugin.Base
:
La estructura myIP actualmente cumple con la interfaz Accessor. Más adelante en el tutorial se añadirá un método para implementar una de las interfaces funcionales del plugin, el Exporter
.
Tu plugin necesita las claves de las métricas para recopilar datos y proporcionarlos al servidor o proxy de Zabbix.
plugin.RegisterMetrics()
dentro de la función run()
:func run() error {
p := &myIP{}
// Registrar la clave de la métrica `myip`.
err := plugin.RegisterMetrics(
p,
"MyIP", // Nombre del plugin
"myip", // Nombre de la clave de la métrica
"Devuelve la dirección IP del equipo.", // Descripción de la clave de la métrica
)
if err != nil {
return errs.Wrap(err, "no se pudo registrar las métricas")
}
return nil
}
Para registrar varias claves de métricas, repite los parámetros nombre de la métrica y descripción para cada métrica. Por ejemplo:
plugin.RegisterMetrics(&impl, "Myip", "metric.one", "Descripción de la métrica uno.", "metric.two", "Descripción de la métrica dos.")
El handler facilita la comunicación entre el agente y el plugin.
run()
agregue el código para crear y configurar un handler:func run() error {
p := &myIP{}
// Registrar la clave de la métrica `myip`.
err := plugin.RegisterMetrics(
p,
"MyIP", // Nombre del plugin
"myip", // Nombre de la clave de la métrica
"Devuelve la dirección IP del equipo.", // Descripción de la clave de la métrica
)
if err != nil {
return errs.Wrap(err, "falló el registro de métricas")
}
// Crear un nuevo handler.
h, err := container.NewHandler("MyIP") // Nombre del plugin
if err != nil {
return errs.Wrap(err, "falló la creación de un nuevo handler")
}
// Configurar el registro para reenviar los logs del plugin al agente.
// Disponible a través de p.Logger.Infof, p.Logger.Debugf, etc.
p.Logger = h
// Iniciar la ejecución del plugin.
// Se bloquea hasta que se recibe una solicitud de terminación del agente.
err = h.Execute()
if err != nil {
return errs.Wrap(err, "falló la ejecución del handler del plugin")
}
return nil
}
La recopilación de datos se realiza a través de la interfaz Exporter, que describe el método Export
:
func Export(
key string, // La clave de la métrica a recopilar.
params []string, // Argumentos pasados a la clave de la métrica (`myip[arg1, arg2]`).
context ContextProvider // Metadatos sobre la recopilación de datos de la clave de la métrica.
) (any, error)
import (
"io"
"net/http"
)
Export
para la estructura myIP
:func (p *myIP) Export(
key string, params []string, context plugin.ContextProvider,
) (any, error) {
// El plugin puede usar diferentes lógicas de recopilación de datos según el parámetro `key`.
// Esta implementación solo verifica que la `key` proporcionada sea compatible.
if key != "myip" {
return nil, errs.Errorf("clave de métrica desconocida %q", key)
}
// El registro se enviará al registro del agente 2.
p.Infof(
"se recibió una solicitud para manejar la clave %q con %d parámetros",
key,
len(params),
)
// Recopile los datos y devuélvalos.
resp, err := http.Get("https://api.ipify.org")
if err != nil {
return nil, errs.Wrap(err, "no se pudo obtener la dirección IP")
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errs.Wrap(err, "no se pudo leer el cuerpo de la respuesta")
}
return string(body), nil
}
Esto debería crear un ejecutable myip
en el directorio actual.
echo "Plugins.MyIP.System.Path=$PATH_TO_THE_MYIP_PLUGIN_EXECUTABLE" > /etc/zabbix_agent2.d/plugins.d/myip.conf
Reemplace $PATH_TO_THE_MYIP_PLUGIN_EXECUTABLE
con la ruta al myip
creado en el paso 5.
El nombre del plugin en el parámetro de configuración (MyIP en este tutorial) debe coincidir con el nombre del plugin definido en la función plugin.RegisterMetrics().
myip
, ejecute:La salida debe contener una dirección IP externa de su equipo y verse similar a esto:
myip [s|192.0.2.0]
Con esto, ha creado un plugin simple y cargable para el agente Zabbix 2. ¡Felicidades!
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{}
// Registrar la clave de métrica `myip`.
err := plugin.RegisterMetrics(
p,
"MyIP", // Nombre del plugin
"myip", // Nombre de la clave de métrica
"Devuelve la dirección IP del equipo.", // Descripción de la clave de métrica
)
if err != nil {
return errs.Wrap(err, "no se pudo registrar la métrica")
}
// Crear un nuevo handler.
h, err := container.NewHandler("MyIP") // Nombre del plugin
if err != nil {
return errs.Wrap(err, "no se pudo crear el nuevo handler")
}
// Configurar el registro para reenviar los logs del plugin al agente.
// Disponible a través de p.Logger.Infof, p.Logger.Debugf, etc.
p.Logger = h
// Iniciar la ejecución del plugin.
// Bloquea hasta que se recibe una solicitud de terminación del agente.
err = h.Execute()
if err != nil {
return errs.Wrap(err, "no se pudo ejecutar el handler del plugin")
}
return nil
}
func (p *myIP) Export(
key string, params []string, context plugin.ContextProvider,
) (any, error) {
// El plugin puede usar diferentes lógicas de recopilación de datos según el parámetro `key`.
// Esta implementación solo verifica que la `key` proporcionada sea compatible.
if key != "myip" {
return nil, errs.Errorf("clave de métrica desconocida %q", key)
}
// El log se reenviará al log del agente 2.
p.Infof(
"se recibió una solicitud para manejar la clave %q con %d parámetros",
key,
len(params),
)
// Recopilar los datos y devolverlos.
resp, err := http.Get("https://api.ipify.org")
if err != nil {
return nil, errs.Wrap(err, "no se pudo obtener la dirección IP")
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errs.Wrap(err, "no se pudo leer el cuerpo de la respuesta")
}
return string(body), nil
}