Browse Source

Merge remote-tracking branch 'origin/pr/342'

* origin/pr/342:
  Added a servicevm feature extension
  Removed unused Qubes Manager extension
  Add vm.icon property
Marek Marczykowski-Górecki 4 years ago
parent
commit
c7d3635972

+ 22 - 0
qubes/ext/core_features.py

@@ -62,3 +62,25 @@ class CoreFeatures(qubes.ext.Extension):
             # if this is the first time qrexec was advertised, now can finish
             #  template setup
             yield from vm.fire_event_async('template-postinstall')
+
+    # pylint: disable=no-self-use
+    def set_servicevm_feature(self, subject):
+        if getattr(subject, 'provides_network', False):
+            subject.features['servicevm'] = 1
+        elif 'servicevm' in subject.features:
+            del subject.features['servicevm']
+
+    @qubes.ext.handler('property-set:provides_network')
+    def on_property_set(self, subject, event, name, newvalue, oldvalue=None):
+        # pylint: disable=unused-argument
+        self.set_servicevm_feature(subject)
+
+    @qubes.ext.handler('property-del:provides_network')
+    def on_property_del(self, subject, event, name):
+        # pylint: disable=unused-argument
+        self.set_servicevm_feature(subject)
+
+    @qubes.ext.handler('domain-load')
+    def on_domain_load(self, subject, event):
+        # pylint: disable=unused-argument
+        self.set_servicevm_feature(subject)

+ 0 - 70
qubes/ext/qubesmanager.py

@@ -1,70 +0,0 @@
-#
-# The Qubes OS Project, https://www.qubes-os.org/
-#
-# Copyright (C) 2014-2015  Joanna Rutkowska <joanna@invisiblethingslab.com>
-# Copyright (C) 2014       Marek Marczykowski-Górecki
-#                               <marmarek@invisiblethingslab.com>
-# Copyright (C) 2015       Wojtek Porczyk <woju@invisiblethingslab.com>
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, see <https://www.gnu.org/licenses/>.
-#
-
-'''Qubes Manager hooks.
-
-.. warning:: API defined here is not declared stable.
-'''
-
-import dbus
-import qubes.ext
-
-
-class QubesManager(qubes.ext.Extension):
-    def __init__(self, *args, **kwargs):
-        super(QubesManager, self).__init__(*args, **kwargs)
-        try:
-            self._system_bus = dbus.SystemBus()
-        except dbus.exceptions.DBusException:
-            # we can't access Qubes() object here to check for offline mode,
-            # so lets assume it is this case...
-            self._system_bus = None
-
-    # pylint: disable=no-self-use,unused-argument,too-few-public-methods
-
-    @qubes.ext.handler('status:error')
-    def on_status_error(self, vm, event, status, message):
-        if self._system_bus is None:
-            return
-        try:
-            qubes_manager = self._system_bus.get_object(
-                'org.qubesos.QubesManager',
-                '/org/qubesos/QubesManager')
-            qubes_manager.notify_error(vm.name, message,
-                dbus_interface='org.qubesos.QubesManager')
-        except dbus.DBusException:
-            # ignore the case when no qubes-manager is running
-            pass
-
-    @qubes.ext.handler('status:no-error')
-    def on_status_no_error(self, vm, event, status, message):
-        if self._system_bus is None:
-            return
-        try:
-            qubes_manager = self._system_bus.get_object(
-                'org.qubesos.QubesManager',
-                '/org/qubesos/QubesManager')
-            qubes_manager.clear_error_exact(vm.name, message,
-                dbus_interface='org.qubesos.QubesManager')
-        except dbus.DBusException:
-            # ignore the case when no qubes-manager is running
-            pass

+ 13 - 0
qubes/tests/ext.py

@@ -34,8 +34,11 @@ class TC_00_CoreFeatures(qubes.tests.QubesTestCase):
         self.features = {}
         self.vm.configure_mock(**{
             'features.get.side_effect': self.features.get,
+            'features.items.side_effect': self.features.items,
+            'features.__iter__.side_effect': self.features.__iter__,
             'features.__contains__.side_effect': self.features.__contains__,
             'features.__setitem__.side_effect': self.features.__setitem__,
+            'features.__delitem__.side_effect': self.features.__delitem__,
             })
 
     def test_010_notify_tools(self):
@@ -181,6 +184,16 @@ class TC_00_CoreFeatures(qubes.tests.QubesTestCase):
             ('features.__contains__', ('gui',), {}),
         ])
 
+    def test_100_servicevm_feature(self):
+        self.vm.provides_network = True
+        self.ext.set_servicevm_feature(self.vm)
+        self.assertEqual(self.features['servicevm'], 1)
+
+        self.vm.provides_network = False
+        self.ext.set_servicevm_feature(self.vm)
+        self.assertNotIn('servicevm', self.features)
+
+
 class TC_10_WindowsFeatures(qubes.tests.QubesTestCase):
     def setUp(self):
         super().setUp()

+ 4 - 1
qubes/tests/vm/__init__.py

@@ -65,7 +65,10 @@ class TestPool(object):
         return TestVolume(self)
 
 class TestApp(qubes.tests.TestEmitter):
-    labels = {1: qubes.Label(1, '0xcc0000', 'red')}
+    labels = {1: qubes.Label(1, '0xcc0000', 'red'),
+              2: qubes.Label(2, '0x00cc00', 'green'),
+              3: qubes.Label(3, '0x0000cc', 'blue'),
+              4: qubes.Label(4, '0xcccccc', 'black')}
     check_updates_vm = False
 
     def get_label(self, label):

+ 31 - 6
qubes/tests/vm/qubesvm.py

@@ -47,7 +47,10 @@ import qubes.tests
 import qubes.tests.vm
 
 class TestApp(object):
-    labels = {1: qubes.Label(1, '0xcc0000', 'red')}
+    labels = {1: qubes.Label(1, '0xcc0000', 'red'),
+              2: qubes.Label(2, '0x00cc00', 'green'),
+              3: qubes.Label(3, '0x0000cc', 'blue'),
+              4: qubes.Label(4, '0xcccccc', 'black')}
 
     def __init__(self):
         self.domains = {}
@@ -394,24 +397,46 @@ class TC_90_QubesVM(QubesVMTestsMixin, qubes.tests.QubesTestCase):
         with self.assertRaises(AttributeError):
             vm.uuid = uuid.uuid4()
 
-    @unittest.skip('TODO: how to not fail on making an icon symlink here?')
-    def test_130_label(self):
+    @unittest.mock.patch("os.symlink")
+    def test_130_label(self, _):
         vm = self.get_vm()
         self.assertPropertyDefaultValue(vm, 'label')
         self.assertPropertyValue(vm, 'label', self.app.labels[1],
-            self.app.labels[1], 'label-1')
+            self.app.labels[1], 'red')
         del vm.label
         self.assertPropertyDefaultValue(vm, 'label')
         self.assertPropertyValue(vm, 'label', 'red',
-            self.app.labels[1], 'label-1')
+            self.app.labels[1], 'red')
         self.assertPropertyValue(vm, 'label', 'label-1',
-            self.app.labels[1], 'label-1')
+            self.app.labels[1], 'red')
 
     def test_131_label_invalid(self):
         vm = self.get_vm()
         self.assertPropertyInvalidValue(vm, 'label', 'invalid')
         self.assertPropertyInvalidValue(vm, 'label', 123)
 
+    @unittest.mock.patch("os.symlink")
+    def test_135_icon(self, _):
+        vm = self.get_vm(cls=qubes.vm.appvm.AppVM)
+        vm.label = "red"
+        self.assertEqual(vm.icon, "appvm-red")
+
+        templatevm = self.get_vm(cls=qubes.vm.templatevm.TemplateVM)
+        templatevm.label = "blue"
+        self.assertEqual(templatevm.icon, "templatevm-blue")
+
+        vm.template_for_dispvms = True
+        dispvm = self.get_vm(cls=qubes.vm.dispvm.DispVM, template=vm,
+                             dispid=10)
+        dispvm.label = "black"
+        self.assertEqual(dispvm.icon, "dispvm-black")
+
+        vm = self.get_vm()
+        vm.label = "green"
+        vm.features["servicevm"] = 1
+        self.assertEqual(vm.icon, "servicevm-green")
+
+
     def test_160_memory(self):
         vm = self.get_vm()
         self.assertPropertyDefaultValue(vm, 'memory', 400)

+ 14 - 0
qubes/vm/qubesvm.py

@@ -2101,6 +2101,20 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
 
         return None
 
+    @qubes.stateless_property
+    def icon(self):
+        """freedesktop icon name, suitable for use in
+        :py:meth:`PyQt4.QtGui.QIcon.fromTheme`"""
+        #  pylint: disable=comparison-with-callable
+        raw_icon_name = self.label.name
+        if self.klass == 'TemplateVM':
+            return 'templatevm-' + raw_icon_name
+        if self.klass == 'DispVM':
+            return 'dispvm-' + raw_icon_name
+        if self.features.get('servicevm', False):
+            return 'servicevm-' + raw_icon_name
+        return 'appvm-' + raw_icon_name
+
     @property
     def kernelopts_common(self):
         """Kernel options which should be used in addition to *kernelopts*

+ 0 - 1
rpm_spec/core-dom0.spec.in

@@ -277,7 +277,6 @@ fi
 %{python3_sitelib}/qubes/ext/gui.py
 %{python3_sitelib}/qubes/ext/audio.py
 %{python3_sitelib}/qubes/ext/pci.py
-%{python3_sitelib}/qubes/ext/qubesmanager.py
 %{python3_sitelib}/qubes/ext/r3compatibility.py
 %{python3_sitelib}/qubes/ext/services.py
 %{python3_sitelib}/qubes/ext/windows.py

+ 0 - 1
setup.py

@@ -62,7 +62,6 @@ if __name__ == '__main__':
             'qubes.ext': [
                 'qubes.ext.admin = qubes.ext.admin:AdminExtension',
                 'qubes.ext.core_features = qubes.ext.core_features:CoreFeatures',
-                'qubes.ext.qubesmanager = qubes.ext.qubesmanager:QubesManager',
                 'qubes.ext.gui = qubes.ext.gui:GUI',
                 'qubes.ext.audio = qubes.ext.audio:AUDIO',
                 'qubes.ext.r3compatibility = qubes.ext.r3compatibility:R3Compatibility',