From b28ddb6621b4f42b0d02cfe67a6b6e8b63ac7dee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Wed, 20 Sep 2017 19:12:24 +0200 Subject: [PATCH] Implement "blind mode" to avoid listing objects This allows to perform actions on objects (VM, storage etc), without listing them. This is useful when calling VM have minimal permissions and only selected actions are allowed. This means that app.domains['some-name'] will not raise KeyError, even when domain do not exists. But performing actual action (like vm.start()) will fail in that case. --- qubesadmin/app.py | 11 ++++++++--- qubesadmin/base.py | 2 +- qubesadmin/tests/app.py | 22 ++++++++++++++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/qubesadmin/app.py b/qubesadmin/app.py index fbe16b4..1a88fe5 100644 --- a/qubesadmin/app.py +++ b/qubesadmin/app.py @@ -83,11 +83,14 @@ class VMCollection(object): del self._vm_objects[name] def __getitem__(self, item): - if item not in self: + if not self.app.blind_mode and item not in self: raise KeyError(item) if item not in self._vm_objects: - cls = qubesadmin.utils.get_entry_point_one(VM_ENTRY_POINT, - self._vm_list[item]['class']) + if self.app.blind_mode: + cls = qubesadmin.vm.QubesVM + else: + cls = qubesadmin.utils.get_entry_point_one(VM_ENTRY_POINT, + self._vm_list[item]['class']) self._vm_objects[item] = cls(self.app, item) return self._vm_objects[item] @@ -128,6 +131,8 @@ class QubesBase(qubesadmin.base.PropertyHolder): qubesd_connection_type = None #: logger log = None + #: do not check for object (VM, label etc) existence before really needed + blind_mode = False def __init__(self): super(QubesBase, self).__init__(self, 'admin.property.', 'dom0') diff --git a/qubesadmin/base.py b/qubesadmin/base.py index 7ff5672..84f1848 100644 --- a/qubesadmin/base.py +++ b/qubesadmin/base.py @@ -292,7 +292,7 @@ class WrapperObjectsCollection(object): del self._objects[name] def __getitem__(self, item): - if item not in self: + if not self.app.blind_mode and item not in self: raise KeyError(item) if item not in self._objects: self._objects[item] = self._object_class(self.app, item) diff --git a/qubesadmin/tests/app.py b/qubesadmin/tests/app.py index 2d5384a..b0a3dc6 100644 --- a/qubesadmin/tests/app.py +++ b/qubesadmin/tests/app.py @@ -99,6 +99,28 @@ class TC_00_VMCollection(qubesadmin.tests.QubesTestCase): set(['test-vm', 'test-vm2'])) self.assertAllCalled() + def test_007_getitem_blind_mode(self): + self.app.blind_mode = True + try: + vm = self.app.domains['test-vm'] + self.assertEqual(vm.name, 'test-vm') + except KeyError: + self.fail('VM not found in collection') + self.assertAllCalled() + + with self.assertNotRaises(KeyError): + vm = self.app.domains['test-non-existent'] + self.assertAllCalled() + + def test_008_in_blind_mode(self): + self.app.blind_mode = True + self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \ + b'0\x00test-vm class=AppVM state=Running\n' + self.assertIn('test-vm', self.app.domains) + self.assertAllCalled() + + self.assertNotIn('test-non-existent', self.app.domains) + self.assertAllCalled() class TC_10_QubesBase(qubesadmin.tests.QubesTestCase):