diff --git a/Makefile b/Makefile index e5538477..d871570e 100644 --- a/Makefile +++ b/Makefile @@ -35,6 +35,7 @@ ADMIN_API_METHODS_SIMPLE = \ admin.pool.volume.Set.rw \ admin.pool.volume.Snapshot \ admin.property.Get \ + admin.property.GetAll \ admin.property.GetDefault \ admin.property.Help \ admin.property.HelpRst \ @@ -87,6 +88,7 @@ ADMIN_API_METHODS_SIMPLE = \ admin.vm.firewall.SetPolicy \ admin.vm.firewall.Reload \ admin.vm.property.Get \ + admin.vm.property.GetAll \ admin.vm.property.GetDefault \ admin.vm.property.Help \ admin.vm.property.HelpRst \ diff --git a/qubes/api/admin.py b/qubes/api/admin.py index 4432b00f..678cb98a 100644 --- a/qubes/api/admin.py +++ b/qubes/api/admin.py @@ -169,7 +169,11 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI): self.fire_event_for_permission() - property_def = dest.property_get_def(self.arg) + return self._serialize_property(dest, self.arg) + + @staticmethod + def _serialize_property(dest, prop): + property_def = dest.property_get_def(prop) # explicit list to be sure that it matches protocol spec if isinstance(property_def, qubes.vm.VMProperty): property_type = 'vm' @@ -177,21 +181,51 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI): property_type = 'int' elif property_def.type is bool: property_type = 'bool' - elif self.arg == 'label': + elif prop == 'label': property_type = 'label' else: property_type = 'str' try: - value = getattr(dest, self.arg) + value = getattr(dest, str(prop)) except AttributeError: return 'default=True type={} '.format(property_type) else: return 'default={} type={} {}'.format( - str(dest.property_is_default(self.arg)), + str(dest.property_is_default(prop)), property_type, str(value) if value is not None else '') + @qubes.api.method('admin.vm.property.GetAll', no_payload=True, + scope='local', read=True) + @asyncio.coroutine + def vm_property_get_all(self): + """Get values of all VM properties""" + return self._property_get_all(self.dest) + + @qubes.api.method('admin.property.GetAll', no_payload=True, + scope='global', read=True) + @asyncio.coroutine + def property_get_all(self): + """Get value all global properties""" + self.enforce(self.dest.name == 'dom0') + return self._property_get_all(self.app) + + def _property_get_all(self, dest): + self.enforce(not self.arg) + + properties = dest.property_list() + + properties = self.fire_event_for_filter(properties) + + return ''.join( + '{} {}\n'.format(str(prop), + self._serialize_property(dest, prop). + replace('\\', '\\\\').replace('\n', '\\n')) + for prop in sorted(properties)) + + + @qubes.api.method('admin.vm.property.GetDefault', no_payload=True, scope='local', read=True) @asyncio.coroutine diff --git a/qubes/tests/api_admin.py b/qubes/tests/api_admin.py index da964636..a35a1b64 100644 --- a/qubes/tests/api_admin.py +++ b/qubes/tests/api_admin.py @@ -180,6 +180,38 @@ class TC_00_VMs(AdminAPITestCase): b'provides_network') self.assertEqual(value, 'type=bool False') + def test_027_vm_property_get_all(self): + # any string property, test \n encoding + self.vm.kernelopts = 'opt1\nopt2\nopt3\\opt4' + with unittest.mock.patch.object(self.vm, 'property_list') as list_mock: + list_mock.return_value = [ + self.vm.property_get_def('name'), + self.vm.property_get_def('default_user'), + self.vm.property_get_def('netvm'), + self.vm.property_get_def('klass'), + self.vm.property_get_def('debug'), + self.vm.property_get_def('label'), + self.vm.property_get_def('kernelopts'), + self.vm.property_get_def('qrexec_timeout'), + self.vm.property_get_def('qid'), + self.vm.property_get_def('updateable'), + ] + 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 +klass default=True type=str AppVM +label default=False type=label red +name default=False type=str test-vm1 +qid default=False type=int 2 +qrexec_timeout default=True type=int 60 +updateable default=True type=bool False +kernelopts default=False type=str opt1\\nopt2\\nopt3\\\\opt4 +netvm default=True type=vm +''' + self.assertEqual(value, expected) + + 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)