Browse Source

features: add check_with_netvm, similar to check_with_template

Allow using default feature value from netvm, not template. This makes
sense for network-related features like using tor, supporting ipv6 etc.

Similarly to check_with_template, expose it also on Admin API.
Marek Marczykowski-Górecki 6 years ago
parent
commit
bf59b00f1d
4 changed files with 57 additions and 0 deletions
  1. 1 0
      Makefile
  2. 13 0
      qubes/api/admin.py
  3. 29 0
      qubes/tests/api_admin.py
  4. 14 0
      qubes/vm/__init__.py

+ 1 - 0
Makefile

@@ -69,6 +69,7 @@ ADMIN_API_METHODS_SIMPLE = \
 	admin.vm.device.mic.Detach \
 	admin.vm.device.mic.List \
 	admin.vm.device.mic.Set.persistent \
+	admin.vm.feature.CheckWithNetvm \
 	admin.vm.feature.CheckWithTemplate \
 	admin.vm.feature.Get \
 	admin.vm.feature.List \

+ 13 - 0
qubes/api/admin.py

@@ -883,6 +883,19 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
             raise qubes.exc.QubesFeatureNotFoundError(self.dest, self.arg)
         return value
 
+    @qubes.api.method('admin.vm.feature.CheckWithNetvm', no_payload=True,
+        scope='local', read=True)
+    @asyncio.coroutine
+    def vm_feature_checkwithnetvm(self):
+        # validation of self.arg done by qrexec-policy is enough
+
+        self.fire_event_for_permission()
+        try:
+            value = self.dest.features.check_with_netvm(self.arg)
+        except KeyError:
+            raise qubes.exc.QubesFeatureNotFoundError(self.dest, self.arg)
+        return value
+
     @qubes.api.method('admin.vm.feature.Remove', no_payload=True,
         scope='local', write=True)
     @asyncio.coroutine

+ 29 - 0
qubes/tests/api_admin.py

@@ -90,6 +90,10 @@ class AdminAPITestCase(qubes.tests.QubesTestCase):
         self.base_dir_patch.stop()
         if os.path.exists(self.test_base_dir):
             shutil.rmtree(self.test_base_dir)
+        try:
+            del self.netvm
+        except AttributeError:
+            pass
         del self.vm
         del self.template
         self.app.close()
@@ -1047,6 +1051,31 @@ class TC_00_VMs(AdminAPITestCase):
                 b'test-vm1', b'test-feature')
         self.assertFalse(self.app.save.called)
 
+    def test_315_feature_checkwithnetvm(self):
+        self.vm.features['test-feature'] = 'some-value'
+        value = self.call_mgmt_func(b'admin.vm.feature.CheckWithNetvm',
+            b'test-vm1', b'test-feature')
+        self.assertEqual(value, 'some-value')
+        self.assertFalse(self.app.save.called)
+
+    def test_316_feature_checkwithnetvm_netvm(self):
+        self.netvm = self.app.add_new_vm('AppVM', label='red',
+            name='test-netvm1',
+            template='test-template',
+            provides_network=True)
+        self.vm.netvm = self.netvm
+        self.netvm.features['test-feature'] = 'some-value'
+        value = self.call_mgmt_func(b'admin.vm.feature.CheckWithNetvm',
+            b'test-vm1', b'test-feature')
+        self.assertEqual(value, 'some-value')
+        self.assertFalse(self.app.save.called)
+
+    def test_317_feature_checkwithnetvm_none(self):
+        with self.assertRaises(qubes.exc.QubesFeatureNotFoundError):
+            self.call_mgmt_func(b'admin.vm.feature.CheckWithNetvm',
+                b'test-vm1', b'test-feature')
+        self.assertFalse(self.app.save.called)
+
     def test_320_feature_set(self):
         value = self.call_mgmt_func(b'admin.vm.feature.Set',
             b'test-vm1', b'test-feature', b'some-value')

+ 14 - 0
qubes/vm/__init__.py

@@ -186,6 +186,20 @@ class Features(dict):
 
         return default
 
+    def check_with_netvm(self, feature, default=_NO_DEFAULT):
+        ''' Check if the vm's netvm has the specified feature. '''
+        if feature in self:
+            return self[feature]
+
+        if hasattr(self.vm, 'netvm') and self.vm.netvm is not None:
+            return self.vm.netvm.features.check_with_netvm(feature,
+                default)
+
+        if default is self._NO_DEFAULT:
+            raise KeyError(feature)
+
+        return default
+
 
 class Tags(set):
     '''Manager of the tags.