"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py" between
cinder-17.0.1.tar.gz and cinder-17.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 "Victoria" series (latest release).

storwize_svc_common.py  (cinder-17.0.1):storwize_svc_common.py  (cinder-17.1.0)
skipping to change at line 756 skipping to change at line 756
# 'type': to indicate the type of this value. # 'type': to indicate the type of this value.
WAIT_TIME = 5 WAIT_TIME = 5
svc_qos_keys = {'IOThrottling': {'default': '0', svc_qos_keys = {'IOThrottling': {'default': '0',
'param': 'rate', 'param': 'rate',
'type': int}} 'type': int}}
def __init__(self, run_ssh): def __init__(self, run_ssh):
self.ssh = StorwizeSSH(run_ssh) self.ssh = StorwizeSSH(run_ssh)
self.check_fcmapping_interval = 3 self.check_fcmapping_interval = 3
self.code_level = None self.code_level = None
self.stats = {}
@staticmethod @staticmethod
def handle_keyerror(cmd, out): def handle_keyerror(cmd, out):
msg = (_('Could not find key in output of command %(cmd)s: %(out)s.') msg = (_('Could not find key in output of command %(cmd)s: %(out)s.')
% {'out': out, 'cmd': cmd}) % {'out': out, 'cmd': cmd})
raise exception.VolumeBackendAPIException(data=msg) raise exception.VolumeBackendAPIException(data=msg)
def compression_enabled(self): def compression_enabled(self):
"""Return whether or not compression is enabled for this system.""" """Return whether or not compression is enabled for this system."""
resp = self.ssh.lslicense() resp = self.ssh.lslicense()
skipping to change at line 825 skipping to change at line 826
"""Return attributes for the specified pool.""" """Return attributes for the specified pool."""
return self.ssh.lsmdiskgrp(pool) return self.ssh.lsmdiskgrp(pool)
def is_pool_defined(self, pool_name): def is_pool_defined(self, pool_name):
"""Check if vdisk is defined.""" """Check if vdisk is defined."""
attrs = self.get_pool_attrs(pool_name) attrs = self.get_pool_attrs(pool_name)
return attrs is not None return attrs is not None
def is_data_reduction_pool(self, pool_name): def is_data_reduction_pool(self, pool_name):
"""Check if pool is data reduction pool.""" """Check if pool is data reduction pool."""
# Check pool is data reduction pool or not from pool information
# saved in stats.
for pool in self.stats.get('pools', []):
if pool['pool_name'] == pool_name:
return pool['data_reduction']
pool_data = self.get_pool_attrs(pool_name) pool_data = self.get_pool_attrs(pool_name)
if (pool_data and 'data_reduction' in pool_data and if (pool_data and 'data_reduction' in pool_data and
pool_data['data_reduction'] == 'yes'): pool_data['data_reduction'] == 'yes'):
return True return True
return False return False
def get_pool_volumes(self, pool): def get_pool_volumes(self, pool):
"""Return volumes for the specified pool.""" """Return volumes for the specified pool."""
vdisks = self.ssh.lsvdisks_from_filter('mdisk_grp_name', pool) vdisks = self.ssh.lsvdisks_from_filter('mdisk_grp_name', pool)
return vdisks.result return vdisks.result
skipping to change at line 2069 skipping to change at line 2076
"Exception: %(ex)s.", {'fcmap': fc_map_id, "Exception: %(ex)s.", {'fcmap': fc_map_id,
'ex': ex}) 'ex': ex})
return None return None
def _get_flashcopy_consistgrp_attr(self, fc_map_id): def _get_flashcopy_consistgrp_attr(self, fc_map_id):
resp = self.ssh.lsfcconsistgrp(fc_map_id) resp = self.ssh.lsfcconsistgrp(fc_map_id)
if not len(resp): if not len(resp):
return None return None
return resp[0] return resp[0]
def _check_vdisk_fc_mappings(self, name, @cinder_utils.trace
allow_snaps=True, allow_fctgt=False): def _check_delete_vdisk_fc_mappings(self, name, allow_snaps=True,
allow_fctgt=False):
"""FlashCopy mapping check helper.""" """FlashCopy mapping check helper."""
LOG.debug('Loopcall: _check_vdisk_fc_mappings(), vdisk %s.', name)
mapping_ids = self._get_vdisk_fc_mappings(name) mapping_ids = self._get_vdisk_fc_mappings(name)
wait_for_copy = False wait_for_copy = False
for map_id in mapping_ids: for map_id in mapping_ids:
attrs = self._get_flashcopy_mapping_attributes(map_id) attrs = self._get_flashcopy_mapping_attributes(map_id)
# We should ignore GMCV flash copies # We should ignore GMCV flash copies
# Hyperswap flash copies are also ignored. # Hyperswap flash copies are also ignored.
if not attrs or 'yes' == attrs['rc_controlled']: if not attrs or 'yes' == attrs['rc_controlled']:
continue continue
source = attrs['source_vdisk_name'] source = attrs['source_vdisk_name']
target = attrs['target_vdisk_name'] target = attrs['target_vdisk_name']
copy_rate = attrs['copy_rate'] copy_rate = attrs['copy_rate']
status = attrs['status'] status = attrs['status']
progress = attrs['progress']
LOG.debug('Loopcall: source: %s, target: %s, copy_rate: %s, '
'status: %s, progress: %s, mapid: %s', source, target,
copy_rate, status, progress, map_id)
if allow_fctgt and target == name and status == 'copying': if allow_fctgt and target == name and status == 'copying':
self.ssh.stopfcmap(map_id) try:
attrs = self._get_flashcopy_mapping_attributes(map_id) self.ssh.stopfcmap(map_id)
except exception.VolumeBackendAPIException as ex:
LOG.warning(ex)
wait_for_copy = True
try:
attrs = self._get_flashcopy_mapping_attributes(map_id)
except exception.VolumeBackendAPIException as ex:
LOG.warning(ex)
wait_for_copy = True
continue
if attrs: if attrs:
status = attrs['status'] status = attrs['status']
else: else:
continue continue
if copy_rate == '0': if copy_rate == '0':
if source == name: if source == name:
# Vdisk with snapshots. Return False if snapshot # Vdisk with snapshots. Return False if snapshot
# not allowed. # not allowed.
if not allow_snaps: if not allow_snaps:
skipping to change at line 2110 skipping to change at line 2130
self.ssh.chfcmap(map_id, copyrate='50', autodel='on') self.ssh.chfcmap(map_id, copyrate='50', autodel='on')
wait_for_copy = True wait_for_copy = True
else: else:
# A snapshot # A snapshot
if target != name: if target != name:
msg = (_('Vdisk %(name)s not involved in ' msg = (_('Vdisk %(name)s not involved in '
'mapping %(src)s -> %(tgt)s.') % 'mapping %(src)s -> %(tgt)s.') %
{'name': name, 'src': source, 'tgt': target}) {'name': name, 'src': source, 'tgt': target})
LOG.error(msg) LOG.error(msg)
raise exception.VolumeDriverException(message=msg) raise exception.VolumeDriverException(message=msg)
if status in ['copying', 'prepared']: try:
self.ssh.stopfcmap(map_id) if status in ['copying', 'prepared']:
# Need to wait for the fcmap to change to self.ssh.stopfcmap(map_id)
# stopped state before remove fcmap # Need to wait for the fcmap to change to
wait_for_copy = True # stopped state before remove fcmap
elif status in ['stopping', 'preparing']: wait_for_copy = True
elif status in ['stopping', 'preparing']:
wait_for_copy = True
else:
self.ssh.rmfcmap(map_id)
except exception.VolumeBackendAPIException as ex:
LOG.warning(ex)
wait_for_copy = True wait_for_copy = True
else:
self.ssh.rmfcmap(map_id)
# Case 4: Copy in progress - wait and will autodelete # Case 4: Copy in progress - wait and will autodelete
else: else:
if status == 'prepared': try:
self.ssh.stopfcmap(map_id) if status == 'prepared':
self.ssh.rmfcmap(map_id) self.ssh.stopfcmap(map_id)
elif status in ['idle_or_copied', 'stopped']: self.ssh.rmfcmap(map_id)
# Prepare failed or stopped elif status in ['idle_or_copied', 'stopped']:
self.ssh.rmfcmap(map_id) # Prepare failed or stopped
else: self.ssh.rmfcmap(map_id)
elif (status in ['copying', 'prepared'] and
progress == '100'):
self.ssh.stopfcmap(map_id)
else:
wait_for_copy = True
except exception.VolumeBackendAPIException as ex:
LOG.warning(ex)
wait_for_copy = True wait_for_copy = True
if not wait_for_copy or not len(mapping_ids): if not wait_for_copy or not len(mapping_ids):
raise loopingcall.LoopingCallDone(retvalue=True) raise loopingcall.LoopingCallDone(retvalue=True)
@cinder_utils.trace
def _check_vdisk_fc_mappings(self, name, allow_snaps=True,
allow_fctgt=False):
"""FlashCopy mapping check helper."""
# if this is a remove disk we need to be down to one fc clone
mapping_ids = self._get_vdisk_fc_mappings(name)
if len(mapping_ids) > 1 and allow_fctgt:
LOG.debug('Loopcall: vdisk %s has '
'more than one fc map. Waiting.', name)
for map_id in mapping_ids:
attrs = self._get_flashcopy_mapping_attributes(map_id)
if not attrs:
continue
source = attrs['source_vdisk_name']
target = attrs['target_vdisk_name']
copy_rate = attrs['copy_rate']
status = attrs['status']
progress = attrs['progress']
LOG.debug('Loopcall: source: %s, target: %s, copy_rate: %s, '
'status: %s, progress: %s, mapid: %s',
source, target, copy_rate, status, progress, map_id)
if copy_rate != '0' and source == name:
try:
if status in ['copying'] and progress == '100':
self.ssh.stopfcmap(map_id)
elif status == 'idle_or_copied' and progress == '100':
# wait for auto-delete of fcmap.
continue
elif status in ['idle_or_copied', 'stopped']:
# Prepare failed or stopped
self.ssh.rmfcmap(map_id)
# handle VolumeBackendAPIException to let it go through
# next attempts in case of any cli exception.
except exception.VolumeBackendAPIException as ex:
LOG.warning(ex)
return
return self._check_delete_vdisk_fc_mappings(
name, allow_snaps=allow_snaps, allow_fctgt=allow_fctgt)
def ensure_vdisk_no_fc_mappings(self, name, allow_snaps=True, def ensure_vdisk_no_fc_mappings(self, name, allow_snaps=True,
allow_fctgt=False): allow_fctgt=False):
"""Ensure vdisk has no flashcopy mappings.""" """Ensure vdisk has no flashcopy mappings."""
timer = loopingcall.FixedIntervalLoopingCall( timer = loopingcall.FixedIntervalLoopingCall(
self._check_vdisk_fc_mappings, name, self._check_vdisk_fc_mappings, name,
allow_snaps, allow_fctgt) allow_snaps, allow_fctgt)
# Create a timer greenthread. The default volume service heart # Create a timer greenthread. The default volume service heart
# beat is every 10 seconds. The flashcopy usually takes hours # beat is every 10 seconds. The flashcopy usually takes hours
# before it finishes. Don't set the sleep interval shorter # before it finishes. Don't set the sleep interval shorter
# than the heartbeat. Otherwise volume service heartbeat # than the heartbeat. Otherwise volume service heartbeat
skipping to change at line 2584 skipping to change at line 2656
if status in ['copying', 'prepared'] and target == name: if status in ['copying', 'prepared'] and target == name:
if copy_rate != '0' and progress != '100': if copy_rate != '0' and progress != '100':
msg = (_('Cannot start revert since fcmap %(map_id)s ' msg = (_('Cannot start revert since fcmap %(map_id)s '
'in progress, current progress is %(progress)s') 'in progress, current progress is %(progress)s')
% {'map_id': map_id, 'progress': progress}) % {'map_id': map_id, 'progress': progress})
LOG.error(msg) LOG.error(msg)
raise exception.VolumeDriverException(message=msg) raise exception.VolumeDriverException(message=msg)
elif copy_rate != '0' and progress == '100': elif copy_rate != '0' and progress == '100':
LOG.debug('Split completed clone map_id=%(map_id)s fcmap', LOG.debug('Split completed clone map_id=%(map_id)s fcmap',
{'map_id': map_id}) {'map_id': map_id})
self.ssh.stopfcmap(map_id, split=True) self.ssh.stopfcmap(map_id)
class CLIResponse(object): class CLIResponse(object):
"""Parse SVC CLI output and generate iterable.""" """Parse SVC CLI output and generate iterable."""
def __init__(self, raw, ssh_cmd=None, delim='!', with_header=True): def __init__(self, raw, ssh_cmd=None, delim='!', with_header=True):
super(CLIResponse, self).__init__() super(CLIResponse, self).__init__()
if ssh_cmd: if ssh_cmd:
self.ssh_cmd = ' '.join(ssh_cmd) self.ssh_cmd = ' '.join(ssh_cmd)
else: else:
self.ssh_cmd = 'None' self.ssh_cmd = 'None'
skipping to change at line 2776 skipping to change at line 2848
# This boolean is used to indicate whether replication is supported # This boolean is used to indicate whether replication is supported
# by this storage. # by this storage.
self._replica_enabled = False self._replica_enabled = False
# This list is used to save the supported replication modes. # This list is used to save the supported replication modes.
self._supported_replica_types = [] self._supported_replica_types = []
# This is used to save the available pools in failed-over status # This is used to save the available pools in failed-over status
self._secondary_pools = None self._secondary_pools = None
# This dictionary is used to save pools information.
self._stats = {}
# Storwize has the limitation that can not burst more than 3 new ssh # Storwize has the limitation that can not burst more than 3 new ssh
# connections within 1 second. So slow down the initialization. # connections within 1 second. So slow down the initialization.
time.sleep(1) time.sleep(1)
def do_setup(self, ctxt): def do_setup(self, ctxt):
"""Check that we have all configuration details from the storage.""" """Check that we have all configuration details from the storage."""
LOG.debug('enter: do_setup') LOG.debug('enter: do_setup')
# v2.1 replication setup # v2.1 replication setup
self._get_storwize_config() self._get_storwize_config()
# Validate that the pool exists # Validate that the pool exists
self._validate_pools_exist() self._validate_pools_exist()
# Get list of all volumes # Get list of all volumes
self._get_all_volumes() self._get_all_volumes()
# Update the pool stats
self._update_volume_stats()
# Save the pool stats information in helpers class.
self._master_backend_helpers.stats = self._stats
# Build the list of in-progress vdisk copy operations # Build the list of in-progress vdisk copy operations
if ctxt is None: if ctxt is None:
admin_context = context.get_admin_context() admin_context = context.get_admin_context()
else: else:
admin_context = ctxt.elevated() admin_context = ctxt.elevated()
volumes = objects.VolumeList.get_all_by_host(admin_context, self.host) volumes = objects.VolumeList.get_all_by_host(admin_context, self.host)
for volume in volumes: for volume in volumes:
metadata = volume.admin_metadata metadata = volume.admin_metadata
curr_ops = metadata.get('vdiskcopyops', None) curr_ops = metadata.get('vdiskcopyops', None)
skipping to change at line 3581 skipping to change at line 3662
volumes_update.extend(rep_vols_in_grp_update) volumes_update.extend(rep_vols_in_grp_update)
bypass_volumes_update = self._bypass_volume_process(bypass_volumes) bypass_volumes_update = self._bypass_volume_process(bypass_volumes)
volumes_update.extend(bypass_volumes_update) volumes_update.extend(bypass_volumes_update)
self._helpers = self._master_backend_helpers self._helpers = self._master_backend_helpers
self._active_backend_id = None self._active_backend_id = None
self._state = self._master_state self._state = self._master_state
self._update_volume_stats() self._update_volume_stats()
self._master_backend_helpers.stats = self._stats
return storwize_const.FAILBACK_VALUE, volumes_update, groups_update return storwize_const.FAILBACK_VALUE, volumes_update, groups_update
def _failback_replica_volumes(self, ctxt, rep_volumes): def _failback_replica_volumes(self, ctxt, rep_volumes):
LOG.debug('enter: _failback_replica_volumes') LOG.debug('enter: _failback_replica_volumes')
volumes_update = [] volumes_update = []
for volume in rep_volumes: for volume in rep_volumes:
rep_type = self._get_volume_replicated_type(ctxt, volume) rep_type = self._get_volume_replicated_type(ctxt, volume)
replica_obj = self._get_replica_obj(rep_type) replica_obj = self._get_replica_obj(rep_type)
tgt_volume = storwize_const.REPLICA_AUX_VOL_PREFIX + volume['name'] tgt_volume = storwize_const.REPLICA_AUX_VOL_PREFIX + volume['name']
skipping to change at line 3830 skipping to change at line 3913
bypass_volumes_update = self._bypass_volume_process(bypass_volumes) bypass_volumes_update = self._bypass_volume_process(bypass_volumes)
volumes_update.extend(bypass_volumes_update) volumes_update.extend(bypass_volumes_update)
self._helpers = self._aux_backend_helpers self._helpers = self._aux_backend_helpers
self._active_backend_id = self._replica_target['backend_id'] self._active_backend_id = self._replica_target['backend_id']
self._secondary_pools = [self._replica_target['pool_name']] self._secondary_pools = [self._replica_target['pool_name']]
self._state = self._aux_state self._state = self._aux_state
self._update_volume_stats() self._update_volume_stats()
self._aux_backend_helpers.stats = self._stats
return self._active_backend_id, volumes_update, groups_update return self._active_backend_id, volumes_update, groups_update
def _failover_replica_volumes(self, ctxt, rep_volumes): def _failover_replica_volumes(self, ctxt, rep_volumes):
LOG.debug('enter: _failover_replica_volumes') LOG.debug('enter: _failover_replica_volumes')
volumes_update = [] volumes_update = []
for volume in rep_volumes: for volume in rep_volumes:
rep_type = self._get_volume_replicated_type(ctxt, volume) rep_type = self._get_volume_replicated_type(ctxt, volume)
replica_obj = self._get_replica_obj(rep_type) replica_obj = self._get_replica_obj(rep_type)
# Try do the fail-over. # Try do the fail-over.
skipping to change at line 5630 skipping to change at line 5715
data['replication'] = self._replica_enabled data['replication'] = self._replica_enabled
data['replication_enabled'] = self._replica_enabled data['replication_enabled'] = self._replica_enabled
data['replication_targets'] = self._get_replication_targets() data['replication_targets'] = self._get_replication_targets()
data['consistent_group_replication_enabled'] = True data['consistent_group_replication_enabled'] = True
self._stats = data self._stats = data
def _build_pool_stats(self, pool): def _build_pool_stats(self, pool):
"""Build pool status""" """Build pool status"""
QoS_support = True QoS_support = True
pool_stats = {} pool_stats = {}
is_dr_pool = False
pool_data = self._helpers.get_pool_attrs(pool) pool_data = self._helpers.get_pool_attrs(pool)
if pool_data: if pool_data:
easy_tier = pool_data['easy_tier'] in ['on', 'auto'] easy_tier = pool_data['easy_tier'] in ['on', 'auto']
total_capacity_gb = float(pool_data['capacity']) / units.Gi total_capacity_gb = float(pool_data['capacity']) / units.Gi
free_capacity_gb = float(pool_data['free_capacity']) / units.Gi free_capacity_gb = float(pool_data['free_capacity']) / units.Gi
allocated_capacity_gb = (float(pool_data['used_capacity']) / allocated_capacity_gb = (float(pool_data['used_capacity']) /
units.Gi) units.Gi)
provisioned_capacity_gb = float( provisioned_capacity_gb = float(
pool_data['virtual_capacity']) / units.Gi pool_data['virtual_capacity']) / units.Gi
skipping to change at line 5653 skipping to change at line 5739
use_thick_provisioning = rsize == -1 or rsize == 100 use_thick_provisioning = rsize == -1 or rsize == 100
over_sub_ratio = self.configuration.safe_get( over_sub_ratio = self.configuration.safe_get(
'max_over_subscription_ratio') 'max_over_subscription_ratio')
location_info = ('StorwizeSVCDriver:%(sys_id)s:%(pool)s' % location_info = ('StorwizeSVCDriver:%(sys_id)s:%(pool)s' %
{'sys_id': self._state['system_id'], {'sys_id': self._state['system_id'],
'pool': pool_data['name']}) 'pool': pool_data['name']})
multiattach = (self.configuration. multiattach = (self.configuration.
storwize_svc_multihostmap_enabled) storwize_svc_multihostmap_enabled)
backend_state = ('up' if pool_data['status'] == 'online' else backend_state = ('up' if pool_data['status'] == 'online' else
'down') 'down')
# Get the data_reduction information for pool and set
# is_dr_pool flag.
if pool_data.get('data_reduction') == 'Yes':
is_dr_pool = True
elif pool_data.get('data_reduction') == 'No':
is_dr_pool = False
pool_stats = { pool_stats = {
'pool_name': pool_data['name'], 'pool_name': pool_data['name'],
'total_capacity_gb': total_capacity_gb, 'total_capacity_gb': total_capacity_gb,
'free_capacity_gb': free_capacity_gb, 'free_capacity_gb': free_capacity_gb,
'allocated_capacity_gb': allocated_capacity_gb, 'allocated_capacity_gb': allocated_capacity_gb,
'provisioned_capacity_gb': provisioned_capacity_gb, 'provisioned_capacity_gb': provisioned_capacity_gb,
'compression_support': self._state['compression_enabled'], 'compression_support': self._state['compression_enabled'],
'reserved_percentage': 'reserved_percentage':
self.configuration.reserved_percentage, self.configuration.reserved_percentage,
'QoS_support': QoS_support, 'QoS_support': QoS_support,
'consistencygroup_support': True, 'consistencygroup_support': True,
'location_info': location_info, 'location_info': location_info,
'easytier_support': easy_tier, 'easytier_support': easy_tier,
'multiattach': multiattach, 'multiattach': multiattach,
'thin_provisioning_support': not use_thick_provisioning, 'thin_provisioning_support': not use_thick_provisioning,
'thick_provisioning_support': use_thick_provisioning, 'thick_provisioning_support': use_thick_provisioning,
'max_over_subscription_ratio': over_sub_ratio, 'max_over_subscription_ratio': over_sub_ratio,
'consistent_group_snapshot_enabled': True, 'consistent_group_snapshot_enabled': True,
'backend_state': backend_state, 'backend_state': backend_state,
'data_reduction': is_dr_pool,
} }
if self._replica_enabled: if self._replica_enabled:
pool_stats.update({ pool_stats.update({
'replication_enabled': self._replica_enabled, 'replication_enabled': self._replica_enabled,
'replication_type': self._supported_replica_types, 'replication_type': self._supported_replica_types,
'replication_targets': self._get_replication_targets(), 'replication_targets': self._get_replication_targets(),
'replication_count': len(self._get_replication_targets()), 'replication_count': len(self._get_replication_targets()),
'consistent_group_replication_enabled': True 'consistent_group_replication_enabled': True
}) })
skipping to change at line 5693 skipping to change at line 5788
LOG.error('Failed getting details for pool %s.', pool) LOG.error('Failed getting details for pool %s.', pool)
pool_stats = {'pool_name': pool, pool_stats = {'pool_name': pool,
'total_capacity_gb': 0, 'total_capacity_gb': 0,
'free_capacity_gb': 0, 'free_capacity_gb': 0,
'allocated_capacity_gb': 0, 'allocated_capacity_gb': 0,
'provisioned_capacity_gb': 0, 'provisioned_capacity_gb': 0,
'thin_provisioning_support': True, 'thin_provisioning_support': True,
'thick_provisioning_support': False, 'thick_provisioning_support': False,
'max_over_subscription_ratio': 0, 'max_over_subscription_ratio': 0,
'reserved_percentage': 0, 'reserved_percentage': 0,
'data_reduction': is_dr_pool,
'backend_state': 'down'} 'backend_state': 'down'}
return pool_stats return pool_stats
def _get_replication_targets(self): def _get_replication_targets(self):
return [self._replica_target['backend_id']] return [self._replica_target['backend_id']]
def _manage_input_check(self, ref): def _manage_input_check(self, ref):
"""Verify the input of manage function.""" """Verify the input of manage function."""
# Check that the reference is valid # Check that the reference is valid
 End of changes. 21 change blocks. 
21 lines changed or deleted 117 lines changed or added

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