diff --git a/qubes/app.py b/qubes/app.py index d9b077f5..caa96b93 100644 --- a/qubes/app.py +++ b/qubes/app.py @@ -437,14 +437,17 @@ class VMCollection(object): raise KeyError(key) - def __delitem__(self, key): vm = self[key] + if not vm.is_halted(): + msg = "Can't remove, vm {!s}, beacuse it's in state {!s}." + msg = msg.format(vm, vm.get_power_state()) + raise qubes.exc.QubesVMNotHaltedError(msg) self.app.fire_event_pre('domain-pre-delete', vm) + vm.libvirt_domain.undefine() del self._dict[vm.qid] self.app.fire_event('domain-delete', vm) - def __contains__(self, key): return any((key == vm or key == vm.qid or key == vm.name) for vm in self) diff --git a/qubes/tests/app.py b/qubes/tests/app.py index 0c81d733..adbe8447 100644 --- a/qubes/tests/app.py +++ b/qubes/tests/app.py @@ -24,7 +24,6 @@ # import os -import unittest import uuid import lxml.etree @@ -42,6 +41,18 @@ class TestVM(qubes.vm.BaseVM): netid = qid uuid = uuid.uuid5(uuid.NAMESPACE_DNS, 'testvm') + class MockLibvirt(object): + def undefine(self): + pass + + libvirt_domain = MockLibvirt() + + def is_halted(self): + return True + + def get_power_state(self): + return "Halted" + class TestApp(qubes.tests.TestEmitter): pass @@ -157,7 +168,7 @@ class TC_90_Qubes(qubes.tests.QubesTestCase): os.unlink('/tmp/qubestest.xml') except: pass - app = qubes.Qubes.create_empty_store('/tmp/qubestest.xml') + qubes.Qubes.create_empty_store('/tmp/qubestest.xml') @qubes.tests.skipUnlessGit def test_900_example_xml_in_doc(self): diff --git a/qubes/tests/init.py b/qubes/tests/init.py index 6969afc0..99105e47 100644 --- a/qubes/tests/init.py +++ b/qubes/tests/init.py @@ -23,7 +23,6 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # -import os import unittest import uuid @@ -70,7 +69,7 @@ class TC_10_property(qubes.tests.QubesTestCase): try: class MyTestHolder(qubes.tests.TestEmitter, qubes.PropertyHolder): testprop1 = qubes.property('testprop1') - except: # pylint: disable=bare-except + except: # pylint: disable=bare-except self.skipTest('MyTestHolder class definition failed') self.holder = MyTestHolder(None) @@ -120,6 +119,7 @@ class TC_10_property(qubes.tests.QubesTestCase): self.assertIs(prop, MyTestHolder.testprop1) self.assertEquals(value, 'testvalue') return 'settervalue' + class MyTestHolder(qubes.tests.TestEmitter, qubes.PropertyHolder): testprop1 = qubes.property('testprop1', setter=setter) holder = MyTestHolder(None) @@ -219,7 +219,6 @@ class TC_20_PropertyHolder(qubes.tests.QubesTestCase): self.holder = TestHolder(xml) - def test_000_property_list(self): self.assertListEqual([p.__name__ for p in self.holder.property_list()], ['testprop1', 'testprop2', 'testprop3', 'testprop4']) @@ -293,6 +292,18 @@ class TestVM(qubes.vm.BaseVM): netid = qid uuid = uuid.uuid5(uuid.NAMESPACE_DNS, 'testvm') + class MockLibvirt(object): + def undefine(self): + pass + + libvirt_domain = MockLibvirt() + + def is_halted(self): + return True + + def get_power_state(self): + return "Halted" + class TestApp(qubes.tests.TestEmitter): pass diff --git a/qubes/vm/qubesvm.py b/qubes/vm/qubesvm.py index e65e78be..96ff4560 100644 --- a/qubes/vm/qubesvm.py +++ b/qubes/vm/qubesvm.py @@ -1094,6 +1094,11 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): def remove_from_disk(self): '''Remove domain remnants from disk.''' + if not self.is_halted(): + msg = "Can't remove, vm {!s}, beacuse it's in state {!s}." + msg = msg.format(self, self.get_power_state()) + raise qubes.exc.QubesVMNotHaltedError(msg) + self.fire_event('domain-remove-from-disk') shutil.rmtree(self.dir_path) self.storage.remove()