diff --git a/Makefile b/Makefile index 241ef477..82ea9c2b 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,7 @@ ADMIN_API_METHODS_SIMPLE = \ admin.pool.volume.Revert \ admin.pool.volume.Snapshot \ admin.property.Get \ + admin.property.GetDefault \ admin.property.Help \ admin.property.HelpRst \ admin.property.List \ @@ -78,6 +79,7 @@ ADMIN_API_METHODS_SIMPLE = \ admin.vm.firewall.SetPolicy \ admin.vm.firewall.Reload \ admin.vm.property.Get \ + admin.vm.property.GetDefault \ admin.vm.property.Help \ admin.vm.property.HelpRst \ admin.vm.property.List \ diff --git a/qubes/api/admin.py b/qubes/api/admin.py index a5e78f72..25a542fd 100644 --- a/qubes/api/admin.py +++ b/qubes/api/admin.py @@ -191,6 +191,49 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI): property_type, str(value) if value is not None else '') + @qubes.api.method('admin.vm.property.GetDefault', no_payload=True, + scope='local', read=True) + @asyncio.coroutine + def vm_property_get_default(self): + '''Get a value of one property''' + return self._property_get_default(self.dest) + + @qubes.api.method('admin.property.GetDefault', no_payload=True, + scope='global', read=True) + @asyncio.coroutine + def property_get_default(self): + '''Get a value of one global property''' + assert self.dest.name == 'dom0' + return self._property_get_default(self.app) + + def _property_get_default(self, dest): + if self.arg not in dest.property_list(): + raise qubes.exc.QubesNoSuchPropertyError(dest, self.arg) + + self.fire_event_for_permission() + + property_def = dest.property_get_def(self.arg) + # explicit list to be sure that it matches protocol spec + if isinstance(property_def, qubes.vm.VMProperty): + property_type = 'vm' + elif property_def.type is int: + property_type = 'int' + elif property_def.type is bool: + property_type = 'bool' + elif self.arg == 'label': + property_type = 'label' + else: + property_type = 'str' + + try: + value = property_def.get_default(dest) + except AttributeError: + return None + else: + return 'type={} {}'.format( + property_type, + str(value) if value is not None else '') + @qubes.api.method('admin.vm.property.Set', scope='local', write=True) @asyncio.coroutine diff --git a/qubes/tests/api_admin.py b/qubes/tests/api_admin.py index 72d3ab86..9fb44900 100644 --- a/qubes/tests/api_admin.py +++ b/qubes/tests/api_admin.py @@ -159,6 +159,21 @@ class TC_00_VMs(AdminAPITestCase): b'netvm') self.assertEqual(value, 'default=True type=vm ') + def test_025_vm_property_get_default_vm_none(self): + value = self.call_mgmt_func( + b'admin.vm.property.GetDefault', + b'test-vm1', + b'template') + self.assertEqual(value, None) + + def test_026_vm_property_get_default_bool(self): + self.vm.provides_network = True + value = self.call_mgmt_func( + b'admin.vm.property.GetDefault', + b'test-vm1', + b'provides_network') + self.assertEqual(value, 'type=bool False') + 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)