backups: add support for restoring old backup format
Actually the code is quite similar, so just add few "if" instead of copying the whole functions.
This commit is contained in:
parent
eaebf04b34
commit
3d70402778
154
core/backup.py
154
core/backup.py
@ -770,7 +770,7 @@ def restore_vm_dirs (backup_source, restore_tmpdir, passphrase, vms_dirs, vms,
|
||||
|
||||
if BACKUP_DEBUG:
|
||||
print_callback("Working in temporary dir:"+restore_tmpdir)
|
||||
print_callback(str(vms_size)+" bytes to restore")
|
||||
print_callback("Extracting data: " + size_to_human(vms_size)+" to restore")
|
||||
|
||||
vmproc = None
|
||||
if appvm != None:
|
||||
@ -889,15 +889,27 @@ def load_hmac(hmac):
|
||||
|
||||
return hmac
|
||||
|
||||
def backup_detect_format_version(backup_location):
|
||||
if os.path.exists(os.path.join(backup_location, 'qubes.xml')):
|
||||
return 1
|
||||
else:
|
||||
return 2
|
||||
|
||||
def backup_restore_header(source, passphrase,
|
||||
print_callback = print_stdout, error_callback = print_stderr,
|
||||
encrypted=False, appvm=None):
|
||||
encrypted=False, appvm=None, format_version = None):
|
||||
|
||||
vmproc = None
|
||||
|
||||
feedback_file = tempfile.NamedTemporaryFile()
|
||||
restore_tmpdir = tempfile.mkdtemp(prefix="/var/tmp/restore_")
|
||||
|
||||
if format_version == None:
|
||||
format_version = backup_detect_format_version(source)
|
||||
|
||||
if format_version == 1:
|
||||
return (restore_tmpdir, os.path.join(source, 'qubes.xml'))
|
||||
|
||||
os.chdir(restore_tmpdir)
|
||||
|
||||
if BACKUP_DEBUG:
|
||||
@ -923,13 +935,23 @@ def backup_restore_header(source, passphrase,
|
||||
|
||||
return (restore_tmpdir, "qubes.xml")
|
||||
|
||||
def backup_restore_prepare(backup_dir, qubes_xml, passphrase, options = {},
|
||||
host_collection = None, encrypt=False, appvm=None):
|
||||
def backup_restore_prepare(backup_location, qubes_xml, passphrase, options = {},
|
||||
host_collection = None, encrypt=False, appvm=None, format_version=None):
|
||||
# Defaults
|
||||
backup_restore_set_defaults(options)
|
||||
|
||||
#### Private functions begin
|
||||
def is_vm_included_in_backup (backup_dir, vm):
|
||||
def is_vm_included_in_backup_v1 (backup_dir, vm):
|
||||
if vm.qid == 0:
|
||||
return os.path.exists(os.path.join(backup_dir,'dom0-home'))
|
||||
|
||||
backup_vm_dir_path = vm.dir_path.replace (system_path["qubes_base_dir"], backup_dir)
|
||||
|
||||
if os.path.exists (backup_vm_dir_path):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
def is_vm_included_in_backup_v2 (backup_dir, vm):
|
||||
if vm.backup_content:
|
||||
return True
|
||||
else:
|
||||
@ -944,6 +966,21 @@ def backup_restore_prepare(backup_dir, qubes_xml, passphrase, options = {},
|
||||
|
||||
return template
|
||||
#### Private functions end
|
||||
|
||||
# Format versions:
|
||||
# 1 - Qubes R1, Qubes R2 beta1, beta2
|
||||
# 2 - Qubes R2 beta3
|
||||
|
||||
if format_version is None:
|
||||
format_version = backup_detect_format_version(backup_location)
|
||||
|
||||
if format_version == 1:
|
||||
is_vm_included_in_backup = is_vm_included_in_backup_v1
|
||||
elif format_version == 2:
|
||||
is_vm_included_in_backup = is_vm_included_in_backup_v2
|
||||
else:
|
||||
raise QubesException("Unknown backup format version: %s" % str(format_version))
|
||||
|
||||
if BACKUP_DEBUG:
|
||||
print "Loading file", qubes_xml
|
||||
backup_collection = QubesVmCollection(store_filename = qubes_xml)
|
||||
@ -970,7 +1007,7 @@ def backup_restore_prepare(backup_dir, qubes_xml, passphrase, options = {},
|
||||
if vm.qid == 0:
|
||||
# Handle dom0 as special case later
|
||||
continue
|
||||
if is_vm_included_in_backup (backup_dir, vm):
|
||||
if is_vm_included_in_backup (backup_location, vm):
|
||||
if BACKUP_DEBUG:
|
||||
print vm.name,"is included in backup"
|
||||
|
||||
@ -997,7 +1034,7 @@ def backup_restore_prepare(backup_dir, qubes_xml, passphrase, options = {},
|
||||
# Maybe the (custom) template is in the backup?
|
||||
template_vm_on_backup = backup_collection.get_vm_by_name (templatevm_name)
|
||||
if template_vm_on_backup is None or not \
|
||||
(is_vm_included_in_backup(backup_dir, template_vm_on_backup) and \
|
||||
(is_vm_included_in_backup(backup_location, template_vm_on_backup) and \
|
||||
template_vm_on_backup.is_template()):
|
||||
if options['use-default-template']:
|
||||
vms_to_restore[vm.name]['orig-template'] = templatevm_name
|
||||
@ -1026,7 +1063,7 @@ def backup_restore_prepare(backup_dir, qubes_xml, passphrase, options = {},
|
||||
netvm_on_backup = backup_collection.get_vm_by_name (netvm_name)
|
||||
if not ((netvm_on_backup is not None) and \
|
||||
netvm_on_backup.is_netvm() and \
|
||||
is_vm_included_in_backup(backup_dir, netvm_on_backup)):
|
||||
is_vm_included_in_backup(backup_location, netvm_on_backup)):
|
||||
if options['use-default-netvm']:
|
||||
vms_to_restore[vm.name]['netvm'] = host_collection.get_default_netvm().name
|
||||
vm.uses_default_netvm = True
|
||||
@ -1041,14 +1078,19 @@ def backup_restore_prepare(backup_dir, qubes_xml, passphrase, options = {},
|
||||
|
||||
# ...and dom0 home
|
||||
if options['dom0-home'] and \
|
||||
is_vm_included_in_backup(backup_dir, backup_collection[0]):
|
||||
is_vm_included_in_backup(backup_location, backup_collection[0]):
|
||||
vm = backup_collection[0]
|
||||
vms_to_restore['dom0'] = {}
|
||||
vms_to_restore['dom0']['subdir'] = vm.backup_path
|
||||
vms_to_restore['dom0']['size'] = vm.backup_size
|
||||
if format_version == 1:
|
||||
vms_to_restore['dom0']['subdir'] = \
|
||||
os.listdir(os.path.join(backup_location, 'dom0-home'))[0]
|
||||
vms_to_restore['dom0']['size'] = 0 # unknown
|
||||
else:
|
||||
vms_to_restore['dom0']['subdir'] = vm.backup_path
|
||||
vms_to_restore['dom0']['size'] = vm.backup_size
|
||||
local_user = grp.getgrnam('qubes').gr_mem[0]
|
||||
|
||||
dom0_home = vm.backup_path
|
||||
dom0_home = vms_to_restore['dom0']['subdir']
|
||||
|
||||
vms_to_restore['dom0']['username'] = os.path.basename(dom0_home)
|
||||
if vms_to_restore['dom0']['username'] != local_user:
|
||||
@ -1060,7 +1102,8 @@ def backup_restore_prepare(backup_dir, qubes_xml, passphrase, options = {},
|
||||
vms_to_restore['dom0']['good-to-go'] = True
|
||||
|
||||
# Not needed - all the data stored in vms_to_restore
|
||||
os.unlink(qubes_xml)
|
||||
if format_version == 2:
|
||||
os.unlink(qubes_xml)
|
||||
return vms_to_restore
|
||||
|
||||
def backup_restore_print_summary(restore_info, print_callback = print_stdout):
|
||||
@ -1162,10 +1205,24 @@ def backup_restore_print_summary(restore_info, print_callback = print_stdout):
|
||||
|
||||
print_callback(s)
|
||||
|
||||
def backup_restore_do(backup_dir, restore_tmpdir, passphrase, restore_info,
|
||||
def backup_restore_do(backup_location, restore_tmpdir, passphrase, restore_info,
|
||||
host_collection = None, print_callback = print_stdout,
|
||||
error_callback = print_stderr, progress_callback = None,
|
||||
encrypted=False, appvm=None):
|
||||
encrypted=False, appvm=None, format_version = None):
|
||||
|
||||
### Private functions begin
|
||||
def restore_vm_dir_v1 (backup_dir, src_dir, dst_dir):
|
||||
|
||||
backup_src_dir = src_dir.replace (system_path["qubes_base_dir"], backup_dir)
|
||||
|
||||
# We prefer to use Linux's cp, because it nicely handles sparse files
|
||||
retcode = subprocess.call (["cp", "-rp", backup_src_dir, dst_dir])
|
||||
if retcode != 0:
|
||||
raise QubesException("*** Error while copying file {0} to {1}".format(backup_src_dir, dest_dir))
|
||||
### Private functions end
|
||||
|
||||
if format_version is None:
|
||||
format_version = backup_detect_format_version(backup_location)
|
||||
|
||||
lock_obtained = False
|
||||
if host_collection is None:
|
||||
@ -1175,34 +1232,35 @@ def backup_restore_do(backup_dir, restore_tmpdir, passphrase, restore_info,
|
||||
lock_obtained = True
|
||||
|
||||
# Perform VM restoration in backup order
|
||||
vms_dirs = []
|
||||
vms_size = 0
|
||||
vms = {}
|
||||
for vm_info in restore_info.values():
|
||||
if not vm_info['good-to-go']:
|
||||
continue
|
||||
if 'vm' not in vm_info:
|
||||
continue
|
||||
vm = vm_info['vm']
|
||||
vms_size += vm.backup_size
|
||||
vms_dirs.append(vm.backup_path)
|
||||
vms[vm.name] = vm
|
||||
if format_version == 2:
|
||||
vms_dirs = []
|
||||
vms_size = 0
|
||||
vms = {}
|
||||
for vm_info in restore_info.values():
|
||||
if not vm_info['good-to-go']:
|
||||
continue
|
||||
if 'vm' not in vm_info:
|
||||
continue
|
||||
vm = vm_info['vm']
|
||||
vms_size += vm.backup_size
|
||||
vms_dirs.append(vm.backup_path)
|
||||
vms[vm.name] = vm
|
||||
|
||||
if 'dom0' in restore_info.keys() and restore_info['dom0']['good-to-go']:
|
||||
vms_dirs.append('dom0-home')
|
||||
vms_size += restore_info['dom0']['size']
|
||||
if 'dom0' in restore_info.keys() and restore_info['dom0']['good-to-go']:
|
||||
vms_dirs.append('dom0-home')
|
||||
vms_size += restore_info['dom0']['size']
|
||||
|
||||
restore_vm_dirs (backup_dir,
|
||||
restore_tmpdir,
|
||||
passphrase=passphrase,
|
||||
vms_dirs=vms_dirs,
|
||||
vms=vms,
|
||||
vms_size=vms_size,
|
||||
print_callback=print_callback,
|
||||
error_callback=error_callback,
|
||||
progress_callback=progress_callback,
|
||||
encrypted=encrypted,
|
||||
appvm=appvm)
|
||||
restore_vm_dirs (backup_location,
|
||||
restore_tmpdir,
|
||||
passphrase=passphrase,
|
||||
vms_dirs=vms_dirs,
|
||||
vms=vms,
|
||||
vms_size=vms_size,
|
||||
print_callback=print_callback,
|
||||
error_callback=error_callback,
|
||||
progress_callback=progress_callback,
|
||||
encrypted=encrypted,
|
||||
appvm=appvm)
|
||||
|
||||
# Add VM in right order
|
||||
for (vm_class_name, vm_class) in sorted(QubesVmClasses.items(),
|
||||
@ -1236,8 +1294,13 @@ def backup_restore_do(backup_dir, restore_tmpdir, passphrase, restore_info,
|
||||
template=template,
|
||||
installed_by_rpm=False)
|
||||
|
||||
shutil.move(os.path.join(restore_tmpdir, vm.backup_path),
|
||||
new_vm.dir_path)
|
||||
if format_version == 1:
|
||||
restore_vm_dir_v1(backup_location,
|
||||
vm.dir_path,
|
||||
os.path.dirname(new_vm.dir_path))
|
||||
elif format_version == 2:
|
||||
shutil.move(os.path.join(restore_tmpdir, vm.backup_path),
|
||||
new_vm.dir_path)
|
||||
|
||||
new_vm.verify_files()
|
||||
except Exception as err:
|
||||
@ -1293,7 +1356,10 @@ def backup_restore_do(backup_dir, restore_tmpdir, passphrase, restore_info,
|
||||
home_file = home_dir + '/' + f
|
||||
if os.path.exists(home_file):
|
||||
os.rename(home_file, home_dir + '/' + restore_home_backupdir + '/' + f)
|
||||
shutil.move(backup_dom0_home_dir + '/' + f, home_file)
|
||||
if format_version == 1:
|
||||
retcode = subprocess.call (["cp", "-nrp", backup_dom0_home_dir + '/' + f, home_file])
|
||||
elif format_version == 2:
|
||||
shutil.move(backup_dom0_home_dir + '/' + f, home_file)
|
||||
retcode = subprocess.call(['sudo', 'chown', '-R', local_user, home_dir])
|
||||
if retcode != 0:
|
||||
error_callback("*** Error while setting home directory owner")
|
||||
|
Loading…
Reference in New Issue
Block a user