Support pool-aware drivers

This patch adds pool support to cinderlib.

The Backend class now has the property `pool_names` with available pools
in the driver.

When creating a volume we can specify `pool_name` to use a specific
pool.

Pool is stored as part of the `host` field in volumes.  The `host` field
now follows Cinder's naming "host@backend#pool".
This commit is contained in:
Gorka Eguileor 2018-11-20 16:41:59 +01:00
parent 09abcf4df4
commit c491c71f47
6 changed files with 36 additions and 9 deletions

View File

@ -13,6 +13,7 @@ History
- Provide better message when device is not available.
- Backend name stored in host instead of in the AZ (backward incompatible).
- Support multi-pool drivers.
0.2.2 (2018-07-24)
------------------

View File

@ -76,6 +76,14 @@ class Backend(object):
self.driver.set_initialized()
self._driver_cfg = driver_cfg
self._volumes = None
# init_capabilities already calls get_volume_stats with refresh=True
# so we can call it without refresh to get pool names.
self._pool_names = tuple(pool['pool_name']
for pool in self.get_volume_stats()['pools'])
@property
def pool_names(self):
return self._pool_names
def __repr__(self):
return '<cinderlib.Backend %s>' % self.id

View File

@ -275,17 +275,16 @@ class Volume(NamedObject):
_ignore_keys = ('id', CONNECTIONS_OVO_FIELD, 'snapshots')
def __init__(self, backend_or_vol, **kwargs):
def __init__(self, backend_or_vol, pool_name=None, **kwargs):
# Accept backend name for convenience
if isinstance(backend_or_vol, six.string_types):
kwargs.setdefault('host',
'%s@%s' % (CONFIGURED_HOST, backend_or_vol))
backend_name = backend_or_vol
backend_or_vol = self._get_backend(backend_or_vol)
elif isinstance(backend_or_vol, self.backend_class):
kwargs.setdefault('host',
'%s@%s' % (CONFIGURED_HOST, backend_or_vol.id))
# Accept a volume as additional source data
backend_name = backend_or_vol.id
elif isinstance(backend_or_vol, Volume):
backend_name, pool = backend_or_vol._ovo.host.split('#')
pool_name = pool_name or pool
for key in backend_or_vol._ovo.fields:
if (backend_or_vol._ovo.obj_attr_is_set(key) and
key not in self._ignore_keys):
@ -307,6 +306,13 @@ class Volume(NamedObject):
self._populate_data()
self.local_attach = None
# If we overwrote the host, then we ignore pool_name and don't set a
# default value or copy the one from the source either.
if 'host' not in kwargs and '__ovo' not in kwargs:
pool_name = pool_name or backend_or_vol.pool_names[0]
self._ovo.host = ('%s@%s#%s' %
(CONFIGURED_HOST, backend_name, pool_name))
if qos_specs or extra_specs:
if qos_specs:
qos_specs = cinder_objs.QualityOfServiceSpecs(

View File

@ -253,4 +253,9 @@ relevant sections:
- `global_setup` has been covered in the :doc:`initialization` section.
- `pool_names` tuple with all the pools available in the driver. Non pool
aware drivers will have only 1 pool and use the name of the backend as its
name. Pool aware drivers may report multiple values, which can be passed to
the `create_volume` method in the `pool_name` parameter.
.. _OpenStack's Cinder volume driver configuration documentation: https://docs.openstack.org/cinder/latest/configuration/block-storage/volume-drivers.html

View File

@ -109,9 +109,15 @@ Some of the fields we could be interested in are:
- `host`: Used to store the backend name information together with the host
name where cinderlib is running. This information is stored as a string in
the form of *host@backend*. This is an optional parameter, and passing it to
`create_volume` will override default value. Issues will arise if parameter
doesn't contain correct information.
the form of *host@backend#pool*. This is an optional parameter, and passing
it to `create_volume` will override default value, allowing us caller to
request a specific pool for multi-pool backends, though we recommend using
the `pool_name` parameter instead. Issues will arise if parameter doesn't
contain correct information.
- `pool_name`: Pool name to use when creating the volume. Default is to use
the first or only pool. To know possible values for a backend use the
`pool_names` property on the *Backend* instance.
- `size`: Volume size in GBi.

View File

@ -24,3 +24,4 @@ class FakeBackend(cinderlib.Backend):
cinderlib.Backend.backends[driver_name] = self
self._driver_cfg = {'volume_backend_name': driver_name}
self.driver = mock.Mock()
self._pool_names = (driver_name,)