BLOG
2018 年 01 月 12 日
Zabbix 3.2以降の新機能解説(Zabbix 4.0を見据えて) その8 - プロキシでのリモートコマンドの実行 (その1)
こんにちは、MIRACLE ZBX サポートを担当している花島タケシです。「Zabbix 3.2 以降の新機能解説(4.0)を見据えて」のシリーズの 8 回目となります。今回から 2 回に渡って「プロキシでのリモートコマンドの実行」について解説を行います。Task Manager プロセスを利用した最後のサービスについての解説となります。
プロキシでのリモートコマンドの実行(その 1)
今回は Task Manager プロセスを利用した最後のサービスについての解説となります。
参考
Remote command support through proxies
これが 3.4.0 での新規機能として紹介されるということは、つまり 3.2.x まではプロキシでリモートコマンドが実行できませんでした。
これはプロキシ配下で監視されるエージェントでも同様です。
実際の設定方法は上記の URL を参考にしてください。
変更点を見ていく
この機能追加に関する、Zabbix LLC の SVN リポジトリへコミットされた差分が多くてちょっとどこから解説をするべきか悩んでいます。
とりあえず、リモートコマンドを「どこで」実行すべきか?というオプションが Web フロントエンドに付け加えられました。
リモートコマンドのデータは scripts テーブルへ保存されますが、特にこのテーブルへの変更はされていません。
というのも、以前から Zabbix サーバー、Zabbix エージェントのどちらかで実行することができていたため、execute_on カラムが存在しており、「プロキシで実行する」という情報もここに保存すれば良いからです。
DB への追加情報
結果として、DB へ追加・変更された情報は下記となります。
- task テーブルへ、status, clock, ttl, proxy_hostid カラムの追加
- task_remote_command テーブルの追加
- task_remote_command_result テーブルの追加
task テーブルへの情報の挿入
リモートコマンドは、アクションとして実行されます。Zabbix サーバーの各プロセスの関係図を思い出してほしいのですが、調査は Escalator プロセスから始めます。
Escalator プロセスは、定期的に DB( 特に escalations テーブル ) のポーリングを行います。
処理すべきデータがあった場合、process_db_escalations() から escalation_execute() と呼ばれます。
escalation_execute() は障害発生時に呼び出される関数となります。
リカバリー時は escalation_recover() が呼び出されますし、「障害対応」がされた場合は、escalation_acknowlege() が呼び出されます。
詳しくは、process_db_escalations() にある分岐を見てください。
こういった機能調査をしていくときに最初から全てを網羅して読み進めていくと、実装自体を理解しづらくなります。
したがって、本解説では障害発生時の処理に注目していきます。
escalation_execute() から、何もせずに escalation_execute_operations() が呼び出されます。この関数内では実際に設定されたオペレーションに対する処理が進みます。
1284 switch (operationtype)
1285 {
1286 case OPERATION_TYPE_MESSAGE:
1287 if (SUCCEED == DBis_null(row[4]))
1288 break;
...
1304 add_object_msg(action->actionid, operationid, mediatypeid, &user_msg,
1305 subject, message, event, NULL, NULL, MACRO_TYPE_MESSAGE_NORMAL);
1306 break;
1307 case OPERATION_TYPE_COMMAND:
1308 execute_commands(event, NULL, NULL, action->actionid, operationid,
1309 escalation->esc_step, MACRO_TYPE_MESSAGE_NORMAL);
1310 break;
1311 }
1312 }
今回注目する対象はリモートコマンドとなります。
この場合 l.1307 からのブロックに記述されている execute_commands() が対象となります。
実行するアクションがメール送信等の場合は Escalator プロセスが alert テーブルへ情報を挿入するだけですが、リモートコマンドの場合は直接コマンドを実行します。
といっても、これは過去の話になったわけです。
つまり、プロキシ経由でコマンドを実行するために、然るべき領域へデータを挿入して終了します。
この処理が、execute_commands() にて行われます。
750 static void execute_commands(const DB_EVENT *event, const DB_EVENT *r_event, const DB_ACKNOWLEDGE *ack,
751 zbx_uint64_t actionid, zbx_uint64_t operationid, int esc_step, int macro_type)
752 {
...
SQL を生成する処理がかなりあります。
...
844 while (NULL != (row = DBfetch(result)))
845 {
...
933 if (SUCCEED == (rc = zbx_script_prepare(&script, &host, NULL, error, sizeof(error))))
934 {
935 if (0 == host.proxy_hostid || ZBX_SCRIPT_EXECUTE_ON_SERVER == script.execute_on)
936 {
937 rc = zbx_script_execute(&script, &host, NULL, error, sizeof(error));
938 status = ALERT_STATUS_SENT;
939 }
940 else
941 {
942 if (0 == zbx_script_create_task(&script, &host, alertid, time(NULL)))
943 rc = FAIL;
944 }
945 }
上記が追加されたコードとなります。
対象となるアクションがサーバー上で実行する場合は、これまでのように zbx_script_execute() がコールされ、サーバー上でスクリプトが実行されます。
一方、そうでない場合、zbx_script_create_task() がコールされます。
関数名から task テーブルに関する処理だと想像できます。
zbx_script_task_create_task() は、src/zabbix_server/scripts/scripts.c に記述されています。
510 zbx_uint64_t zbx_script_create_task(const zbx_script_t *script, const DC_HOST *host, zbx_uint64_t alertid, int now)
511 {
512 zbx_tm_task_t *task;
513 unsigned short port;
514 zbx_uint64_t taskid;
515
516 if (NULL != script->port && '\0' != script->port[0])
517 is_ushort(script->port, &port);
518 else
519 port = 0;
520
521 taskid = DBget_maxid("task");
522
523 task = zbx_tm_task_create(taskid, ZBX_TM_TASK_REMOTE_COMMAND, ZBX_TM_STATUS_NEW, now,
524 ZBX_REMOTE_COMMAND_TTL, host->proxy_hostid);
525
526 task->data = zbx_tm_remote_command_create(script->type, script->command, script->execute_on, port,
527 script->authtype, script->username, script->password, script->publickey, script->privatekey,
528 taskid, host->hostid, alertid);
529
530 if (FAIL == zbx_tm_save_task(task))
531 taskid = 0;
532
533 zbx_tm_task_free(task);
534
535 return taskid;
536 }
ll. 523-528 にて実行するコマンドに関するデータを作成し、l.530 の zbx_tm_save_task() にて、task テーブルへデータを挿入した後に、task_remote_command テーブルへも挿入を行っています。
src/libs/zbxtasks/task.c
409 int zbx_tm_save_task(zbx_tm_task_t *task)
410 {
...
415 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
416
417 switch (task->type)
418 {
419 case ZBX_TM_TASK_REMOTE_COMMAND:
420 save_task_data_func = tm_save_remote_command_tasks;
421 break;
422 case ZBX_TM_TASK_REMOTE_COMMAND_RESULT:
423 save_task_data_func = tm_save_remote_command_result_tasks;
424 break;
425 default:
426 THIS_SHOULD_NEVER_HAPPEN;
427 return FAIL;
428 }
429
430 if (0 == task->taskid)
431 task->taskid = DBget_maxid("task");
432
433 if (SUCCEED == (ret = tm_save_tasks(&task, 1)))
434 ret = save_task_data_func(&task, 1);
435
436 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
437
438 return ret;
439 }
l.433 の tm_save_tasks() で task テーブルへ挿入され、l.434 の save_task_data_func( 実体は、l.420 での tm_save_remote_command_tasks()) にて、task_remote_command テーブルに挿入されています。
次回へ続く
Task Manager プロセスは、task テーブルをポーリングして処理を行っているプロセスでした。Escalator プロセスがプロキシ経由でのリモートコマンドの実行データを task_remote_command テーブルへ挿入していることはどういった理由があるのでしょう?
これは、サーバーとプロキシの関係に理由があります。次回は、実際にプロキシがリモートコマンドを実行するにあたり、どのようにサーバーからデータを受け取るかを記します。
ちなみに、大差はありませんが、対象となるプロキシはアクティブプロキシとなります。
関連記事
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
注意事項
- 本ドキュメントの内容は、予告なしに変更される場合があります。
- 本ドキュメントは、限られた評価環境における検証結果をもとに作成しており、全ての環境での動作を保証するものではありません。
- 本ドキュメントの内容に基づき、導入、設定、運用を行なったことにより損害が生じた場合でも、当社はその損害についての責任を負いません。あくまでお客さまのご判断にてご使用ください。