Izveidot spraudni (pamācība)

Šī ir soli pa solim pamācība par to, kā izveidot vienkāršu ielādējamu spraudni Zabbix aģentam 2.

Varat arī izmantot piemēra repozitoriju kā veidni vai ceļvedi savu spraudņu izveidei.

Ko jūs izveidosiet

Šajā pamācībā ir parādīts, kā izveidot jaunu ielādējamu spraudni MyIP. Spraudnis īstenos vienu vienuma atslēgu myip, kas atgriezīs tā hosta ārējo IP adresi, kurā darbojas Zabbix aģents 2.

1. darbība: iestatīšana

  1. Spraudnis ir standarta Go modulis. Sāciet ar go.mod faila inicializēšanu spraudņa direktorijā, lai sekotu spraudņa atkarībām:
cd path/to/plugins/myip # Pārslēdzieties uz savu 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 commit hash no golang.zabbix.com/sdk repozitorija attiecīgajā laidiena zarā. Piemēram:

go get golang.zabbix.com/sdk@af85407

Ņemiet vērā, ka golang.zabbix.com/sdk versēšana 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 pirmkoda vajadzībām:
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ņa 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ūtiskas 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 saskarni Collector.
    • Collector - pārvalda periodisku datu apkopošanu.
    • Runner - definē spraudņa palaišanas un apturēšanas procedūras.
    • Watcher - ļauj implementēt neatkarīgu metriku aptauju, apejot aģenta iekšējo plānotāju; noder uz slazdiem balstītai vai uz 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ā apmā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. Vēlāk apmācībā tiks pievienota metode vienas no funkcionālajām spraudņa saskarnēm - Exporter - implementēšanai.

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

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

  1. Importējiet pakotni errs 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{}

    // Reģistrē `myip` vienuma atslēgu.
    err := plugin.RegisterMetrics(
        p,
        "MyIP",                           // Spraudņa nosaukums
        "myip",                           // Vienuma atslēgas nosaukums
        "Atgriež hosts IP adresi.",       // Vienuma atslēgas apraksts
    )
    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 metric name un description katram metrikam. 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ģentu un spraudni.

  1. Importējiet pakotni container:
import "golang.zabbix.com/sdk/plugin/container"
  1. Funkcijas run() iekšpusē pievienojiet kodu, lai izveidotu un iestatītu apstrādātāju:
func run() error {
    p := &myIP{}

    // Reģistrējiet `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")
    }

    // Izveidojiet 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")
    }

    // Iestatiet žurnāloš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āciet spraudņa izpildi.
    // Bloķējas līdz no aģenta tiek saņemts pārtraukšanas pieprasījums.
    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 interfeisu, kas apraksta Export metodi:

func Export(
  key string,             // Vienuma atslēga, no kuras vākt datus.
  params []string,        // Argumenti, kas tiek 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. Implementējiet Export metodi struktūrai myIP:
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ā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āmu 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ā.

Spraudņa nosaukumam konfigurācijas parametra nosaukumā (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 avota kods

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ējiet `myip` vienuma atslēgu.
    err := plugin.RegisterMetrics(
        p,
        "MyIP",                           // Spraudņa nosaukums
        "myip",                           // Vienuma atslēgas nosaukums
        "Atgriež hosta IP adresi.",        // Vienuma atslēgas apraksts
    )
    if err != nil {
        return errs.Wrap(err, "neizdevās reģistrēt metriku")
    }

    // Izveidojiet jaunu apstrādātāju.
    h, err := container.NewHandler("MyIP") // Spraudņa nosaukums
    if err != nil {
        return errs.Wrap(err, "neizdevās izveidot jaunu apstrādātāju")
    }

    // Iestatiet žurnāloš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āciet spraudņa izpildi.
    // Bloķējas, līdz no aģenta tiek saņemts pārtraukšanas pieprasījums.
    err = h.Execute()
    if err != nil {
        return errs.Wrap(err, "neizdevās izpildīt spraudņa apstrādātāju")
    }

    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("nezināma vienuma atslēga %q", key)
    }

    // Žurnāls tiks pārsūtīts uz aģenta 2 žurnālu.
    p.Infof(
        "saņemts pieprasījums apstrādāt %q atslēgu ar %d parametriem",
        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, "neizdevās iegūt IP adresi")
    }

    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, errs.Wrap(err, "neizdevās nolasīt atbildes ķermeni")
    }

    return string(body), nil
}