Browse Source

Changing AppVM template breaks running DispVMs

So prevent changing a VM’s template if there are running DispVMs based
on it.
Demi Marie Obenour 3 years ago
parent
commit
d46657a244
3 changed files with 20 additions and 14 deletions
  1. 9 7
      qubes/vm/appvm.py
  2. 1 7
      qubes/vm/dispvm.py
  3. 10 0
      qubes/vm/mix/dvmtemplate.py

+ 9 - 7
qubes/vm/appvm.py

@@ -27,6 +27,14 @@ import qubes.vm.qubesvm
 import qubes.vm.mix.dvmtemplate
 from qubes.config import defaults
 
+def template_changed_update_storage(self, volume_config):
+    '''Update storage configuration for TemplateVM changes'''
+    for volume_name, conf in volume_config.items():
+        if conf.get('snap_on_start', False) and \
+                conf.get('source', None) is None:
+            config = conf.copy()
+            self.volume_config[volume_name] = config
+            self.storage.init_volume(volume_name, config)
 
 class AppVM(qubes.vm.mix.dvmtemplate.DVMTemplateMixin,
         qubes.vm.qubesvm.QubesVM):
@@ -120,10 +128,4 @@ class AppVM(qubes.vm.mix.dvmtemplate.DVMTemplateMixin,
         ''' Adjust root (and possibly other snap_on_start=True) volume
         on template change.
         '''  # pylint: disable=unused-argument
-
-        for volume_name, conf in self.default_volume_config.items():
-            if conf.get('snap_on_start', False) and \
-                    conf.get('source', None) is None:
-                config = conf.copy()
-                self.volume_config[volume_name] = config
-                self.storage.init_volume(volume_name, config)
+        template_changed_update_storage(self, self.default_volume_config)

+ 1 - 7
qubes/vm/dispvm.py

@@ -165,13 +165,7 @@ class DispVM(qubes.vm.qubesvm.QubesVM):
         ''' Adjust root (and possibly other snap_on_start=True) volume
         on template change.
         '''  # pylint: disable=unused-argument
-
-        for volume_name, conf in self.default_volume_config.items():
-            if conf.get('snap_on_start', False) and \
-                    conf.get('source', None) is None:
-                config = conf.copy()
-                self.volume_config[volume_name] = config
-                self.storage.init_volume(volume_name, config)
+        qubes.vm.appvm.template_changed_update_storage(self, DispVM.default_volume_config)
 
     @qubes.events.handler('domain-shutdown')
     @asyncio.coroutine

+ 10 - 0
qubes/vm/mix/dvmtemplate.py

@@ -45,6 +45,16 @@ class DVMTemplateMixin(qubes.events.Emitter):
         self.__on_pre_set_dvmtemplate(
             event, name, False, oldvalue)
 
+    @qubes.events.handler('property-pre-set:template')
+    def __on_pre_property_set_template(self, event, name, newvalue,
+            oldvalue=None):
+        # pylint: disable=unused-argument
+        for vm in self.dispvms:
+            if vm.is_running:
+                raise qubes.exc.QubesVMNotHaltedError(self,
+                    'Cannot change template while there are running DispVMs'
+                    'based on this DVM template')
+
     @qubes.events.handler('property-set:template')
     def __on_property_set_template(self, event, name, newvalue,
             oldvalue=None):