diff --git a/qubes/tests/__init__.py b/qubes/tests/__init__.py index f0db98fbb..c884d071d 100644 --- a/qubes/tests/__init__.py +++ b/qubes/tests/__init__.py @@ -1233,6 +1233,19 @@ def shutdown_and_wait(self, vm, timeout=60): del vm self.fail("Timeout while waiting for VM {} shutdown".format(name)) + def shutdown_paused(self, vm, timeout=60): + self.loop.run_until_complete(vm.pause()) + with self.assertRaises(qubes.exc.QubesVMNotRunningError): + self.loop.run_until_complete( + vm.shutdown(wait=True, timeout=timeout, force=False)) + try: + self.loop.run_until_complete( + vm.shutdown(wait=True, timeout=timeout, force=True)) + except qubes.exc.QubesException: + name = vm.name + del vm + self.fail("Timeout while waiting for VM {} shutdown".format(name)) + def prepare_hvm_system_linux(self, vm, init_script, extra_files=None): if not os.path.exists('/usr/lib/grub/i386-pc'): self.skipTest('grub2 not installed') diff --git a/qubes/tests/integ/basic.py b/qubes/tests/integ/basic.py index 47517267f..c659f4d74 100644 --- a/qubes/tests/integ/basic.py +++ b/qubes/tests/integ/basic.py @@ -353,6 +353,15 @@ def test_204_udev_block_exclude_custom_file(self): pool=pool)) self.assertVolumesExcludedFromUdev(self.vm) + def test_206_shutdown_paused(self): + vmname = self.make_vm_name('vm') + self.vm = self.app.add_new_vm(qubes.vm.appvm.AppVM, + name=vmname, template=self.app.default_template, + label='red') + self.loop.run_until_complete(self.vm.create_on_disk()) + self.loop.run_until_complete(self.vm.start()) + self.shutdown_paused(self.vm) + class TC_01_Properties(qubes.tests.SystemTestCase): # pylint: disable=attribute-defined-outside-init diff --git a/qubes/vm/qubesvm.py b/qubes/vm/qubesvm.py index fa7fd3ec6..bbbc74b3c 100644 --- a/qubes/vm/qubesvm.py +++ b/qubes/vm/qubesvm.py @@ -1382,10 +1382,17 @@ async def shutdown(self, force=False, wait=False, timeout=None): await self.fire_event_async('domain-pre-shutdown', pre_event=True, force=force) + if self.is_paused() and not force: + raise qubes.exc.QubesVMNotRunningError(self) + if self.__waiter is None: self.__waiter = asyncio.get_running_loop().create_future() waiter = self.__waiter - self.libvirt_domain.shutdown() + + if self.is_paused(): + self.libvirt_domain.destroy() + else: + self.libvirt_domain.shutdown() if wait: if timeout is None: