Explorar o código

storage/lvm: fix Volume() instance init when physical volume is unavailable

First, cache objects created with init_volume - this is the only place
where we have full volume configuration (including snap_on_start and
save_on_stop properties).
But also implement get_volume method, to get a volume instance for given
volume id. Such volume instance may be incomplete (other attributes are
available only in owning domain configuration), but it will be enough
for basic operations - like cheching and changing its size, cloning
etc.
Listing volumes still use list of physically present volumes.

This makes it possible to start qubesd service, without physical
presence of some storage devices. Starting VMs using such storage would
still fail, of course.

Fixes QubesOS/qubes-issues#2960
Marek Marczykowski-Górecki %!s(int64=6) %!d(string=hai) anos
pai
achega
6e5fe58128
Modificáronse 1 ficheiros con 21 adicións e 1 borrados
  1. 21 1
      qubes/storage/lvm.py

+ 21 - 1
qubes/storage/lvm.py

@@ -61,6 +61,8 @@ class ThinPool(qubes.storage.Pool):
         self._pool_id = "{!s}/{!s}".format(volume_group, thin_pool)
         self.log = logging.getLogger('qube.storage.lvm.%s' % self._pool_id)
 
+        self._volume_objects_cache = {}
+
     @property
     def config(self):
         return {
@@ -91,11 +93,27 @@ class ThinPool(qubes.storage.Pool):
 
         volume_config['volume_group'] = self.volume_group
         volume_config['pool'] = self
-        return ThinVolume(**volume_config)
+        volume = ThinVolume(**volume_config)
+        self._volume_objects_cache[volume_config['vid']] = volume
+        return volume
 
     def setup(self):
         pass  # TODO Should we create a non existing pool?
 
+    def get_volume(self, vid):
+        ''' Return a volume with given vid'''
+        if vid in self._volume_objects_cache:
+            return self._volume_objects_cache[vid]
+
+        config = {
+                'pool': self,
+                'vid': vid,
+                'name': vid,
+                'volume_group': self.volume_group,
+            }
+        # don't cache this object, as it doesn't carry full configuration
+        return ThinVolume(**config)
+
     def list_volumes(self):
         ''' Return a list of volumes managed by this pool '''
         volumes = []
@@ -288,6 +306,8 @@ class ThinVolume(qubes.storage.Volume):
         cmd = ['remove', self.vid]
         qubes_lvm(cmd, self.log)
         reset_cache()
+        # pylint: disable=protected-access
+        self.pool._volume_objects_cache.pop(self.vid, None)
 
     def export(self):
         ''' Returns an object that can be `open()`. '''