採用情報

お問い合わせ

BLOG

Zabbix テック・ラウンジ

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 テーブルに挿入されています。

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

次回へ続く

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

注意事項

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