これは、Zabbixエージェント2用のシンプルでロード可能なプラグインを作成するためのステップバイステップのチュートリアルです。
独自のプラグインを作成するためのテンプレートまたはガイドとして、サンプルリポジトリを使用することもできます。
このチュートリアルでは、新しいロード可能なプラグインMyIPを作成する方法を説明します。 このプラグインは、Zabbixエージェント2が動作しているホストの外部IPアドレスを返す単一のアイテムキーmyipを実装します。
go.mod
ファイルを初期化します。golang.zabbix.com/sdk
)をインストールします。$LATEST_COMMIT_HASH
を、適切なリリースブランチのgolang.zabbix.com/sdk
リポジトリにある最新のHEAD
コミットハッシュに置き換えます。 例:
golang.zabbix.com/sdk
のバージョン管理は現在サポートされていませんが、将来変更される可能性があります。
必要に応じて、go get
を使用して追加の依存関係をインストールできます。
main.go
ファイルを作成します。これで初期設定が完了し、プラグインの開発準備が整いました。
前のステップでインストールしたgolang.zabbix.com/sdk
モジュールは、プラグイン開発に必要なフレームワークを提供し、すべてのプラグインの一貫した構造を保証します。
まず、プラグインのメインの実行フローを定義します。次のコードをmain.go
に追加します。
package main
func main() {
err := run()
if err != nil {
panic(err)
}
}
func run() error {
return nil
}
これで、プラグインの基本的な実行フローが確立されます。 run関数には、後でプラグインのコアロジックが含まれます。
Zabbixエージェント2プラグインは、golang.zabbix.com/sdk/plugin
パッケージのインターフェースを実装する構造体で表現されます。
これらのインターフェースは独自に実装することも、Zabbix Go SDKが提供するデフォルトのインターフェースを必要に応じて変更して使用することもできます。 このチュートリアルではデフォルトの実装を使用します。
pluginパッケージをインポートし、plugin.Base
構造体を埋め込むmyIP
構造体を作成します。
myIP構造体は現在、Accessorインターフェースを満たしています。 関数型プラグインインターフェースの1つであるExporter
を実装するメソッドは、このチュートリアルの後半で追加します。
プラグインは、データを収集し、Zabbixサーバーまたはプロキシに提供するためにアイテムキーが必要です。
run()
関数内のplugin.RegisterMetrics()
関数を使用して、アイテムキーを登録します。func run() error {
p := &myIP{}
// `myip`アイテムキーを登録します。
err := plugin.RegisterMetrics(
p,
"MyIP", // プラグイン名
"myip", // アイテムキー名
"Returns the host's IP address.", // アイテムキーの説明
)
if err != nil {
return errs.Wrap(err, "failed to register metrics")
}
return nil
}
複数のアイテムキーを登録するには、各メトリックに対してパラメーターmetric nameとdescriptionを繰り返します。 例:
plugin.RegisterMetrics(&impl, "Myip", "metric.one", "Metric one description.", "metric.two", "Metric two description.")
ハンドラーは、エージェントとプラグイン間の通信を容易にします。
run()
関数に、ハンドラーの作成と設定を行うコードを追加します。func run() error {
p := &myIP{}
// `myip`アイテムキーを登録します。
err := plugin.RegisterMetrics(
p,
"MyIP", // プラグイン名
"myip", // アイテムキー名
"Returns the host's IP address.", // アイテムキーの説明
)
if err != nil {
return errs.Wrap(err, "failed to register metrics")
}
// 新しいハンドラーを作成します。
h, err := container.NewHandler("MyIP") // プラグイン名
if err != nil {
return errs.Wrap(err, "failed to create new handler")
}
// プラグインからエージェントへログを転送するためのログ記録を設定します。
// p.Logger.Infof、p.Logger.Debugfなどから利用可能です。
p.Logger = h
// プラグインの実行を開始します。
// エージェントから終了要求を受信するまでブロックします。
err = h.Execute()
if err != nil {
return errs.Wrap(err, "failed to execute plugin handler")
}
return nil
}
データ収集は、Export
メソッドを記述するExporterインターフェースを介して行われます。
func Export(
key string, // 収集するアイテムキー
params []string, // アイテムキー(`myip[arg1, arg2]`)に渡される引数
context ContextProvider // アイテムキーデータ収集に関するメタデータ
) (any, error)
import (
"io"
"net/http"
)
myIP
構造体のExport
メソッドを実装します。func (p *myIP) Export(
key string, params []string, context plugin.ContextProvider,
) (any, error) {
// プラグインは、`key`パラメーターに基づいて異なるデータ収集ロジックを使用できます。
// この実装は、指定された`key`がサポートされているかどうかのみを検証します。
if key != "myip" {
return nil, errs.Errorf("unknown item key %q", key)
}
// ログはエージェント2のログに転送されます。
p.Infof(
"received request to handle %q key with %d parameters",
key,
len(params),
)
// データを収集して返します。
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
}
これにより、カレントディレクトリに実行ファイルmyip
が作成されます。
echo "Plugins.MyIP.System.Path=$PATH_TO_THE_MYIP_PLUGIN_EXECUTABLE" > /etc/zabbix_agent2.d/plugins.d/myip.conf
$PATH_TO_THE_MYIP_PLUGIN_EXECUTABLE
を、ステップ5で作成したmyip
へのパスに置き換えます。
設定パラメーター名(このチュートリアルでは_MyIP_)のプラグイン名は、_plugin.RegisterMetrics()_関数で定義されたプラグイン名と一致する必要があります。
myip
アイテムをテストするには、次のコマンドを実行します。出力にはホストの外部IPアドレスが含まれ、以下のようになります。
myip [s|192.0.2.0]
これで、Zabbixエージェント2用のシンプルな読み込み可能なプラグインが作成されました。 おめでとうございます!
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{}
// `myip`アイテムキーを登録します。
err := plugin.RegisterMetrics(
p,
"MyIP", // プラグイン名
"myip", // アイテムキー名
"Returns the host's IP address.", // アイテムキーの説明
)
if err != nil {
return errs.Wrap(err, "failed to register metrics")
}
// 新しいハンドラーを作成します。
h, err := container.NewHandler("MyIP") // Plugin name
if err != nil {
return errs.Wrap(err, "failed to create new handler")
}
// プラグインからエージェントにログを転送するためのログ設定を行います。
// p.Logger.Infof、p.Logger.Debugfなどから利用可能です。
p.Logger = h
// プラグインの実行を開始します。
// エージェントからの終了要求を受信するまでブロックします。
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) {
// プラグインは、`key`パラメーターに基づいて異なるデータ収集ロジックを使用できます。
// この実装では、指定された`key`がサポートされているかどうかのみ確認します。
if key != "myip" {
return nil, errs.Errorf("unknown item key %q", key)
}
// ログはエージェント2のログに転送されます。
p.Infof(
"received request to handle %q key with %d parameters",
key,
len(params),
)
// データを収集して返します。
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
}