From 6e5fe5812882f5722c922829d96a13e7e6de8f62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Sat, 12 Aug 2017 22:44:03 +0200 Subject: [PATCH] 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 --- qubes/storage/lvm.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/qubes/storage/lvm.py b/qubes/storage/lvm.py index 1beaa639..680607da 100644 --- a/qubes/storage/lvm.py +++ b/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()`. '''