Zabbixでは、自作したモジュールをZabbix ServerやZabbix Agentからロードすることが可能な仕様になっています。
そこで、ここでは Go
を使ってロード可能モジュール(Loadable modules)を作ってみます。
Zabbix3.2のモジュールを作った時に少しハマったのでメモしておきます :-)
環境
項目 | バージョン |
---|---|
OS | CentOS 7.2 |
Zabbix | 3.2 |
Go | 1.8.1 |
GoのZabbixモジュールアダプタ
g2z
Zabbixのネイティブモジュールが作成できるGoバイディングである g2z
を使用します。
ドキュメント
インストール
パッケージインストール
(1) 必要なパッケージをインストールします。
[root@localhost ~]# yum -y install git gcc
g2zインストール
(1) g2z
をインストールします。Zabbixは3.2を使うのでバージョン3を指定しています。
[root@localhost ~]# go get -v gopkg.in/cavaliercoder/g2z.v3
gopkg.in/cavaliercoder/g2z.v3
# gopkg.in/cavaliercoder/g2z.v3
In file included from $WORK/gopkg.in/cavaliercoder/g2z.v3/_obj/_cgo_export.c:3:0:
go/src/gopkg.in/cavaliercoder/g2z.v3/module.go: 関数 ‘append_metric’ 内:
go/src/gopkg.in/cavaliercoder/g2z.v3/module.go:44:2: 警告: 組み込み関数 ‘memcpy’ の互換性がない暗黙的な宣言です [デフォルトで有効]
memcpy(list, n, sizeof(ZBX_METRIC));
^
# gopkg.in/cavaliercoder/g2z.v3
go/src/gopkg.in/cavaliercoder/g2z.v3/module.go: 関数 ‘append_metric’ 内:
go/src/gopkg.in/cavaliercoder/g2z.v3/module.go:44:2: 警告: 組み込み関数 ‘memcpy’ の互換性がない暗黙的な宣言です [デフォルトで有効]
memcpy(list, n, sizeof(ZBX_METRIC));
^
g2zの修正
修正しなくてはいけない理由
Zabbix 3.2から ZBX_MODULE_API_VERSION_ONE
から ZBX_MODULE_API_VERSION
に変更されています。
そのため、g2zをインストールしてモジュールをビルドしZabbixへ組み込んだあとに起動すると以下のエラーが発生します。
5603:20170529:003940.573 using configuration file: /etc/zabbix/zabbix_agentd.conf
5603:20170529:003940.577 unsupported module "example.so" version: 1 <- サポートしていないバージョンなので起動できない
5603:20170529:003940.577 loading modules failed, exiting...
Zabbixのソースコードを見てみましょう。
[root@localhost SOURCES]# grep -n 'ZBX_MODULE_API_VERSION' ./zabbix-3.2.6/include/module.h
29:#define ZBX_MODULE_API_VERSION 2 <- バージョンが 2 になっていることが確認できます
32:#define ZBX_MODULE_API_VERSION_ONE ZBX_MODULE_API_VERSION <- 古いのは新しいので上書きされています
35:/* #if ZBX_MODULE_API_VERSION == X */
3.2以上でロード可能モジュールを開発する場合は、g2zでもこの修正が必要になります。
修正手順
(1) g2zの module.h
の ZBX_MODULE_API_VERSION
を 2
に修正します。
[root@localhost ~]# vi go/src/gopkg.in/cavaliercoder/g2z.v3/module.h
(snip)
#define ZBX_MODULE_API_VERSION_ONE 2
これが、一番簡単な修正方法かと思います。
または module.h
に ZBX_MODULE_API_VERSION
を新しく追加して go/src/gopkg.in/cavaliercoder/g2z.v3/module.go
の zbx_module_api_version
関数内を修正しても大丈夫だと思います。
//export zbx_module_api_version
func zbx_module_api_version() int {
return C.ZBX_MODULE_API_VERSION_ONE <- ここ
}
ちなみに、本家にはプルリクがきている模様
モジュールのビルド及び組み込み
ここでは、g2zの例にあるソースをビルドしてZabbix Agentへ組み込んでみます。
(1) 以下のソースコードを使用します。
package main
import (
g2z "gopkg.in/cavaliercoder/g2z.v3"
"strings"
)
func main() {
panic("THIS_SHOULD_NEVER_HAPPEN")
}
func init() {
g2z.RegisterStringItem("go.echo", "Hello,world", Echo)
}
func Echo(request *g2z.AgentRequest) (string, error) {
return strings.Join(request.Params, " "), nil
}
(2) ビルドします。
[root@localhost ~]# go build -buildmode=c-shared -o example.so example.go
# gopkg.in/cavaliercoder/g2z.v3
In file included from $WORK/gopkg.in/cavaliercoder/g2z.v3/_obj/_cgo_export.c:3:0:
go/src/gopkg.in/cavaliercoder/g2z.v3/module.go: 関数 ‘append_metric’ 内:
go/src/gopkg.in/cavaliercoder/g2z.v3/module.go:44:2: 警告: 組み込み関数 ‘memcpy’ の互換性がない暗黙的な宣言です [デフォルトで有効]
memcpy(list, n, sizeof(ZBX_METRIC));
^
# gopkg.in/cavaliercoder/g2z.v3
go/src/gopkg.in/cavaliercoder/g2z.v3/module.go: 関数 ‘append_metric’ 内:
go/src/gopkg.in/cavaliercoder/g2z.v3/module.go:44:2: 警告: 組み込み関数 ‘memcpy’ の互換性がない暗黙的な宣言です [デフォルトで有効]
memcpy(list, n, sizeof(ZBX_METRIC));
^
(3) モジュールを任意の場所へ保存します。ここでは /etc/zabbix/modules
配下へ保存します。
[root@localhost ~]# mkdir /etc/zabbix/modules
[root@localhost ~]# mv example.so /etc/zabbix/modules/
(4) Zabbix Agentへ組み込みます。
[root@localhost ~]# vi /etc/zabbix/zabbix_agentd.conf
(snip)
### Option: LoadModulePath
# Full path to location of agent modules.
# Default depends on compilation options.
#
# Mandatory: no
# Default:
# LoadModulePath=${libdir}/modules
LoadModulePath=/etc/zabbix/modules
### Option: LoadModule
# Module to load at agent startup. Modules are used to extend functionality of the agent.
# Format: LoadModule=<module.so>
# The modules must be located in directory specified by LoadModulePath.
# It is allowed to include multiple LoadModule parameters.
#
# Mandatory: no
# Default:
# LoadModule=
LoadModule=example.so
(5) Zabbix Agentを起動します。
[root@localhost ~]# systemctl start zabbix-agent
[root@localhost ~]# systemctl status zabbix-agent
● zabbix-agent.service - Zabbix Agent
Loaded: loaded (/usr/lib/systemd/system/zabbix-agent.service; disabled; vendor preset: disabled)
Active: active (running) since 月 2017-05-29 00:50:05 JST; 1min 59s ago
(snip)
動作確認
(1) 動作確認をしてみます。
[root@localhost ~]# zabbix_get -s 127.0.0.1 -k 'go.echo['test', 'hoge']'
test hoge
(2) Discoveryのソースコード例を組み込んで実行してみました。
[root@localhost ~]# zabbix_get -s 127.0.0.1 -k 'go.discovery'
{
"data":[
{
"{#INDEX}":"0"},
{
"{#INDEX}":"1"},
{
"{#INDEX}":"2"},
{
"{#INDEX}":"3"},
{
"{#INDEX}":"4"}]}
これで、3.2のモジュールが開発できるようになりました :-)
(独り言)3.4はいつでるんやろ...
参考文献
追記
Goルーチンの処理が入る場合は動かないようです。
https://github.com/cavaliercoder/g2z/issues/5
実際にやってみたら動かなかった(´・_・`)