From ce0d2308668e1e8fc264863aa6350eacbec79ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Fri, 12 Jan 2018 23:33:32 +0100 Subject: [PATCH] Add property_get_default method It is useful to get property default value, without changing it to default. For example to list it in GUI tools Fixes QubesOS/qubes-issues#3197 --- qubesadmin/base.py | 33 ++++++++++++++++++++++++++++++- qubesadmin/tests/vm/properties.py | 24 ++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/qubesadmin/base.py b/qubesadmin/base.py index 950841d..1f694ed 100644 --- a/qubesadmin/base.py +++ b/qubesadmin/base.py @@ -154,6 +154,25 @@ class PropertyHolder(object): assert isinstance(is_default, bool) return is_default + def property_get_default(self, item): + ''' + Get default property value, regardless of the current value + + :param str item: name of property + :return: default value + ''' + if item.startswith('_'): + raise AttributeError(item) + property_str = self.qubesd_call( + self._method_dest, + self._method_prefix + 'GetDefault', + item, + None) + if not property_str: + raise AttributeError(item + ' has no default') + (prop_type, value) = property_str.split(b' ', 1) + return self._parse_type_value(prop_type, value) + def clone_properties(self, src, proplist=None): '''Clone properties from other object. @@ -172,7 +191,6 @@ class PropertyHolder(object): continue def __getattr__(self, item): - # pylint: disable=too-many-return-statements if item.startswith('_'): raise AttributeError(item) try: @@ -184,6 +202,19 @@ class PropertyHolder(object): except qubesadmin.exc.QubesDaemonNoResponseError: raise qubesadmin.exc.QubesPropertyAccessError(item) (_default, prop_type, value) = property_str.split(b' ', 2) + return self._parse_type_value(prop_type, value) + + def _parse_type_value(self, prop_type, value): + ''' + Parse `type=... ...` qubesd response format. Return a value of + appropriate type. + + :param bytes prop_type: 'type=...' part of the response (including + `type=` prefix) + :param bytes value: 'value' part of the response + :return: parsed value + ''' + # pylint: disable=too-many-return-statements prop_type = prop_type.decode('ascii') if not prop_type.startswith('type='): raise qubesadmin.exc.QubesDaemonCommunicationError( diff --git a/qubesadmin/tests/vm/properties.py b/qubesadmin/tests/vm/properties.py index fe78eec..2cbd11b 100644 --- a/qubesadmin/tests/vm/properties.py +++ b/qubesadmin/tests/vm/properties.py @@ -164,6 +164,30 @@ class TC_00_Properties(qubesadmin.tests.vm.VMTestCase): del self.vm.prop1 self.assertAllCalled() + def test_040_get_default(self): + self.app.expected_calls[ + ('test-vm', 'admin.vm.property.GetDefault', 'prop1', None)] = \ + b'0\x00type=str some value' + default_value = self.vm.property_get_default('prop1') + self.assertEqual(default_value, 'some value') + self.assertAllCalled() + + def test_041_get_default_int(self): + self.app.expected_calls[ + ('test-vm', 'admin.vm.property.GetDefault', 'prop1', None)] = \ + b'0\x00type=int 42' + default_value = self.vm.property_get_default('prop1') + self.assertEqual(default_value, 42) + self.assertAllCalled() + + def test_042_get_default_none(self): + self.app.expected_calls[ + ('test-vm', 'admin.vm.property.GetDefault', 'prop1', None)] = \ + b'0\x00' + with self.assertRaises(AttributeError): + self.vm.property_get_default('prop1') + self.assertAllCalled() + class TC_01_SpecialCases(qubesadmin.tests.vm.VMTestCase): def test_000_get_name(self):