チュートリアル:nagios(check_http)でIWSSを監視する

(2010/11/10)


nagiosはOSS(Open Source Software)として提供されている、ネットワーク機器やサーバなどの監視ツールです。職場で動いているのはやや古いバージョン(nagios-2.5.1)で、以前コンサルな人に実装してもらったものです。これにIWSSの監視を追加しようと思いましたが、どうもうまくいきません。そもそもデバッグのやり方がわかりません。特定のサービスだけ個別にCLIで動かす機能とかがあってもよさそうなのですが。

本番環境で実験するのはよろしくないので、該当部分だけを単体試験するために別ホストにnagiosを入れてみました。このドキュメントはその時の作業をチュートリアル形式にしたものです。OSは CentOS 5.5 latest、ホスト名はwingroadです。常にアップデートを当ててOSが最新環境になっていることが前提です。ドメイン名はexample.comに変えています。引用している設定ファイル中のコメント部分は適宜和訳しています。サービス(デーモン)の調整方法に関する参考になれば幸いです。

本来はドキュメントや書籍を1から読んで、すべてを理解してから実装するというのが王道なのは言うまでもありません。しかしながら、現実は費用や作業時間等いろいろな制約条件があり、どうしても場当たり的な対応になってしまいがちです。ただここでは、同じ場当たりでも、単純なコピペではない、学習を兼ねた場当たりを提案しています。一応『nagios(check_http)でIWSSを監視する』という最終目的はあるのですが、学習という要素を入れているので、正解に辿りつかずに寄り道した部分の記述や、まだ未解決の部分もあることを、あらかじめご了承ください。

インストール

他の血を入れることにはなりますが、rpmforgeからもらってくるという、安易な方を選びました。

m-hotta@wingroad:~$ wget http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.1-1.el5.rf.i386.rpm
m-hotta@wingroad:~$ sudo rpm -Uvh rpmforge-release-0.5.1-1.el5.rf.i386.rpm
m-hotta@wingroad:~$ sudo yum install nagios*

Installed:
  nagios.i386 0:3.2.2-1.el5.rf
  nagios-devel.i386 0:3.2.2-1.el5.rf
  nagios-nrpe.i386 0:2.12-1.el5.rf
  nagios-nsca.i386 0:2.7.2-2.el5.rf
  nagios-nsca-client.i386 0:2.7.2-2.el5.rf
  nagios-plugins.i386 0:1.4.15-1.el5.rf
  nagios-plugins-nrpe.i386 0:2.12-1.el5.rf
  nagios-plugins-setuid.i386 0:1.4.15-1.el5.rf

Dependency Installed:
  fping.i386 0:2.4-1.b2.3.el5.rf
  libmcrypt.i386 0:2.5.8-4.el5.centos
  perl-Crypt-DES.i386 0:2.05-3.2.el5.rf 
  perl-Net-SNMP.noarch 0:5.2.0-1.2.el5.rf

Complete!

3.2.2が落ちてきたようです。まぁそこそこ新しいのでよしとします(最新は3.2.3)。

デフォルト状態で動作確認

m-hotta@wingroad:~$ sudo su -
root@wingroad:~# service httpd restart

とりあえずブラウザから http://wingroad/nagios/ にアクセスしてみると、Basic認証がかかっているようです。/etc/httpd/conf.d/nagios.confによると、/etc/nagios/htpasswd.usersで認証しているみたい。

root@wingroad:~# cat /etc/nagios/htpasswd.users
cat: /etc/nagios/htpasswd.users: そのようなファイルやディレクトリはありません

適当に(*1)設定してみます。

root@wingroad:~# htpasswd -c /etc/nagios/htpasswd.users nagiosadmin
New password: ********
Re-type new password: ********
Adding password for user nagiosadmin

これで http://wingroad/nagios/ を開けるようになったようです。

(*1)…nagiosadminはデフォルトの管理者名であり、/etc/nagios/cgi.cfgで定義されています。

root@wingroad:~# service nagios configtest
Checking config for nagios:                                [  OK  ]
root@wingroad:~# service nagios start
nagios は停止しています
nagios を起動中:                                           [  OK  ]

nagios本体側も、デフォルトの状態で正しく起動するようです。

監視したいホストを追加

nagiosのメインの設定ファイルは/etc/nagios/nagios.cfgです。ここに監視したいホストcalina(10.6.3.17)の定義を追加してみました。デフォルトで入っているlocalhostに対するチェックは(ログが汚れそうなので)コメントアウトし、日付の形式もYYYY-MM-DD HH:MM:SS形式に変えてあります。値の意味は/etc/nagios/nagios.cfgの中にコメントとして書いてあります(ただし英語)。

root@wingroad:/etc/nagios# diff -Nr nagios.cfg.pkg-orig nagios.cfg
36c36
< cfg_file=/etc/nagios/objects/localhost.cfg
---
> ## cfg_file=/etc/nagios/objects/localhost.cfg
1087c1087
< date_format=us
---
> date_format=iso8601
1320a1321,1323
>
> # added by M.Hotta 2010/11/09
> cfg_file=/etc/nagios/objects/calina.cfg

calina.cfgの中身は以下のような感じ。/etc/nagios/objects/localhost.cfgの中から適当にコピペしただけです。

root@wingroad:/etc/nagios# cat objects/calina.cfg
define host {
    use         linux-server    ; 使用するホストテンプレート名
    host_name   calina.example.com
    alias       calina
    address     10.6.3.17
}

define service  {
    use         local-service   ; 使用するサービステンプレート名
    host_name   calina.example.com
    service_description     IWSS
    check_command           check_http
    notifications_enabled   1
}

文法が正しいことを確認し、サービスを再起動します。

root@wingroad:~# service nagios configtest
Checking config for nagios:                                [  OK  ]
root@wingroad:~# service nagios restart
nagios を停止中:                                           [  OK  ]
nagios を起動中:                                           [  OK  ]

もし文法が間違っている場合、以下のような出力になります。

root@wingroad:~# service nagios configtest
Checking config for nagios: Configuration validation failed[失敗]

しかし、これでは間違っている箇所がわかりません。エラー内容を知りたい場合は以下のようにします。

root@wingroad:~# nagios -v ./nagios.cfg
(中略)
Reading configuration data...
Error in configuration file '/etc/nagios/./nagios.cfg' - Line 1324 (NULL value)
   Error processing main config file!

GUI による確認

http://wingroad/nagios/ にアクセスして左のメニューからHostsを選択します。ホストとしてはUpしていますが、サービスとしてはPending(未確定)になっています。

calina-pending

しばらく待っていると、PendingがCritical(重大なエラー)に変わりました。ホストcalina上ではIWSSが正常に稼働しているはずなのですが、nagiosからはこれをうまく認識できていないようです。

calina-critical

コラム:文字化け発生(未解決)

CentOS 5.5を普通にインストールした場合、OSの文字コードはUTF-8になります。これでローカライズされているコマンドの出力は日本語になりますが、nagiosでは一部が化けてしまうことがあるようです。具体的には、GUIからServicesを選択したとき、calinaのStatus Informationが化けていました(『接続を拒否されました』(後述)と表示しようとしているのではないかと想像。)。

文字化け

このため、下記の処理を入れてみました。

root@wingroad:~# echo 'LANG=C' >> /etc/sysconfig/nagios

これはservice管理コマンド経由で動かすサービスに対して環境変数を設定するための常套手段です。たとえばnagiosサービス(/etc/init.d/nagios)の場合は以下のところから呼び出されます。

root@wingroad:~# grep sysconfig /etc/init.d/nagios
[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog

ところがこれを入れても、まだ文字化けが直りません。そもそも、サービスを起動すると、すぐにcalinaがCriticalになってしまいます(起動直後はPendingだったはず)。これは、nagiosが前回の結果をキャッシュ(objects.cach)しているからのようです。また、サービス停止時に状態を保持するファイル(retention.dat)もあるようなので、これもついでに消しました。ちなみにretention.datはサービスを停止する際、もしなければ自動的に作成されるようです。

root@wingroad:/var/nagios# rm -f objects.cache retention.dat

これでサービスを再起動すると、初期状態のPendingに戻ってくれました。でもやっぱり文字化けは直っていません(継続調査)。外部プラグインを呼ぶときの問題のような気が…。 未確認ですが、/etc/sysconfig/i18nを変更してサーバをリブートすれば、直りそうな気もします。ただこれだとOS全体が英語になってしまいそうで悔しいので、ペンディングにしておきます;ー)

ちなみに、nagiosの設定項目の中にretain_status_information/retain_nonstatus_informationというのがありました。これを0にすることで、サービスの停止時に前回の情報を保持しないようにできるようです。

チューニング項目

起動直後はPending状態だったホストは、しばらくするとCritical状態になりました。『しばらく』がどれくらいの時間なのかは、チューニング次第となります。これらの値はcalina.cfg(下記に再掲)では明示的には指定していないので、calinaのホスト定義で使っているlocal-serviceというテンプレートの定義に従います。

root@wingroad:~# cat /etc/nagios/objects/calina.cfg
define host {
    use         linux-server    ; 使用するホストテンプレート名
    host_name   calina.example.com
    alias       calina
    address     10.6.3.17
}

define service  {
    use         local-service   ; 使用するサービステンプレート名
    host_name                   calina.example.com
    service_description     IWSS
    check_command           check_http
    notifications_enabled   1
}

local-serviceというサービスの定義は/etc/nagios/objects/templates.cfgにありました(便宜的にコメント部分を和訳しています)。

root@wingroad:~# tail /etc/nagios/objects/templates.cfg
define service{
    name        local-service   ; このサービステンプレートの名前
    use         generic-service ; デフォルト値をgeneric-serviceから継承する
    max_check_attempts      4   ; 最終の(HARD)状態と認定するまで、最大4回再検査する
    normal_check_interval   5   ; 通常時は5秒おきにサービスを検査する
    retry_check_interval    1   ; HARD状態になるまで1分ごとに再検査する
    register                0   ; この定義を登録しないこと。これは実際のサービスではなく、単なるテンプレートです!
}

これによれば、『正常(Ok)』時は5分間隔で検査。『未確定(Pending)』時は1分おきに4回まで調査して、それでもだめなら『異常(Critical)』になるようです。これ以外にもたくさんのチューニング項目があります。local-serviceというサービスにおいては、これ以外のチューニング項目はgeneric-serviceで定義されている値を使うようです。

ログの確認

ログは標準では以下のものがあるようです。一般にRHEL/Fedora/CentOSでは、ログファイルは/var/logもしくは/var/log/サービス名配下に置かれます。

root@wingroad:~# ls -lR /var/log/nagios/
/var/log/nagios/:
合計 8
drwxr-xr-x 2 nagios nagios 4096 11月  9 00:00 archives
-rw-r--r-- 1 nagios nagios 2159 11月  9 11:41 nagios.log

/var/log/nagios/archives:
合計 4
-rw-r--r-- 1 nagios nagios 1519 11月  8 23:54 nagios-11-09-2010-00.log

ただ、中身をみても大した情報がないので、デバッグレベルを最大まで上げてみます。デバッグレベルはnagios.cfg中のコメント(和訳)によれば、以下のようになっています。

# デバッグレベル
# このオプションは、(もしあれば)どれくらいの量のデバッグ情報をデバッグ用
# ファイルに書き出すかを規定する。(パイプ記号'|'でつないだ)OR値を使えば
# 複数の値を定義可能。
# 値:
#     -1 = 全部
#      0 = なし
#      1 = 関数
#      2 = 設定
#      4 = プロセス情報
#      8 = スケジュールされたイベント
#     16 = Host/service 検査
#     32 = 通知
#     64 = イベントブローカ
#     128 = 外部コマンド
#     256 = コマンド
#     512 = スケジュールされたサービス停止
#    1024 = コメント
#    2048 = マクロ
root@wingroad:/etc/nagios# diff -Nr nagios.cfg.orig nagios.cfg
1292c1292
< debug_level=0
---
> debug_level=-1
1302c1302
< debug_verbosity=1
---
> debug_verbosity=2
root@wingroad:/etc/nagios# service nagios reload
nagios (pid 22127) を実行中...
nagios を再読み込み中:                                     [  OK  ]
root@wingroad:~# ls -lR /var/log/nagios/
/var/log/nagios/:
合計 380
drwxr-xr-x 2 nagios nagios   4096 11月  9 00:00 archives
-rw-r--r-- 1 nagios nagios 373870 11月  9 11:53 nagios.debug
-rw-r--r-- 1 nagios nagios   2915 11月  9 11:51 nagios.log

/var/log/nagios/archives:
合計 4
-rw-r--r-- 1 nagios nagios 1519 11月  8 23:54 nagios-11-09-2010-00.log

nagios.debugというファイルが作られています。ただかなり大きいので、慣れてきたらデバッグレベルを下げたほうがよいでしょう。nagios.debugを開いて'IWSS'で検索すると、以下のような出力を見つけました。

[1289271886.119169] [2048.1] [pid=22337] **** BEGIN MACRO PROCESSING ***********
[1289271886.119180] [2048.1] [pid=22337] Processing: '$USER1$/check_http -I $HOSTADDRESS$ $ARG1$'
[1289271886.119192] [2048.2] [pid=22337]   Processing part: ''
[1289271886.119205] [2048.2] [pid=22337]   Not currently in macro.  Running output (0): ''
[1289271886.119217] [2048.2] [pid=22337]   Processing part: 'USER1'
[1289271886.119233] [2048.2] [pid=22337]   Processed 'USER1', Clean Options: 0, Free: 0
[1289271886.119244] [2048.2] [pid=22337]   Processed 'USER1', Clean Options: 0, Free: 0
[1289271886.119256] [2048.2] [pid=22337]   Cleaning options: global=0, local=0, effective=0
[1289271886.119269] [2048.2] [pid=22337]   Uncleaned macro.  Running output (23): '/usr/lib/nagios/plugins'
[1289271886.119281] [2048.2] [pid=22337]   Just finished macro.  Running output (23): '/usr/lib/nagios/plugins'
[1289271886.119292] [2048.2] [pid=22337]   Processing part: '/check_http -I '
[1289271886.119329] [2048.2] [pid=22337]   Not currently in macro.  Running output (38): '/usr/lib/nagios/plugins/check_http -I '
[1289271886.119341] [2048.2] [pid=22337]   Processing part: 'HOSTADDRESS'
[1289271886.119353] [2048.2] [pid=22337]   macro_x[2] (HOSTADDRESS) match.
[1289271886.119366] [2048.2] [pid=22337]   Processed 'HOSTADDRESS', Clean Options: 0, Free: 1
[1289271886.119378] [2048.2] [pid=22337]   Processed 'HOSTADDRESS', Clean Options: 0, Free: 1
[1289271886.119389] [2048.2] [pid=22337]   Cleaning options: global=0, local=0, effective=0
[1289271886.119404] [2048.2] [pid=22337]   Uncleaned macro.  Running output (47): '/usr/lib/nagios/plugins/check_http -I 10.6.3.17'
[1289271886.119416] [2048.2] [pid=22337]   Just finished macro.  Running output (47): '/usr/lib/nagios/plugins/check_http -I 10.6.3.17'
[1289271886.119427] [2048.2] [pid=22337]   Processing part: ' '
[1289271886.119439] [2048.2] [pid=22337]   Not currently in macro.  Running output (48): '/usr/lib/nagios/plugins/check_http -I 10.6.3.17 '
[1289271886.119451] [2048.2] [pid=22337]   Processing part: 'ARG1'
[1289271886.119464] [2048.2] [pid=22337]   Processed 'ARG1', Clean Options: 0, Free: 0
[1289271886.119476] [2048.2] [pid=22337]   Processing part: ''
[1289271886.119487] [2048.2] [pid=22337]   Not currently in macro.  Running output (48): '/usr/lib/nagios/plugins/check_http -I 10.6.3.17 '
[1289271886.119499] [2048.1] [pid=22337]   Done.  Final output: '/usr/lib/nagios/plugins/check_http -I 10.6.3.17 '
[1289271886.119510] [2048.1] [pid=22337] **** END MACRO PROCESSING *************

calina.cfgで定義した IWSS というサービスでは、以下のことを実行しているようです。

Just finished macro.  Running output (47): '/usr/lib/nagios/plugins/check_http -I 10.6.3.17'

check_httpというのは、nagios-pluginsパッケージが提供しているプラグインです。

root@wingroad:~# rpm -qf /usr/lib/nagios/plugins/check_http
nagios-plugins-1.4.15-1.el5.rf

check_httpとは?

では、これをコマンドラインで実行してみましょう。

root@wingroad:~# /usr/lib/nagios/plugins/check_http -I 10.6.3.17
接続を拒否されました
HTTP CRITICAL - Unable to open TCP socket

コマンドの実行はできていますが、相手先ホストのポートが開いていないようで、接続が拒否されています。

check_httpは独立したプログラムです(*2)。実体はバイナリの実行ファイルのようです。引数なしで実行すると、簡単なヘルプが出ました。

(*2)…実際は、この説明は正確ではありませんでした。プラグインの一つであると同時に、nagios内で定義されたコマンド名でもあります。この勘違いにより、あとからハマることになります(後述)。
root@wingroad:~# file /usr/lib/nagios/plugins/check_http
/usr/lib/nagios/plugins/check_http: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), for GNU/Linux 2.6.9, not stripped
root@wingroad:~# /usr/lib/nagios/plugins/check_http
check_http: Could not parse arguments
Usage:
 check_http -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]
       [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-a auth]
       [-b proxy_auth] [-f <ok|warning|critcal|follow|sticky|stickyport>]
       [-e <expect>] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]
       [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]
       [-A string] [-k string] [-S] [--sni] [-C <age>] [-T <content-type>]
       [-j method]

--helpオプションをつけると詳細なヘルプが表示されます。これを簡単に訳したものを示します。

-h, --help
詳細なヘルプを表示する
-V, --version
バージョン情報を表示する
-H, --hostname=ADDRESS
サーバのホスト名。HTTPヘッダ中のhostヘッダ(Virtula Host)で使う。 ポート番号を付加してもよい(例: example.com:5000)。
-I, --IP-address=ADDRESS
IPアドレスもしくはホスト名。IPアドレスで指定すればDNS検索をバイパスできる。
-p, --port=INTEGER
ポート番号(デフォルト:80)
-4, --use-ipv4
IPv4接続を使う
-6, --use-ipv6
IPv6接続を使う
-S, --ssl
SSL経由で接続する。ポート番号のデフォルトは443。
--sni
SSL/TLS ホスト名拡張をサポートする(SNI)
-C, --certificate=INTEGER
証明書の最小有効日数。ポート番号のデフォルトは443。(このオプションを使うとURLはチェックされない)
-e, --expect=STRING
カンマで区切られた文字列のリスト。少なくともその中のいずれかが、サーバ応答(デフォルトはHTTP/1)の1行目とマッチすることを期待する。これが指定された場合、他のすべてのステータス行(例:3xx, 4xx, 5xx)はスキップされる。
-s, --string=STRING
コンテンツの中で期待する文字列
-u, --url=PATH
GETまたはPOSTするURL(デフォルト:/)
-P, --post=STRING
URLエンコードされたHTTP POSTデータ
-j, --method=STRING(例: HEAD, OPTIONS, TRACE, PUT, DELETE)
HTTPメソッドをセットする
-N, --no-body
コンテンツ本文を待たず、ヘッダを読み終わったら処理を中止する。 (注意:HEADではなく、あくまでもGETまたはPOSTを行う)
-M, --max-age=SECONDS
返ってきたドキュメントがSECONDS秒以上古い場合は警告する。書式として"10m"(分)、"10h"(時間)、"10d"(日)も指定可能。
-T, --content-type=STRING
POSTの際のContent-Typeヘッダ(メディアタイプ)を指定する
-l, --linespan
正規表現で改行記号を許可(-r/-Rより前に指定すること)
-r, --regex, --ereg=STRING
検索するページを正規表現で指定する
-R, --eregi=STRING
検索するページを正規表現(大文字小文字を無視)で指定する
--invert-regex
見つかればCRITICAL、そうでなければOKを返す
-a, --authorization=AUTH_PAIR
Basic認証がかかっているページで使用するUsername:password
-b, --proxy-authorization=AUTH_PAIR
Basic認証がかかっているプロキシサーバで使用するUsername:password
-A, --useragent=STRING
"User Agent"として使われるHTTPヘッダ
-k, --header=STRING
HTTPヘッダとして指定したいその他のタグ。複数回指定することも可能
-L, --link
HTMLリンクで出力を折り返す(urlizeで取って代られた)
-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport>
リダイレクトページの処理方法。stickyはfollowと同じだが、指定されたIPアドレスに連携する。stickyportは引き続き同じポート番号を使う。
-m, --pagesize=INTEGER<:INTEGER>
必要とするページサイズの最小値(バイト数):最大ページサイズ(バイト数)
-w, --warning=DOUBLE
警告状態に移行するまで応答時間(秒)
-c, --critical=DOUBLE
エラー状態に移行するまで応答時間(秒)
-t, --timeout=INTEGER
接続待ちタイムアウトまでの秒数(デフォルト:10)
-v, --verbose
コマンドラインデバッグのために詳細を表示する(ただしnagiosが出力を切り詰めることがある)

ログの調整

-vオプションというのがあるので、早速使ってみます。『ログなんかどうせユーザに見える部分じゃないし、結局動きゃいいのでは?』という考え方もあるかもしれませんが、それはたぶん問題の先送りです。ちょっと規模の大きなサイトを管理するようになってくると、結局細かいことを調べないといけなくなるので、今のうちに見えないところにも時間をかけておくことをお勧めします。calina.cfgの方にデバッグオプションをつけ、メインの設定ファイルの方はデバッグレベルをマクロのみに落としました。

root@wingroad:/etc/nagios# diff -Nr nagios.cfg.orig nagios.cfg
1292c1292
< debug_level=-1
---
> debug_level=2048
1302c1302
< debug_verbosity=2
---
> debug_verbosity=0
root@wingroad:/etc/nagios/objects# diff -Nr calina.cfg.orig calina.cfg
12c12
<     check_command           check_http
---
>     check_command           check_http -v
root@wingroad:/etc/nagios# nagios -v ./nagios.cfg
Error: Service check command 'check_http -v' specified in service 'IWSS' for host 'calina.example.com' not defined anywhere!

文法チェックをしたところ、エラーになってしまいました。どうも'check_http -v''check_http'とは別物とみなされてしまうようで、『'check_http -v'なんてコマンドはない』と怒られています。objects/localhost.cfgを参考にして、以下のように修正しました。コマンドライン中のスペースは'!'で置換しないといけないらしい。

root@wingroad:/etc/nagios/objects# diff -Nr calina.cfg.orig calina.cfg
12c12
<     check_command           check_http
---
>     check_command           check_http!-v
root@wingroad:~# nagios -v /etc/nagios/nagios.cfg
(中略)
Total Warnings: 0
Total Errors:   0

今度は大丈夫のようです。念のため、サービスを止め、ログファイルも消してからやり直してみます。

root@wingroad:/var/log/nagios# service nagios stop
root@wingroad:/var/log/nagios# rm nag*
root@wingroad:/var/log/nagios# ls
archives
root@wingroad:/var/log/nagios# service nagios start
nagios は停止しています
nagios を起動中:                                           [  OK  ]
root@wingroad:/var/log/nagios# ls -l
合計 8
drwxr-xr-x 2 nagios nagios 4096 11月  9 00:00 archives
-rw-r--r-- 1 nagios nagios  189 11月  9 15:29 nagios.log

この状態でログファイルを監視します。エラーを検出すると、ログファイルで正しく捕獲できるようになりました。

root@wingroad:/etc/nagios# tail -f /var/log/nagios/nagios.log
[1289288442] SERVICE ALERT: calina.example.com;IWSS;CRITICAL;SOFT;1;接続を拒否されました
[1289288502] SERVICE ALERT: calina.example.com;IWSS;CRITICAL;SOFT;2;接続を拒否されました
[1289288562] SERVICE ALERT: calina.example.com;IWSS;CRITICAL;SOFT;3;接続を拒否されました
[1289288622] SERVICE ALERT: calina.example.com;IWSS;CRITICAL;HARD;4;接続を拒否されました
[1289288622] SERVICE NOTIFICATION: nagiosadmin;calina.example.com;IWSS;CRITICAL;notify-service-by-email;接続を拒否されました

指定された検査を4回行った後、内部状態がSOFTからHARDに変わり、サービス通知(SERVICE NOTIFICATION)というアクションを起こしているのがわかります。第一フィールドはタイムスタンプのようです。見にくいのですが、これをhuman readableにする方法はわかりません。php-cliパッケージが入っていれば、コマンドラインで変換することはできます。

m-hotta@wingroad:~$ php -r 'print date("Y/m/d H:i:s\n", 1289288622);'
2010/11/09 16:43:42

check_httpのデバッグ

やっと本題です。check_httpでIWSSを叩いて正しく認識できるように、コマンドラインパラメータを調整します。アクセス対象には本サイト(http://net-newbie.com)を使います。ちなみにホストwingroadは、直接NATでインターネットに出られるようになっています。構成は以下のような感じです。

直接(NAT)接続:
クライアント(wingroad) → (F/W) → net-newbie.com(グローバル:80)
プロキシ接続:
クライアント(wingroad) → IWSS(calina:8080) → (F/W) → net-newbie.com(グローバル:80)
root@wingroad:~# /usr/lib/nagios/plugins/check_http -H net-newbie.com
HTTP OK: HTTP/1.1 200 OK - 6847 bytes in 2.323 second response time |time=2.323302s;;;0.000000 size=6847B;;;0

当然ですが、直接宛先サイトを指定すればうまくいきます。次は、IWSSを経由させてみます。運用の観点からすると本来はホスト名指定が環境の変化に強くて望ましいのですが、今はトラブル解析中ですので、名前解決関連の原因を排除するために直接IPで指定しています。

root@wingroad:~# /usr/lib/nagios/plugins/check_http -H net-newbie.com -I 10.6.3.17 -p 8080
CRITICAL - Socket timeout after 10 seconds

なぜかタイムアウトになってしまっています。IWSS側のポートの情報は以下の通りですので、IWSSプロセス(iwssd)がポート8080番で待っているのは間違いないです。

root@calina:~# netstat -tlnp | grep 8080
tcp  0  0  0.0.0.0:8080  0.0.0.0:*  LISTEN  7500/iwssd

しょうがないのでクライアント側(wingroad)でパケットを拾ってみます。ここではtcpdumpというコマンドを使っています。不慣れな方はTCP/IP入門にむかし書いた文章があるので参考にしてみてください。

root@wingroad:~# tcpdump -nn port 8080
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
10:41:57.583478 IP 10.16.2.16.40613 > 10.6.3.17.8080: S 3949392880:3949392880(0) win 5840 <mss 1460,sackOK,timestamp 1938240951 0,nop,wscale 6>
10:41:57.586328 IP 10.6.3.17.8080 > 10.16.2.16.40613: S 832538701:832538701(0) ack 3949392881 win 5792 <mss 1460,sackOK,timestamp 1015865844 1938240951,nop,wscale 7>
10:41:57.586345 IP 10.16.2.16.40613 > 10.6.3.17.8080: . ack 1 win 92 <nop,nop,timestamp 1938240952 1015865844>
10:41:57.586593 IP 10.16.2.16.40613 > 10.6.3.17.8080: P 1:121(120) ack 1 win 92 <nop,nop,timestamp 1938240952 1015865844>
10:41:57.589469 IP 10.6.3.17.8080 > 10.16.2.16.40613: . ack 121 win 46 <nop,nop,timestamp 1015865847 1938240952>

プロキシ(calina:IWSS)に対しては、速やかにTCPセッションが張れています。ということは、IWSSからhttp://net-newbie.comに対しても8080でそのまま行っているのかもしれません。IWSS側で確認してみました。

root@calina:~# tcpdump -nn host net-newbie.com
tcpdump: WARNING: eth0: no IPv4 address assigned
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
11:04:54.342629 IP 10.6.3.17.60369 > 182.163.92.143.8080: S 2285474795:2285474795(0) win 5840 <mss 1460,sackOK,timestamp 1017242850 0,nop,wscale 7>

やはりそのようです。ちなみにhttp://net-newbie.comでは8080ポートなんて待ってない(iptablesで落としている)ので、タイムアウトするのは当たり前です。今度は明示的にURLを指定してからやってみましょう。

root@wingroad:~# /usr/lib/nagios/plugins/check_http -H net-newbie.com -I 10.6.3.17 -p 8080 -u http://net-newbie.com
HTTP OK: HTTP/1.1 200 OK - 6834 bytes in 0.105 second response time |time=0.104757s;;;0.000000 size=6834B;;;0

今度はうまくいったようです。これでcheck_httpレベルではOKですので、後はこれをnagiosから呼び出せるように、nagios側の設定を変更してみましょう。

nagios本体からの呼び出し

デバッグ中ですので、まず余計な状態をクリアします。その後以下のように組み込んで、サービスを再起動してみました。

root@wingroad:~# service nagios stop
nagios (pid 27302) を実行中...
Stopping nagios:                                           [  OK  ]
root@wingroad:~# cd /var/nagios/
root@wingroad:/var/nagios# rm -f objects.cache retention.dat
root@wingroad:/var/nagios# cd /etc/nagios/objects/
root@wingroad:/etc/nagios/objects# cp calina.cfg calina.cfg.orig
root@wingroad:/etc/nagios/objects# vi calina.cfg
root@wingroad:/etc/nagios/objects# diff -N calina.cfg.orig calina.cfg
12c12
<     check_command           check_http!-v
---
>     check_command           check_http!-v!-H!net-newbie.com!-I!10.6.3.17!-p!8080!-u!http://net-newbie.com
root@wingroad:/etc/nagios/objects# service nagios start
nagios は停止しています
Starting nagios:                                           [  OK  ]

さて、どうなるか。ログで監視してみます。

root@wingroad:~# tail -f /var/log/nagios/nagios.log
[1289355503] Nagios 3.2.2 starting... (PID=27374)
[1289355503] Local time is Wed Nov 10 11:18:23 JST 2010
[1289355503] LOG VERSION: 2.0
[1289355503] Finished daemonizing... (New PID=27375)
[1289356221] SERVICE ALERT: calina.example.com;IWSS;CRITICAL;SOFT;1;接続を拒否されました

ガーン。相変わらずダメっぽいです。次はデバッグログ。

root@wingroad:/var/log/nagios# view nagios.debug
(中略)
[1289363891.150452] [2320.2] [pid=27604] Raw Command Input: $USER1$/check_http -I $HOSTADDRESS$ $ARG1$

どうも想定したコマンドラインになっていないようです。check_httpを名乗る別の何かがいるのでしょうか?探してみると、

root@wingroad:/etc/nagios# grep -w check_http *
command-plugins.cfg:command[check_http]=/usr/lib/nagios/plugins/check_http -H $HOSTADDRESS$ -I $HOSTADDRESS$
command-plugins.cfg:command[check_http2]=/usr/lib/nagios/plugins/check_http -H $ARG1$ -I $HOSTADDRESS$ -w $ARG2$ -c $ARG3$
command-plugins.cfg:# Using check_http will allow verification of authenticated proxies
command-plugins.cfg:command[check_squid]=/usr/lib/nagios/plugins/check_http -H $HOSTADDRESS$ -p $ARG1$  -u $ARG2$  -e 'HTTP/1.0 200 OK'

なんか怪しいのがいます。どうもcommand[check_http]というのがcheck_httpの実体のような気がしてきました(後述しますが、この判断は間違っています)。

新しいコマンドを追加する

試しに、ここに新しいコマンドcheck_http3を追加してみることにします。

root@wingroad:/etc/nagios# cp command-plugins.cfg command-plugins.cfg.orig
root@wingroad:/etc/nagios# vi command-plugins.cfg
root@wingroad:/etc/nagios# diff -N command-plugins.cfg.orig command-plugins.cfg
85a86
> command[check_http3]=/usr/lib/nagios/plugins/check_http -v -H net-newbie.com -I 10.6.3.17 -p 8080 -u http://net-newbie.com

まず動かすのが先決なので、パラメータはベタで貼りつけています。これを使うように、calina.cfgの中を変えます。

root@wingroad:/etc/nagios/objects# diff calina.cfg.orig calina.cfg
12c12
<     check_command           check_http!-v!-H!net-newbie.com!-I!10.6.3.17!-p!8080!-u!http://net-newbie.com
---
>     check_command           check_http3
root@wingroad:~# nagios -v /etc/nagios/nagios.cfg
Error: Service check command 'check_http3' specified in service 'IWSS' for host 'calina.example.com' not defined anywhere!

check_http3が定義されていないと言ってます。そんなはずは…と思って、command-plugins.cfgがどこからインクルードされているのか調べてみると、

root@wingroad:/etc/nagios# grep -r command-plugins.cfg *
(何も出ない)

アレ?どこからもインクルードされてない…。でもcheck_httpの方は呼び出せていたんだから、使われてはいるはず。仕組みを調べてみようと、もう一度command-plugins.cfgを開いて最初のコメント部分を読んでみると、以下の記述がありました(適宜和訳)。

###############################################################################
# コマンド定義
#
# 書式:
# command[<command_name>]=<command_line>
#
# <command_name> = コマンド識別用の短い名前
# <command_line> = 実際のコマンドライン。コマンドラインを引用符でくくる
#   必要はないが、その中に引用符を含む場合はあり得る。単一引用符''' を
#   コマンドの外で使うと、シェルがコマンドが実行する際にコマンドライン
#   展開で問題になることがあるので注意すること。シェルで使えるものなら
#   何を指定してもよい。複数のコマンドをセミコロンでつないで使ってもよいし、
#   パイプラインも使える。コマンドラインにはマクロを含むことができるが、
#   (通知、サービスチェック等の)どんな時でもマクロが使えるわけではない。
#   コマンド中におけるマクロの使い方についてはHTMLドキュメントを参照の
#   こと。(訳注:ドキュメントはGUIのページのDocumentationボタンから辿れます。)
#
# 注意:サービスチェック、サービス通知、ホストチェック、ホスト通知、
#    サービスイベントハンドラ、ホストイベントハンドラ関数のすべてが
#    ここで定義されている。
#
# 注意:このファイルをオブジェクトファイルに変換するには、Nagios配布物
#   (訳注:今回の環境では nagios RPM パッケージ)の contrib ディレクトリ
#   にある convertcfg プログラムを使うこと。
#
###############################################################################

command-plugins.cfgファイルを変換しないといけない?

ということで、このソースファイルを変換しないといけないのか?どんどん深みにハマって参りました。

root@wingroad:~# rpm -ql nagios | grep convertcfg
/usr/bin/convertcfg

コンバータ自体はnagiosパッケージに含まれているようです。さて、変換後のファイルはどこに置けばよいのでしょう?つまり、nagios本体はcommand-plugins.cfgの代わりにどのオブジェクトファイルを参照しているのでしょうか?

実行ファイルの動きを追うためには、straceコマンドが使えます。

root@wingroad:~# yum install strace
root@wingroad:~# strace nagios -v /etc/nagios/nagios.cfg 2>&1 | grep -e ^open -e ^Error  | sed -n /nagios.cfg/,//p
open("/etc/nagios/nagios.cfg", O_RDONLY|O_LARGEFILE) = 3
open("/etc/nagios/resource.cfg", O_RDONLY|O_LARGEFILE) = 4
open("/tmp", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY) = 4
open("/var/nagios/spool/checkresults", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY) = 4
open("/etc/localtime", O_RDONLY)        = 4
open("/proc/sys/kernel/ngroups_max", O_RDONLY) = 3
open("/etc/nagios/nagios.cfg", O_RDONLY|O_LARGEFILE) = 3
open("/etc/nagios/nagios.cfg", O_RDONLY|O_LARGEFILE) = 3
open("/etc/nagios/objects/commands.cfg", O_RDONLY|O_LARGEFILE) = 4
open("/etc/nagios/objects/contacts.cfg", O_RDONLY|O_LARGEFILE) = 4
open("/etc/nagios/objects/timeperiods.cfg", O_RDONLY|O_LARGEFILE) = 4
open("/etc/nagios/objects/templates.cfg", O_RDONLY|O_LARGEFILE) = 4
open("/etc/nagios/objects/calina.cfg", O_RDONLY|O_LARGEFILE) = 4
open("/var/nagios/spool/checkresults/nagiosBI833t", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600) = 3
open("/var/nagios/spool/checkresults/nagios7PWPFB", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600) = 3
Error: Service check command 'check_http3' specified in service 'IWSS' for host 'calina.example.com' not defined anywhere!

コマンドがややトリッキーなので少し説明します。

strace nagios -v /etc/nagios/nagios.cfg
nagios -v /etc/nagios/nagios.cfgというコマンドのシステムコール・トレースを取ります。
2>&1
標準エラー出力(stderr)を標準出力(stdout)にまとめます。
| grep -e ^open -e ^Error
ここで調べたいのは『どんなファイルをオープンしているか?』ですので、open(2)システムコールだけを抽出します。これに加えてエラーメッセージも補足します。
| sed -n /nagios.cfg/,//p
実行ファイルの起動時にオープンされる大量の*.so(Shared Object)ファイルをスキップし、/etc/nagios/nagios.cfgファイルが開かれた後の分だけを抽出します。

出力結果を見てみると、『いかにもcommand-plugins.cfgをコンパイルしたものです』的なファイルを読み込んでいる形跡はないようです。確信はありませんが、このファイルは単なるサンプルであると思うことにしました。

ようやく解決へ

結果的には、最初に探し始めた時のコマンド

root@wingroad:/etc/nagios# grep -w check_http *

が失敗だったようです。ここは以下のようにしなければなりませんでした。

root@wingroad:/etc/nagios# grep -rl check_http * | grep -v orig$
command-plugins.cfg
objects/localhost.cfg
objects/commands.cfg
objects/calina.cfg

どうもcheck_httpコマンドの定義は、objects/commands.cfgの方が使われているようです。中身を見てみましょう。

root@wingroad:/etc/nagios/objects# sed -n /check_http/,+4p commands.cfg
# 'check_http' command definition
define command{
        command_name    check_http
        command_line    $USER1$/check_http -I $HOSTADDRESS$ $ARG1$
        }

デバッグログの中に現れていたコマンドも、まさにこのパターンでした。かなり寄り道をしてしまいましたが、このファイルにcheck_iwssコマンドを組み込んでみます。check_http3のところもcheck_iwssに変えました。

root@wingroad:/etc/nagios/objects# cp commands.cfg commands.cfg.orig
root@wingroad:/etc/nagios/objects# vi commands.cfg
root@wingroad:/etc/nagios/objects# diff commands.cfg.orig commands.cfg
150a151,157
> # 'check_iwss' command definition
> define command  {
>     command_name    check_iwss
>     command_line    $USER1$/check_http -v -H net-newbie.com -I 10.6.3.17 -p 8080 -u http://net-newbie.com
> }
root@wingroad:/etc/nagios/objects# cp calina.cfg calina.cfg.orig
root@wingroad:/etc/nagios/objects# vi calina.cfg
root@wingroad:/etc/nagios/objects# diff calina.cfg.orig calina.cfg
12c12
<     check_command           check_http3
---
>     check_command           check_iwss
root@wingroad:~# nagios -v /etc/nagios/nagios.cfg
Total Warnings: 0
Total Errors:   0

これでサービスを起動したら、ようやくOKになりました。GUIの画面でもステータス情報が正しく取得できています。

calina-ok

まだまだわからないところは多々ありますが、とりあえず最初の目標は達成できました。めでたしめでたし。

使用コマンド一覧(順不同)

ここまでのハック/試行錯誤で使ったコマンドの一覧を載せておきます(nagiosの付属物は除く)。もし知らなかったものがあれば、コマンド名 --helpman コマンド名、Webサイト等で調べてみるとよいでしょう。

wget
Web上のドキュメントを非会話的に取得
su
Suitch User. 別ユーザ(デフォルトはroot)に切り替える。
sudo
Suitch User and DO. 別ユーザ(デフォルトはroot)としてコマンドを実行
rpm
Redhat Package Manager. ローカルのパッケージ管理ツール。
yum
YellowDog Update Manager. ネットワーク対応のパッケージ管理ツール
cat
conCATinate. ファイルの連結、表示。
htpasswd
Apacheに付属しているパスワードファイル保守ツール
service
サービス管理コマンド
diff
ファイルの差分を表示
echo(bashの内部コマンド)
文字列を表示
grep
Global Regular Expression Print. 文字列検索。
rm
ファイルを削除
tail
ファイルの末尾を表示
ls
ファイル名の一覧を表示
file
ファイルの種別(種類)を表示
php
万能インタプリタ(a.k.a.Webプログラミング言語)
netstat
ネットワーク関連リソースの表示。pオプション使用時は管理者権限が必要。
tcpdump
パケットキャプチャ。管理者権限が必要。
cp
ファイルのコピー
vi
エディタ(実体はvim)
strace
システムコールのトレース
sed
Stream EDitor. テキスト整形・編集
up