2011-06-11 : post-commit スクリプトを修正しました。
昨日の記事で紹介した、”Subversionのリポジトリをsvnsyncコマンド使ってミラーリングする”方法の追記です。
昨日は簡単に書くと、本家リポジトリのコミット完了後に分家リポジトリにsvnsyncを発行する、というところまでやりました。
今回は、分家サーバが稼働中のときだけ svnsync する、という処理を加えましょう。
分家サーバは動いていないことも・・・
実は分家サーバは事務所に設置してあります。基本は常時稼働していますが、どうしても電源を切らざるをえないケースがあります。
恥ずかしながら、空調を入れてブレーカーが落ちるとか、そんな理由なのですけど。
とにかく、分家サーバは稼働していないことがあるのです。
稼働していないタイミングで、本家リポジトリにコミットされると、利用者の画面(TortoiseSVNなど)にエラーが表示されます。実際にはコミットはされているのですが、その後のsvnsync で(分家リポジトリにsvnsyncを発行できないので)エラーが発生するためです。
気にしなければそれでもいいのですが、事情を知らない利用者にとっては不安でしょう。
post-commit を改造
そこで、分家サーバが稼働している時だけ、svnsyncコマンドを発行するようにします。
ping はブロックしているので、httpアクセスで稼働チェックをします。
最も単純な「アクセスできればよし」から、厳格に「秘密鍵で暗号化したものを返してもらって、公開鍵で復号化できればよし」まで、いろいろな方法が考えられますが、今回は「文字列を送って、そのまま返ってきたらよし」ということにします。
まずは 本家リポジトリ/hooks/post-commit ファイル。作成したら忘れずに、chmod +x で実行できるようにしてください。
#! /bin/sh
REPOS=(リポジトリ名)
DEST=http://(分家(バックアップ先)サーバ)/svn/${REPOS}
TIMEOUT=3
RETRY=1
USER=(リポジトリのユーザ名)
PASS=(リポジトリのパスワード)
REQ_STRING=`date +%Y%m%d.%H%M%S`.$$ (←日付.時刻.プロセスID を送る)
RESP_FILE=/tmp/svn.${REPOS}.${REQ_STRING} (←応答を受け取るファイル名)
ALIVE=http://(分家(バックアップ先)サーバ)/is_working.php?req=${REQ_STRING} (←稼働確認用URL)
wget -O ${RESP_FILE} -T ${TIMEOUT} -t ${RETRY} ${ALIVE} > /dev/null 2> /dev/null
if test $? -eq 0
then
if test "`cat ${RESP_FILE}`" == "${REQ_STRING}"
then
echo "svnsync ..." >&2
svnsync sync ${DEST} --username ${USER} --password ${PASS}
else
echo "The mirroring server returns unexpected response." >&2
fi
else
echo "The mirroring server is not running." >&2
fi
rm -rf ${RESP_FILE}
2010-06-11 : タイムアウトとリトライの設定を追加しました。これがないと分家が停止していると、コミットが終了しません。
そして、分家側。is_working.php は、受け取った文字列をそのまま返すだけです。本家からの稼働確認に応えるためのものです。本家のスクリプトで書いた、${ALIVE}でアクセスできる位置に書いてください。
<?php
echo $_GET[req];
?>
簡単な説明
シェルスクリプトが読める方には説明不要ですが。。。
wgetコマンドで、生存確認用URLにユニークな(日付時刻とプロセス番号が入っている)文字列を送ります。この時点で生存確認用URLにアクセスできなければ、それで終わり。
次に、wgetコマンドの応答(${RESP_FILE}に入る)と、送った文字列を比較します。これが違っていたら、分家サーバが正しく稼働していなさそうなので終わり。
wgetコマンドも通じて、応答も正しかった場合にのみ、svnsyncコマンドを発行します。
分家サーバ復旧時の処理
あとは、分家サーバが復旧した時の処理です。
停止していた間に本家に入ったコミットに、追いつかないといけません。
今のところ思いつくのは3つ。
- 何もしない。次回のコミットで追いつくから別にいいでしょ、という考え方。
- 一定時間ごとに実行する(crontab に設定しておく)。例えばフルバックアップの前にsvnsyncしておくとか。
- 起動時に svnsync を実行する。例えば /etc/rc.local の最後に書いておくとか。
最後の rc.localの最後に書くなら、
(略)
for repopath in /var/lib/svn/*
do
svnsync sync file:///$repopath --username ユーザ名 --password パスワード
done
こんな感じでしょうか。一つ一つユーザ名/パスワードや、リポジトリの場所が違うなら、forループではなく列挙してください。
うちでは、rc.local の最後と、念のためフルバックアップ前にもsvnsyncしています。