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:
|
if BACKUP_DEBUG:
|
||||||
print_callback("Working in temporary dir:"+restore_tmpdir)
|
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
|
vmproc = None
|
||||||
if appvm != None:
|
if appvm != None:
|
||||||
@ -889,15 +889,27 @@ def load_hmac(hmac):
|
|||||||
|
|
||||||
return 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,
|
def backup_restore_header(source, passphrase,
|
||||||
print_callback = print_stdout, error_callback = print_stderr,
|
print_callback = print_stdout, error_callback = print_stderr,
|
||||||
encrypted=False, appvm=None):
|
encrypted=False, appvm=None, format_version = None):
|
||||||
|
|
||||||
vmproc = None
|
vmproc = None
|
||||||
|
|
||||||
feedback_file = tempfile.NamedTemporaryFile()
|
feedback_file = tempfile.NamedTemporaryFile()
|
||||||
restore_tmpdir = tempfile.mkdtemp(prefix="/var/tmp/restore_")
|
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)
|
os.chdir(restore_tmpdir)
|
||||||
|
|
||||||
if BACKUP_DEBUG:
|
if BACKUP_DEBUG:
|
||||||
@ -923,13 +935,23 @@ def backup_restore_header(source, passphrase,
|
|||||||
|
|
||||||
return (restore_tmpdir, "qubes.xml")
|
return (restore_tmpdir, "qubes.xml")
|
||||||
|
|
||||||
def backup_restore_prepare(backup_dir, qubes_xml, passphrase, options = {},
|
def backup_restore_prepare(backup_location, qubes_xml, passphrase, options = {},
|
||||||
host_collection = None, encrypt=False, appvm=None):
|
host_collection = None, encrypt=False, appvm=None, format_version=None):
|
||||||
# Defaults
|
# Defaults
|
||||||
backup_restore_set_defaults(options)
|
backup_restore_set_defaults(options)
|
||||||
|
|
||||||
#### Private functions begin
|
#### 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:
|
if vm.backup_content:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
@ -944,6 +966,21 @@ def backup_restore_prepare(backup_dir, qubes_xml, passphrase, options = {},
|
|||||||
|
|
||||||
return template
|
return template
|
||||||
#### Private functions end
|
#### 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:
|
if BACKUP_DEBUG:
|
||||||
print "Loading file", qubes_xml
|
print "Loading file", qubes_xml
|
||||||
backup_collection = QubesVmCollection(store_filename = 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:
|
if vm.qid == 0:
|
||||||
# Handle dom0 as special case later
|
# Handle dom0 as special case later
|
||||||
continue
|
continue
|
||||||
if is_vm_included_in_backup (backup_dir, vm):
|
if is_vm_included_in_backup (backup_location, vm):
|
||||||
if BACKUP_DEBUG:
|
if BACKUP_DEBUG:
|
||||||
print vm.name,"is included in backup"
|
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?
|
# Maybe the (custom) template is in the backup?
|
||||||
template_vm_on_backup = backup_collection.get_vm_by_name (templatevm_name)
|
template_vm_on_backup = backup_collection.get_vm_by_name (templatevm_name)
|
||||||
if template_vm_on_backup is None or not \
|
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()):
|
template_vm_on_backup.is_template()):
|
||||||
if options['use-default-template']:
|
if options['use-default-template']:
|
||||||
vms_to_restore[vm.name]['orig-template'] = templatevm_name
|
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)
|
netvm_on_backup = backup_collection.get_vm_by_name (netvm_name)
|
||||||
if not ((netvm_on_backup is not None) and \
|
if not ((netvm_on_backup is not None) and \
|
||||||
netvm_on_backup.is_netvm() 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']:
|
if options['use-default-netvm']:
|
||||||
vms_to_restore[vm.name]['netvm'] = host_collection.get_default_netvm().name
|
vms_to_restore[vm.name]['netvm'] = host_collection.get_default_netvm().name
|
||||||
vm.uses_default_netvm = True
|
vm.uses_default_netvm = True
|
||||||
@ -1041,14 +1078,19 @@ def backup_restore_prepare(backup_dir, qubes_xml, passphrase, options = {},
|
|||||||
|
|
||||||
# ...and dom0 home
|
# ...and dom0 home
|
||||||
if options['dom0-home'] and \
|
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]
|
vm = backup_collection[0]
|
||||||
vms_to_restore['dom0'] = {}
|
vms_to_restore['dom0'] = {}
|
||||||
vms_to_restore['dom0']['subdir'] = vm.backup_path
|
if format_version == 1:
|
||||||
vms_to_restore['dom0']['size'] = vm.backup_size
|
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]
|
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)
|
vms_to_restore['dom0']['username'] = os.path.basename(dom0_home)
|
||||||
if vms_to_restore['dom0']['username'] != local_user:
|
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
|
vms_to_restore['dom0']['good-to-go'] = True
|
||||||
|
|
||||||
# Not needed - all the data stored in vms_to_restore
|
# 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
|
return vms_to_restore
|
||||||
|
|
||||||
def backup_restore_print_summary(restore_info, print_callback = print_stdout):
|
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)
|
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,
|
host_collection = None, print_callback = print_stdout,
|
||||||
error_callback = print_stderr, progress_callback = None,
|
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
|
lock_obtained = False
|
||||||
if host_collection is None:
|
if host_collection is None:
|
||||||
@ -1175,34 +1232,35 @@ def backup_restore_do(backup_dir, restore_tmpdir, passphrase, restore_info,
|
|||||||
lock_obtained = True
|
lock_obtained = True
|
||||||
|
|
||||||
# Perform VM restoration in backup order
|
# Perform VM restoration in backup order
|
||||||
vms_dirs = []
|
if format_version == 2:
|
||||||
vms_size = 0
|
vms_dirs = []
|
||||||
vms = {}
|
vms_size = 0
|
||||||
for vm_info in restore_info.values():
|
vms = {}
|
||||||
if not vm_info['good-to-go']:
|
for vm_info in restore_info.values():
|
||||||
continue
|
if not vm_info['good-to-go']:
|
||||||
if 'vm' not in vm_info:
|
continue
|
||||||
continue
|
if 'vm' not in vm_info:
|
||||||
vm = vm_info['vm']
|
continue
|
||||||
vms_size += vm.backup_size
|
vm = vm_info['vm']
|
||||||
vms_dirs.append(vm.backup_path)
|
vms_size += vm.backup_size
|
||||||
vms[vm.name] = vm
|
vms_dirs.append(vm.backup_path)
|
||||||
|
vms[vm.name] = vm
|
||||||
|
|
||||||
if 'dom0' in restore_info.keys() and restore_info['dom0']['good-to-go']:
|
if 'dom0' in restore_info.keys() and restore_info['dom0']['good-to-go']:
|
||||||
vms_dirs.append('dom0-home')
|
vms_dirs.append('dom0-home')
|
||||||
vms_size += restore_info['dom0']['size']
|
vms_size += restore_info['dom0']['size']
|
||||||
|
|
||||||
restore_vm_dirs (backup_dir,
|
restore_vm_dirs (backup_location,
|
||||||
restore_tmpdir,
|
restore_tmpdir,
|
||||||
passphrase=passphrase,
|
passphrase=passphrase,
|
||||||
vms_dirs=vms_dirs,
|
vms_dirs=vms_dirs,
|
||||||
vms=vms,
|
vms=vms,
|
||||||
vms_size=vms_size,
|
vms_size=vms_size,
|
||||||
print_callback=print_callback,
|
print_callback=print_callback,
|
||||||
error_callback=error_callback,
|
error_callback=error_callback,
|
||||||
progress_callback=progress_callback,
|
progress_callback=progress_callback,
|
||||||
encrypted=encrypted,
|
encrypted=encrypted,
|
||||||
appvm=appvm)
|
appvm=appvm)
|
||||||
|
|
||||||
# Add VM in right order
|
# Add VM in right order
|
||||||
for (vm_class_name, vm_class) in sorted(QubesVmClasses.items(),
|
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,
|
template=template,
|
||||||
installed_by_rpm=False)
|
installed_by_rpm=False)
|
||||||
|
|
||||||
shutil.move(os.path.join(restore_tmpdir, vm.backup_path),
|
if format_version == 1:
|
||||||
new_vm.dir_path)
|
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()
|
new_vm.verify_files()
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
@ -1293,7 +1356,10 @@ def backup_restore_do(backup_dir, restore_tmpdir, passphrase, restore_info,
|
|||||||
home_file = home_dir + '/' + f
|
home_file = home_dir + '/' + f
|
||||||
if os.path.exists(home_file):
|
if os.path.exists(home_file):
|
||||||
os.rename(home_file, home_dir + '/' + restore_home_backupdir + '/' + f)
|
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])
|
retcode = subprocess.call(['sudo', 'chown', '-R', local_user, home_dir])
|
||||||
if retcode != 0:
|
if retcode != 0:
|
||||||
error_callback("*** Error while setting home directory owner")
|
error_callback("*** Error while setting home directory owner")
|
||||||
|
Loading…
Reference in New Issue
Block a user