[SVF] Support volume-resize to hyperswap volume
[Spectrum Virtualize Family] Added support to extend a volume which is created using hyperswap volume-type template Implements: blueprint ibm-svf-hyperswap-volume-resize-support Change-Id: I19bc034343bc106acb6a217bc5e53c7f60c58ef2
This commit is contained in:
parent
f602a1d00d
commit
e832ddb061
@ -96,7 +96,8 @@ class StorwizeSVCManagementSimulator(object):
|
||||
'lslicense': '',
|
||||
'lsguicapabilities': '',
|
||||
'lshost': '',
|
||||
'lsrcrelationship': ''
|
||||
'lsrcrelationship': '',
|
||||
'expandvdisksize': ''
|
||||
}
|
||||
self._errors = {
|
||||
'CMMVC5701E': ('', 'CMMVC5701E No object ID was specified.'),
|
||||
@ -167,6 +168,14 @@ class StorwizeSVCManagementSimulator(object):
|
||||
'is not in a group.'),
|
||||
'CMMVC9012E': ('', 'CMMVC9012E The copy type differs from other '
|
||||
'copies already in the consistency group.'),
|
||||
'CMMVC9201E': ('', 'CMMVC9201E Task failed because volume has a '
|
||||
'copy that is fully allocated and is part of a '
|
||||
'Metro Mirror or Global Mirror relationship.'),
|
||||
'CMMVC8587E': ('', 'CMMVC8587E The command failed because the '
|
||||
'volume is fast formatting.'),
|
||||
'CMMVC8783E': ('', 'CMMVC8783E The volume copy was not deleted '
|
||||
'because the volume is part of a consistency '
|
||||
'group.'),
|
||||
}
|
||||
self._fc_transitions = {'begin': {'make': 'idle_or_copied'},
|
||||
'idle_or_copied': {'prepare': 'preparing',
|
||||
@ -1037,6 +1046,14 @@ port_speed!N/A
|
||||
if vol_name not in self._volumes_list:
|
||||
return self._errors['CMMVC5753E']
|
||||
|
||||
vol = self._volumes_list[kwargs['obj']]
|
||||
if self._next_cmd_error['expandvdisksize'] == 'fast_formatting':
|
||||
if vol['RC_name']:
|
||||
rcrel = self._rcrelationship_list[vol['RC_name']]
|
||||
if rcrel.get('copy_type', None):
|
||||
return self._errors['CMMVC9201E']
|
||||
return self._errors['CMMVC8587E']
|
||||
|
||||
curr_size = int(self._volumes_list[vol_name]['capacity'])
|
||||
addition = size * units.Gi
|
||||
self._volumes_list[vol_name]['capacity'] = (
|
||||
@ -2964,6 +2981,11 @@ port_speed!N/A
|
||||
return self._errors['CMMVC5701E']
|
||||
vol_name = kwargs['obj'].strip('\'\"')
|
||||
site1_volume_info = self._volumes_list[vol_name]
|
||||
if site1_volume_info['RC_name']:
|
||||
rcrel = self._rcrelationship_list[site1_volume_info['RC_name']]
|
||||
if rcrel.get('consistency_group_name', None):
|
||||
return self._errors['CMMVC8783E']
|
||||
|
||||
site2_volume_info = self._volumes_list['site2' + vol_name]
|
||||
|
||||
del self._rcrelationship_list[self._volumes_list[vol_name]['RC_name']]
|
||||
@ -2985,6 +3007,9 @@ port_speed!N/A
|
||||
del self._fcmappings_list[site2fcmap['id']]
|
||||
|
||||
del site2_volume_info
|
||||
del self._volumes_list['site2' + vol_name]
|
||||
del self._volumes_list['fcsite1' + vol_name]
|
||||
del self._volumes_list['fcsite2' + vol_name]
|
||||
site1_volume_info['RC_name'] = ''
|
||||
site1_volume_info['RC_id'] = ''
|
||||
return ('', '')
|
||||
@ -7643,12 +7668,78 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
'system_id': '0123456789ABCDEF'}
|
||||
get_system_info.return_value = fake_system_info
|
||||
self.driver.do_setup(None)
|
||||
|
||||
hyper_type = self._create_hyperswap_type('test_hyperswap_type')
|
||||
vol = self._create_hyperswap_volume(hyper_type)
|
||||
spec = {'drivers:volume_topology': 'hyperswap',
|
||||
'peer_pool': 'hyperswap2'}
|
||||
vol_type_ref = volume_types.create(self.ctxt, 'test_hyperswap_type',
|
||||
spec)
|
||||
vol = self._create_hyperswap_volume(vol_type_ref)
|
||||
self._assert_vol_exists(vol.name, True)
|
||||
self.assertRaises(exception.InvalidInput,
|
||||
self.driver.extend_volume, vol, '16')
|
||||
|
||||
self.driver.extend_volume(vol, '13')
|
||||
attrs = self.driver._helpers.get_vdisk_attributes(vol['name'])
|
||||
vol_size = int(attrs['capacity']) / units.Gi
|
||||
self.assertAlmostEqual(vol_size, 13)
|
||||
self.driver.delete_volume(vol)
|
||||
|
||||
# Extend hyperswap volume with thick_provisioning_support.
|
||||
spec = {'drivers:volume_topology': 'hyperswap',
|
||||
'peer_pool': 'hyperswap2',
|
||||
'drivers:rsize': -1}
|
||||
hs_thick_type = volume_types.create(
|
||||
self.ctxt, 'test_hyperswap_thick_type', spec)
|
||||
hs_vol = self._create_hyperswap_volume(hs_thick_type)
|
||||
self._assert_vol_exists(hs_vol.name, True)
|
||||
|
||||
if self.USESIM:
|
||||
# tell expandvdisksize to fail while called extend_volume
|
||||
# because volume is fast formatting
|
||||
self.sim.error_injection('expandvdisksize', 'fast_formatting')
|
||||
self.assertRaises(exception.VolumeDriverException,
|
||||
self.driver.extend_volume, hs_vol, 15)
|
||||
attrs = self.driver._helpers.get_vdisk_attributes(hs_vol['name'])
|
||||
vol_size = int(attrs['capacity']) / units.Gi
|
||||
self.assertAlmostEqual(vol_size, 1)
|
||||
self.driver.delete_volume(hs_vol)
|
||||
|
||||
# Extend hyperswap volume that added to group.
|
||||
with mock.patch.object(storwize_svc_common.StorwizeHelpers,
|
||||
'extend_vdisk') as extend_vdisk:
|
||||
group_specs = {'hyperswap_group_enabled': '<is> True'}
|
||||
group_type_ref = group_types.create(self.ctxt, 'testgroup',
|
||||
group_specs)
|
||||
hyper_group = testutils.create_group(
|
||||
self.ctxt, name='hypergroup',
|
||||
group_type_id=group_type_ref['id'],
|
||||
volume_type_ids=[vol_type_ref['id']])
|
||||
model_update = self.driver.create_group(self.ctxt, hyper_group)
|
||||
self.assertEqual(fields.GroupStatus.AVAILABLE,
|
||||
model_update['status'])
|
||||
|
||||
vol = self._create_hyperswap_volume(vol_type_ref)
|
||||
self.db.volume_update(context.get_admin_context(), vol['id'],
|
||||
{'group_id': hyper_group.id})
|
||||
add_volumes = [vol]
|
||||
del_volumes = []
|
||||
|
||||
(model_update, add_volumes_update,
|
||||
remove_volumes_update) = self.driver.update_group(self.ctxt,
|
||||
hyper_group,
|
||||
add_volumes,
|
||||
del_volumes)
|
||||
self.assertEqual(fields.GroupStatus.AVAILABLE,
|
||||
model_update['status'])
|
||||
self.assertEqual([{'id': vol.id, 'group_id': hyper_group.id}],
|
||||
add_volumes_update)
|
||||
self.assertEqual([], remove_volumes_update)
|
||||
|
||||
self.assertRaises(exception.VolumeDriverException,
|
||||
self.driver.extend_volume, vol, 15)
|
||||
|
||||
self.assertFalse(extend_vdisk.called)
|
||||
attrs = self.driver._helpers.get_vdisk_attributes(vol['name'])
|
||||
vol_size = int(attrs['capacity']) / units.Gi
|
||||
self.assertAlmostEqual(vol_size, 1)
|
||||
self.driver.delete_volume(vol)
|
||||
|
||||
def test_migrate_hyperswap_volume(self):
|
||||
with mock.patch.object(storwize_svc_common.StorwizeHelpers,
|
||||
|
@ -1680,7 +1680,8 @@ class StorwizeHelpers(object):
|
||||
params.append('-compressed')
|
||||
else:
|
||||
params.append('-thin')
|
||||
params.extend(['-grainsize', six.text_type(opts['grainsize'])])
|
||||
params.extend(['-grainsize',
|
||||
six.text_type(opts['grainsize'])])
|
||||
return params
|
||||
|
||||
def create_hyperswap_volume(self, vol_name, size, units, pool, opts):
|
||||
@ -1712,11 +1713,32 @@ class StorwizeHelpers(object):
|
||||
pool = attr['mdisk_grp_name']
|
||||
self.check_hyperswap_pool(pool, opts['peer_pool'])
|
||||
hyper_pool = '%s' % opts['peer_pool']
|
||||
is_dr_pool = self.is_volume_type_dr_pools(pool, opts)
|
||||
if is_dr_pool and opts['rsize'] != -1:
|
||||
params = []
|
||||
if opts['rsize'] != -1:
|
||||
is_dr_pool = self.is_volume_type_dr_pools(pool, opts)
|
||||
if is_dr_pool:
|
||||
self.check_data_reduction_pool_params(opts)
|
||||
params = self._get_hyperswap_volume_create_params(opts,
|
||||
is_dr_pool)
|
||||
self.ssh.addvolumecopy(vol_name, hyper_pool, params)
|
||||
|
||||
def convert_extended_volume_to_hyperswap(self, vol_name, opts, state):
|
||||
vol_name = '%s' % vol_name
|
||||
attr = self.get_vdisk_attributes(vol_name)
|
||||
if attr is None:
|
||||
msg = (_('convert_volume_to_hyperswap: Failed to get '
|
||||
'attributes for volume %s.') % vol_name)
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeDriverException(message=msg)
|
||||
hyper_pool = '%s' % opts['peer_pool']
|
||||
params = []
|
||||
if opts['rsize'] != -1:
|
||||
is_dr_pool = self.is_volume_type_dr_pools(attr['mdisk_grp_name'],
|
||||
opts)
|
||||
if is_dr_pool:
|
||||
self.check_data_reduction_pool_params(opts)
|
||||
params = self._get_hyperswap_volume_create_params(opts, is_dr_pool)
|
||||
self.ssh.addvolumecopy(vol_name, hyper_pool, params)
|
||||
self.ssh.addvolumecopy(vol_name, hyper_pool, params)
|
||||
|
||||
def convert_hyperswap_volume_to_normal(self, vol_name, peer_pool):
|
||||
vol_name = '%s' % vol_name
|
||||
@ -3519,11 +3541,6 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
||||
def _extend_volume_op(self, volume, new_size, old_size=None):
|
||||
LOG.debug('enter: _extend_volume_op: volume %s', volume['id'])
|
||||
volume_name = self._get_target_vol(volume)
|
||||
if self.is_volume_hyperswap(volume):
|
||||
msg = _('_extend_volume_op: Extending a hyperswap volume is '
|
||||
'not supported.')
|
||||
LOG.error(msg)
|
||||
raise exception.InvalidInput(message=msg)
|
||||
|
||||
ret = self._helpers.ensure_vdisk_no_fc_mappings(volume_name,
|
||||
allow_snaps=False)
|
||||
@ -3540,51 +3557,84 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
||||
rel_info = self._helpers.get_relationship_info(volume_name)
|
||||
if rel_info:
|
||||
LOG.warning('_extend_volume_op: Extending a volume with '
|
||||
'remote copy is not recommended.')
|
||||
try:
|
||||
rep_type = rel_info['copy_type']
|
||||
cyclingmode = rel_info['cycling_mode']
|
||||
self._master_backend_helpers.delete_relationship(
|
||||
volume.name)
|
||||
tgt_vol = (storwize_const.REPLICA_AUX_VOL_PREFIX +
|
||||
volume.name)
|
||||
self._master_backend_helpers.extend_vdisk(volume.name,
|
||||
extend_amt)
|
||||
self._aux_backend_helpers.extend_vdisk(tgt_vol, extend_amt)
|
||||
tgt_sys = self._aux_backend_helpers.get_system_info()
|
||||
if storwize_const.GMCV_MULTI == cyclingmode:
|
||||
tgt_change_vol = (
|
||||
storwize_const.REPLICA_CHG_VOL_PREFIX +
|
||||
tgt_vol)
|
||||
source_change_vol = (
|
||||
storwize_const.REPLICA_CHG_VOL_PREFIX +
|
||||
volume.name)
|
||||
self._master_backend_helpers.extend_vdisk(
|
||||
source_change_vol, extend_amt)
|
||||
self._aux_backend_helpers.extend_vdisk(
|
||||
tgt_change_vol, extend_amt)
|
||||
src_change_opts = self._get_vdisk_params(
|
||||
volume.volume_type_id)
|
||||
cycle_period_seconds = src_change_opts.get(
|
||||
'cycle_period_seconds')
|
||||
self._master_backend_helpers.create_relationship(
|
||||
volume.name, tgt_vol, tgt_sys.get('system_name'),
|
||||
True, True, source_change_vol, cycle_period_seconds)
|
||||
self._aux_backend_helpers.change_relationship_changevolume(
|
||||
tgt_vol, tgt_change_vol, False)
|
||||
self._master_backend_helpers.start_relationship(
|
||||
volume.name)
|
||||
else:
|
||||
self._master_backend_helpers.create_relationship(
|
||||
volume.name, tgt_vol, tgt_sys.get('system_name'),
|
||||
True if storwize_const.GLOBAL == rep_type else False)
|
||||
except Exception as e:
|
||||
msg = (_('Failed to extend a volume with remote copy '
|
||||
'%(volume)s. Exception: '
|
||||
'%(err)s.') % {'volume': volume.id,
|
||||
'err': e})
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeDriverException(message=msg)
|
||||
'remote copy or with "active-active" relationship is '
|
||||
'not recommended.')
|
||||
rep_type = rel_info['copy_type']
|
||||
cyclingmode = rel_info['cycling_mode']
|
||||
master_helper = self._master_backend_helpers
|
||||
target_helper = self._aux_backend_helpers
|
||||
if rep_type == 'activeactive':
|
||||
hs_opts = self._get_vdisk_params(volume['volume_type_id'],
|
||||
volume_metadata=
|
||||
volume.get(
|
||||
'volume_matadata'))
|
||||
try:
|
||||
master_helper.convert_hyperswap_volume_to_normal(
|
||||
volume_name, hs_opts['peer_pool'])
|
||||
except Exception as e:
|
||||
msg = (_('_extend_volume_op: Failed to convert hyperswap '
|
||||
'volume to normal volume %(volume)s. Exception: '
|
||||
'%(err)s.') % {'volume': volume.id, 'err': e})
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeDriverException(message=msg)
|
||||
|
||||
try:
|
||||
master_helper.extend_vdisk(volume_name, extend_amt)
|
||||
except Exception as e:
|
||||
msg = (_('_extend_volume_op: Failed to extend a hyperswap '
|
||||
'volume %(volume)s. Exception: '
|
||||
'%(err)s.') % {'volume': volume.id, 'err': e})
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeDriverException(message=msg)
|
||||
finally:
|
||||
try:
|
||||
master_helper.convert_extended_volume_to_hyperswap(
|
||||
volume_name, hs_opts, self._state)
|
||||
except Exception as e:
|
||||
msg = (_('_extend_volume_op: Failed to convert volume '
|
||||
'to hyperswap volume %(volume)s. Exception: '
|
||||
'%(err)s.') % {'volume': volume.id, 'err': e})
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeDriverException(message=msg)
|
||||
else:
|
||||
try:
|
||||
master_helper.delete_relationship(volume.name)
|
||||
tgt_vol = (storwize_const.REPLICA_AUX_VOL_PREFIX +
|
||||
volume.name)
|
||||
master_helper.extend_vdisk(volume.name, extend_amt)
|
||||
target_helper.extend_vdisk(tgt_vol, extend_amt)
|
||||
tgt_sys = target_helper.get_system_info()
|
||||
if storwize_const.GMCV_MULTI == cyclingmode:
|
||||
tgt_change_vol = (
|
||||
storwize_const.REPLICA_CHG_VOL_PREFIX +
|
||||
tgt_vol)
|
||||
source_change_vol = (
|
||||
storwize_const.REPLICA_CHG_VOL_PREFIX +
|
||||
volume.name)
|
||||
master_helper.extend_vdisk(source_change_vol,
|
||||
extend_amt)
|
||||
target_helper.extend_vdisk(tgt_change_vol, extend_amt)
|
||||
src_change_opts = self._get_vdisk_params(
|
||||
volume.volume_type_id)
|
||||
cycle_period_seconds = src_change_opts.get(
|
||||
'cycle_period_seconds')
|
||||
master_helper.create_relationship(
|
||||
volume.name, tgt_vol, tgt_sys.get('system_name'),
|
||||
True, True, source_change_vol,
|
||||
cycle_period_seconds)
|
||||
target_helper.change_relationship_changevolume(
|
||||
tgt_vol, tgt_change_vol, False)
|
||||
master_helper.start_relationship(volume.name)
|
||||
else:
|
||||
master_helper.create_relationship(
|
||||
volume.name, tgt_vol, tgt_sys.get('system_name'),
|
||||
True if cyclingmode == 'none' else False)
|
||||
except Exception as e:
|
||||
msg = (_('Failed to extend a volume with remote copy '
|
||||
'%(volume)s. Exception: '
|
||||
'%(err)s.') % {'volume': volume.id, 'err': e})
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeDriverException(message=msg)
|
||||
else:
|
||||
self._helpers.extend_vdisk(volume_name, extend_amt)
|
||||
LOG.debug('leave: _extend_volume_op: volume %s', volume.id)
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
IBM Spectrum Virtualize Family driver: Added volume-extend support for
|
||||
volumes created using a HyperSwap volume-type template.
|
Loading…
Reference in New Issue
Block a user