自宅に設置してある Web サーバの生死を自宅外の Linux サーバから監視したい。そのためのシェルスクリプトを書いた。
自宅で運用しているサーバから応答がなくなることがある。実際にはサーバがダウンしているのではなく,自宅入口の ADSL モデムがダウンしている。ADSL モデムは富士通 FA11-M2 である (nlog(n): ADSL モデム FA11-M2 を設置)。
自宅のPCで自宅のサーバへアクセスしている場合,ADSL モデムが停止していても問題はないため,どうしても発見が遅くなってしまう。外部から HTTP アクセスができなくなったときにメールで通知してくれるようなシステムが欲しい。もちろん,そのメールは自宅サーバ宛ではない方向で。
Voodoo Marketing さんがこの目的にぴったりのシェルスクリプトを公開している (WEBサーバ死活監視シェルスクリプト » Voodoo Marketing)。これはいい。問題があるとすれば,サーバが応答しない場合,シェルスクリプトが起動する度にメールを送ってしまうことである。そこで,サーバが応答しなくなったときに1度だけ,サーバが応答を始めたときに1度だけ,メールを送信するような仕組みを持たせることにした。
スクリプト本体は以下の通り。例えば,deadoralive.sh という名前をつけておき,chmod で実行許可を与えておく。自宅サーバを監視するには,自宅外のサーバに設置する必要がある。
設定が必要なのは,URL, STATFILE, MAIL の3つ。URL に監視したい Web サーバの URL を,STATFILE は現在のサーバステータスを保存しておくためのテキストファイルへのパスを,MAIL には通知したいメールアドレスを,それぞれ設定する。
crontab には,例えば5分に1度起動するように登録しておけばよい。
PREVIOUSSTAT, CURRENTSTAT には,Web サーバのステータスが代入される。どちらも wget で取得したもので,PREVIOUSSTAT は前回のチェック時のステータスをファイルから読み込んだもので,CURRENTSTAT は現在のステータスを wget から受け取って設定する。wget は --spider でスパイダーモードで動作してページのダウンロードを行わず,-nv で基本的な情報だけを出力するようにし,--tries=1 で試行回数を1回に (デフォルト20回),--timeout=10 でタイムアウトを10秒 (デフォルト900秒) にしている (GNU Wget 1.9 Manual: 呼び出し)。
「-nv」スイッチは「no verbose モード」という意味の短縮表記である。このスイッチだけ短い形式にしたのは,バージョンによって長い形式の書き方が違うからである。Wget 1.10 までは「--non-verbose」,Wget 1.11 以降は「--no-verbose」となっている。
ステータスとしては,次のようなものが返ってくる。接続できた場合は,
接続に失敗した場合は,普通
で,たまたま別のウェブサーバだったりすると,
となる場合もまれにある。そのサーバが OK を応答すれば「200 OK」が返ってくる (この場合は死んでいることの確認はできない)。何も返ってこない場合には,CURRENTCODE に「Connection timed out.」を設定する。
PREVIOUSCODE と CURRENTCODE は,それぞれ PREVIOUSSTAT, CURRENTSTAT で受け取ったステータス内の,サーバレスポンスの3桁の数値だけが入る。数値がない場合は空欄になる。この3桁の数値を取り出すところが難しい。Perl を呼び出してもできるが (例えば「perl -e 'while(<>){if(/\d{3}/){print $&;}}'」のように),それならば全部 Perl でやればという話になる。ここでは expr コマンド (Manpage of expr) を呼び出すことにした。マッチのさせ方が Perl とは違うので注意が必要だ。
expr の第2引数は,全体をシングルクォートで囲む。数字3文字にマッチさせて,マッチした数字だけを取り出したいので,([[:digit:]]{3}) となるが,丸括弧 () と中括弧 {} はエスケープする必要があるので \([[:digit:]]\{3\}\) となる。数字の前後には任意の文字が並ぶ可能性があるので「.*」を前後につけると,最終的に '.*\([[:digit:]]\{3\}\).*' となるのである。丸括弧 () にエスケープが必要なのはマニュアルに書いてあるが,中括弧にも必要なことは書いてないのでハマった。例が見つかったので (Unix and Linux - grep tutorial) ようやく解決した。マッチのさせ方に関しては,前後の文字にもマッチするように書くというところが,Perl と決定的に異なる点である。
スクリプトでは,最終的に,状態に変化があったとき,すなわち「生→死」または「死→生」のときだけメールを送るようになっている。
スクリプトの内部では,変数を文字として扱っている。"$CURRENTCODE" のようにダブルクォートで囲めば文字として扱われ,$CURRENTCODE のように囲まなければ数値として扱われる。CURRENTCODE には数値が入ることを期待しているが,空欄になる場合もあり,空欄は文字の扱いとなるため,数値も含めて文字として扱うようにしてある。数値扱いの変数に空文字が入っていたりすると,
というメッセージでエラーになる。「-ne」や「-eq」は数値変数の比較演算子で,文字変数ならそれぞれ「!=」「=」に対応するものである。
上のスクリプトでは変数をすべて文字として扱ったが,「数値は数値として扱いたい」という思いも捨てきれない。ただし,応答がなかった場合の扱いが問題になる。プログラムを単純なものに留めておくには,応答がない場合にも何らかのステータスコードを割り当てるのがよさそうだ。HTTP のステータスコードとしては,100番台から500番台までが使用されるので (HTTPステータスコード - Wikipedia),これら以外の数値である必要がある。例えば「999」割り当てることにすると,スクリプトは次のようになる。
「何でもいいから前後に空白のある3文字にマッチ」と思って,expr の第2引数に '.*\ (...\) .*' と書いたら,「エラー」という日本語3文字にマッチした。日本語1文字も1文字として扱うようになっていて驚いた。
死活監視をしてくれるフリーのオンラインサービスには,livedoor の 無料のサーバ監視、ネットワーク監視のことならデータホテルパトロール や (紹介記事: ライブドア、インターネットサーバーの死活監視サービスを無償提供),Are My Sites Up? (紹介記事: サーバの死活監視をしてくれる『Are My Sites Up?』 | CREAMU) などがあるようだ。
Posted by n at 2011-01-27 22:33 | Edit | Comments (0) | Trackback(0)
Master Archive Index
Total Entry Count: 1957