XenServer5.5でsnapshotをrollback(revert to snapshot)してみる
XenでもXenServerの話。
XenServerは体感ではVMwareよりずっと軽く感じる*1ので、最近はとても愛用しているのですが、XenServer5.5のXenCenterにはスナップショットから元に戻す機能が付いていないので少し不満でした。
調べてみると、どうやらXenServer5.5ではcheckpoint(revert to snapshot)の機能は消されているようです。
http://community.citrix.com/display/ocb/2009/07/02/XenServer+-+LVM-based+Snapshots
"Revert"(旧checkpoint)は5.5では提供されていません
でも、スナップショットの中身がLVM-BaseならCLIの機能でいけるんじゃないか、と検索してみました。
http://docs.vmd.citrix.com/XenServer/5.5.0/1.0/en_gb/reference.html#id2584877
ちょっと面倒ですが、いちおういけそう。*2
- 取得したスナップショット名をメモ
- 元に戻すVMのMACアドレスをメモ
- VMの情報を取得
- domain0でUUIDを調べる (xe vm-list)
- VMをシャットダウン(xe vm-shutdown uuid=
) - VMを削除(xe vm-destroy uuid=
) - スナップショットからVMをあたらしく作成(xe vm-install new-name-label=
template= ) - VMを起動(xe vm-start name-label=
) - MACアドレスを元に戻す
こんなの手でやってられないのでスクリプト化。やっつけでまともにテストしてないので保障なし。
require 'optparse' require 'pp' def xelist(sub_command, label) return nil unless ["vm-list", "template-list"].index(sub_command) data = IO.popen("xe #{sub_command} 2> /dev/null", "r").map vms = [] while 0 < data.size hash = {} if data[1].split(":").size == 3 else 3.times {|n| elems = data[n].split(":") key, value = elems[0].split[0].strip.chomp, elems[-1].strip.chomp hash[key] = value } vms << hash end 5.times {|n| data.shift} end key = label.is_uuid? ? "uuid" : "name-label" vms.each {|vm| if vm[key] == label if sub_command == "template-list" return vm["uuid"] else return vm["uuid"] ,vm["name-label"] ,vm["power-state"] end end } return nil end def xevmvif(label) data = IO.popen("xe vm-vif-list 2> /dev/null", "r").map vms = [] while 0 < data.size hash = {} 6.times {|n| elems = data[n].split(":") key, value = elems[0].split[0].strip.chomp, elems[1..-1].join(":").strip.chomp hash[key] = value } vms << hash 8.times {|n| data.shift} end vms.each {|vm| return vm["MAC"] if vm["vm-name-label"] == label } return nil end class String def is_uuid? uuid = self.split("-") return nil unless uuid.size == 5 [8,4,4,4,12] == [uuid[0].size, uuid[1].size, uuid[2].size, uuid[3].size, uuid[4].size] end end def system_e(command_line) puts " $ " + command_line system(command_line) end # main o = {} opt = OptionParser.new opt.on("--vm", "--vm-list {uuid|label-name}") {|v| o[:vm] = v} opt.on("--template", "--templatet {uuid|label-name}") {|v| o[:template] = v} begin opt.parse! rescue OptionParser::ParseError => e puts opt.help exit 2 else [:vm, :template].each {|x| unless o[x] puts opt.help exit 2 end } end result = {} # source vm exist? result[:vm_uuid], result[:vm_label], result[:vm_state] = xelist("vm-list", o[:vm]) # template exist? result[:tvm_uuid] = xelist("template-list", o[:template]) if result[:vm_uuid].nil? puts "#{result[:vm_uuid]} source vm not found."; exit end if result[:tvm_uuid].nil? puts "#{result[:tvm_uuid]} template vm not found."; exit end result[:mac] = xevmvif(result[:vm_label]) system_e("xe vm-shutdown uuid=#{result[:vm_uuid]}") if result[:vm_state] == "running" system_e("xe vm-destroy uuid=#{result[:vm_uuid]}") system_e("xe vm-install new-name-label=#{result[:vm_label]} template=#{result[:tvm_uuid]} > /dev/null 2>&1") system_e("xe vm-start name-label=#{result[:vm_label]}") puts "Please change your mac address - #{result[:mac]}" exit
こんな感じで。ruby revert.rb --vm [対象のvm] --template [戻すスナップショット]
# ruby revert.rb --template test0001_snapshot --vm testvmname $ xe vm-shutdown uuid=4f3ba61b-1253-4d23-eabf-ac82399a659c $ xe vm-destroy uuid=4f3ba61b-1253-4d23-eabf-ac82399a659c $ xe vm-install new-name-label=testvmname template=64610fff-80ff-e294-323a-7297aa5491f9 > /dev/null 2>&1 $ xe vm-start name-label=testvmname Please change your mac address - 3e:da:82:89:cc:7d