From 2a42b7c7c7ebd6db9225cf66344552a3f58da5d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Wed, 29 May 2019 23:47:09 +0200 Subject: [PATCH 1/2] vm/net: make 'dns' property visible in Admin API Serialize the list with a space as a separator. QubesOS/qubes-issues#5050 --- qubes/vm/mix/net.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/qubes/vm/mix/net.py b/qubes/vm/mix/net.py index baa8732b..51fd1af0 100644 --- a/qubes/vm/mix/net.py +++ b/qubes/vm/mix/net.py @@ -91,6 +91,16 @@ def _setter_provides_network(self, prop, value): return value +class StrSerializableTuple(tuple): + def __str__(self): + # verify it can be deserialized later(currently 'dns' + # property is the only using this, and it is safe) + if any(' ' in el for el in self): + raise ValueError( + 'space found in a list element {!r}'.format(self)) + return ' '.join(self) + + class NetVMMixin(qubes.events.Emitter): ''' Mixin containing network functionality ''' mac = qubes.property('mac', type=str, @@ -224,14 +234,14 @@ class NetVMMixin(qubes.events.Emitter): # used in both # - @property + @qubes.stateless_property def dns(self): - '''Secondary DNS server set up for this domain.''' + '''DNS servers set up for this domain.''' if self.netvm is not None or self.provides_network: - return ( + return StrSerializableTuple(( '10.139.1.1', '10.139.1.2', - ) + )) return None From 41e559d9992f3a7645b4a7b0572e4a6240ad26db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Wed, 29 May 2019 23:48:10 +0200 Subject: [PATCH 2/2] tests/api_admin: list serialized into a str property, using 'dns' property QubesOS/qubes-issues#5050 --- qubes/tests/api_admin.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/qubes/tests/api_admin.py b/qubes/tests/api_admin.py index 9b5b3b54..83cb1e83 100644 --- a/qubes/tests/api_admin.py +++ b/qubes/tests/api_admin.py @@ -211,6 +211,8 @@ class TC_00_VMs(AdminAPITestCase): def test_027_vm_property_get_all(self): # any string property, test \n encoding self.vm.kernelopts = 'opt1\nopt2\nopt3\\opt4' + # let it have 'dns' property + self.vm.provides_network = True with unittest.mock.patch.object(self.vm, 'property_list') as list_mock: list_mock.return_value = [ self.vm.property_get_def('name'), @@ -223,11 +225,13 @@ class TC_00_VMs(AdminAPITestCase): self.vm.property_get_def('qrexec_timeout'), self.vm.property_get_def('qid'), self.vm.property_get_def('updateable'), + self.vm.property_get_def('dns'), ] value = self.call_mgmt_func(b'admin.vm.property.GetAll', b'test-vm1') self.maxDiff = None expected = '''debug default=True type=bool False default_user default=True type=str user +dns default=True type=str 10.139.1.1 10.139.1.2 klass default=True type=str AppVM label default=False type=label red name default=False type=str test-vm1 @@ -238,6 +242,29 @@ kernelopts default=False type=str opt1\\nopt2\\nopt3\\\\opt4 netvm default=True type=vm \n''' self.assertEqual(value, expected) + def test_028_vm_property_get_list(self): + self.vm.provides_network = True + value = self.call_mgmt_func( + b'admin.vm.property.Get', + b'test-vm1', + b'dns') + self.assertEqual(value, 'default=True type=str 10.139.1.1 10.139.1.2') + + def test_029_vm_property_get_list_none(self): + value = self.call_mgmt_func( + b'admin.vm.property.Get', + b'test-vm1', + b'dns') + self.assertEqual(value, 'default=True type=str ') + + def test_029_vm_property_get_list_default(self): + self.vm.provides_network = True + value = self.call_mgmt_func( + b'admin.vm.property.GetDefault', + b'test-vm1', + b'dns') + self.assertEqual(value, 'type=str 10.139.1.1 10.139.1.2') + def test_030_vm_property_set_vm(self): netvm = self.app.add_new_vm('AppVM', label='red', name='test-net', template='test-template', provides_network=True)