現在位置: ホーム / 製品・サービス / 統合システム監視 MIRACLE ZBX / MIRACLE ZBX - Zabbix テック・ラウンジ / Zabbix 3.2以降の新機能解説(Zabbix 4.0を見据えて) その8

Zabbix 3.2以降の新機能解説(Zabbix 4.0を見据えて) その8

こんにちは、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テーブルへ挿入していることはどういった理由があるのでしょう?

これは、サーバとプロキシの関係に理由があります。次回は、実際にプロキシがリモートコマンドを実行するにあたり、どのようにサーバからデータを受け取るかを記します。

ちなみに、大差はありませんが、対象となるプロキシはアクティブプロキシとなります。 

関連記事

注意事項

本ドキュメントの内容は、予告なしに変更される場合があります。
本ドキュメントは、限られた評価環境における検証結果をもとに作成しており、全ての環境での動作を保証するものではありません。
本ドキュメントの内容に基づき、導入、設定、運用を行なったことにより損害が生じた場合でも、当社はその損害についての責任を負いません。あくまでお客さまのご判断にてご使用ください。

 

MIRACLE ZBX 製品・サポートサービス 詳しくはこちら

MIRACLE ZBX Virtual Appliance V3.0 評価版のお申し込み

製品・サービスについてのお問い合わせ

お問い合わせフォームMIRACLE ZBX製品やサポートサービスについてのご相談やご質問は、「お問い合わせフォーム」よりお気軽にお問い合わせください。