Créer un plugin (tutoriel)
Ce tutoriel explique, étape par étape, comment créer un plugin simple chargeable pour Zabbix agent 2.
Vous pouvez également utiliser le dépôt d'exemple comme modèle ou guide pour créer vos propres plugins.
Ce que vous allez créer
Ce tutoriel montre comment créer un nouveau plugin chargeable MyIP. Le plugin implémentera une seule clé d'élément, myip, qui renvoie l'adresse IP externe de l'hôte sur lequel l'agent 2 Zabbix est en cours d'exécution.
Étape 1: Configuration
- Un plugin est un module Go standard.
Commencez par initialiser le fichier
go.moddans le répertoire du plugin afin de suivre les dépendances du plugin:
cd path/to/plugins/myip # Passez dans le répertoire de votre plugin
go mod init myip
- Installez la dépendance obligatoire Zabbix Go SDK (
golang.zabbix.com/sdk):
go get golang.zabbix.com/sdk@$LATEST_COMMIT_HASH
Remplacez $LATEST_COMMIT_HASH par le hash du dernier commit HEAD du dépôt golang.zabbix.com/sdk dans la branche de version appropriée.
Par exemple:
go get golang.zabbix.com/sdk@af85407
Notez que le versionnement de golang.zabbix.com/sdk n'est actuellement pas pris en charge, mais cela pourrait changer à l'avenir.
Des dépendances supplémentaires peuvent être installées selon les besoins à l'aide de go get.
- Créez un fichier
main.govide pour le code source du plugin:
touch main.go
La configuration initiale est maintenant terminée, et le plugin est prêt pour le développement.
Étape 2: Structure du modèle
Le module golang.zabbix.com/sdk, installé à l'étape précédente, fournit le cadre nécessaire au développement de plugins et garantit que tous les plugins ont une structure cohérente.
- Configurez le flux d'exécution de base.
Commencez par définir le flux d'exécution principal du plugin. Ajoutez le code suivant à main.go :
package main
func main() {
err := run()
if err != nil {
panic(err)
}
}
func run() error {
return nil
}
Cela établit le flux d'exécution de base pour le plugin. La fonction run contiendra plus tard la logique principale du plugin.
- Explorez les interfaces du plugin.
Un plugin Zabbix agent 2 doit être représenté par une struct qui implémente les interfaces du package golang.zabbix.com/sdk/plugin :
- Accessor - définit les méthodes essentielles que tous les plugins doivent implémenter, comme la définition du nom du plugin et la gestion des délais d'attente des clés d'élément.
- Une ou plusieurs des interfaces fonctionnelles de plugin suivantes :
- Exporter - effectue une interrogation et renvoie une valeur (ou des valeurs), rien, ou une erreur ; souvent utilisé avec l'interface Collector.
- Collector - gère la collecte périodique des données.
- Runner - définit les procédures de démarrage et d'arrêt du plugin.
- Watcher - permet d'implémenter une interrogation indépendante des métriques, en contournant le planificateur interne de l'agent ; utile pour la surveillance basée sur des traps ou pilotée par des événements.
- Configurator - définit la manière dont le plugin lit et applique ses paramètres de configuration.
Vous pouvez soit implémenter ces interfaces vous-même, soit utiliser celles fournies par défaut par le Zabbix Go SDK, en les modifiant si nécessaire.
Ce tutoriel utilise les implémentations par défaut.
- Créez la struct du plugin.
Importez maintenant le package plugin et créez une struct myIP qui intègre la struct plugin.Base :
import "golang.zabbix.com/sdk/plugin"
type myIP struct {
plugin.Base
}
La struct myIP satisfait actuellement l'interface Accessor.
Une méthode permettant d'implémenter l'une des interfaces fonctionnelles du plugin, Exporter, sera ajoutée plus tard dans le tutoriel.
Étape 3: Définir les clés d'élément
Votre plugin a besoin des clés d'élément pour collecter des données et les fournir au serveur Zabbix ou au proxy.
- Importez le package errs pour la gestion des erreurs :
import "golang.zabbix.com/sdk/errs"
- Enregistrez les clés d'élément à l'aide de la fonction
plugin.RegisterMetrics()dans la fonctionrun():
func run() error {
p := &myIP{}
// Enregistrer la clé d'élément `myip`.
err := plugin.RegisterMetrics(
p,
"MyIP", // Nom du plugin
"myip", // Nom de la clé d'élément
"Returns the host's IP address.", // Description de la clé d'élément
)
if err != nil {
return errs.Wrap(err, "failed to register metrics")
}
return nil
}
Pour enregistrer plusieurs clés d'élément, répétez les paramètres metric name et description pour chaque métrique. Par exemple :
plugin.RegisterMetrics(&impl, "Myip", "metric.one", "Metric one description.", "metric.two", "Metric two description.")
Étape 4: Configurer le handler
Le handler facilite la communication entre l'agent et le plugin.
- Importez le package container :
import "golang.zabbix.com/sdk/plugin/container"
- Dans la fonction
run(), ajoutez le code pour créer et configurer un handler :
func run() error {
p := &myIP{}
// Enregistrer la clé d'élément `myip`.
err := plugin.RegisterMetrics(
p,
"MyIP", // Nom du plugin
"myip", // Nom de la clé d'élément
"Returns the host's IP address.", // Description de la clé d'élément
)
if err != nil {
return errs.Wrap(err, "failed to register metrics")
}
// Créer un nouveau handler.
h, err := container.NewHandler("MyIP") // Nom du plugin
if err != nil {
return errs.Wrap(err, "failed to create new handler")
}
// Configurer la journalisation pour transférer les journaux du plugin vers l'agent.
// Disponible via p.Logger.Infof, p.Logger.Debugf, etc.
p.Logger = h
// Démarrer l'exécution du plugin.
// Bloque jusqu'à la réception d'une demande de terminaison de la part de l'agent.
err = h.Execute()
if err != nil {
return errs.Wrap(err, "failed to execute plugin handler")
}
return nil
}
Étape 5: Implémenter la collecte de données
La collecte de données s'effectue via l'interface Exporter, qui décrit la méthode Export :
func Export(
key string, // La clé d'élément à collecter.
params []string, // Arguments transmis à la clé d'élément (`myip[arg1, arg2]`).
context ContextProvider // Métadonnées sur la collecte des données de la clé d'élément.
) (any, error)
- Importez les packages requis pour les requêtes HTTP et la lecture des réponses :
import (
"io"
"net/http"
)
- Implémentez la méthode
Exportpour la structuremyIP:
func (p *myIP) Export(
key string, params []string, context plugin.ContextProvider,
) (any, error) {
// Le plugin peut utiliser une logique de collecte de données différente selon le paramètre `key`.
// Cette implémentation vérifie uniquement que la `key` fournie est prise en charge.
if key != "myip" {
return nil, errs.Errorf("unknown item key %q", key)
}
// Le journal sera transmis au journal de agent 2.
p.Infof(
"received request to handle %q key with %d parameters",
key,
len(params),
)
// Collectez les données et renvoyez-les.
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
}
Étape 6: Compiler et configurer le plugin
- Pour compiler le plugin, exécutez :
go mod tidy
go build
Cela devrait créer un exécutable myip dans le répertoire courant.
- Configurez Zabbix agent 2 pour utiliser le plugin :
echo "Plugins.MyIP.System.Path=$PATH_TO_THE_MYIP_PLUGIN_EXECUTABLE" > /etc/zabbix_agent2.d/plugins.d/myip.conf
Remplacez $PATH_TO_THE_MYIP_PLUGIN_EXECUTABLE par le chemin vers le myip créé à l'étape 5.
Le nom du plugin dans le nom du paramètre de configuration (MyIP dans ce tutoriel) doit correspondre au nom du plugin défini dans la fonction plugin.RegisterMetrics().
- Pour tester le plugin et son élément
myip, exécutez :
zabbix_agent2 -c /etc/zabbix_agent2.conf -t myip
La sortie doit contenir une adresse IP externe de votre hôte et ressembler à ceci :
myip [s|192.0.2.1]
Ainsi, vous avez créé un plugin chargeable simple pour Zabbix agent 2. Félicitations !
Code source complet
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{}
// Enregistrer la clé d'élément `myip`.
err := plugin.RegisterMetrics(
p,
"MyIP", // Nom du plugin
"myip", // Nom de la clé d'élément
"Renvoie l'adresse IP de l'hôte.", // Description de la clé d'élément
)
if err != nil {
return errs.Wrap(err, "échec de l'enregistrement des métriques")
}
// Créer un nouveau gestionnaire.
h, err := container.NewHandler("MyIP") // Nom du plugin
if err != nil {
return errs.Wrap(err, "échec de la création d'un nouveau gestionnaire")
}
// Configurer la journalisation pour transférer les journaux du plugin vers l'agent.
// Disponible via p.Logger.Infof, p.Logger.Debugf, etc.
p.Logger = h
// Démarrer l'exécution du plugin.
// Bloque jusqu'à la réception d'une demande d'arrêt de l'agent.
err = h.Execute()
if err != nil {
return errs.Wrap(err, "échec de l'exécution du gestionnaire du plugin")
}
return nil
}
func (p *myIP) Export(
key string, params []string, context plugin.ContextProvider,
) (any, error) {
// Le plugin peut utiliser une logique de collecte de données différente selon le paramètre `key`.
// Cette implémentation vérifie uniquement que la `key` fournie est prise en charge.
if key != "myip" {
return nil, errs.Errorf("clé d'élément inconnue %q", key)
}
// Le journal sera transféré vers le journal de l'agent 2.
p.Infof(
"requête reçue pour traiter la clé %q avec %d paramètres",
key,
len(params),
)
// Collecter les données et les renvoyer.
resp, err := http.Get("https://api.ipify.org")
if err != nil {
return nil, errs.Wrap(err, "échec de l'obtention de l'adresse IP")
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errs.Wrap(err, "échec de la lecture du corps de la réponse")
}
return string(body), nil
}