背景
監視ソフトを導入できるほど予算がないけど、特定プロセスが稼働しているかどうかは簡易的にでも確認したい…そんなときに。
プロセス起動確認の考え方
まずプロセス起動していることをどうやって確認するのか?について整理します。
シェルスクリプトで実現するとしたら、次の方針が多いんじゃないでしょうか。
A)psコマンドでプロセス一覧を表示して、grepで検索結果を絞り込み。結果が存在するかどうかをチェックする
B)プロセスファイルが存在するかチェックする
たとえばA)の場合は下記のような感じで。
ps -aux | grep <プロセス名> | grep -v grep | wc -l
パイプが多くて直感的に分かりづらいかもしれませんが、条件に合致するプロセス名を標準出力に表示、その行数をカウントすることで、当該プロセスが存在しているかを確認する理屈です。
これをWindowsのbatで実現してみるとこんな感じです。
tasklist | find "<プロセス名>"
IF ERRORLEVEL 1 GOTO CHECK_NG
findコマンドはfindstrコマンドでも良いです。findstrだとAND条件と正規表現が使えるので、便利です。
findコマンド
findstrコマンド
つづいてB)の場合です。たとえばpostgresqlだと起動中はプロセスIDファイルが作成されるので、そのファイル中内の先頭に記述されるプロセスIDをチェックして、そのプロセスIDに生存監視用のシグナルを送信して結果を確認する、という理屈です。
processFile="/var/lib/pgsql/data/postmaster.pid"
kill -0 $(head -1 processFile)
if [ $? -eq 0 ]; then
# プロセス正常起動時のなんらかの処理
else
# プロセス未起動時のなんらかの処理
fi
killコマンドはプロセスに対してシグナルを送信します。-0はそのプロセスが生存しているかどうかを判定するときに指定します。
[ ]←これは正確にはコマンドの一種のようですが、よくif文と組み合わせて使用されます。条件式を記述するのに使います。
この辺りは下記を参照すると分かりやすいかなと思います。
https://shellscript.sunone.me/if_and_test.html
[] は /usr/bin 配下に存在する通常のコマンドである。正確には [ がコマンド本体で ] はパラメータということになる。[ の直後にスペースがないとエラーになるのはそのためでもある (ちなみに if 文自体も正確には文ではなくコマンドである)。
どちらかというとA)のほうが簡単なのですが、プロセスが実際に稼働しているかどうかはチェックできていないのが微妙ポイントです。
なので、できれば実際にアプリケーションにアクセスして応答をチェックするのが良いかと思います。いわゆるL7のチェックです。
L7?
OS上で稼働しているアプリケーションが使用するプロトコルは、OSI参照モデルでいうレイヤ7に分類されるものがほとんどです。HTTPとかね。
OSI参照モデルの解説としては下記が好きです。
https://www.cisco.com/c/m/ja_jp/primer/osi-reference-model.html
アプリケーションが使用するプロトコルを使って、アプリケーションにアクセスを行う。その実行結果をチェックする。という流れです。
シェルスクリプトでは下記のようになります。チェックと結果表示処理を分離するのに、関数を使ってみました。
function httpProtocolConfirm () {
# HTTPステータスコードを取得
curl -m ${timeout} -LI ${checkURI} -o /dev/null -w '%{http_code}\n' -s
}
function httpProtocolResult () {
# チェック結果を返却
if [ $1 = '200' ]; then
echo "チェックURI: [${checkURI}]"
echo "チェック結果OK code:$1"
else
echo "チェックURI] [${checkURI}]"
echo "チェック結果NG"
fi
}
result=`httpProtocolConfirm`
httpProtocolResult $result
curlの-wオプションはHTTPステータスコードのみを取得するための整形が目的です。
PowerShellでL7チェック
さきほどのcurlと似たようなことをPowerShellでやります。Invoke-WebRequestコマンドレットを使います。
curlと違ってInvoke-WebRequestはHTTP固定です。
try{
# HTTPステータスコードを取得
$response = Invoke-WebRequest -Uri $checkURI -TimeoutSec $timeout
$statusCode=$response.StatusCode
}catch [System.Net.WebException]{
$statusCode=$_.Exception.Response.StatusCode.value__
}
返却値のうち、HTTPステータスコード部分を取得するのに工夫しています。この辺りの工夫については、下記が参考になります。
https://stackoverflow.com/questions/19122378/powershell-web-request-without-throwing-exception-on-4xx-5xx
try-catchでHTTPステータスコードを捕まえられるか?
try-catchが使えるなら、スローされた例外のプロパティを参照したらHTTPステータスコードが拾えるんじゃないかと考えたのですが、どうもシンプルな話ではないようです。
というのも、Invoke-WebRequestで存在しないホストにリクエストをしたときと、ホストは存在するけどURIが間違っている場合とで、発生する例外が異なるからです。
そういうものなのかな、、
具体的な例が整理出来たら、追記しようと思います。
参考書籍
シェルスクリプトを書くにあたって下記書籍を参考にしました。サンプルが付いてるので、後半が特に参考になります。はじめてシェルスクリプトを書く人は定石を学ぶためにもちょうど良いのではないでしょうか。
ポケットリファレンス