#!/usr/bin/env ruby -w

require 'libvirt'
require 'pp'
require 'rexml/document'

DOMAIN   = 'winxp'
SAVEPATH = '/mnt/backups/'
LVCREATE = 'sudo lvcreate'
LVREMOVE = 'sudo lvremove'
DD       = 'sudo dd bs=4096'
SNAPSIZE = '2G'
VIRHOST  = 'qemu:///system'

datei = Time.now.strftime("%Y%m%d")

conn = Libvirt::open(VIRHOST)

module Libvirt
	class Connect
		def domains(type = :name)
			if type == :name
				[
					self.list_defined_domains,
					self.list_domains.map do |id|
						self.lookup_domain_by_id(id).name
					end
				]
			elsif type == :object
				[
					self.list_defined_domains.map do |name|
						lookup_domain_by_name(name)
					end,
					self.list_domains.map do |id|
						self.lookup_domain_by_id(id)
					end
				]
			else
				raise "unknown type #{type}"
			end
		end
	end
end

stopped, running = conn.domains

puts "stopped domains :"
puts " - " + stopped.join("\n - ")

puts "running domains :"
puts " - " + running.join("\n - ")

dom = conn.lookup_domain_by_name(DOMAIN)

tosnapshot = {}
rexml = REXML::Document.new(dom.xml_desc)
rexml.elements.each('*/devices/disk["disk"]') do |item|
	next unless item.attributes['device'] == 'disk'
	lvpath = item.elements['source'].attributes['dev']
	tosnapshot[lvpath] = nil
end
puts "will snapshot the following disks for '#{DOMAIN}' :"
puts " - "+tosnapshot.keys.join("\n - ")

tosnapshot.each do |src,dst|
	dst = "#{File.basename(src)}_snap_#{datei}"
	tosnapshot[src] = "#{File.dirname(src)}/#{dst}"
	puts "snapshot '#{src}' to '#{dst}'"
	`#{LVCREATE} -L#{SNAPSIZE} -s -n #{dst} #{src}`
end

memsnapfile = File.join(SAVEPATH,"#{DOMAIN}_memsnap_#{datei}")
puts "suspending and saving status in '#{memsnapfile}'"
dom.suspend
dom.save(memsnapfile)

puts "reloading and resuming status from '#{memsnapfile}'"
Libvirt::Domain.restore(conn, memsnapfile)

dom = conn.lookup_domain_by_name(DOMAIN)
sleep 1
dom.resume

tosnapshot.each do |src,dst|
	raise "error with dst '#{dst}'" if dst.empty?
	snaplv = dst
	puts "making a copy of '#{snaplv}'"
	snapfile = File.join(SAVEPATH, File.basename(snaplv)+".img")
	`#{DD} if=#{snaplv} | #{DD} of=#{snapfile}`
	puts "deleting snapshot '#{snaplv}'"
	`#{LVREMOVE} -f #{snaplv}`
end

