storage: simplify pool.volumes usage

Add convenient collection wrapper for easier getting selected volume.
Storage pool implementation may still provide only volume listing
function (pool.list_volumes), or, additionally, optimized
pool.get_volume.

This means it is both possible to iterate over volumes:
```python
for volume in pool.volumes:
    ...

```

And get a single volume:
```python
volume = pool.volumes[vid]
```

QubesOS/qubes-issues#2256
This commit is contained in:
Marek Marczykowski-Górecki 2017-06-26 02:46:49 +02:00
parent 65d15e6040
commit ae600e24bf
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
3 changed files with 67 additions and 5 deletions

View File

@ -614,6 +614,58 @@ class Storage(object):
return self.vm.volumes[volume].import_data_end(success=success)
class VolumesCollection(object):
'''Convenient collection wrapper for pool.get_volume and
pool.list_volumes
'''
def __init__(self, pool):
self._pool = pool
def __getitem__(self, item):
''' Get a single volume with given Volume ID.
You can also a Volume instance to get the same Volume or KeyError if
Volume no longer exists.
:param item: a Volume ID (str) or a Volume instance
'''
if isinstance(item, Volume):
if item.pool == self._pool:
return self[item.vid]
else:
raise KeyError(item)
try:
return self._pool.get_volume(item)
except NotImplementedError:
for vol in self:
if vol.vid == item:
return vol
# if list_volumes is not implemented too, it will raise
# NotImplementedError again earlier
raise KeyError(item)
def __iter__(self):
''' Get iterator over pool's volumes '''
return iter(self._pool.list_volumes())
def __contains__(self, item):
''' Check if given volume (either Volume ID or Volume instance) is
present in the pool
'''
try:
return self[item] is not None
except KeyError:
return False
def keys(self):
''' Return list of volume IDs '''
return [vol.vid for vol in self]
def values(self):
''' Return list of Volumes'''
return [vol for vol in self]
class Pool(object):
''' A Pool is used to manage different kind of volumes (File
based/LVM/Btrfs/...).
@ -626,6 +678,7 @@ class Pool(object):
def __init__(self, name, revisions_to_keep=1, **kwargs):
super(Pool, self).__init__(**kwargs)
self._volumes_collection = VolumesCollection(self)
self.name = name
self.revisions_to_keep = revisions_to_keep
kwargs['name'] = self.name
@ -684,8 +737,19 @@ class Pool(object):
@property
def volumes(self):
''' Return a collection of volumes managed by this pool '''
return self._volumes_collection
def list_volumes(self):
''' Return a list of volumes managed by this pool '''
raise self._not_implemented("volumes")
raise self._not_implemented("list_volumes")
def get_volume(self, vid):
''' Return a volume with *vid* from this pool
:raise KeyError: if no volume is found
'''
raise self._not_implemented("get_volume")
def _not_implemented(self, method_name):
''' Helper for emitting helpful `NotImplementedError` exceptions '''

View File

@ -152,8 +152,7 @@ class FilePool(qubes.storage.Pool):
return os.path.join(self.dir_path, self._vid_prefix(vm))
@property
def volumes(self):
def list_volumes(self):
return self._volumes

View File

@ -120,8 +120,7 @@ class ThinPool(qubes.storage.Pool):
def setup(self):
pass # TODO Should we create a non existing pool?
@property
def volumes(self):
def list_volumes(self):
''' Return a list of volumes managed by this pool '''
volumes = []
for vid, vol_info in size_cache.items():