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. solis: spraudņa struktūra

Modulis golang.zabbix.com/sdk, kas tika instalēts iepriekšējā solī, nodrošina nepieciešamo ietvaru spraudņu izstrādei 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 šādu 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 saturēs spraudņa pamatloģiku.

  1. Iepazīstieties ar spraudņa interfeisiem.

Zabbix aģents 2 spraudnim jābūt attēlotam ar struktūru, kas implementē interfeisus 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 noildzes apstrādi.
  • Vienu vai vairākus no šiem funkcionālajiem spraudņa interfeisiem:
    • Exporter - veic aptauju un atgriež vērtību (vai vērtības), neko vai kļūdu; bieži tiek izmantots kopā ar Collector interfeisu.
    • Collector - pārvalda periodisku datu apkopošanu.
    • Runner - definē spraudņa palaišanas un apturēšanas procedūras.
    • Watcher - ļauj ieviest neatkarīgu metrikas aptauju, apejot aģenta iekšējo plānotāju; noderīgs uz trigeriem vai notikumiem balstītai uzraudzībai.
    • Configurator - definē, kā spraudnis nolasa un piemēro savus konfigurācijas iestatījumus.

Jūs varat šos interfeisus implementēt paši vai izmantot Zabbix Go SDK nodrošinātos noklusējuma variantus, pielāgojot tos pēc vajadzības. Šajā pamācībā tiek izmantotas noklusējuma implementācijas.

  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
}

Pašlaik myIP struktūra atbilst Accessor interfeisam. Vēlāk pamācībā tiks pievienota metode viena no funkcionālajiem spraudņa interfeisiem, 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ā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_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_agent2.conf -t myip

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

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
}