採用情報

お問い合わせ

BLOG

Zabbix テック・ラウンジ

2018 年 01 月 25 日

Zabbix 3.2以降の新機能解説(Zabbix 4.0を見据えて) その9 - プロキシでのリモートコマンドの実行 (その2)

こんにちは、MIRACLE ZBX サポートを担当している花島タケシです。 今回は Task Manager プロセスを利用した最後のサービスについての後編の解説となります。

プロキシでのリモートコマンドの実行(その 2)

今回は Task Manager プロセスを利用した最後のサービスについての後編の解説となります。

参考

Remote command support through proxies

前回は、Escalator プロセスが通常のアラート処理と異なり、alert テーブルへ情報を挿入せずに、リモートコマンドをプロキシで実行するために task_remote_command テーブルへと挿入しているところまで解説を行いました。

 リモートコマンド(zbx-tl-020 用)

今回はそのデータをどのようにプロキシに渡し、プロキシがどうやって実行しているか?ということを解説してきます。

アクティブプロキシとパッシブプロキシ

Zabbix においてプロキシはアクティブプロキシとパッシブプロキシの二種類が存在します。

それらの違いは、名前からも分かるように主体性の違いとなります。アクティブプロキシは、プロキシが起動した直後からサーバーへ問い合わせを行い、サーバーからそのプロキシが受け持つべきホストの監視設定を受け取ります。

監視設定は刻一刻と変化するため、プロキシは定期的にサーバーへ問い合わせを行います。
それとは逆に、パッシブプロキシは自ら問い合わせを行うことはなく、Zabbix サーバーが起動後にプロキシに対して監視設定を送信します。当然こちらも定期的に送信することになります。

リモートコマンド情報はどうやって送り込む ?

前回の説明でリモートコマンド情報は task_remote_command テーブルへと一旦格納されていることを説明しました。実際には task テーブルへの挿入も行いますが、コマンド実行の直接的な情報ではありません。

Task Manager プロセスは、task テーブルをポーリングして処理を行うプロセスです。

task テーブルを参照して、関連する情報を task_remote_command テーブルから参照してもパッシブプロキシにデータを送信することはできますが、アクティブプロキシに、強制的にでも、データを送信することはできません。

では、どうしているのか?というと、アクティブプロキシに対しての任務は、Trapper プロセスが受け持ちます。というよりも、サーバーが主体的に行えない通信のほとんどは Trapper プロセスが受け持つこととなります。

Trapper プロセスによる受送信

Trapper プロセスは、なんらかの受信を行うと process_trap() をコールして、受信したデータの解析を行い、それに準じた処理をし、返信を行います。
これは、src/zabbix_server/trapper/trapper.c を眺めていただければと思います。

アクティブプロキシは、サーバーから監視設定を受け取るために、定期的にサーバーへ要求を送信します。

と書きましたが、実は正確ではありません。「監視等によって得られたデータを送信し、そのときにサーバーは監視設定を送信する」が正しいです。

このときに、ZBX_PROTO_VALUE_PROXY_DATA タグを付けて送信を行います。

src/zabbix_proxy/datasender/datasender.c

59 static int proxy_data_sender(int *more, int now)
60 {
...
78  zbx_json_init(&j, 16 * ZBX_KIBIBYTE);
79
80  zbx_json_addstring(&j, ZBX_PROTO_TAG_REQUEST, ZBX_PROTO_VALUE_PROXY_DATA, ZBX_JSON_TYPE_STRING);
...
203 ZBX_THREAD_ENTRY(datasender_thread, args)
204 {
...
235     records += proxy_data_sender(&more, (int)time_now);

一方、これを受け取ったサーバーの Trapper プロセスはこのタグに対する処理を行います。

920 static int process_trap(zbx_socket_t *sock, char *s, zbx_timespec_t *ts)
921 {
...
979     else if (0 == strcmp(value, ZBX_PROTO_VALUE_PROXY_DATA))
980     {
981      if (0 != (program_type & ZBX_PROGRAM_TYPE_SERVER))
982       zbx_recv_proxy_data(sock, &jp, ts);
983      else if (0 != (program_type & ZBX_PROGRAM_TYPE_PROXY_PASSIVE))
984       zbx_send_proxy_data(sock, ts);
985     }

l.981 は稼働しているデーモンが Zabbix サーバーであるかを判定しています。
l.983 はパッシブプロキシ (Zabbix サーバーからの受信 ) の判定となります。

今回は Zabbix サーバーでの処理に着目しているため、src/zabbix_server/trapper/proxydata.c :zbx_recv_proxy_data() を見ていきます。

この関数から、返信用のデータを生成する zbx_send_proxy_data_respose() がコールされます。
ここから、zbx_tm_get_remote_tasks() がコールされ、件の task_remote_command テーブルを参照することになります。

プロキシでのリモートコマンド実行

説明を省いてしまいますが、サーバーからの返信を受け取ったプロキシはリモートコマンドの実行データを zbx_tm_save_tasks() をコールして、プロキシ側の task テーブルと task_remote_command テーブルに挿入します。

プロキシ側の Task Manager プロセスは、サーバー側と同様に task テーブルをポーリングします。

src/zabbix_proxy/taskmanager/taskmanager.c

205 ZBX_THREAD_ENTRY(taskmanager_thread, args)
206 {
...
228   for (;;)
229   {
...
238     tasks_num = tm_process_tasks((int)sec1);

ただし、サーバー側とは異なり現在のところ、リモートコマンドの実行に対する処理しか実装されていません。

149 static int tm_process_tasks(int now)
150 {
...
157   result = DBselect("select taskid,type,clock,ttl"
158      " from task"
159      " where status=%d"
160      " and type=%d"
161      " order by taskid",
162     ZBX_TM_STATUS_NEW, ZBX_TM_TASK_REMOTE_COMMAND);
163
164   while (NULL != (row = DBfetch(result)))
165   {
166    ZBX_STR2UINT64(taskid, row[0]);
167    ZBX_STR2UCHAR(type, row[1]);
168    clock = atoi(row[2]);
169    ttl = atoi(row[3]);
170
171    switch (type)
172    {
173     case ZBX_TM_TASK_REMOTE_COMMAND:
174      ret = tm_execute_remote_command(taskid, clock, ttl, now);
175      break;
176     default:
177      THIS_SHOULD_NEVER_HAPPEN;
178      ret = FAIL;
179      break;
180    }

tm_execute_remote_command() の処理の概要を説明します。

51 static int tm_execute_remote_command(zbx_uint64_t taskid, int clock, int ttl, int now)
52 {
...
71  task = zbx_tm_task_create(0, ZBX_TM_TASK_REMOTE_COMMAND_RESULT, ZBX_TM_STATUS_NEW, time(NULL), 0, 0);
...
116   if (SUCCEED != (ret = zbx_script_execute(&script, &host, &info, error, sizeof(error))))
117    task->data = zbx_tm_remote_command_result_create(parent_taskid, ret, error);
118   else
119    task->data = zbx_tm_remote_command_result_create(parent_taskid, ret, info);
...
125   DBbegin();
126
127   if (NULL != task)
128   {
129    zbx_tm_save_task(task);
130    zbx_tm_task_free(task);
131   }
132
133   DBexecute("update task set status=%d where taskid=" ZBX_FS_UI64, ZBX_TM_STATUS_DONE, taskid);
134
135   DBcommit();
136
137   return ret;
138 }

l.71 の zbx_tm_task_create() により初期データを作成します。二番目の type 引数に ZBX_TM_TASK_REMOTE_COMMAND_RESULT を指定しています。

これは、l.129 でコールされる zbx_tm_save_task() にて効果を持ちます。

l.116 にて実装にコマンドを実行した後に、zbx_tm_save_task() をコールします。ここで上記の type により、結果が task_remote_command_result テーブルへ挿入されることになります。

最後に、task テーブルの情報をアップデートして終了します。

task_remote_command_result テーブルへ収められたコマンド結果はどうなるか?というと、最初のプロキシの proxy_data_sender() に帰着します。
ここで、zbx_tm_get_remote_tasks() からデータを取得し、サーバーへ返送されます。

まとめ

以上で、二回に渡りリモートコマンドがプロキシで実行する実装の解説を行いました。
task テーブルは使用していますが、サーバー側では Task Manager があまり関与せず、プロキシ側では Task Manager に頼った実装となっていることが理解できたと思います。

 リモートコマンド(zbx-tl-021 用)

関連記事

Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 1
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 2
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 3
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 4
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 5
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 6
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 7
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 8
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 9
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 10
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 11
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 12
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 13
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 14
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 15
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 16
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 17
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 18
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 19
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 20
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 21

注意事項

  • 本ドキュメントの内容は、予告なしに変更される場合があります。
  • 本ドキュメントは、限られた評価環境における検証結果をもとに作成しており、全ての環境での動作を保証するものではありません。
  • 本ドキュメントの内容に基づき、導入、設定、運用を行なったことにより損害が生じた場合でも、当社はその損害についての責任を負いません。あくまでお客さまのご判断にてご使用ください。
CentOS 7 延長サポートサービス
デジタルトランスフォーメーションのための電子認証基盤 iTrust
SSL/TLS サーバー証明書 SureServer Prime