Spraudņa izveide

Šī lapa ir paredzēta tiem, kurus interesē sava spraudņa (neatkarīga datu vācēja) izstrāde Zabbix aģentam 2.

Pielāgots spraudnis paplašina Zabbix aģenta 2 funkcionalitāti, pārsniedzot nodrošināto iebūvēto spraudņu un ielādējamo spraudņu iespējas.

Katrs spraudnis ir Go pakotne, kas definē struktūru un īsteno vienu vai vairākas saskarnes (Exporter, Configurator, Runner). Papildinformāciju skatiet sadaļās Spraudņu saskarnes un Savienojumu diagramma.

Šī rokasgrāmata palīdzēs izveidot pielāgotu ielādējamu spraudni.

Papildu norādījumus skatiet arī šādās repozitorijās:

Ko jūs izveidosiet

Šī ir soli pa solim apmācība, kā izveidot vienkāršu ielādējamu spraudni ar nosaukumu MyIP. Šis spraudnis ieviesīs vienu vienuma atslēgu (myip), kas atgriež Zabbix aģenta hosta ārējo IP adresi.

1. darbība: Iestatīšana

  1. Spraudnis ir standarta Go modulis. Sāciet ar go.mod faila inicializēšanu spraudņa direktorijā, lai izsekotu spraudņa atkarības:
cd path/to/plugins/myip # Pārslēgties uz jūsu spraudņa direktoriju
go mod init myip
  1. Instalējiet obligāto atkarību Zabbix Go SDK (golang.zabbix.com/sdk):
go get golang.zabbix.com/sdk@$LATEST_COMMIT_HASH

Aizstājiet $LATEST_COMMIT_HASH ar jaunāko HEAD izmaiņu hash no golang.zabbix.com/sdk repozitorija atbilstošajā laidiena zarā. Piemēram:

go get golang.zabbix.com/sdk@af85407

Ņemiet vērā, ka golang.zabbix.com/sdk versiju pārvaldība pašlaik netiek atbalstīta, taču nākotnē tas var mainīties.

Papildu atkarības pēc vajadzības var instalēt, izmantojot go get.

  1. Izveidojiet tukšu main.go failu spraudņa pirmkodam:
touch main.go

Tagad sākotnējā iestatīšana ir pabeigta, un spraudnis ir gatavs izstrādei.

2. darbība: spraudņa struktūra

Iepriekšējā darbībā instalētais modulis golang.zabbix.com/sdk nodrošina nepieciešamo ietvaru spraudņu izstrādei un nodrošina, ka visiem spraudņiem ir konsekventa struktūra.

  1. Iestatiet pamata izpildes plūsmu.

Sāciet, definējot spraudņa galveno izpildes plūsmu. Pievienojiet tālāk norādīto kodu failam main.go:

package main

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

func run() error {
    return nil
}

Tas izveido spraudņa pamata izpildes plūsmu. Funkcija run vēlāk ietvers spraudņa galveno loģiku.

  1. Izpētiet spraudņu saskarnes.

Zabbix aģenta 2 spraudnim ir jābūt attēlotam kā struktūrai, kas implementē saskarnes no pakotnes golang.zabbix.com/sdk/plugin:

  • Accessor - definē būtiskās metodes, kas jāimplementē visiem spraudņiem, piemēram, spraudņa nosaukuma iestatīšanu un vienuma atslēgas taimautu apstrādi.
  • Vienu vai vairākas no tālāk norādītajām funkcionālajām spraudņa saskarnēm:
    • Exporter - veic aptauju un atgriež vērtību (vai vērtības), neko vai kļūdu; bieži tiek izmantots kopā ar Collector saskarni.
    • Collector - pārvalda periodisku datu apkopošanu.
    • Runner - definē spraudņa palaišanas un apturēšanas procedūras.
    • Watcher - nodrošina neatkarīgu metrikas aptauju, apejot aģenta iekšējo plānotāju; noder uz slazdiem vai notikumiem balstītai uzraudzībai.
    • Configurator - definē, kā spraudnis nolasa un piemēro konfigurācijas iestatījumus.

Šīs saskarnes varat implementēt paši vai izmantot Zabbix Go SDK nodrošinātās noklusējuma saskarnes, pēc vajadzības tās modificējot. Šajā pamācībā tiek izmantotas noklusējuma implementācijas.

  1. Izveidojiet spraudņa struktūru.

Tagad importējiet pakotni plugin un izveidojiet struktūru myIP, kas ietver struktūru plugin.Base:

import "golang.zabbix.com/sdk/plugin"

type myIP struct {
    plugin.Base
}

Struktūra myIP pašlaik atbilst saskarnei Accessor. Metode vienas no funkcionālajām spraudņa saskarnēm, Exporter, implementēšanai tiks pievienota vēlāk šajā pamācībā.

3. darbība: Definējiet vienumu atslēgas

Jūsu spraudnim ir nepieciešamas vienumu atslēgas, lai vāktu datus un nodotu tos Zabbix serverim vai starpniekserverim.

  1. Importējiet errs pakotni kļūdu apstrādei:
import "golang.zabbix.com/sdk/errs"
  1. Reģistrējiet vienumu atslēgas, izmantojot funkciju plugin.RegisterMetrics() funkcijā run():
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
}

Lai reģistrētu vairākas vienumu atslēgas, atkārtojiet parametrus metrikas nosaukums un apraksts katrai metrikai.
Piemēram:

plugin.RegisterMetrics(&impl, "Myip", "metric.one", "Metric one description.", "metric.two", "Metric two description.")

4. darbība: Iestatiet apstrādātāju

Apstrādātājs nodrošina saziņu starp aģents un spraudni.

  1. Importējiet container pakotni:
import "golang.zabbix.com/sdk/plugin/container"
  1. Funkcijā run() pievienojiet kodu, lai izveidotu un iestatītu apstrādātāju:
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
}

5. darbība: Datu vākšanas ieviešana

Datu vākšana tiek veikta, izmantojot Exporter saskarni, kas apraksta Export metodi:

func Export(
  key string,             // Vācamā vienuma atslēga.
  params []string,        // Argumenti, kas nodoti vienuma atslēgai (`myip[arg1, arg2]`).
  context ContextProvider // Metadati par vienuma atslēgas datu vākšanu.
) (any, error)
  1. Importējiet nepieciešamās pakotnes HTTP pieprasījumiem un atbildes nolasīšanai:
import (
    "io"
    "net/http"
)
  1. Ieviesiet Export metodi myIP struktūrai:
func (p *myIP) Export(
    key string, params []string, context plugin.ContextProvider,
) (any, error) {
    // Spraudnis var izmantot atšķirīgu datu vākšanas loģiku atkarībā no parametra `key`.
    // Šī ieviešana tikai pārbauda, vai norādītā `key` vērtība tiek atbalstīta.
    if key != "myip" {
        return nil, errs.Errorf("unknown item key %q", key)
    }

    // Žurnāla ieraksts tiks pārsūtīts uz aģents 2 žurnālu.
    p.Infof(
        "received request to handle %q key with %d parameters",
        key,
        len(params),
    )

    // Savāciet datus un atgrieziet tos.

    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
}

6. darbība: izveidojiet un konfigurējiet spraudni

  1. Lai izveidotu spraudni, palaidiet:
go mod tidy
go build

Tam vajadzētu izveidot izpildāmo failu myip pašreizējā direktorijā.

  1. Konfigurējiet Zabbix aģents 2, lai izmantotu spraudni:
echo "Plugins.MyIP.System.Path=$PATH_TO_THE_MYIP_PLUGIN_EXECUTABLE" > /etc/zabbix/zabbix_agent2.d/plugins.d/myip.conf

Aizstājiet $PATH_TO_THE_MYIP_PLUGIN_EXECUTABLE ar ceļu uz myip, kas tika izveidots 5. darbībā.

Konfigurācijas parametra nosaukumā norādītajam spraudņa nosaukumam (MyIP šajā pamācībā) ir jāsakrīt ar spraudņa nosaukumu, kas definēts funkcijā plugin.RegisterMetrics().

  1. Lai pārbaudītu spraudni un tā myip vienumu, palaidiet:
zabbix_agent2 -c /etc/zabbix/zabbix_agent2.conf -t myip

Izvadē jābūt jūsu hosta ārējai IP adresei, un tai vajadzētu izskatīties līdzīgi šādi:

myip                                          [s|192.0.2.1]

Tādējādi jūs esat izveidojis vienkāršu ielādējamu spraudni Zabbix aģents 2.

Apsveicam!

Pilns pirmkods

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{}

    // Reģistrē `myip` vienuma atslēgu.
    err := plugin.RegisterMetrics(
        p,
        "MyIP",                           // Spraudņa nosaukums
        "myip",                           // Vienuma atslēgas nosaukums
        "Returns the host's IP address.", // Vienuma atslēgas apraksts
    )
    if err != nil {
        return errs.Wrap(err, "failed to register metrics")
    }

    // Izveido jaunu apstrādātāju.
    h, err := container.NewHandler("MyIP") // Spraudņa nosaukums
    if err != nil {
        return errs.Wrap(err, "failed to create new handler")
    }

    // Iestata žurnalēšanu, lai pārsūtītu žurnālus no spraudņa uz aģentu.
    // Pieejams, izmantojot p.Logger.Infof, p.Logger.Debugf utt.
    p.Logger = h

    // Sāk spraudņa izpildi.
    // Bloķē, līdz tiek saņemts izbeigšanas pieprasījums no aģenta.
    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) {
    // Spraudnis var izmantot atšķirīgu datu vākšanas loģiku atkarībā no `key` parametra.  
    // Šī implementācija tikai pārbauda, vai norādītais `key` tiek atbalstīts. 
    if key != "myip" {
        return nil, errs.Errorf("unknown item key %q", key)
    }

    // Žurnāls tiks pārsūtīts uz aģenta 2 žurnālu.
    p.Infof(
        "received request to handle %q key with %d parameters",
        key,
        len(params),
    )

    // Savāc datus un atgriež tos.

    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
}