From 84ca0c6df5a85738ac85ee8cde5dd90b0bbe40ea Mon Sep 17 00:00:00 2001 From: Rusty Bird Date: Thu, 22 Feb 2018 20:26:39 +0000 Subject: [PATCH 1/4] Use !auto_cleanup as DispVM include_in_backups default --- qubes/vm/dispvm.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qubes/vm/dispvm.py b/qubes/vm/dispvm.py index b60279fb..4554998e 100644 --- a/qubes/vm/dispvm.py +++ b/qubes/vm/dispvm.py @@ -41,6 +41,10 @@ class DispVM(qubes.vm.qubesvm.QubesVM): auto_cleanup = qubes.property('auto_cleanup', type=bool, default=False, doc='automatically remove this VM upon shutdown') + include_in_backups = qubes.property('include_in_backups', type=bool, + default=(lambda self: not self.auto_cleanup), + doc='If this domain is to be included in default backup.') + def __init__(self, app, xml, *args, **kwargs): self.volume_config = { 'root': { From dbaf60ca24567edd29a71314b7fc14011f80dceb Mon Sep 17 00:00:00 2001 From: Rusty Bird Date: Thu, 22 Feb 2018 20:26:41 +0000 Subject: [PATCH 2/4] Add include_in_backups property for AdminVM --- qubes/vm/adminvm.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qubes/vm/adminvm.py b/qubes/vm/adminvm.py index 39c174d2..2d044f67 100644 --- a/qubes/vm/adminvm.py +++ b/qubes/vm/adminvm.py @@ -50,6 +50,10 @@ class AdminVM(qubes.vm.BaseVM): default=(lambda self: self.app.default_dispvm), doc='Default VM to be used as Disposable VM for service calls.') + include_in_backups = qubes.property('include_in_backups', + default=True, type=bool, + doc='If this domain is to be included in default backup.') + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) From 59abdeb30eaf0a135719b18ed468380e17da69b2 Mon Sep 17 00:00:00 2001 From: Rusty Bird Date: Thu, 22 Feb 2018 20:50:23 +0000 Subject: [PATCH 3/4] Allow include=None to be passed to admin.backup.Info This is forwarded to qubes.backup.Backup(), which uses None to choose VMs according to their include_in_backups property. ('git show -w' recommended) --- qubes/api/admin.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/qubes/api/admin.py b/qubes/api/admin.py index 8b1f6596..b42d6479 100644 --- a/qubes/api/admin.py +++ b/qubes/api/admin.py @@ -1293,8 +1293,9 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI): dest_vm = profile_data['destination_vm'] dest_path = profile_data['destination_path'] include_vms = profile_data['include'] - # convert old keywords to new keywords - include_vms = [vm.replace('$', '@') for vm in include_vms] + if include_vms is not None: + # convert old keywords to new keywords + include_vms = [vm.replace('$', '@') for vm in include_vms] exclude_vms = profile_data.get('exclude', []) # convert old keywords to new keywords exclude_vms = [vm.replace('$', '@') for vm in exclude_vms] @@ -1339,14 +1340,17 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI): 'specify passphrase_text or passphrase_vm') # handle include - vms_to_backup = set(vm for vm in self.app.domains - if any(qubes.utils.match_vm_name_with_special(vm, name) - for name in include_vms)) + if include_vms is None: + vms_to_backup = None + else: + vms_to_backup = set(vm for vm in self.app.domains + if any(qubes.utils.match_vm_name_with_special(vm, name) + for name in include_vms)) - # handle exclude - vms_to_backup.difference_update(vm for vm in self.app.domains - if any(qubes.utils.match_vm_name_with_special(vm, name) - for name in exclude_vms)) + # handle exclude + vms_to_backup.difference_update(vm for vm in self.app.domains + if any(qubes.utils.match_vm_name_with_special(vm, name) + for name in exclude_vms)) kwargs = { 'target_vm': dest_vm, From 6886e70aa965d75c603e67004ebe058e0bf3f3ef Mon Sep 17 00:00:00 2001 From: Rusty Bird Date: Sat, 24 Feb 2018 22:43:53 +0000 Subject: [PATCH 4/4] backup.py: add vmN/empty file if no other files to backup --- linux/system-config/tmpfiles-qubes.conf | 1 + qubes/backup.py | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/linux/system-config/tmpfiles-qubes.conf b/linux/system-config/tmpfiles-qubes.conf index 834541f8..c3ca33b0 100644 --- a/linux/system-config/tmpfiles-qubes.conf +++ b/linux/system-config/tmpfiles-qubes.conf @@ -1,3 +1,4 @@ d /var/run/qubes 2770 root qubes f /var/run/qubes/xl-lock 0660 root qubes +f /var/run/qubes/empty 0444 root qubes d /var/run/xen-hotplug 0755 root root diff --git a/qubes/backup.py b/qubes/backup.py index a3b4f7aa..e3e6f1ec 100644 --- a/qubes/backup.py +++ b/qubes/backup.py @@ -381,6 +381,15 @@ class Backup(object): if os.path.exists(firewall_conf): vm_files.append(self.FileToBackup(firewall_conf, subdir)) + if not vm_files: + # subdir/ is needed in the tar file, otherwise restore + # of a (Disp)VM without any backed up files is going + # to fail. Adding a zero-sized file here happens to be + # more straightforward than adding an empty directory. + empty = self.FileToBackup("/var/run/qubes/empty", subdir) + assert empty.size == 0 + vm_files.append(empty) + files_to_backup[vm.qid] = self.VMToBackup(vm, vm_files, subdir) # Dom0 user home