Spraudņa izveide

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

Pielāgots spraudnis ļauj paplašināt Zabbix aģents 2 funkcionalitāti ārpus piedāvātajiem iebūvētajiem spraudņiem un ielādējamajiem spraudņiem.

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

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

Papildu norādījumus skatiet arī šo repozitoriju saturā:

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 spraudņu izstrādei nepieciešamo ietvaru un garantē, ka visiem spraudņiem ir vienota struktūra.

  1. Iestatiet pamata izpildes plūsmu.

Sāciet ar spraudņa galvenās izpildes plūsmas definēšanu. Pievienojiet main.go failam šādu kodu:

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 saturēs spraudņa pamatloģiku.

  1. Izpētiet spraudņa saskarnes.

Zabbix aģents 2 spraudnis ir jāattēlo ar struktūru, kas ievieš saskarnes no pakotnes golang.zabbix.com/sdk/plugin:

  • Accessor — definē būtiskās metodes, kas jāievieš visiem spraudņiem, piemēram, spraudņa nosaukuma iestatīšanu un vienuma atslēgas noildzes apstrādi.
  • Viena vai vairākas no šī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 izmantota kopā ar Collector saskarni.
    • Collector — pārvalda periodisku datu vākšanu.
    • Runner — definē spraudņa palaišanas un apturēšanas procedūras.
    • Watcher — ļauj ieviest neatkarīgu metriku aptaujāšanu, 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 savus konfigurācijas iestatījumus.

Jūs varat vai nu ieviest šīs saskarnes pats, vai izmantot Zabbix Go SDK nodrošinātās noklusējuma saskarnes, vajadzības gadījumā tās pielāgojot.
Šajā pamācībā tiek izmantotas noklusējuma ieviešanas.

  1. Izveidojiet spraudņa struktūru.

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

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

type myIP struct {
    plugin.Base
}

Struktūra myIP pašlaik atbilst Accessor saskarnei.
Metode vienas no funkcionālajām spraudņa saskarnēm — Exporter — ievieš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. solis: Izveidojiet un konfigurējiet spraudni

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

Tādējādi pašreizējā direktorijā tiks izveidots izpildāms fails myip.

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

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

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

  1. Lai pārbaudītu spraudni un tā myip vienumu, izpildiet:
zabbix_agent2 -c /etc/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.0]

Ar to 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
}