Merge remote-tracking branch 'qubesos/pr/52'
* qubesos/pr/52: backup: don't crash when no 'qubes' group is present tests: dom0 backup restore, both v3 and v4 backup: add support for openssl 1.1.0 options backup: skip dom0's properties while restoring core2 backup unused variable style issues Fix dom0 restore Fix dom0 handling Fix AdminVm class name
This commit is contained in:
commit
d07475427f
@ -256,6 +256,9 @@ class Core2Qubes(qubesadmin.backup.BackupApp):
|
|||||||
kwargs = {}
|
kwargs = {}
|
||||||
if vm_class_name in ["QubesTemplateVm", "QubesTemplateHVm"]:
|
if vm_class_name in ["QubesTemplateVm", "QubesTemplateHVm"]:
|
||||||
vm.klass = "TemplateVM"
|
vm.klass = "TemplateVM"
|
||||||
|
elif element.get('qid') == '0':
|
||||||
|
kwargs['dir_path'] = element.get('dir_path')
|
||||||
|
vm.klass = "AdminVM"
|
||||||
elif element.get('template_qid').lower() == "none":
|
elif element.get('template_qid').lower() == "none":
|
||||||
kwargs['dir_path'] = element.get('dir_path')
|
kwargs['dir_path'] = element.get('dir_path')
|
||||||
vm.klass = "StandaloneVM"
|
vm.klass = "StandaloneVM"
|
||||||
@ -264,6 +267,15 @@ class Core2Qubes(qubesadmin.backup.BackupApp):
|
|||||||
vm.template = \
|
vm.template = \
|
||||||
self.qid_map[int(element.get('template_qid'))]
|
self.qid_map[int(element.get('template_qid'))]
|
||||||
vm.klass = "AppVM"
|
vm.klass = "AppVM"
|
||||||
|
|
||||||
|
vm.backup_content = element.get('backup_content', False) == 'True'
|
||||||
|
vm.backup_path = element.get('backup_path', None)
|
||||||
|
vm.size = element.get('backup_size', 0)
|
||||||
|
|
||||||
|
if vm.klass == 'AdminVM':
|
||||||
|
# don't set any other dom0 property
|
||||||
|
return
|
||||||
|
|
||||||
# simple attributes
|
# simple attributes
|
||||||
for attr, default in {
|
for attr, default in {
|
||||||
#'installed_by_rpm': 'False',
|
#'installed_by_rpm': 'False',
|
||||||
@ -321,10 +333,6 @@ class Core2Qubes(qubesadmin.backup.BackupApp):
|
|||||||
feature = repl_feature
|
feature = repl_feature
|
||||||
vm.features[feature] = value
|
vm.features[feature] = value
|
||||||
|
|
||||||
vm.backup_content = element.get('backup_content', False) == 'True'
|
|
||||||
vm.backup_path = element.get('backup_path', None)
|
|
||||||
vm.size = element.get('backup_size', 0)
|
|
||||||
|
|
||||||
pci_strictreset = element.get('pci_strictreset', True)
|
pci_strictreset = element.get('pci_strictreset', True)
|
||||||
pcidevs = element.get('pcidevs')
|
pcidevs = element.get('pcidevs')
|
||||||
if pcidevs:
|
if pcidevs:
|
||||||
@ -348,7 +356,7 @@ class Core2Qubes(qubesadmin.backup.BackupApp):
|
|||||||
|
|
||||||
self.globals['default_kernel'] = tree.getroot().get("default_kernel")
|
self.globals['default_kernel'] = tree.getroot().get("default_kernel")
|
||||||
|
|
||||||
vm_classes = ["AdminVM", "TemplateVm", "TemplateHVm",
|
vm_classes = ["AdminVm", "TemplateVm", "TemplateHVm",
|
||||||
"AppVm", "HVm", "NetVm", "ProxyVm"]
|
"AppVm", "HVm", "NetVm", "ProxyVm"]
|
||||||
|
|
||||||
# First build qid->name map
|
# First build qid->name map
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
import errno
|
import errno
|
||||||
import fcntl
|
import fcntl
|
||||||
import functools
|
import functools
|
||||||
|
import getpass
|
||||||
import grp
|
import grp
|
||||||
import logging
|
import logging
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
@ -564,6 +565,10 @@ class ExtractWorker3(Process):
|
|||||||
else:
|
else:
|
||||||
# ignore this directory
|
# ignore this directory
|
||||||
tar2_cmdline = None
|
tar2_cmdline = None
|
||||||
|
elif os.path.dirname(inner_name) == "dom0-home":
|
||||||
|
tar2_cmdline = ['cat']
|
||||||
|
redirect_stdout = subprocess.PIPE
|
||||||
|
|
||||||
elif inner_name in self.handlers:
|
elif inner_name in self.handlers:
|
||||||
tar2_cmdline = ['tar',
|
tar2_cmdline = ['tar',
|
||||||
'-%svvO' % ("t" if self.verify_only else "x"),
|
'-%svvO' % ("t" if self.verify_only else "x"),
|
||||||
@ -578,14 +583,18 @@ class ExtractWorker3(Process):
|
|||||||
os.remove(filename)
|
os.remove(filename)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
tar_compress_cmd = None
|
||||||
if self.compressed:
|
if self.compressed:
|
||||||
if self.compression_filter:
|
if self.compression_filter:
|
||||||
tar2_cmdline.insert(-1,
|
tar_compress_cmd = self.compression_filter
|
||||||
"--use-compress-program=%s" %
|
|
||||||
self.compression_filter)
|
|
||||||
else:
|
else:
|
||||||
tar2_cmdline.insert(-1, "--use-compress-program=%s" %
|
tar_compress_cmd = DEFAULT_COMPRESSION_FILTER
|
||||||
DEFAULT_COMPRESSION_FILTER)
|
if os.path.dirname(inner_name) == "dom0-home":
|
||||||
|
# Replaces 'cat' for compressed dom0-home!
|
||||||
|
tar2_cmdline = [tar_compress_cmd, "-d"]
|
||||||
|
else:
|
||||||
|
tar2_cmdline.insert(-1, "--use-compress-program=%s " %
|
||||||
|
tar_compress_cmd)
|
||||||
|
|
||||||
self.log.debug("Running command %s", str(tar2_cmdline))
|
self.log.debug("Running command %s", str(tar2_cmdline))
|
||||||
if self.encrypted:
|
if self.encrypted:
|
||||||
@ -647,7 +656,7 @@ class ExtractWorker3(Process):
|
|||||||
os.remove(filename)
|
os.remove(filename)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self.log.debug("Releasing next chunck")
|
self.log.debug("Releasing next chunk")
|
||||||
self.feed_tar2(filename, input_pipe)
|
self.feed_tar2(filename, input_pipe)
|
||||||
|
|
||||||
self.tar2_current_file = filename
|
self.tar2_current_file = filename
|
||||||
@ -694,8 +703,12 @@ def get_supported_hmac_algo(hmac_algorithm=None):
|
|||||||
yield hmac_algorithm
|
yield hmac_algorithm
|
||||||
if hmac_algorithm != 'scrypt':
|
if hmac_algorithm != 'scrypt':
|
||||||
yield 'scrypt'
|
yield 'scrypt'
|
||||||
proc = subprocess.Popen(['openssl', 'list-message-digest-algorithms'],
|
proc = subprocess.Popen(
|
||||||
stdout=subprocess.PIPE)
|
'openssl list-message-digest-algorithms || '
|
||||||
|
'openssl list -digest-algorithms',
|
||||||
|
shell=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.DEVNULL)
|
||||||
try:
|
try:
|
||||||
for algo in proc.stdout.readlines():
|
for algo in proc.stdout.readlines():
|
||||||
algo = algo.decode('ascii')
|
algo = algo.decode('ascii')
|
||||||
@ -1540,7 +1553,11 @@ class BackupRestore(object):
|
|||||||
vm = self.backup_app.domains['dom0']
|
vm = self.backup_app.domains['dom0']
|
||||||
vms_to_restore['dom0'] = self.Dom0ToRestore(vm,
|
vms_to_restore['dom0'] = self.Dom0ToRestore(vm,
|
||||||
self.backup_app.domains['dom0'].backup_path)
|
self.backup_app.domains['dom0'].backup_path)
|
||||||
|
try:
|
||||||
local_user = grp.getgrnam('qubes').gr_mem[0]
|
local_user = grp.getgrnam('qubes').gr_mem[0]
|
||||||
|
except KeyError:
|
||||||
|
# if no qubes group is present, assume username matches
|
||||||
|
local_user = vms_to_restore['dom0'].username
|
||||||
|
|
||||||
if vms_to_restore['dom0'].username != local_user:
|
if vms_to_restore['dom0'].username != local_user:
|
||||||
if not self.options.ignore_username_mismatch:
|
if not self.options.ignore_username_mismatch:
|
||||||
@ -1660,33 +1677,29 @@ class BackupRestore(object):
|
|||||||
reverse=True)
|
reverse=True)
|
||||||
|
|
||||||
|
|
||||||
def _handle_dom0(self, backup_path):
|
def _handle_dom0(self, stream):
|
||||||
'''Extract dom0 home'''
|
'''Extract dom0 home'''
|
||||||
|
try:
|
||||||
local_user = grp.getgrnam('qubes').gr_mem[0]
|
local_user = grp.getgrnam('qubes').gr_mem[0]
|
||||||
home_dir = pwd.getpwnam(local_user).pw_dir
|
home_dir = pwd.getpwnam(local_user).pw_dir
|
||||||
backup_dom0_home_dir = os.path.join(self.tmpdir, backup_path)
|
except KeyError:
|
||||||
restore_home_backupdir = "home-pre-restore-{0}".format(
|
home_dir = os.path.expanduser('~')
|
||||||
|
local_user = getpass.getuser()
|
||||||
|
restore_home_backupdir = "home-restore-{0}".format(
|
||||||
time.strftime("%Y-%m-%d-%H%M%S"))
|
time.strftime("%Y-%m-%d-%H%M%S"))
|
||||||
|
|
||||||
self.log.info("Restoring home of user '%s'...", local_user)
|
self.log.info("Restoring home of user '%s' to '%s' directory...",
|
||||||
self.log.info("Existing files/dirs backed up in '%s' dir",
|
local_user, restore_home_backupdir)
|
||||||
restore_home_backupdir)
|
os.mkdir(os.path.join(home_dir, restore_home_backupdir))
|
||||||
os.mkdir(home_dir + '/' + restore_home_backupdir)
|
tar3_cmdline = ['tar', '-C',
|
||||||
for f_name in os.listdir(backup_dom0_home_dir):
|
os.path.join(home_dir, restore_home_backupdir), '-x']
|
||||||
home_file = home_dir + '/' + f_name
|
retcode = subprocess.call(tar3_cmdline, stdin=stream)
|
||||||
if os.path.exists(home_file):
|
|
||||||
os.rename(home_file,
|
|
||||||
home_dir + '/' + restore_home_backupdir + '/' + f_name)
|
|
||||||
if self.header_data.version == 1:
|
|
||||||
subprocess.call(
|
|
||||||
["cp", "-nrp", "--reflink=auto",
|
|
||||||
backup_dom0_home_dir + '/' + f_name, home_file])
|
|
||||||
elif self.header_data.version >= 2:
|
|
||||||
shutil.move(backup_dom0_home_dir + '/' + f_name, home_file)
|
|
||||||
retcode = subprocess.call(['sudo', 'chown', '-R',
|
|
||||||
local_user, home_dir])
|
|
||||||
if retcode != 0:
|
if retcode != 0:
|
||||||
self.log.error("*** Error while setting home directory owner")
|
raise QubesException("Inner tar error for dom0-home")
|
||||||
|
retcode = subprocess.call(['sudo', 'chown', '-R',
|
||||||
|
local_user, os.path.join(home_dir, restore_home_backupdir)])
|
||||||
|
if retcode != 0:
|
||||||
|
self.log.error("*** Error while setting restore directory owner")
|
||||||
|
|
||||||
def _handle_appmenus_list(self, vm, stream):
|
def _handle_appmenus_list(self, vm, stream):
|
||||||
'''Handle whitelisted-appmenus.list file'''
|
'''Handle whitelisted-appmenus.list file'''
|
||||||
@ -1827,7 +1840,8 @@ class BackupRestore(object):
|
|||||||
new_vm = None
|
new_vm = None
|
||||||
vm_name = restore_info[vm.name].name
|
vm_name = restore_info[vm.name].name
|
||||||
|
|
||||||
if self.options.verify_only:
|
if self.options.verify_only or vm.name == 'dom0':
|
||||||
|
# can't create vm, but need backup info
|
||||||
new_vm = self.backup_app.domains[vm_name]
|
new_vm = self.backup_app.domains[vm_name]
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#
|
#
|
||||||
import functools
|
import functools
|
||||||
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
from distutils import spawn
|
from distutils import spawn
|
||||||
@ -29,6 +30,8 @@ import subprocess
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import unittest.mock as mock
|
import unittest.mock as mock
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@ -147,8 +150,8 @@ parsed_qubes_xml_r2 = {
|
|||||||
'tags': set(),
|
'tags': set(),
|
||||||
'features': {},
|
'features': {},
|
||||||
'template': None,
|
'template': None,
|
||||||
'backup_path': None,
|
'backup_path': 'dom0-home/user',
|
||||||
'included_in_backup': False,
|
'included_in_backup': True,
|
||||||
},
|
},
|
||||||
'fedora-20-x64': {
|
'fedora-20-x64': {
|
||||||
'klass': 'TemplateVM',
|
'klass': 'TemplateVM',
|
||||||
@ -426,8 +429,8 @@ parsed_qubes_xml_v4 = {
|
|||||||
'tags': set(),
|
'tags': set(),
|
||||||
'features': {},
|
'features': {},
|
||||||
'template': None,
|
'template': None,
|
||||||
'backup_path': None,
|
'backup_path': 'dom0-home/user',
|
||||||
'included_in_backup': False,
|
'included_in_backup': True,
|
||||||
},
|
},
|
||||||
'fedora-25': {
|
'fedora-25': {
|
||||||
'klass': 'TemplateVM',
|
'klass': 'TemplateVM',
|
||||||
@ -967,6 +970,45 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
"vm-templates/test-template-clone")),
|
"vm-templates/test-template-clone")),
|
||||||
appmenus_list)
|
appmenus_list)
|
||||||
|
|
||||||
|
self.create_dom0_files()
|
||||||
|
|
||||||
|
dom0_dirs = ('Downloads', 'Pictures', 'Documents', '.config', '.local')
|
||||||
|
dom0_files = ('.bash_history', 'some-file.txt',
|
||||||
|
'Pictures/another-file.png')
|
||||||
|
|
||||||
|
def create_dom0_files(self):
|
||||||
|
# dom0 files
|
||||||
|
os.mkdir(self.fullpath('dom0-home'))
|
||||||
|
os.mkdir(self.fullpath('dom0-home/user'))
|
||||||
|
for d in self.dom0_dirs:
|
||||||
|
os.mkdir(self.fullpath('dom0-home/user/' + d))
|
||||||
|
for f in self.dom0_files:
|
||||||
|
with open(self.fullpath('dom0-home/user/' + f), 'w') as ff:
|
||||||
|
ff.write('some content')
|
||||||
|
|
||||||
|
def assertDirectoryExists(self, path):
|
||||||
|
if not os.path.exists(path):
|
||||||
|
self.fail(path + ' missing')
|
||||||
|
if not os.path.isdir(path):
|
||||||
|
self.fail(path + ' is not a directory')
|
||||||
|
|
||||||
|
def assertFileExists(self, path):
|
||||||
|
if not os.path.exists(path):
|
||||||
|
self.fail(path + ' missing')
|
||||||
|
if not os.path.isfile(path):
|
||||||
|
self.fail(path + ' is not a file')
|
||||||
|
|
||||||
|
def assertDom0Restored(self, timestamp):
|
||||||
|
expected_dir = os.path.expanduser(
|
||||||
|
'~/home-restore-' + timestamp + '/dom0-home/user')
|
||||||
|
self.assertTrue(os.path.exists(expected_dir))
|
||||||
|
for d in self.dom0_dirs:
|
||||||
|
self.assertDirectoryExists(os.path.join(expected_dir, d))
|
||||||
|
for f in self.dom0_files:
|
||||||
|
self.assertFileExists(os.path.join(expected_dir, f))
|
||||||
|
# cleanup
|
||||||
|
shutil.rmtree(expected_dir)
|
||||||
|
|
||||||
def create_v4_files(self):
|
def create_v4_files(self):
|
||||||
appmenus_list = [
|
appmenus_list = [
|
||||||
"firefox", "gnome-terminal", "evince", "evolution",
|
"firefox", "gnome-terminal", "evince", "evolution",
|
||||||
@ -1041,6 +1083,8 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
"vm-templates/test-fedora-25-clone")),
|
"vm-templates/test-fedora-25-clone")),
|
||||||
appmenus_list)
|
appmenus_list)
|
||||||
|
|
||||||
|
self.create_dom0_files()
|
||||||
|
|
||||||
def scrypt_encrypt(self, f_name, output_name=None, password='qubes',
|
def scrypt_encrypt(self, f_name, output_name=None, password='qubes',
|
||||||
basedir=None):
|
basedir=None):
|
||||||
if basedir is None:
|
if basedir is None:
|
||||||
@ -1094,6 +1138,7 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
data = encryptor.stdout
|
data = encryptor.stdout
|
||||||
else:
|
else:
|
||||||
data = tar.stdout
|
data = tar.stdout
|
||||||
|
encryptor = None
|
||||||
|
|
||||||
stage1_dir = self.fullpath(os.path.join("stage1", subdir))
|
stage1_dir = self.fullpath(os.path.join("stage1", subdir))
|
||||||
if not os.path.exists(stage1_dir):
|
if not os.path.exists(stage1_dir):
|
||||||
@ -1105,6 +1150,9 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
os.path.basename(f_name+"."))],
|
os.path.basename(f_name+"."))],
|
||||||
stdin=data)
|
stdin=data)
|
||||||
data.close()
|
data.close()
|
||||||
|
tar.wait()
|
||||||
|
if encryptor:
|
||||||
|
encryptor.wait()
|
||||||
|
|
||||||
for part in sorted(os.listdir(stage1_dir)):
|
for part in sorted(os.listdir(stage1_dir)):
|
||||||
if not re.match(
|
if not re.match(
|
||||||
@ -1142,6 +1190,7 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
os.path.basename(f_name+"."))],
|
os.path.basename(f_name+"."))],
|
||||||
stdin=data)
|
stdin=data)
|
||||||
data.close()
|
data.close()
|
||||||
|
tar.wait()
|
||||||
|
|
||||||
for part in sorted(os.listdir(stage1_dir)):
|
for part in sorted(os.listdir(stage1_dir)):
|
||||||
if not re.match(
|
if not re.match(
|
||||||
@ -1211,6 +1260,12 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
compressed=compressed,
|
compressed=compressed,
|
||||||
encrypted=encrypted)
|
encrypted=encrypted)
|
||||||
|
|
||||||
|
self.handle_v3_file(
|
||||||
|
'dom0-home/user',
|
||||||
|
'dom0-home/', output,
|
||||||
|
compressed=compressed,
|
||||||
|
encrypted=encrypted)
|
||||||
|
|
||||||
output.close()
|
output.close()
|
||||||
|
|
||||||
def create_v4_backup(self, compressed=True):
|
def create_v4_backup(self, compressed=True):
|
||||||
@ -1249,6 +1304,11 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
os.path.join(vm_dir, f_name),
|
os.path.join(vm_dir, f_name),
|
||||||
subdir+'/', output, compressed=compressed)
|
subdir+'/', output, compressed=compressed)
|
||||||
|
|
||||||
|
self.handle_v4_file(
|
||||||
|
'dom0-home/user',
|
||||||
|
'dom0-home/', output,
|
||||||
|
compressed=compressed)
|
||||||
|
|
||||||
output.close()
|
output.close()
|
||||||
|
|
||||||
def setup_expected_calls(self, parsed_qubes_xml, templates_map=None):
|
def setup_expected_calls(self, parsed_qubes_xml, templates_map=None):
|
||||||
@ -1260,6 +1320,9 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
if not vm['included_in_backup']:
|
if not vm['included_in_backup']:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if name == 'dom0':
|
||||||
|
continue
|
||||||
|
|
||||||
if self.storage_pool:
|
if self.storage_pool:
|
||||||
self.app.expected_calls[
|
self.app.expected_calls[
|
||||||
('dom0', 'admin.vm.CreateInPool.' + vm['klass'],
|
('dom0', 'admin.vm.CreateInPool.' + vm['klass'],
|
||||||
@ -1426,6 +1489,7 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
firewall_data.encode())] = b'0\0'
|
firewall_data.encode())] = b'0\0'
|
||||||
qubesd_calls_queue = multiprocessing.Queue()
|
qubesd_calls_queue = multiprocessing.Queue()
|
||||||
|
|
||||||
|
dummy_timestamp = time.strftime("test-%Y-%m-%d-%H%M%S")
|
||||||
patches = [
|
patches = [
|
||||||
mock.patch('qubesadmin.storage.Volume',
|
mock.patch('qubesadmin.storage.Volume',
|
||||||
functools.partial(MockVolume, qubesd_calls_queue)),
|
functools.partial(MockVolume, qubesd_calls_queue)),
|
||||||
@ -1435,6 +1499,9 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
mock.patch(
|
mock.patch(
|
||||||
'qubesadmin.firewall.Firewall',
|
'qubesadmin.firewall.Firewall',
|
||||||
functools.partial(MockFirewall, qubesd_calls_queue)),
|
functools.partial(MockFirewall, qubesd_calls_queue)),
|
||||||
|
mock.patch(
|
||||||
|
'time.strftime',
|
||||||
|
return_value=dummy_timestamp)
|
||||||
]
|
]
|
||||||
for patch in patches:
|
for patch in patches:
|
||||||
patch.start()
|
patch.start()
|
||||||
@ -1455,6 +1522,8 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
|
|
||||||
self.assertAllCalled()
|
self.assertAllCalled()
|
||||||
|
|
||||||
|
self.assertDom0Restored(dummy_timestamp)
|
||||||
|
|
||||||
def test_220_r2_encrypted(self):
|
def test_220_r2_encrypted(self):
|
||||||
self.create_v3_backup(True)
|
self.create_v3_backup(True)
|
||||||
|
|
||||||
@ -1488,6 +1557,7 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
|
|
||||||
qubesd_calls_queue = multiprocessing.Queue()
|
qubesd_calls_queue = multiprocessing.Queue()
|
||||||
|
|
||||||
|
dummy_timestamp = time.strftime("test-%Y-%m-%d-%H%M%S")
|
||||||
patches = [
|
patches = [
|
||||||
mock.patch('qubesadmin.storage.Volume',
|
mock.patch('qubesadmin.storage.Volume',
|
||||||
functools.partial(MockVolume, qubesd_calls_queue)),
|
functools.partial(MockVolume, qubesd_calls_queue)),
|
||||||
@ -1497,6 +1567,9 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
mock.patch(
|
mock.patch(
|
||||||
'qubesadmin.firewall.Firewall',
|
'qubesadmin.firewall.Firewall',
|
||||||
functools.partial(MockFirewall, qubesd_calls_queue)),
|
functools.partial(MockFirewall, qubesd_calls_queue)),
|
||||||
|
mock.patch(
|
||||||
|
'time.strftime',
|
||||||
|
return_value=dummy_timestamp)
|
||||||
]
|
]
|
||||||
for patch in patches:
|
for patch in patches:
|
||||||
patch.start()
|
patch.start()
|
||||||
@ -1517,6 +1590,8 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
|
|
||||||
self.assertAllCalled()
|
self.assertAllCalled()
|
||||||
|
|
||||||
|
self.assertDom0Restored(dummy_timestamp)
|
||||||
|
|
||||||
def test_230_r2_uncompressed(self):
|
def test_230_r2_uncompressed(self):
|
||||||
self.create_v3_backup(False, False)
|
self.create_v3_backup(False, False)
|
||||||
self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = (
|
self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = (
|
||||||
@ -1549,6 +1624,7 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
|
|
||||||
qubesd_calls_queue = multiprocessing.Queue()
|
qubesd_calls_queue = multiprocessing.Queue()
|
||||||
|
|
||||||
|
dummy_timestamp = time.strftime("test-%Y-%m-%d-%H%M%S")
|
||||||
patches = [
|
patches = [
|
||||||
mock.patch('qubesadmin.storage.Volume',
|
mock.patch('qubesadmin.storage.Volume',
|
||||||
functools.partial(MockVolume, qubesd_calls_queue)),
|
functools.partial(MockVolume, qubesd_calls_queue)),
|
||||||
@ -1558,6 +1634,9 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
mock.patch(
|
mock.patch(
|
||||||
'qubesadmin.firewall.Firewall',
|
'qubesadmin.firewall.Firewall',
|
||||||
functools.partial(MockFirewall, qubesd_calls_queue)),
|
functools.partial(MockFirewall, qubesd_calls_queue)),
|
||||||
|
mock.patch(
|
||||||
|
'time.strftime',
|
||||||
|
return_value=dummy_timestamp)
|
||||||
]
|
]
|
||||||
for patch in patches:
|
for patch in patches:
|
||||||
patch.start()
|
patch.start()
|
||||||
@ -1578,6 +1657,8 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
|
|
||||||
self.assertAllCalled()
|
self.assertAllCalled()
|
||||||
|
|
||||||
|
self.assertDom0Restored(dummy_timestamp)
|
||||||
|
|
||||||
@unittest.skipUnless(spawn.find_executable('scrypt'),
|
@unittest.skipUnless(spawn.find_executable('scrypt'),
|
||||||
"scrypt not installed")
|
"scrypt not installed")
|
||||||
def test_230_r4(self):
|
def test_230_r4(self):
|
||||||
@ -1612,6 +1693,7 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
|
|
||||||
qubesd_calls_queue = multiprocessing.Queue()
|
qubesd_calls_queue = multiprocessing.Queue()
|
||||||
|
|
||||||
|
dummy_timestamp = time.strftime("test-%Y-%m-%d-%H%M%S")
|
||||||
patches = [
|
patches = [
|
||||||
mock.patch('qubesadmin.storage.Volume',
|
mock.patch('qubesadmin.storage.Volume',
|
||||||
functools.partial(MockVolume, qubesd_calls_queue)),
|
functools.partial(MockVolume, qubesd_calls_queue)),
|
||||||
@ -1621,6 +1703,9 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
mock.patch(
|
mock.patch(
|
||||||
'qubesadmin.firewall.Firewall',
|
'qubesadmin.firewall.Firewall',
|
||||||
functools.partial(MockFirewall, qubesd_calls_queue)),
|
functools.partial(MockFirewall, qubesd_calls_queue)),
|
||||||
|
mock.patch(
|
||||||
|
'time.strftime',
|
||||||
|
return_value=dummy_timestamp)
|
||||||
]
|
]
|
||||||
for patch in patches:
|
for patch in patches:
|
||||||
patch.start()
|
patch.start()
|
||||||
@ -1641,6 +1726,8 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
|
|
||||||
self.assertAllCalled()
|
self.assertAllCalled()
|
||||||
|
|
||||||
|
self.assertDom0Restored(dummy_timestamp)
|
||||||
|
|
||||||
@unittest.skipUnless(spawn.find_executable('scrypt'),
|
@unittest.skipUnless(spawn.find_executable('scrypt'),
|
||||||
"scrypt not installed")
|
"scrypt not installed")
|
||||||
def test_230_r4_compressed(self):
|
def test_230_r4_compressed(self):
|
||||||
@ -1676,6 +1763,7 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
|
|
||||||
qubesd_calls_queue = multiprocessing.Queue()
|
qubesd_calls_queue = multiprocessing.Queue()
|
||||||
|
|
||||||
|
dummy_timestamp = time.strftime("test-%Y-%m-%d-%H%M%S")
|
||||||
patches = [
|
patches = [
|
||||||
mock.patch('qubesadmin.storage.Volume',
|
mock.patch('qubesadmin.storage.Volume',
|
||||||
functools.partial(MockVolume, qubesd_calls_queue)),
|
functools.partial(MockVolume, qubesd_calls_queue)),
|
||||||
@ -1685,6 +1773,9 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
mock.patch(
|
mock.patch(
|
||||||
'qubesadmin.firewall.Firewall',
|
'qubesadmin.firewall.Firewall',
|
||||||
functools.partial(MockFirewall, qubesd_calls_queue)),
|
functools.partial(MockFirewall, qubesd_calls_queue)),
|
||||||
|
mock.patch(
|
||||||
|
'time.strftime',
|
||||||
|
return_value=dummy_timestamp)
|
||||||
]
|
]
|
||||||
for patch in patches:
|
for patch in patches:
|
||||||
patch.start()
|
patch.start()
|
||||||
@ -1705,6 +1796,8 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
|||||||
|
|
||||||
self.assertAllCalled()
|
self.assertAllCalled()
|
||||||
|
|
||||||
|
self.assertDom0Restored(dummy_timestamp)
|
||||||
|
|
||||||
|
|
||||||
class TC_11_BackupCompatibilityIntoLVM(TC_10_BackupCompatibility):
|
class TC_11_BackupCompatibilityIntoLVM(TC_10_BackupCompatibility):
|
||||||
storage_pool = 'some-pool'
|
storage_pool = 'some-pool'
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<QubesVmCollection updatevm="3" default_kernel="3.7.6-2" default_netvm="3" default_fw_netvm="2" default_template="1" clockvm="2">
|
<QubesVmCollection updatevm="3" default_kernel="3.7.6-2" default_netvm="3" default_fw_netvm="2" default_template="1" clockvm="2">
|
||||||
|
<QubesAdminVm autostart="False" backup_content="True" backup_path="dom0-home/user" backup_size="837570560" backup_timestamp="1470279173" conf_file="dom0.conf" debug="False" default_user="user" dir_path="/var/lib/qubes/servicevms/dom0" dispvm_netvm="none" firewall_conf="firewall.xml" include_in_backups="True" installed_by_rpm="False" internal="False" label="black" maxmem="0" memory="300" name="dom0" netid="0" pci_e820_host="True" pci_strictreset="True" pcidevs="[]" pool_name="default" qid="0" qrexec_timeout="60" services="{'meminfo-writer': True}" template_qid="none" uses_default_dispvm_netvm="True" vcpus="0"/>
|
||||||
<QubesTemplateVm installed_by_rpm="True" kernel="3.7.6-2" uses_default_kernelopts="True" qid="1" include_in_backups="True" uses_default_kernel="True" qrexec_timeout="60" internal="False" conf_file="fedora-20-x64.conf" label="black" template_qid="none" kernelopts="" memory="400" default_user="user" netvm_qid="3" uses_default_netvm="True" volatile_img="volatile.img" services="{ 'meminfo-writer': True}" maxmem="1535" pcidevs="[]" name="fedora-20-x64" private_img="private.img" vcpus="2" root_img="root.img" debug="False" dir_path="/var/lib/qubes/vm-templates/fedora-20-x64"/>
|
<QubesTemplateVm installed_by_rpm="True" kernel="3.7.6-2" uses_default_kernelopts="True" qid="1" include_in_backups="True" uses_default_kernel="True" qrexec_timeout="60" internal="False" conf_file="fedora-20-x64.conf" label="black" template_qid="none" kernelopts="" memory="400" default_user="user" netvm_qid="3" uses_default_netvm="True" volatile_img="volatile.img" services="{ 'meminfo-writer': True}" maxmem="1535" pcidevs="[]" name="fedora-20-x64" private_img="private.img" vcpus="2" root_img="root.img" debug="False" dir_path="/var/lib/qubes/vm-templates/fedora-20-x64"/>
|
||||||
<QubesNetVm installed_by_rpm="False" kernel="3.7.6-2" uses_default_kernelopts="True" qid="2" include_in_backups="True" uses_default_kernel="True" qrexec_timeout="60" internal="False" conf_file="netvm.conf" label="red" template_qid="1" kernelopts="iommu=soft swiotlb=4096" memory="200" default_user="user" volatile_img="volatile.img" services="{'ntpd': False, 'meminfo-writer': False}" maxmem="1535" pcidevs="['02:00.0', '03:00.0']" name="netvm" netid="1" private_img="private.img" vcpus="2" root_img="root.img" debug="False" dir_path="/var/lib/qubes/servicevms/netvm"/>
|
<QubesNetVm installed_by_rpm="False" kernel="3.7.6-2" uses_default_kernelopts="True" qid="2" include_in_backups="True" uses_default_kernel="True" qrexec_timeout="60" internal="False" conf_file="netvm.conf" label="red" template_qid="1" kernelopts="iommu=soft swiotlb=4096" memory="200" default_user="user" volatile_img="volatile.img" services="{'ntpd': False, 'meminfo-writer': False}" maxmem="1535" pcidevs="['02:00.0', '03:00.0']" name="netvm" netid="1" private_img="private.img" vcpus="2" root_img="root.img" debug="False" dir_path="/var/lib/qubes/servicevms/netvm"/>
|
||||||
<QubesProxyVm installed_by_rpm="False" kernel="3.7.6-2" uses_default_kernelopts="True" qid="3" include_in_backups="True" uses_default_kernel="True" qrexec_timeout="60" internal="False" conf_file="firewallvm.conf" label="green" template_qid="1" kernelopts="" memory="200" default_user="user" netvm_qid="2" volatile_img="volatile.img" services="{'meminfo-writer': True}" maxmem="1535" pcidevs="[]" name="firewallvm" netid="2" private_img="private.img" vcpus="2" root_img="root.img" debug="False" dir_path="/var/lib/qubes/servicevms/firewallvm"/>
|
<QubesProxyVm installed_by_rpm="False" kernel="3.7.6-2" uses_default_kernelopts="True" qid="3" include_in_backups="True" uses_default_kernel="True" qrexec_timeout="60" internal="False" conf_file="firewallvm.conf" label="green" template_qid="1" kernelopts="" memory="200" default_user="user" netvm_qid="2" volatile_img="volatile.img" services="{'meminfo-writer': True}" maxmem="1535" pcidevs="[]" name="firewallvm" netid="2" private_img="private.img" vcpus="2" root_img="root.img" debug="False" dir_path="/var/lib/qubes/servicevms/firewallvm"/>
|
||||||
|
@ -105,7 +105,11 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<property name="label">label-8</property>
|
<property name="label">label-8</property>
|
||||||
</properties>
|
</properties>
|
||||||
<features/>
|
<features>
|
||||||
|
<feature name="backup-content">True</feature>
|
||||||
|
<feature name="backup-path">dom0-home/user</feature>
|
||||||
|
<feature name="backup-size">20971520</feature>
|
||||||
|
</features>
|
||||||
<devices class="pci"/>
|
<devices class="pci"/>
|
||||||
<devices class="block"/>
|
<devices class="block"/>
|
||||||
<devices class="usb"/>
|
<devices class="usb"/>
|
||||||
|
@ -188,13 +188,12 @@ def handle_broken(app, args, restore_info):
|
|||||||
"--ignore-username-mismatch to continue anyway.")
|
"--ignore-username-mismatch to continue anyway.")
|
||||||
else:
|
else:
|
||||||
app.log.warning("Continuing as directed.")
|
app.log.warning("Continuing as directed.")
|
||||||
app.log.warning("NOTE: Before restoring the dom0 home directory, "
|
app.log.warning("NOTE: The archived dom0 home directory "
|
||||||
"a new directory named "
|
"will be restored to a new directory "
|
||||||
"'home-pre-restore-<current-time>' will be "
|
"'home-restore-<current-time>' "
|
||||||
"created inside the dom0 home directory. If any "
|
"created inside the dom0 home directory. Restored "
|
||||||
"restored files conflict with existing files, "
|
"files should be copied or moved out of the new "
|
||||||
"the existing files will be moved to this new "
|
"directory before using them.")
|
||||||
"directory.")
|
|
||||||
|
|
||||||
def main(args=None, app=None):
|
def main(args=None, app=None):
|
||||||
'''Main function of qvm-backup-restore'''
|
'''Main function of qvm-backup-restore'''
|
||||||
|
Loading…
Reference in New Issue
Block a user