2016年3月23日水曜日

システムバックアップその6

さて、バックアップを取得するための器は出来上がった。
今回は、バックアップ対象である内蔵ディスクの構成情報をバックアップしよう。
構成情報は、ざっと以下の内容を取っておく必要がある。
  1. efibootに必要なefibootmgr情報
    (今回の機器は、uEFIマシンのため、efi構成情報が必要だ。レガシーBIOSの人は、特に必要無いぞ)
  2. LVM構成情報
    1. vg構成
    2. pvのuuid等
  3. 内蔵ディスクのfdiskパーティション情報
    (MBRもしくはGPT。uEFIなので、GPTになるはずだ。)
  4. 各ファイルシステムのファイルシステムフォーマット情報やuuid情報
2.~4.に関しては、1エントリだけじゃなく、複数エントリが存在する可能性がある。
そのため、複数エントリに対応した作りにする必要がある。
そのあたりを考慮しながら、1つずつ作っていこう。
いつも通り、sudo su - で root にスイッチしてから作業を行おう。
# cd
# cd backup/bin
# vi 0030_create_config
まずは、以下の内容を作る。
--ココから--
#!/bin/sh
 
BINDIR=`/usr/bin/dirname $0`
BINDIR=`/usr/bin/realpath ${BINDIR}`
ETCDIR=`/usr/bin/realpath ${BINDIR}/../etc`
 
. ${ETCDIR}/config
/bin/efibootmgr -v > ${BACKUPPOINT}/current/config/efiboot

--ココまで--
最後の1行以外は、これまでのスクリプトと大した差がないので特に解説は不要だろう。
最後の efibootmgr コマンドが初出だ。
これは、現在のefibootの構成情報が出力されるコマンドだ。(uEFIにboot情報をに設定することも可能なコマンドだ。)
efibootmgr -v で、現在のefibootの詳細情報が出力されるので、それをファイルにリダイレクトし、保存している。
気になるようなら、実際に実行してみるといい。
# efibootmgr -v
BootCurrent: 0001
Timeout: 1 seconds
BootOrder: 0001,0005,0002,0000
Boot0000* Windows Boot Manager  VenHw(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)WINDOWS.........x...B.C.D.O.B.J.E.C.T.=.{.x.x.x.x.x.x.x.x.-.x.x.x.x.-.x.x.x.x.-.x.x.x.x.-.x.x.x.x.x.x.x.x.x.x.x.x.}....................
Boot0001* ubuntu        HD(1,GPT,xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,0x800,0xf3800)/File(\EFI\ubuntu\shimx64.efi)
Boot0002* LAN : IBA GE Slot 00C8 v1553  BBS(Network,,0x0)..BO
Boot0005* SATA : PORT 0 : INTEL SSDSC2BW120H6 : PART 0 : Boot Drive     BBS(HD,,0x0)..BO
こんな風に色々と出てくる。
現在のuEFIのブートエントリ一式と、「今ブートしているのは、そのエントリの何番か?」「ブート順」等の情報が出てきている。
これらを保存しておこう、というのが先ほどの行の目的だ。
ただ…実はリストアにはこの結果は用いていない。そのため「何かトラブった時の参考情報」として保存している程度の情報だ。
これが、「1.efibootに必要なefibootmgr情報」の取得に該当する部分だ。
 
続けて、0030_create_config に以下の1行を追記しよう。
--追記ココから--
/sbin/vgcfgbackup -f ${BACKUPPOINT}/current/config/vgcfgbackup.${ROOTVG} ${ROOTVG}

--追記ココまで--
vgcfgbackup というコマンド名からある程度予想が出来ると思うけど、vgの構成情報を取得しているコマンドだ。
「-f ファイル名」で、構成情報を保存するファイル名を指定している。
引数の最後に vg名を指定することで、指定した vg の構成情報が取得できる。
LVM制御下のバックアップ対象領域は、全て vg-root に属することにしているため、引数は対象は vg-root だが、敢えて変数を指定している。
まずは、どんな情報が取得出来るのか、自分の目で確認してみて欲しい。
# vgcfgbackup -f /tmp/vg-root vg-root
# cat /tmp/vg-root
(ここにズラズラと内容が出てくる)
# rm /tmp/vg-root
どうだろう?ホスト名やVG名、VGを構成しているPVの名前、各LVの名前やサイズ等が記録されているはずだ。
リストアする時には、このファイルを使えば、いちいちlvcreate等をしていく必要が無く、LVM構成情報はサクッと戻せる。
 
で、先ほどの1行に戻って欲しいのだが、変数として${ROOTVG}というのを使用している。これは初めて出てくる変数だ。この変数は、configファイルに定義しておこう。(configファイルは前回作成しているはずなので、追記しよう。)
# vi ../etc/config
--以下の内容を追記--
#
# ROOTVG:
# The name of the Volume Group that make up the OS.
# Only one can be specified.
#
ROOTVG=vg-root

--追記ココまで--
これで、「2.LVM構成情報 - 1.vg構成」を取得する部分が完了だ。
 
次は順番からしたら「2.LVM構成情報 - 2.PVのuuid等」になるんだけど、スクリプトを書いた時、ちょっと異なる順番で書いている。
そのため、次は「3.内蔵ディスクのfdiskパーティション情報」だ。
先ほどと同様に、0030_create_config に以下の内容を追記しよう。
--ココから--
for ROOTPV in ${ROOTPVS}
do
  /sbin/sfdisk --dump /dev/${ROOTPV} > ${BACKUPPOINT}/current/config/sfdisk.${ROOTPV}
done

--ココまで--
いきなりグッとプログラムっぽくなった。
ここで注目して欲しいのは以下の行。
/sbin/sfdisk --dump /dev/${ROOTPV} > ${BACKUPPOINT}/current/config/sfdisk.${ROOTPV}
sfdisk コマンドに --dump というオプションを付けて実行している。
その次の /dev/${ROOTPV} は、具体的には /dev/sda 等に置き換わると思って欲しい。
そして、リダイレクトを用いてファイルに書き出している。
そのため、実際にやっているコマンドは以下の通りだ。
sfdisk --dump /dev/sda
実際にやってもらうと分かるが、/dev/sda ディスクの fdiskパーティション情報を出力しているコマンドだ。(ファイルにリダイレクトしているので、最終的にファイルに書き出されるのだが)
単純にコレだけの処理なのに、わざわざ複雑にしている。
それは以下の理由による。
  • OS領域のバックアップとしては、vg-rootを構成する情報を取得しておく必要がある。
  • 今の構成は、vg-root を形作る PV は、 /dev/sda3 のみ。
  • ディスク領域が足りなくなって、別のディスク(/dev/sdb等)を増設し、vg-root に組み入れる可能性がある。
  • その場合、/dev/sda だけでなく、/dev/sdb の情報もバックアップしておかなければならない
  • バックアップスクリプトとしては、複数のディスク情報(fdisk情報)を取得出来るようにしておくべき
とまあ、そういうわけで少し複雑な作りになっている。
 
ここまで理解してもらったら、スクリプト部分の前に変数を確認しておこう。
今回のブロック、新たに出てきた変数は以下の2つだ。
  • ${ROOTPVS}
  • ${ROOTPV}
このうち、${ROOTPV}の方は、スクリプト内部で自動的に生成しているので、${ROOTPVS}の方が必要になってくる。
${ROOTPVS}についても、config ファイルに定義することになる。config ファイルに以下の内容を追記しよう。
# vi ../etc/config
--追記ココから--
#
# ROOTPVS:
# Device name of the PV that make up the ROOTVG.
# And not the disk partition name, to specify the physical disk name.
# Specifically, we want to specify the /dev/sda1 instead of /dev/sda.
# Because sometimes it is composed of a plurality of devices,
#  specified in the array.
# ex.
# ROOTPVS="sda sdb sdc sde"
#
ROOTPVS="sda"

--追記ココまで--
${ROOTPVS}には、ただ一つ"sda"という値を設定しているだけだ。
ただ、コメントにサンプルを載せている。これを読んでもらえば予想がつくと思うが、vg-root を構成するHDDが、/dev/sda と /dev/sdb の2つになっている場合は、"sda sdb"と指定してもらえばいい。
そういう風に、複数のHDDを指定できるように準備しておいた。
 
さて、スクリプトに戻ると…。
次に注目して欲しいのは、以下の行
for ROOTPV in ${ROOTPVS}
これは「for文」と呼ばれる繰り返しループ処理の制御文だ。
そして、次の do から done までが繰り返し実行される部分になる。
シェルスクリプト(sh系)の場合の for 文は、以下の様な書き方になる。
for 変数 in 値1 値2 値3 ...
do
  繰り返し実行される行
done
一回目の実行は、「値1」が「変数」に格納されて、「繰り返し実行される行」が実行される。
doneまで実行されたら、「値2」が「変数」に格納されて、また「繰り返し実行される行」が実行される。
これが、値Xが無くなるまで繰り返されるのだ。
 
それを踏まえて、もう一度スクリプトを見てみよう。
for ROOTPV in ${ROOTPVS}
先ほどのconfigファイルにより、${ROOTPVS}には"sda"が格納されているはずなので、実際には以下の行に置き換わる。
for ROOTPV in sda
つまり、ROOTPVという変数に、sda という値が格納されて、その下の do ~ done が実行されるわけだ。
で、doneまで行った後、次の変数が無いため、forループが終了する。
これが、${ROOTPVS}が"sda sdb"だった場合はどうなるか?
for ROOTPV in sda sdb
という風に置き換わるため、ROOTPVという変数に、sda という値が格納されて do ~ done が実行され、その後 ROOTPV という変数の値が sdb という値に置き換わって do ~ done が実行される、という具合に動く。
 
ということは、${ROOTPVS}の中身が "sda" のみだった場合は、結局以下のような実行文になる。
for ROOTPV in ${ROOTPVS}
do
  /sbin/sfdisk --dump /dev/${ROOTPV} > ${BACKUPPOINT}/current/config/sfdisk.${ROOTPV}
done
↓
for ROOTPV in sda
do
  /sbin/sfdisk --dump /dev/${ROOTPV} > ${BACKUPPOINT}/current/config/sfdisk.${ROOTPV}
done
↓
ROOTPV=sda
/sbin/sfdisk --dump /dev/${ROOTPV} > ${BACKUPPOINT}/current/config/sfdisk.${ROOTPV}
↓
/sbin/sfdisk --dump /dev/sda > ${BACKUPPOINT}/current/config/sfdisk.sda

もし、${ROOTPVS}の中身が "sda sdb" だった場合は、以下のようになる。
for ROOTPV in ${ROOTPVS}
do
  /sbin/sfdisk --dump /dev/${ROOTPV} > ${BACKUPPOINT}/current/config/sfdisk.${ROOTPV}
done
↓
for ROOTPV in sda sdb
do
  /sbin/sfdisk --dump /dev/${ROOTPV} > ${BACKUPPOINT}/current/config/sfdisk.${ROOTPV}
done
↓
ROOTPV=sda
/sbin/sfdisk --dump /dev/${ROOTPV} > ${BACKUPPOINT}/current/config/sfdisk.${ROOTPV}
ROOTPV=sdb
/sbin/sfdisk --dump /dev/${ROOTPV} > ${BACKUPPOINT}/current/config/sfdisk.${ROOTPV}
↓
/sbin/sfdisk --dump /dev/sda > ${BACKUPPOINT}/current/config/sfdisk.sda
/sbin/sfdisk --dump /dev/sdb > ${BACKUPPOINT}/current/config/sfdisk.sdb

vg-root を構成するディスクが何本になっても、config ファイル内の ${ROOTPVS}の値を書き換えることで対応が可能になった。
この対応のために、少し複雑な作りになっている。
ちなみに、do ~ done の間は1行しか無いが、当然複数行のコマンドを入れることも可能だ。
これで、「3. 内蔵ディスクのfdiskパーティション情報」の情報取得が出来るようになった。
 
続いて「2. LVM構成情報 - 2. pvのuuid情報等」だ。
こちらは1行で実現している。0030_create_config に以下の1行を追記しよう。
--追記ココから--
/sbin/vgs --unquoted --noheadings --nameprefixes
--options pv_name,pv_uuid,vg_name ${ROOTVG} >
 ${BACKUPPOINT}/current/config/vgs.pvid

--追記ココまで--
vgsコマンドを、何やら複雑なオプション付きで実行し、ファイルにリダイレクトしている。
(行が長すぎて3行に渡っているが、実際には1行で書いて欲しい)
リダイレクトしている部分を除くと、以下の様なコマンドだ、ということが分かる。(${ROOTVG}は、既に中身が vg-root ということが分かっているはずなので、敢えて置き換えて表記する)
vgs --unquoted --noheadings --nameprefixes --options pv_name,pv_uuid,vg_name vg-root
これも、参照コマンドなので、よく分からなかったら実行してしまおう。
# vgs --unquoted --noheadings --nameprefixes --options pv_name,pv_uuid,vg_name vg-root
  LVM2_PV_NAME=/dev/sda3 LVM2_PV_UUID=XXXXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XXXXXX LVM2_VG_NAME=vg-root
何やらデータが出てきた。
これ、よく見てみると分かるのだが、vg-rootを構成するpvの「デバイス名」と「UUID」だ。
今の構成では1行しか出力されていないが、vg-root が複数の pv で構成されている場合は、複数行表示されるぞ。
しかもよく見ると、変数宣言っぽい形で出力されている。リストア時は、これを上手く変数として取り込むことが出来れば、有効活用出来そうだ。
これを取り込むのは、リストアスクリプトの方で解説することにしよう。
駆け足だが、これで「2. LVM構成情報 - 2. pvのuuid情報等」が取得できるようになった。
 
次は最後、「4. 各ファイルシステムのファイルシステムフォーマット情報やuuid情報」だ。
こちら、少し複雑なので、次回にしよう。
(いい加減、ちょっと疲れてきたので…)

0 件のコメント:

コメントを投稿