vm: do not allow setting template_for_dispvms=False if there are any DispVMs

Setting template_for_dispvms=False will at least prevent starting
(already existing) DispVMs based on it. Those should be first removed.
Add also tests for this case.
This commit is contained in:
Marek Marczykowski-Górecki 2019-02-27 05:53:29 +01:00
parent 4a3772bb57
commit 8041b72e42
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
3 changed files with 58 additions and 0 deletions

View File

@ -48,6 +48,9 @@ class TestVMsCollection(dict):
def close(self):
self.clear()
def __iter__(self):
return iter(self.values())
class TestVolume(object):
def __init__(self, pool):
self.pool = pool

View File

@ -60,6 +60,9 @@ class TC_00_DispVM(qubes.tests.QubesTestCase):
self.addCleanup(self.cleanup_dispvm)
def cleanup_dispvm(self):
if hasattr(self, 'dispvm'):
self.dispvm.close()
del self.dispvm
self.template.close()
self.appvm.close()
del self.template
@ -120,6 +123,41 @@ class TC_00_DispVM(qubes.tests.QubesTestCase):
with self.assertRaises(qubes.exc.QubesValueError):
dispvm.template = qubes.property.DEFAULT
def test_003_dvmtemplate_template_change(self):
self.appvm.template_for_dispvms = True
orig_domains = self.app.domains
with mock.patch.object(self.app, 'domains', wraps=self.app.domains) \
as mock_domains:
mock_domains.configure_mock(**{
'get_new_unused_dispid': mock.Mock(return_value=42),
'__getitem__.side_effect': orig_domains.__getitem__,
'__iter__.side_effect': orig_domains.__iter__,
'__setitem__.side_effect': orig_domains.__setitem__,
})
self.dispvm = self.app.add_new_vm(qubes.vm.dispvm.DispVM,
name='test-dispvm', template=self.appvm)
with self.assertRaises(qubes.exc.QubesVMInUseError):
self.appvm.template = self.template
with self.assertRaises(qubes.exc.QubesValueError):
self.appvm.template = qubes.property.DEFAULT
def test_004_dvmtemplate_allowed_change(self):
self.appvm.template_for_dispvms = True
orig_domains = self.app.domains
with mock.patch.object(self.app, 'domains', wraps=self.app.domains) \
as mock_domains:
mock_domains.configure_mock(**{
'get_new_unused_dispid': mock.Mock(return_value=42),
'__getitem__.side_effect': orig_domains.__getitem__,
'__iter__.side_effect': orig_domains.__iter__,
'__setitem__.side_effect': orig_domains.__setitem__,
})
self.dispvm = self.app.add_new_vm(qubes.vm.dispvm.DispVM,
name='test-dispvm', template=self.appvm)
with self.assertRaises(qubes.exc.QubesVMInUseError):
self.appvm.template_for_dispvms = False
def test_010_create_direct(self):
self.appvm.template_for_dispvms = True

View File

@ -28,6 +28,23 @@ class DVMTemplateMixin(qubes.events.Emitter):
default=False,
doc='Should this VM be allowed to start as Disposable VM')
@qubes.events.handler('property-pre-set:template_for_dispvms')
def __on_pre_set_dvmtemplate(self, event, name,
newvalue, oldvalue=None):
# pylint: disable=unused-argument
if newvalue:
return
if any(self.dispvms):
raise qubes.exc.QubesVMInUseError(self,
'Cannot change template_for_dispvms to False while there are '
'some DispVMs based on this DVM template')
@qubes.events.handler('property-pre-del:template_for_dispvms')
def __on_pre_del_dvmtemplate(self, event, name,
oldvalue=None):
self.__on_pre_set_dvmtemplate(
event, name, False, oldvalue)
@qubes.events.handler('property-pre-set:template')
def __on_property_pre_set_template(self, event, name, newvalue,
oldvalue=None):