エクスターナルコマンド (External Commands)


・エクスターナルコマンド(External Commands)

NetSaint応用編の第二弾は「エクスターナルコマンド(External Commands)」です。
この「エクスターナルコマンド」が何かというと、
 「NetSaint以外のアプリケーションやCGI等から、NetSaintに対して様々な命令を与え実行させる
仕組みなのです。

具体的にNetSaintにさせることができることは、
  ・ Netsaintを終了させたり、再起動させたりする。
  ・ スタンバイ・モードに変えたり、アクティブ・モードに変えたりする。
  ・ あるサービスのチェックをできなくしたり、再度チェックできるようにする。
  ・ あるホストの全てのサービスのチェックをできなくしたり、再度チェックできるようにする。
  ・ ホストやサービスに関するメールでの通知をできなくしたり、できるようにする。
  ・ ホストやサービスに関するコメントを書き込む。
などがあります。

そして、NetSaintはこれらの命令が与えられたかどうかを次のタイミングでチェックします。
  ・ 定期的なチェック = Main Configuration File(/usr/local/netsaint/etc/netsaint.cfg)の
                「command_check_interval」でチェックする間隔を定義します。
                (基本編「Main Configuration File」のNo.10です。)
  ・ イベントハンドラーが実行された場合。

今回は、「監視対象のホストまたはサービスに異常が発生したり、復旧した場合に、イベントハンドラーが実行され、エクスターナルコマンドによってNetSaintをスタンバイ・モードに変えたり、アクティブ・モードに変える」場合を例に説明していきます。
「スタンバイ・モード」や「アクティブ・モード」が何だったかなぁという人は、基本編の「NetSaintの基本的な用語」を見直してください。

それでは、「エクスターナルコマンド」の設定について説明していきましょう。

(1)前提条件
今回の事例を説明するための簡単なネットワーク構成を下記に示します。
本当に恥ずかしくなるほど、簡単なモデルですが。。。(~_~;)

NetSaintは、通常「アクティブ・モード」で稼動していますが、モデムに何らかのトラブルが発生したとNetSaintが検知した場合、「スタンバイ・モード」に切り替わるようにします。
そして、モデムが復旧したとNetSaintが検知した場合、今度は「アクティブ・モード」に切り替わるようにしてやろう、というわけです。

これは、結構便利です。
といいますのは、インターネットと交信できなくなった場合、異常発生時のメールがキューにたまります。
したがって、交信できない状態が長く続くと、溜まってしまうメールも結構な数になってしまい、「アクティブ・モード」のままですと、復旧時にはウンザリするほどのメールを受信することになります。

しかし、「スタンバイ・モード」にしておけば、ホストやサービスの監視は続けますが、通知メールの発信はされませんので、静かに復旧を待つことができるのです。

当サーバーのインターネットとの回線がいろいろな原因で切断状態(のよう)になることが多く、そのたびに復旧してから大量のメールを受取ることになっていました。
しかも、そのメールをDOCOMOの携帯でも受信するようにしていたため、一度に大量のメールがインターネットから送信されてきたということで、DOCOMOのメールサーバーが受信を拒否するようになってしまいました。
私がエクスターナルコマンドを使うようになった理由はそこにあるのです。(~_~;)


(2)Main Configuration File の修正
NetSaintのデフォルトの設定では、エクスターナルコマンドを使えるようにはなっていません。
そこでまず、エクスターナルコマンドが使えるように Main Configuration File (/usr/local/netsaint/etc/netsaint.cfg) の次の箇所を修正しましょう。
(基本編 「Main Configuration File」 のNo.9の項目です。)

  ・ 「check_external_commands」オプションの値を「1」にする。

デフォルトでは、この値が「0」になっていますので必ず修正するようにしてください。


(3)エクスターナルコマンドのユーザーとパーミッション
さて、イベントハンドラーではスクリプト実行時のユーザーとパーミッションの問題を解決する方法として「sudo」を使うということを説明しました。

エクスターナルコマンドについても、そのコマンドのユーザーとパーミッションの問題がありますが、こちらのほうは「sudo」を使うのではなく、別の方法で対処します。

ここでおさらいですが、NetSaintは「netsaint」というユーザーで稼動しています。
ですから、NetSaint以外のアプリケーションやCGI等が、NetSaintに与える命令(コマンド)は「netsaint」というユーザーに実行権があるように工夫しなければなりません。

その方法をここで説明しますが、まず下記の一覧の処理を御覧ください。
(丸付き数字は、説明のため便宜的に割り振ったものです。)

@ # /usr/sbin/groupadd  nscmd
A # /usr/sbin/usermod  -G  nscmd  netsaint
B # /usr/sbin/usermod  -G nscmd  apache

C # mkdir  /usr/local/netsaint/var/rw
D # chown  netsaint.nscmd  /usr/local/netsaint/var/rw
E # chmod  u+rwx  /usr/local/netsaint/var/rw
F # chmod  g+rw   /usr/local/netsaint/var/rw
G # chmod  g+s    /usr/local/netsaint/var/rw

まず、前半の@〜Bですが、「nscmd」というグループを作成し、ユーザー「netsaint」と「apache」をこのグループに加えています。

次に、Cで「/usr/local/netsaint/var/rw」というディレクトリを作成し、Dでそのディレクトリのユーザー・グループを「netsaint」に変更し、E〜Gでそれぞれのパーミッションを変更しています。
ここで、特にGの「g+s」、すなわち「SGID」(=Set Group ID)がいわゆる「勘所」ということになるのでしょう。

つまり、エクスターナルコマンドを作動させるために、
  ・ エクスターナルコマンドを作り出すCGI等の実行ユーザーである「apache」をNetSaintの実行
   ユーザーである「netsaint」と共通のグループ「nscmd」とし、
  ・ 「/usr/local/netsaint/var/rw」というディレクトリにエクスターナルコマンドのスクリプトを書き
   込ませば、
  ・ そのスクリプトは「SGID」により、ユーザー「netsaint」が所属するグループ「nscmd」の実行権
   で実行されるので、NetSaint本体がその命令を実行することができる。
という仕組みを作成しているのです。
説明が下手ですねぇ。(-_-メ)

まぁ、説明を読むより枠の中の実際の処理(コマンド)をじっくり見たほうがわかりやすいかもしれません。
次、行きますね。(~_~;)


(4)イベントハンドラーの準備
それでは、モデムにトラブルが発生したときに起動するイベントハンドラーを準備しましょう。

このイベントハンドラーのファイル名を
  @ handle-master-host-event    → ホスト用のイベントハンドラー
  A handle-master-service-event  → サービス用のイベントハンドラー
とします。

まず、上記のイベントハンドラーを使うことを 「Host Configuration File (/usr/local/netsaint/etc/host.cfg)」に定義します。
基本編 「Host Configuration File」の(2)HOST CONFIGURATION と (7)SERVICE CONFIGURATION を次のように修正します。

 ・ HOST CONFIGURATION の修正
   host[modem]=MODEM;192.168.0.1;Linux Server;check-router-alive;10;30;24x7;1;1;1;
           
   host[modem]=MODEM;192.168.0.1;Linux Server;check-router-alive;10;30;24x7;1;1;1;
                                      handle-master-host-event
 
                                           (* 実際は1行です。)

 ・ SERVICE CONFIGURATION の修正
   service[modem]=PING;0;24x7;3;5;1;e-RYOICHI.net-admins;60;24x7;1;1;0;;check_ping
   service[modem]=PING;0;24x7;3;5;1;e-RYOICHI.net-admins;60;24x7;1;1;0;
                             handle-master-service-event;check_ping

                                (*これも実際は1行です。)

次に、これらのイベントハンドラーのコマンドを /usr/loca/netsatin/etc/command.cfg ファイルに定義します。
このファイルはその名前からわかるように NetSain で使用される様々なコマンドのフォーマットを定義するものです。
それでは、/usr/local/netsaint/etc/command.cfg ファイルに次の2つのコマンドの定義を追加しましょう。
追加する場所に関しては特に指定はありません。
私の場合、上記ファイルの先頭に書かれているコメントの終了直後に追加しました。

  command[handle-master-host-event]=$USER2$/handle-master-host-event
                    $HOSTSTATE$ $STATETYPE$ $HOSTATTEMPT$

 command[handle-master-service-event]=$USER2$/handle-master-service-event
                    $SERVICESTATE$ $STATETYPE$ $SERVICEATTEMPT$

                                                               *(注):実際にはそれぞれ1行で記述します。

commandの後の[ ]で囲まれた部分がコマンド名です。
そして、「$USER2$/handle-master-host-event」や「$USER2$handle-master-service-event」が実際に実行するスクリプト名です。

ここで、新に「$USER2$」というマクロが使われています。
書き方の雰囲気から、handle-master-host-event や handle-master-service-event のスクリプトファイルを配置するディレトリらしい、ということがわかるかと思います。

ところが、この「$USER2$」というマクロはデフォルトでは定義されておらず、どこで定義されているのかがわかりませんでした。
定義ファイルなのでおそらく /usr/local/netsaint/etc のディレクトリにあるファイルのどこかであろうと推測し、ようやく /usr/local/netsaint/etc/resource.cfg ファイルにあることを見つけ出しました。(^_^)v

この /usr/local/netsaint/etc/resource.cfg ファイルには、 プラグインやイベントハンドラーのパスなどを定義する場所として使われています。

デフォルトの状態では、「$USER1$」のプラグインのパスが定義されていますが、その他の定義はコメントアウトされています。
そこで、「$USER2$」のイベントハンドラーのパスが定義されている行のコメントアウトをはずせばOKです。

No. マクロ名 内        容
1 $USER1$ プラグインのパス
値 : /usr/local/netsaint/libexec
2 $USER2$ イベントハンドラーのパス
値 : /usr/local/netsaint/libexec/eventhandlers


(5)イベントハンドラーのスクリプト
実際のイベントハンドラーのスクリプトは下記のとおりです。

これらのスクリプトは、先ほど定義した「$UESR2$」のディレクトリに配置します。
なお、ここで使われている「$1」、「$2」、「$3」については、「(4)イベントハンドラーの準備」で定義したコマンドのマクロ名のその時点(イベントハンドラーが実行された時点)での値が入ります。

No. 変数 マクロ名 内        容
1 $1 $HOSTSTATE$
$SERVICESTATE$
ホストまたはサービスのステータス・レベル
ホストの場合   : UP、DOWN、UNREACABLE
サービスの場合 : OK、WARNING、UNKNOWN、CRITICAL
2 $2 $STATETYPE$ ステートタイプ。
値 : HARD、SOFT
3 $3 $HOSTATTEMPT$
$SERVICEATTEMPT$
現在のホストまたはサービスの状態をチェックした回数。
値 : 1、2、3、4、5、・・・

また、ここで使われている
   「$eventhandlerdir/enter_standby_mode」や「$eventhandlerdir/enter_active_mode
がNetSaintのプログラムモードを「スタンバイ・モード」や「アクティブ・モード」に変える「エクスターナルコマンド」を発行するスクリプトファイル名です。

@ handle-master-host-event
#!/bin/sh

# Location of the echo and mail commands
echocmd="/bin/echo"
mailcmd="/bin/mail"

# Location of the event handlers
eventhandlerdir="/usr/local/netsaint/libexec/eventhandlers"

# Only take action on hard service states...
case "$2" in
HARD)

      case "$1" in
      DOWN)
            `$eventhandlerdir/enter_standby_mode`
            ;;

      UNREACHABLE)
            `$eventhandlerdir/enter_standby_mode`
            ;;

      UP)
            `$eventhandlerdir/enter_active_mode`
            ;;

      esac
      ;;

SOFT)
      case "$1" in
      DOWN)
            case "$3" in
            2)
                  `$eventhandlerdir/enter_standby_mode`
                  ;;
            esac
            ;;
      esac
      ;;
esac
exit 0

このスクリプトの内容を簡単に説明すると、次のようになります。

  ・ ホストのステート・タイプが「HARD」の状態で、
      ステータス・レベルが「DOWN」、「UNREACABLE」の場合には、
         「スタンバイ・モード」になるエクスターナルコマンドを発行するスクリプト実行します。
  ・ ホストのステート・タイプが「SOFT」の状態で、
      ステータス・レベルが「DOWN」を検出して2回目となった場合には
         「スタンバイ・モード」になるエクスターナルコマンドを発行するスクリプトを実行します。
  ・ ホストのステート・タイプが「HARD」の状態で、
      ステータス・レベルが「UP」の場合には、
         「アクティブ・モード」になるエクスターナルコマンドを発行するスクリプトを実行します。

A handle-master-service-event
#!/bin/sh

# Location of the echo and mail commands
echocmd="/bin/echo"
mailcmd="/bin/mail"

# Location of the event handlers
eventhandlerdir="/usr/local/netsaint/libexec/eventhandlers"

# Only take action on hard service states...
case "$2" in
HARD)

      case "$1" in
      CRITICAL)
            `$eventhandlerdir/enter_standby_mode`
            ;;

      WARNING)
            ;;

      UNKNOWN)
            ;;

      RECOVERED)
            `$eventhandlerdir/enter_active_mode`
            ;;

      OK)
            ;;
      esac
      ;;

SOFT)
      case "$1" in
      CRITICAL)
            case "$3" in
            2)
                  `$eventhandlerdir/enter_standby_mode`
                  ;;
            esac
            ;;
      esac
      ;;
esac
exit 0

このスクリプトの内容を簡単に説明すると、次のようになります。

  ・ サービスのステート・タイプが「HARD」の状態で、
      ステータス・レベルが「WARNING」、「UNKNOWN」、「OK」の場合には、
         なにもしません。
  ・ サービスのステート・タイプが「HARD」の状態で、
      ステータス・レベルが「CRITICAL」の場合には、
         「スタンバイ・モード」になるエクスターナルコマンドを発行するスクリプトを実行します。
  ・ サービスのステート・タイプが「SOFT」の状態で、
      ステータス・レベルが「CRITICAL」を検出して2回目となった場合には
         「スタンバイ・モード」になるエクスターナルコマンドを発行するスクリプトを実行します。
  ・ サービスのステート・タイプが「HARD」の状態で、
      ステータス・レベルが「RECOVERED」の場合には、
         「アクティブ・モード」になるエクスターナルコマンドを発行するスクリプトを実行します。


(6)エクスターナルコマンドを発行するスクリプト
それでは、最後に「エクスターナルコマンド」を発行するスクリプトを示します。
これらのスクリプトにより、/usr/local/netsaint/var/rw のディレクトリに 「netsaint.cmd」というエクスターナルコマンドが書き込まれ、NetSaintがそれを実行し「スタンバイ・モード」や「アクティブ・モード」に移行することになるのです。

@ enter_standby_mode_
#!/bin/sh

echocmd="/bin/echo"

CommandFile="/usr/local/netsaint/var/rw/netsaint.cmd"

# get the current date/time in seconds since UNIX epoch
datetime=`date +%s`

# create the command line to add to the command file
cmdline="[$datetime] ENTER_STANDBY_MODE;$datetime"

# append the command to the end of the command file
`$echocmd $cmdline >> $CommandFile`

A enter_active_mode_
#!/bin/sh

echocmd="/bin/echo"

CommandFile="/usr/local/netsaint/var/rw/netsaint.cmd"

# get the current date/time in seconds since UNIX epoch
datetime=`date +%s`

# create the command line to add to the command file
cmdline="[$datetime] ENTER_ACTIVE_MODE;$datetime"

# append the command to the end of the command file
`$echocmd $cmdline >> $CommandFile`


なお、これらのスクリプトの元になったいろいろなサンプルが、 netsaint--0.0.7.tar.gz を展開した ( /usr/local/src/ ) netsaint-0.0.7/eventhandlers/ のディレクトリ以下にありますので、そちらの方も参考にしてください。


back HOME