2009/04/03

A backup script for Xen DomUs, part 2

A backup script for Xen DomUs, part 1』で紹介したスクリプトxen-backup.shについて解説する。

このスクリプトの大まかな流れは以下の通り:
  1. バックアップ設定ファイルの読み込み: 182行目
  2. バックアップを実行するかどうかの検査: 183行目~215行目
  3. DomU設定の解析: 217行目~228行目
  4. ディスクイメージのマウント@ローカル: 230行目~254行目
  5. ディスクイメージのマウント@リモートDom0: 256行目~263行目
  6. Rsyncによるバックアップ: 265行目~266行目
  7. ディスクイメージのアンマウント@リモートDom0: 268行目~274行目
  8. ディスクイメージのアンマウント@ローカル: 277行目~280行目

バックアップを実行するかどうかの検査
DomUの状態を表示するコマンド
virsh domstate DomU名
を使って、以下の各項目を検査する。
  1. 対象DomUが、ローカルDom0でホストされいるか?
  2. 対象DomUが、ローカルDom0で正常に実行されているか?
  3. 自分自身がDOM0Sに含まれているか?
すべての検査に合格すれば、バックアップを実行する。

DomU設定の解析
コマンド
virsh dumpxml DomU名
で対象となるDomUの設定(XML形式)を得て、ディスクイメージ情報を抽出する。
このとき、関数get_value_from_configを呼び出す。
115: get_value_from_config()
116: {
117:     local xml=$1 num=$2 elem=$3 attr=$4
118:     echo "cat /domain/devices/disk[$num]/$elem/@$attr" | \
119:         xmllint --shell $xml | \
120:         awk -F\" '/^ +'$attr'/{print $2}'
121: }
この中ではxmllintコマンドを使用している。ディスクイメージに対する設定項目/domain/devices/diskは、複数指定される可能性があることに注意。

ディスクイメージのマウント@ローカル
各ディスクイメージをローカルにマウントする。
マウントする前に、ディスクイメージのスナップショットを撮っている(『XenとLVM・その3・スナップショットLVの利用』参照)
238:                 lvcreate --snapshot --name=$snapshot_name --size=$SNAPSHOT_SIZE ${disk_source[$i]}
239:                 add_close_command "lvremove -f /dev/$vgname/$snapshot_name"
240:                 analyze_disk /dev/$vgname/$snapshot_name
マウント時と反対の動作をバックアップ後に実施する必要があるため、add_close_command関数(34行目~38行目)を使って記録する。
実際の解析は、analyze_disk関数(124行目~175行目)を使っている。

analyze_disk関数
マウント時の動作は、リモート側でも実行する必要があるため、add_open_command関数(14行目~19行目)で実行および記録する。
与えられたデバイス$the_diskに対して、
131:     part_type=`parted -s $the_disk print | awk '/^Partition Table:/{print $3}'`
でパーティションの種類を得ている。これがDOSパーティションなら、パーティション毎に分割し、それぞれに対して処理する必要がある。
134:             add_open_command "kpartx -a -p $PSEP $the_disk"
135:             add_close_command "kpartx -d -p $PSEP $the_disk"
ここで、kpartxコマンドに対するオプション「-p 区切文字」を指定していることに注意。例えば、/dev/VolGroup00/LogVolDomUに対して、
kpartx -a /dev/VolGroup00/LogVolDomU1
を実行すると、パーティションごとに
/dev/mapper/LogVolDomU1
/dev/mapper/LogVolDomU1
等のデバイスが作成されるが、元のデバイス名の最後が数字の場合、例えば/dev/VolGroup00/LogVolDomU1の場合は、
/dev/mapper/LogVolDomU1p1
/dev/mapper/LogVolDomU1p1
の様に区切文字「p」が挿入される。オプション「-p 区切文字」を指定すれば、どちらの場合も区切文字が挿入されるので都合が良い。なお、「kpartx -a -p 区切文字」で作成したデバイスは、「-p」を指定して「kpartx -d -p 区切文字」としないと削除できない(この辺りの動作は、kpartxのmanpageにも触れられていない)
136:             while read device[$num] fs_type[$num] mount_point[$num]; do
137:                 ((num++))
138:             done <<EOF
139: $(parted -s $the_disk print | awk '/^ *[0-9]+ /{print $1" "$6" "$7}')
140: EOF
この部分は、一見
parted -s $the_disk print | awk '/^ *[0-9]+ /{print $1" "$6" "$7}' | while read device[$num] fs_type[$num] mount_point[$num]; do
((num++))
done
の様に書き直せそうだが、期待通りの動作とならない。なぜなら、readコマンドをパイプの後で使うと、readコマンドがサブシェルで実行され、サブシェルの変数には代入されるが、元のシェルの変数には反映されないため。
最終的に、mountコマンドでマウントされるデバイスにまで分割できたら、add_fs_table関数(52行目~57行目)で記録しておく。ディレクトリ階層の高い順にマウントする必要があるため、すべてのマウントポイントを解析し終えてからマウントする(252行目~254行目)。

ディスクイメージのマウント@リモートDom0
リモートDom0に対して、SSH経由でマウントを実行する。
258:         ssh -T $remote_dom0 <<EOF
259: ##### COMMANDS FOR TARGET TO OPEN
260: `exec_open_commands | sed 's/-'$$'//'`
261: mkdir -p $target_prefix
262: `mount_fs_all $target_prefix | sed 's/-'$$'//'`
263: EOF
入力がTTYでないことを明示するため、sshコマンドには、「-T」オプションを与えている。

Rsyncによるバックアップ
266:         rsync -avz --delete -e ssh $source_prefix/ $remote_dom0:$target_prefix
引数「$source_prefix/」の最後のスラッシュは必須。省略すると、期待通りに動作しない。


A backup script for Xen DomUs, part 1
A backup script for Xen DomUs, part 2

0 件のコメント: