[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': '',
|
'lslicense': '',
|
||||||
'lsguicapabilities': '',
|
'lsguicapabilities': '',
|
||||||
'lshost': '',
|
'lshost': '',
|
||||||
'lsrcrelationship': ''
|
'lsrcrelationship': '',
|
||||||
|
'expandvdisksize': ''
|
||||||
}
|
}
|
||||||
self._errors = {
|
self._errors = {
|
||||||
'CMMVC5701E': ('', 'CMMVC5701E No object ID was specified.'),
|
'CMMVC5701E': ('', 'CMMVC5701E No object ID was specified.'),
|
||||||
@ -167,6 +168,14 @@ class StorwizeSVCManagementSimulator(object):
|
|||||||
'is not in a group.'),
|
'is not in a group.'),
|
||||||
'CMMVC9012E': ('', 'CMMVC9012E The copy type differs from other '
|
'CMMVC9012E': ('', 'CMMVC9012E The copy type differs from other '
|
||||||
'copies already in the consistency group.'),
|
'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'},
|
self._fc_transitions = {'begin': {'make': 'idle_or_copied'},
|
||||||
'idle_or_copied': {'prepare': 'preparing',
|
'idle_or_copied': {'prepare': 'preparing',
|
||||||
@ -1037,6 +1046,14 @@ port_speed!N/A
|
|||||||
if vol_name not in self._volumes_list:
|
if vol_name not in self._volumes_list:
|
||||||
return self._errors['CMMVC5753E']
|
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'])
|
curr_size = int(self._volumes_list[vol_name]['capacity'])
|
||||||
addition = size * units.Gi
|
addition = size * units.Gi
|
||||||
self._volumes_list[vol_name]['capacity'] = (
|
self._volumes_list[vol_name]['capacity'] = (
|
||||||
@ -2964,6 +2981,11 @@ port_speed!N/A
|
|||||||
return self._errors['CMMVC5701E']
|
return self._errors['CMMVC5701E']
|
||||||
vol_name = kwargs['obj'].strip('\'\"')
|
vol_name = kwargs['obj'].strip('\'\"')
|
||||||
site1_volume_info = self._volumes_list[vol_name]
|
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]
|
site2_volume_info = self._volumes_list['site2' + vol_name]
|
||||||
|
|
||||||
del self._rcrelationship_list[self._volumes_list[vol_name]['RC_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 self._fcmappings_list[site2fcmap['id']]
|
||||||
|
|
||||||
del site2_volume_info
|
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_name'] = ''
|
||||||
site1_volume_info['RC_id'] = ''
|
site1_volume_info['RC_id'] = ''
|
||||||
return ('', '')
|
return ('', '')
|
||||||
@ -7643,12 +7668,78 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
'system_id': '0123456789ABCDEF'}
|
'system_id': '0123456789ABCDEF'}
|
||||||
get_system_info.return_value = fake_system_info
|
get_system_info.return_value = fake_system_info
|
||||||
self.driver.do_setup(None)
|
self.driver.do_setup(None)
|
||||||
|
spec = {'drivers:volume_topology': 'hyperswap',
|
||||||
hyper_type = self._create_hyperswap_type('test_hyperswap_type')
|
'peer_pool': 'hyperswap2'}
|
||||||
vol = self._create_hyperswap_volume(hyper_type)
|
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._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):
|
def test_migrate_hyperswap_volume(self):
|
||||||
with mock.patch.object(storwize_svc_common.StorwizeHelpers,
|
with mock.patch.object(storwize_svc_common.StorwizeHelpers,
|
||||||
|
@ -1680,7 +1680,8 @@ class StorwizeHelpers(object):
|
|||||||
params.append('-compressed')
|
params.append('-compressed')
|
||||||
else:
|
else:
|
||||||
params.append('-thin')
|
params.append('-thin')
|
||||||
params.extend(['-grainsize', six.text_type(opts['grainsize'])])
|
params.extend(['-grainsize',
|
||||||
|
six.text_type(opts['grainsize'])])
|
||||||
return params
|
return params
|
||||||
|
|
||||||
def create_hyperswap_volume(self, vol_name, size, units, pool, opts):
|
def create_hyperswap_volume(self, vol_name, size, units, pool, opts):
|
||||||
@ -1712,8 +1713,29 @@ class StorwizeHelpers(object):
|
|||||||
pool = attr['mdisk_grp_name']
|
pool = attr['mdisk_grp_name']
|
||||||
self.check_hyperswap_pool(pool, opts['peer_pool'])
|
self.check_hyperswap_pool(pool, opts['peer_pool'])
|
||||||
hyper_pool = '%s' % opts['peer_pool']
|
hyper_pool = '%s' % opts['peer_pool']
|
||||||
|
params = []
|
||||||
|
if opts['rsize'] != -1:
|
||||||
is_dr_pool = self.is_volume_type_dr_pools(pool, opts)
|
is_dr_pool = self.is_volume_type_dr_pools(pool, opts)
|
||||||
if is_dr_pool and opts['rsize'] != -1:
|
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)
|
self.check_data_reduction_pool_params(opts)
|
||||||
params = self._get_hyperswap_volume_create_params(opts, is_dr_pool)
|
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)
|
||||||
@ -3519,11 +3541,6 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
def _extend_volume_op(self, volume, new_size, old_size=None):
|
def _extend_volume_op(self, volume, new_size, old_size=None):
|
||||||
LOG.debug('enter: _extend_volume_op: volume %s', volume['id'])
|
LOG.debug('enter: _extend_volume_op: volume %s', volume['id'])
|
||||||
volume_name = self._get_target_vol(volume)
|
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,
|
ret = self._helpers.ensure_vdisk_no_fc_mappings(volume_name,
|
||||||
allow_snaps=False)
|
allow_snaps=False)
|
||||||
@ -3540,18 +3557,53 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
rel_info = self._helpers.get_relationship_info(volume_name)
|
rel_info = self._helpers.get_relationship_info(volume_name)
|
||||||
if rel_info:
|
if rel_info:
|
||||||
LOG.warning('_extend_volume_op: Extending a volume with '
|
LOG.warning('_extend_volume_op: Extending a volume with '
|
||||||
'remote copy is not recommended.')
|
'remote copy or with "active-active" relationship is '
|
||||||
try:
|
'not recommended.')
|
||||||
rep_type = rel_info['copy_type']
|
rep_type = rel_info['copy_type']
|
||||||
cyclingmode = rel_info['cycling_mode']
|
cyclingmode = rel_info['cycling_mode']
|
||||||
self._master_backend_helpers.delete_relationship(
|
master_helper = self._master_backend_helpers
|
||||||
volume.name)
|
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 +
|
tgt_vol = (storwize_const.REPLICA_AUX_VOL_PREFIX +
|
||||||
volume.name)
|
volume.name)
|
||||||
self._master_backend_helpers.extend_vdisk(volume.name,
|
master_helper.extend_vdisk(volume.name, extend_amt)
|
||||||
extend_amt)
|
target_helper.extend_vdisk(tgt_vol, extend_amt)
|
||||||
self._aux_backend_helpers.extend_vdisk(tgt_vol, extend_amt)
|
tgt_sys = target_helper.get_system_info()
|
||||||
tgt_sys = self._aux_backend_helpers.get_system_info()
|
|
||||||
if storwize_const.GMCV_MULTI == cyclingmode:
|
if storwize_const.GMCV_MULTI == cyclingmode:
|
||||||
tgt_change_vol = (
|
tgt_change_vol = (
|
||||||
storwize_const.REPLICA_CHG_VOL_PREFIX +
|
storwize_const.REPLICA_CHG_VOL_PREFIX +
|
||||||
@ -3559,30 +3611,28 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
source_change_vol = (
|
source_change_vol = (
|
||||||
storwize_const.REPLICA_CHG_VOL_PREFIX +
|
storwize_const.REPLICA_CHG_VOL_PREFIX +
|
||||||
volume.name)
|
volume.name)
|
||||||
self._master_backend_helpers.extend_vdisk(
|
master_helper.extend_vdisk(source_change_vol,
|
||||||
source_change_vol, extend_amt)
|
extend_amt)
|
||||||
self._aux_backend_helpers.extend_vdisk(
|
target_helper.extend_vdisk(tgt_change_vol, extend_amt)
|
||||||
tgt_change_vol, extend_amt)
|
|
||||||
src_change_opts = self._get_vdisk_params(
|
src_change_opts = self._get_vdisk_params(
|
||||||
volume.volume_type_id)
|
volume.volume_type_id)
|
||||||
cycle_period_seconds = src_change_opts.get(
|
cycle_period_seconds = src_change_opts.get(
|
||||||
'cycle_period_seconds')
|
'cycle_period_seconds')
|
||||||
self._master_backend_helpers.create_relationship(
|
master_helper.create_relationship(
|
||||||
volume.name, tgt_vol, tgt_sys.get('system_name'),
|
volume.name, tgt_vol, tgt_sys.get('system_name'),
|
||||||
True, True, source_change_vol, cycle_period_seconds)
|
True, True, source_change_vol,
|
||||||
self._aux_backend_helpers.change_relationship_changevolume(
|
cycle_period_seconds)
|
||||||
|
target_helper.change_relationship_changevolume(
|
||||||
tgt_vol, tgt_change_vol, False)
|
tgt_vol, tgt_change_vol, False)
|
||||||
self._master_backend_helpers.start_relationship(
|
master_helper.start_relationship(volume.name)
|
||||||
volume.name)
|
|
||||||
else:
|
else:
|
||||||
self._master_backend_helpers.create_relationship(
|
master_helper.create_relationship(
|
||||||
volume.name, tgt_vol, tgt_sys.get('system_name'),
|
volume.name, tgt_vol, tgt_sys.get('system_name'),
|
||||||
True if storwize_const.GLOBAL == rep_type else False)
|
True if cyclingmode == 'none' else False)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = (_('Failed to extend a volume with remote copy '
|
msg = (_('Failed to extend a volume with remote copy '
|
||||||
'%(volume)s. Exception: '
|
'%(volume)s. Exception: '
|
||||||
'%(err)s.') % {'volume': volume.id,
|
'%(err)s.') % {'volume': volume.id, 'err': e})
|
||||||
'err': e})
|
|
||||||
LOG.error(msg)
|
LOG.error(msg)
|
||||||
raise exception.VolumeDriverException(message=msg)
|
raise exception.VolumeDriverException(message=msg)
|
||||||
else:
|
else:
|
||||||
|
@ -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