"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "cinder/volume/drivers/rbd.py" between
cinder-15.0.1.tar.gz and cinder-15.1.0.tar.gz

About: OpenStack Cinder (Core Service: Block Storage) provides persistent block storage to running instances. Its pluggable driver architecture facilitates the creation and management of block storage devices.
The "Train" series (latest release).

rbd.py  (cinder-15.0.1):rbd.py  (cinder-15.1.0)
skipping to change at line 203 skipping to change at line 203
def __enter__(self): def __enter__(self):
return self return self
def __exit__(self, type_, value, traceback): def __exit__(self, type_, value, traceback):
self.driver._disconnect_from_rados(self.cluster, self.ioctx) self.driver._disconnect_from_rados(self.cluster, self.ioctx)
@property @property
def features(self): def features(self):
features = self.cluster.conf_get('rbd_default_features') features = self.cluster.conf_get('rbd_default_features')
if ((features is None) or (int(features) == 0)): if ((features is None) or (int(features) == 0)):
features = self.driver.rbd.RBD_FEATURE_LAYERING features = self.driver.RBD_FEATURE_LAYERING
return int(features) return int(features)
@interface.volumedriver @interface.volumedriver
class RBDDriver(driver.CloneableImageVD, driver.MigrateVD, class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
driver.ManageableVD, driver.ManageableSnapshotsVD, driver.ManageableVD, driver.ManageableSnapshotsVD,
driver.BaseVD): driver.BaseVD):
"""Implements RADOS block device (RBD) volume commands.""" """Implements RADOS block device (RBD) volume commands."""
VERSION = '1.2.0' VERSION = '1.2.0'
# ThirdPartySystems wiki page # ThirdPartySystems wiki page
CI_WIKI_NAME = "Cinder_Jenkins" CI_WIKI_NAME = "Cinder_Jenkins"
SUPPORTS_ACTIVE_ACTIVE = True SUPPORTS_ACTIVE_ACTIVE = True
SYSCONFDIR = '/etc/ceph/' SYSCONFDIR = '/etc/ceph/'
RBD_FEATURE_LAYERING = 1
RBD_FEATURE_EXCLUSIVE_LOCK = 4
RBD_FEATURE_OBJECT_MAP = 8
RBD_FEATURE_FAST_DIFF = 16
RBD_FEATURE_JOURNALING = 64
def __init__(self, active_backend_id=None, *args, **kwargs): def __init__(self, active_backend_id=None, *args, **kwargs):
super(RBDDriver, self).__init__(*args, **kwargs) super(RBDDriver, self).__init__(*args, **kwargs)
self.configuration.append_config_values(RBD_OPTS) self.configuration.append_config_values(RBD_OPTS)
self._stats = {} self._stats = {}
# allow overrides for testing # allow overrides for testing
self.rados = kwargs.get('rados', rados) self.rados = kwargs.get('rados', rados)
self.rbd = kwargs.get('rbd', rbd) self.rbd = kwargs.get('rbd', rbd)
# All string args used with librbd must be None or utf-8 otherwise # All string args used with librbd must be None or utf-8 otherwise
# librbd will break. # librbd will break.
skipping to change at line 245 skipping to change at line 251
setattr(self.configuration, attr, utils.convert_str(val)) setattr(self.configuration, attr, utils.convert_str(val))
self._backend_name = (self.configuration.volume_backend_name or self._backend_name = (self.configuration.volume_backend_name or
self.__class__.__name__) self.__class__.__name__)
self._active_backend_id = active_backend_id self._active_backend_id = active_backend_id
self._active_config = {} self._active_config = {}
self._is_replication_enabled = False self._is_replication_enabled = False
self._replication_targets = [] self._replication_targets = []
self._target_names = [] self._target_names = []
if self.rbd is not None:
self.RBD_FEATURE_LAYERING = self.rbd.RBD_FEATURE_LAYERING
self.RBD_FEATURE_EXCLUSIVE_LOCK = \
self.rbd.RBD_FEATURE_EXCLUSIVE_LOCK
self.RBD_FEATURE_OBJECT_MAP = self.rbd.RBD_FEATURE_OBJECT_MAP
self.RBD_FEATURE_FAST_DIFF = self.rbd.RBD_FEATURE_FAST_DIFF
self.RBD_FEATURE_JOURNALING = self.rbd.RBD_FEATURE_JOURNALING
self.MULTIATTACH_EXCLUSIONS = (
self.RBD_FEATURE_JOURNALING |
self.RBD_FEATURE_FAST_DIFF |
self.RBD_FEATURE_OBJECT_MAP |
self.RBD_FEATURE_EXCLUSIVE_LOCK)
@staticmethod @staticmethod
def get_driver_options(): def get_driver_options():
return RBD_OPTS return RBD_OPTS
def _get_target_config(self, target_id): def _get_target_config(self, target_id):
"""Get a replication target from known replication targets.""" """Get a replication target from known replication targets."""
for target in self._replication_targets: for target in self._replication_targets:
if target['name'] == target_id: if target['name'] == target_id:
return target return target
if not target_id or target_id == 'default': if not target_id or target_id == 'default':
skipping to change at line 676 skipping to change at line 696
LOG.debug("cloning '%(src_vol)s@%(src_snap)s' to " LOG.debug("cloning '%(src_vol)s@%(src_snap)s' to "
"'%(dest)s'", "'%(dest)s'",
{'src_vol': src_name, 'src_snap': clone_snap, {'src_vol': src_name, 'src_snap': clone_snap,
'dest': dest_name}) 'dest': dest_name})
self.RBDProxy().clone(client.ioctx, src_name, clone_snap, self.RBDProxy().clone(client.ioctx, src_name, clone_snap,
client.ioctx, dest_name, client.ioctx, dest_name,
features=client.features) features=client.features)
except Exception as e: except Exception as e:
src_volume.unprotect_snap(clone_snap) src_volume.unprotect_snap(clone_snap)
src_volume.remove_snap(clone_snap) src_volume.remove_snap(clone_snap)
src_volume.close()
msg = (_("Failed to clone '%(src_vol)s@%(src_snap)s' to " msg = (_("Failed to clone '%(src_vol)s@%(src_snap)s' to "
"'%(dest)s', error: %(error)s") % "'%(dest)s', error: %(error)s") %
{'src_vol': src_name, {'src_vol': src_name,
'src_snap': clone_snap, 'src_snap': clone_snap,
'dest': dest_name, 'dest': dest_name,
'error': e}) 'error': e})
LOG.exception(msg) LOG.exception(msg)
raise exception.VolumeBackendAPIException(data=msg) raise exception.VolumeBackendAPIException(data=msg)
finally:
src_volume.close()
depth = self._get_clone_depth(client, src_name) depth = self._get_clone_depth(client, src_name)
# If dest volume is a clone and rbd_max_clone_depth reached, # If dest volume is a clone and rbd_max_clone_depth reached,
# flatten the dest after cloning. Zero rbd_max_clone_depth means # flatten the dest after cloning. Zero rbd_max_clone_depth means
# infinite is allowed. # infinite is allowed.
if depth >= self.configuration.rbd_max_clone_depth: if depth >= self.configuration.rbd_max_clone_depth:
LOG.info("maximum clone depth (%d) has been reached - " LOG.info("maximum clone depth (%d) has been reached - "
"flattening dest volume", "flattening dest volume",
self.configuration.rbd_max_clone_depth) self.configuration.rbd_max_clone_depth)
dest_volume = self.rbd.Image(client.ioctx, dest_name) dest_volume = self.rbd.Image(client.ioctx, dest_name)
skipping to change at line 750 skipping to change at line 769
return volume_update return volume_update
def _enable_replication(self, volume): def _enable_replication(self, volume):
"""Enable replication for a volume. """Enable replication for a volume.
Returns required volume update. Returns required volume update.
""" """
vol_name = utils.convert_str(volume.name) vol_name = utils.convert_str(volume.name)
with RBDVolumeProxy(self, vol_name) as image: with RBDVolumeProxy(self, vol_name) as image:
had_exclusive_lock = (image.features() & had_exclusive_lock = (image.features() &
self.rbd.RBD_FEATURE_EXCLUSIVE_LOCK) self.RBD_FEATURE_EXCLUSIVE_LOCK)
had_journaling = image.features() & self.rbd.RBD_FEATURE_JOURNALING had_journaling = image.features() & self.RBD_FEATURE_JOURNALING
if not had_exclusive_lock: if not had_exclusive_lock:
image.update_features(self.rbd.RBD_FEATURE_EXCLUSIVE_LOCK, image.update_features(self.RBD_FEATURE_EXCLUSIVE_LOCK,
True) True)
if not had_journaling: if not had_journaling:
image.update_features(self.rbd.RBD_FEATURE_JOURNALING, True) image.update_features(self.RBD_FEATURE_JOURNALING, True)
image.mirror_image_enable() image.mirror_image_enable()
driver_data = self._dumps({ driver_data = self._dumps({
'had_journaling': bool(had_journaling), 'had_journaling': bool(had_journaling),
'had_exclusive_lock': bool(had_exclusive_lock) 'had_exclusive_lock': bool(had_exclusive_lock)
}) })
return {'replication_status': fields.ReplicationStatus.ENABLED, return {'replication_status': fields.ReplicationStatus.ENABLED,
'replication_driver_data': driver_data} 'replication_driver_data': driver_data}
def _enable_multiattach(self, volume): def _enable_multiattach(self, volume):
multipath_feature_exclusions = [
self.rbd.RBD_FEATURE_JOURNALING,
self.rbd.RBD_FEATURE_FAST_DIFF,
self.rbd.RBD_FEATURE_OBJECT_MAP,
self.rbd.RBD_FEATURE_EXCLUSIVE_LOCK,
]
vol_name = utils.convert_str(volume.name) vol_name = utils.convert_str(volume.name)
image_features = None
with RBDVolumeProxy(self, vol_name) as image: with RBDVolumeProxy(self, vol_name) as image:
image_features = image.features() image_features = image.features()
for feature in multipath_feature_exclusions: change_features = self.MULTIATTACH_EXCLUSIONS & image_features
if image_features & feature: image.update_features(change_features, False)
image.update_features(feature, False)
return {'provider_location': return {'provider_location':
self._dumps({'saved_features': image_features})} self._dumps({'saved_features': image_features})}
def _disable_multiattach(self, volume): def _disable_multiattach(self, volume):
multipath_feature_exclusions = [
self.rbd.RBD_FEATURE_EXCLUSIVE_LOCK,
self.rbd.RBD_FEATURE_OBJECT_MAP,
self.rbd.RBD_FEATURE_FAST_DIFF,
self.rbd.RBD_FEATURE_JOURNALING,
]
vol_name = utils.convert_str(volume.name) vol_name = utils.convert_str(volume.name)
with RBDVolumeProxy(self, vol_name) as image: with RBDVolumeProxy(self, vol_name) as image:
try: try:
provider_location = json.loads(volume.provider_location) provider_location = json.loads(volume.provider_location)
image_features = provider_location['saved_features'] image_features = provider_location['saved_features']
except Exception: change_features = self.MULTIATTACH_EXCLUSIONS & image_features
msg = _('Could not find saved image features.') image.update_features(change_features, True)
except IndexError:
msg = "Could not find saved image features."
raise RBDDriverException(reason=msg)
except self.rbd.InvalidArgument:
msg = "Failed to restore image features."
raise RBDDriverException(reason=msg) raise RBDDriverException(reason=msg)
for feature in multipath_feature_exclusions:
if image_features & feature:
image.update_features(feature, True)
return {'provider_location': None} return {'provider_location': None}
def _is_replicated_type(self, volume_type): def _is_replicated_type(self, volume_type):
# We do a safe attribute get because volume_type could be None try:
specs = getattr(volume_type, 'extra_specs', {}) extra_specs = volume_type.extra_specs
return specs.get(EXTRA_SPECS_REPL_ENABLED) == "<is> True" LOG.debug('extra_specs: %s', extra_specs)
return extra_specs.get(EXTRA_SPECS_REPL_ENABLED) == "<is> True"
except Exception:
LOG.debug('Unable to retrieve extra specs info')
return False
def _is_multiattach_type(self, volume_type): def _is_multiattach_type(self, volume_type):
# We do a safe attribute get because volume_type could be None try:
specs = getattr(volume_type, 'extra_specs', {}) extra_specs = volume_type.extra_specs
return specs.get(EXTRA_SPECS_MULTIATTACH) == "<is> True" LOG.debug('extra_specs: %s', extra_specs)
return extra_specs.get(EXTRA_SPECS_MULTIATTACH) == "<is> True"
except Exception:
LOG.debug('Unable to retrieve extra specs info')
return False
def _setup_volume(self, volume, volume_type=None): def _setup_volume(self, volume, volume_type=None):
if volume_type: if volume_type:
had_replication = self._is_replicated_type(volume.volume_type) had_replication = self._is_replicated_type(volume.volume_type)
had_multiattach = self._is_multiattach_type(volume.volume_type) had_multiattach = self._is_multiattach_type(volume.volume_type)
else: else:
had_replication = False had_replication = False
had_multiattach = False had_multiattach = False
volume_type = volume.volume_type volume_type = volume.volume_type
skipping to change at line 1222 skipping to change at line 1237
"""Disable replication on the given volume.""" """Disable replication on the given volume."""
vol_name = utils.convert_str(volume.name) vol_name = utils.convert_str(volume.name)
with RBDVolumeProxy(self, vol_name) as image: with RBDVolumeProxy(self, vol_name) as image:
image.mirror_image_disable(False) image.mirror_image_disable(False)
driver_data = json.loads(volume.replication_driver_data) driver_data = json.loads(volume.replication_driver_data)
# If 'journaling' and/or 'exclusive-lock' have # If 'journaling' and/or 'exclusive-lock' have
# been enabled in '_enable_replication', # been enabled in '_enable_replication',
# they will be disabled here. If not, it will keep # they will be disabled here. If not, it will keep
# what it was before. # what it was before.
if not driver_data['had_journaling']: if not driver_data['had_journaling']:
image.update_features(self.rbd.RBD_FEATURE_JOURNALING, False) image.update_features(self.RBD_FEATURE_JOURNALING, False)
if not driver_data['had_exclusive_lock']: if not driver_data['had_exclusive_lock']:
image.update_features(self.rbd.RBD_FEATURE_EXCLUSIVE_LOCK, image.update_features(self.RBD_FEATURE_EXCLUSIVE_LOCK, False)
False)
return {'replication_status': fields.ReplicationStatus.DISABLED, return {'replication_status': fields.ReplicationStatus.DISABLED,
'replication_driver_data': None} 'replication_driver_data': None}
def retype(self, context, volume, new_type, diff, host): def retype(self, context, volume, new_type, diff, host):
"""Retype from one volume type to another on the same backend.""" """Retype from one volume type to another on the same backend."""
return True, self._setup_volume(volume, new_type) return True, self._setup_volume(volume, new_type)
def _dumps(self, obj): def _dumps(self, obj):
return json.dumps(obj, separators=(',', ':'), sort_keys=True) return json.dumps(obj, separators=(',', ':'), sort_keys=True)
 End of changes. 18 change blocks. 
37 lines changed or deleted 51 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)