diff --git a/qubesadmin/tests/tools/qvm_template_postprocess.py b/qubesadmin/tests/tools/qvm_template_postprocess.py index 585f637..c211d38 100644 --- a/qubesadmin/tests/tools/qvm_template_postprocess.py +++ b/qubesadmin/tests/tools/qvm_template_postprocess.py @@ -57,6 +57,18 @@ class TC_00_qvm_template_postprocess(qubesadmin.tests.QubesTestCase): self.app.expected_calls[('test-vm', 'admin.vm.volume.List', None, None)] = \ b'0\0root\nprivate\nvolatile\nkernel\n' + self.app.expected_calls[ + ('test-vm', 'admin.vm.volume.Info', 'root', None)] = \ + b'0\x00pool=lvm\n' \ + b'vid=qubes_dom0/vm-test-vm-root\n' \ + b'size=10737418240\n' \ + b'usage=0\n' \ + b'rw=True\n' \ + b'source=\n' \ + b'save_on_stop=True\n' \ + b'snap_on_start=False\n' \ + b'revisions_to_keep=3\n' \ + b'is_outdated=False\n' self.app.expected_calls[('test-vm', 'admin.vm.volume.Resize', 'root', str(len(volume_data)).encode())] = \ b'0\0' @@ -82,6 +94,18 @@ class TC_00_qvm_template_postprocess(qubesadmin.tests.QubesTestCase): self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \ b'0\0test-vm class=TemplateVM state=Halted\n' + self.app.expected_calls[ + ('test-vm', 'admin.vm.volume.Info', 'root', None)] = \ + b'0\x00pool=lvm\n' \ + b'vid=qubes_dom0/vm-test-vm-root\n' \ + b'size=10737418240\n' \ + b'usage=0\n' \ + b'rw=True\n' \ + b'source=\n' \ + b'save_on_stop=True\n' \ + b'snap_on_start=False\n' \ + b'revisions_to_keep=3\n' \ + b'is_outdated=False\n' self.app.expected_calls[('test-vm', 'admin.vm.volume.List', None, None)] = \ b'0\0root\nprivate\nvolatile\nkernel\n' @@ -114,17 +138,22 @@ class TC_00_qvm_template_postprocess(qubesadmin.tests.QubesTestCase): b'0\0root\nprivate\nvolatile\nkernel\n' self.app.expected_calls[ ('test-vm', 'admin.vm.volume.Info', 'root', None)] = \ - b'0\0pool=default\nvid=vm-templates/test-vm/root\n' + b'0\x00pool=default\n' \ + b'vid=vm-templates/test-vm/root\n' \ + b'size=10737418240\n' \ + b'usage=0\n' \ + b'rw=True\n' \ + b'source=\n' \ + b'save_on_stop=True\n' \ + b'snap_on_start=False\n' \ + b'revisions_to_keep=3\n' \ + b'is_outdated=False\n' self.app.expected_calls[ ('dom0', 'admin.pool.List', None, None)] = \ b'0\0default\n' self.app.expected_calls[ ('dom0', 'admin.pool.Info', 'default', None)] = \ b'0\0driver=file\ndir_path=' + self.source_dir.name.encode() + b'\n' - self.app.expected_calls[ - ('test-vm', 'admin.vm.volume.Resize', 'root', - str(len(volume_data)).encode())] = \ - b'0\0' vm = self.app.domains['test-vm'] qubesadmin.tools.qvm_template_postprocess.import_root_img( diff --git a/qubesadmin/tools/qvm_template_postprocess.py b/qubesadmin/tools/qvm_template_postprocess.py index 5fb4ae5..b6c43b3 100644 --- a/qubesadmin/tools/qvm_template_postprocess.py +++ b/qubesadmin/tools/qvm_template_postprocess.py @@ -77,8 +77,12 @@ def get_root_img_size(source_dir): def import_root_img(vm, source_dir): '''Import root.img into VM object''' + # Try not break existing data in the volume in case of import failure. If + # volume needs to be extended, do it before import, if reduced - after. + root_size = get_root_img_size(source_dir) - vm.volumes['root'].resize(root_size) + if vm.volumes['root'].size < root_size: + vm.volumes['root'].resize(root_size) root_path = os.path.join(source_dir, 'root.img') if os.path.exists(root_path + '.part.00'): @@ -108,6 +112,15 @@ def import_root_img(vm, source_dir): with open(root_path, 'rb') as root_file: vm.volumes['root'].import_data(stream=root_file) + if vm.volumes['root'].size > root_size: + try: + vm.volumes['root'].resize(root_size) + except qubesadmin.exc.QubesException as err: + vm.log.warning( + 'Failed to resize root volume of {} from {} to {} after ' + 'import: {}'.format(vm.name, vm.volumes['root'].size, + root_size, str(err))) + def import_appmenus(vm, source_dir): '''Import appmenus settings into VM object (later: GUI VM)''' @@ -182,6 +195,7 @@ def post_install(args): '''Handle post-installation tasks''' app = args.app + vm_created = False try: # reinstall vm = app.domains[args.name] @@ -198,13 +212,15 @@ def post_install(args): vm = app.add_new_vm('TemplateVM', name=args.name, label=qubesadmin.config.defaults['template_label']) + vm_created = True vm.log.info('Importing data') try: import_root_img(vm, args.dir) except: # if data import fails, remove half-created VM - del app.domains[vm.name] + if vm_created: + del app.domains[vm.name] raise vm.installed_by_rpm = True import_appmenus(vm, args.dir)