[SVf] Resize of GMCV volumes in group

[Spectrum Virtualize family] Currently, SVf does not support
extend operation for GMCV volumes which are a part of a
consistency group(CG). Added necessary code changes to
storwize cinder driver to support this operation.

Closes-Bug: #1960314
Change-Id: I9e9dd4f81582ec0d60b64c281f47bd48e907d0ea
This commit is contained in:
sreerammounika 2022-04-11 13:04:57 +00:00
parent 85387cae8b
commit f8f9bfabf9
3 changed files with 220 additions and 68 deletions

View File

@ -2203,7 +2203,7 @@ port_speed!N/A
rcrel_info['status'] = 'online'
rcrel_info['sync'] = ''
rcrel_info['copy_type'] = 'global' if 'global' in kwargs else 'metro'
rcrel_info['cycling_mode'] = cyclingmode if cyclingmode else ''
rcrel_info['cycling_mode'] = cyclingmode if cyclingmode else 'none'
rcrel_info['cycle_period_seconds'] = '300'
rcrel_info['master_change_vdisk_id'] = ''
rcrel_info['master_change_vdisk_name'] = ''
@ -2393,6 +2393,11 @@ port_speed!N/A
return '', ''
def _cmd_chrcconsistgrp(self, **kwargs):
if 'obj' not in kwargs:
return self._errors['CMMVC5701E']
return self._chrcconsistgrp_attr(**kwargs)
def _cmd_rmrcrelationship(self, **kwargs):
if 'obj' not in kwargs:
return self._errors['CMMVC5701E']
@ -2460,6 +2465,22 @@ port_speed!N/A
rcrel['cycling_mode'] = cyclingmode
return ('', '')
def _chrcconsistgrp_attr(self, **kwargs):
if 'obj' not in kwargs:
return self._errors['CMMVC5707E']
id_num = kwargs['obj']
try:
rccg = self._rcconsistgrp_list[id_num]
except KeyError:
return self._errors['CMMVC5753E']
if 'cyclingmode' in kwargs:
cyclingmode = kwargs['cyclingmode'].strip('\'\"')
rccg['cycling_mode'] = cyclingmode
return ('', '')
def _rc_state_transition(self, function, rcrel):
if (function == 'wait' and
'wait' not in self._rc_transitions[rcrel['state']]):
@ -10740,6 +10761,17 @@ class StorwizeSSHTestCase(test.TestCase):
'none')
self.assertIsNone(ret)
def test_ch_rcconsistgrp_cyclingmode(self):
with mock.patch.object(
storwize_svc_common.StorwizeSSH,
'run_ssh_assert_no_output') as run_ssh_assert_no_output:
run_ssh_assert_no_output.return_value = None
ret = self.storwize_ssh.ch_rcconsistgrp_cyclingmode('fake_rccg-1',
'multi')
self.assertIsNone(ret)
ret = self.storwize_ssh.ch_rcconsistgrp_cyclingmode('fake_rccg-1')
self.assertIsNone(ret)
def test_mkvdiskhostmap(self):
# mkvdiskhostmap should not be returning anything
with mock.patch.object(
@ -12085,43 +12117,44 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
self.driver.delete_volume(gmcv_volume)
self._validate_replic_vol_deletion(gmcv_volume)
# Extend gmcv volume that added to group with replication.
def test_storwize_extend_gmcv_volume_part_of_group(self):
"""Extend gmcv volume that added to group with replication."""
# Create group with replication.
group = self._create_test_rccg(self.rccg_type,
[self.gmcv_default_type.id])
rccg_name = self.driver._get_rccg_name(group)
# Create gmcv volume
volume, model_update = self._create_test_volume(
self.gmcv_default_type)
self._validate_replic_vol_creation(volume, True)
rcrel = self.driver._helpers.get_relationship_info(volume.name)
self.sim._rc_state_transition('wait', rcrel)
# Add gmcv volume to group.
add_vols = [volume]
(model_update, add_volumes_update,
remove_volumes_update) = self.driver.update_group(
self.ctxt, group, add_vols, [])
self.assertEqual(
rccg_name,
self.driver._helpers.get_rccg_name_by_volume_name(volume.name))
self.assertEqual(fields.GroupStatus.AVAILABLE,
model_update['status'])
self.assertEqual([{'id': volume.id, 'group_id': group.id}],
add_volumes_update)
self.assertEqual([], remove_volumes_update)
# Extend gmcv volume which is a part of group
self.driver.extend_volume(volume, 2)
attrs = self.driver._helpers.get_vdisk_attributes(volume['name'])
vol_size = int(attrs['capacity']) / units.Gi
self.assertAlmostEqual(vol_size, 2)
with mock.patch.object(storwize_svc_common.StorwizeHelpers,
'extend_vdisk') as extend_vdisk:
# Create group with replication.
group = self._create_test_rccg(self.rccg_type,
[self.gmcv_default_type.id])
rccg_name = self.driver._get_rccg_name(group)
# Create gloabl mirror replication with change volumes.
volume, model_update = self._create_test_volume(
self.gmcv_default_type)
self._validate_replic_vol_creation(volume, True)
rcrel = self.driver._helpers.get_relationship_info(volume.name)
self.sim._rc_state_transition('wait', rcrel)
# Add gmcv volume to group.
add_vols = [volume]
(model_update, add_volumes_update,
remove_volumes_update) = self.driver.update_group(
self.ctxt, group, add_vols, [])
self.assertEqual(
rccg_name,
self.driver._helpers.get_rccg_info(volume.name)['name'])
self.assertEqual(fields.GroupStatus.AVAILABLE,
model_update['status'])
self.assertEqual([{'id': volume.id, 'group_id': group.id}],
add_volumes_update)
self.assertEqual([], remove_volumes_update)
self.driver.extend_volume(volume, 3)
extend_vdisk.assert_called_with(volume.name, 2)
self.assertRaises(exception.VolumeDriverException,
self.driver.extend_volume, volume, 15)
self.assertFalse(extend_vdisk.called)
attrs = self.driver._helpers.get_vdisk_attributes(volume['name'])
vol_size = int(attrs['capacity']) / units.Gi
self.assertAlmostEqual(vol_size, 1)
self.driver.delete_volume(volume)
self._validate_replic_vol_deletion(volume)
self.driver.delete_volume(volume)
self._validate_replic_vol_deletion(volume)
def test_convert_global_mirror_volume_to_gmcv(self):
"""Test volume conversion from global to gmcv."""
@ -12134,9 +12167,9 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
model_update['replication_status'])
self._validate_replic_vol_creation(gm_vol)
rcrel = self.driver._helpers.get_relationship_info(gm_vol.name)
self.assertEqual(rcrel['cycling_mode'], '')
self.assertEqual(rcrel['master_change_vdisk_name'], '')
self.assertEqual(rcrel['aux_change_vdisk_name'], '')
self.assertEqual('none', rcrel['cycling_mode'])
self.assertEqual('', rcrel['master_change_vdisk_name'])
self.assertEqual('', rcrel['aux_change_vdisk_name'])
# Validating volume conversion from global to gmcv by checking a few
# property values of RC relationship
@ -12149,11 +12182,11 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
self.driver._convert_global_mirror_volume_to_gmcv(gm_vol, target_vol,
size)
rcrel = self.driver._helpers.get_relationship_info(gm_vol.name)
self.assertEqual(rcrel['cycling_mode'], 'multi')
self.assertEqual(rcrel['master_change_vdisk_name'],
master_change_vol_name)
self.assertEqual(rcrel['aux_change_vdisk_name'],
aux_change_vol_name)
self.assertEqual('multi', rcrel['cycling_mode'])
self.assertEqual(master_change_vol_name,
rcrel['master_change_vdisk_name'])
self.assertEqual(aux_change_vol_name,
rcrel['aux_change_vdisk_name'])
self.driver.delete_volume(gm_vol)
self._validate_replic_vol_deletion(gm_vol)
@ -12175,6 +12208,82 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
self.driver.delete_volume(gm_vol)
self._validate_replic_vol_deletion(gm_vol)
def test_convert_global_mirror_volume_to_gmcv_part_of_group(self):
"""Test volume conversion from global to gmcv part of group."""
group = self._create_test_rccg(self.rccg_type,
[self.gm_type.id])
rccg_name = self.driver._get_rccg_name(group)
gm_vol, model_update = self._create_test_volume(self.gm_type)
self.assertEqual(fields.ReplicationStatus.ENABLED,
model_update['replication_status'])
self._validate_replic_vol_creation(gm_vol)
add_vols = [gm_vol]
(model_update, add_volumes_update,
remove_volumes_update) = self.driver.update_group(
self.ctxt, group, add_vols, [])
self.assertEqual(
rccg_name,
self.driver._helpers.get_rccg_name_by_volume_name(gm_vol.name))
self.assertEqual(fields.GroupStatus.AVAILABLE,
model_update['status'])
self.assertEqual([{'id': gm_vol.id, 'group_id': group.id}],
add_volumes_update)
self.assertEqual([], remove_volumes_update)
rccg_info = self.driver._helpers.get_rccg(rccg_name)
self.assertEqual('none', rccg_info['cycling_mode'])
rcrel = self.driver._helpers.get_relationship_info(gm_vol.name)
self.assertEqual('', rcrel['master_change_vdisk_name'])
self.assertEqual('', rcrel['aux_change_vdisk_name'])
# Validating volume conversion from global to gmcv by checking a few
# property values of rccg and RC relationship
target_vol = storwize_const.REPLICA_AUX_VOL_PREFIX + gm_vol.name
master_change_vol_name = (
storwize_const.REPLICA_CHG_VOL_PREFIX + gm_vol.name)
aux_change_vol_name = (
storwize_const.REPLICA_CHG_VOL_PREFIX + target_vol)
size = 1
self.driver._convert_global_mirror_volume_to_gmcv(
gm_vol, target_vol, size, rccg_name=rccg_name)
rccg_info = self.driver._helpers.get_rccg_info(gm_vol.name)
self.assertEqual('multi', rccg_info['cycling_mode'])
rcrel = self.driver._helpers.get_relationship_info(gm_vol.name)
self.assertEqual(master_change_vol_name,
rcrel['master_change_vdisk_name'])
self.assertEqual(aux_change_vol_name,
rcrel['aux_change_vdisk_name'])
self.driver.delete_volume(gm_vol)
self._validate_replic_vol_deletion(gm_vol)
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
'start_rccg')
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
'change_consistgrp_cyclingmode')
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
'stop_rccg')
def test_calls_in_convert_global_mirror_volume_to_gmcv_part_of_group(
self, start_rccg, change_consistgrp_cyclingmode, stop_rccg):
# Create global mirror replication.
gm_vol, model_update = self._create_test_volume(self.gm_type)
self.assertEqual(fields.ReplicationStatus.ENABLED,
model_update['replication_status'])
self._validate_replic_vol_creation(gm_vol)
rccg_name = "fake_rccg_1"
with (mock.patch.object(storwize_svc_common.StorwizeHelpers,
'create_vdisk')) as create_vdisk:
target_vol = (
storwize_const.REPLICA_AUX_VOL_PREFIX + gm_vol.name)
size = 1
self.driver._convert_global_mirror_volume_to_gmcv(
gm_vol, target_vol, size, rccg_name=rccg_name)
create_vdisk.assert_called()
self.assertEqual(2, create_vdisk.call_count)
stop_rccg.assert_called_once_with(rccg_name)
change_consistgrp_cyclingmode.assert_called_once_with(rccg_name,
'multi')
start_rccg.assert_called_once_with(rccg_name)
self.driver.delete_volume(gm_vol)
self._validate_replic_vol_deletion(gm_vol)
def test_storwize_manage_existing_mismatch_with_volume_replication(self):
# Set replication target.
self.driver.configuration.set_override('replication_device',

View File

@ -384,16 +384,19 @@ class StorwizeSSH(object):
ssh_cmd.append(rc_rel)
self.run_ssh_assert_no_output(ssh_cmd)
def ch_rcconsistgrp_cyclingmode(self, consistgrp,
cyclingmode='none'):
ssh_cmd = ['svctask', 'chrcconsistgrp',
'-cyclingmode', cyclingmode, consistgrp]
self.run_ssh_assert_no_output(ssh_cmd)
def ch_rcrelationship_cyclingmode(self, relationship,
cyclingmode):
cyclingmode='none'):
# Note: Can only change one attribute at a time,
# so define three ch_rcrelationship_xxx here
if cyclingmode:
ssh_cmd = ['svctask', 'chrcrelationship']
ssh_cmd.extend(['-cyclingmode',
str(cyclingmode)])
ssh_cmd.append(relationship)
self.run_ssh_assert_no_output(ssh_cmd)
ssh_cmd = ['svctask', 'chrcrelationship',
'-cyclingmode', cyclingmode, relationship]
self.run_ssh_assert_no_output(ssh_cmd)
def ch_rcrelationship_cycleperiod(self, relationship,
cycle_period_seconds):
@ -2605,12 +2608,18 @@ class StorwizeHelpers(object):
self.ssh.ch_rcrelationship_cycleperiod(vol_attrs['RC_name'],
cycle_period_seconds)
def change_relationship_cyclingmode(self, volume_name, cyclingmode):
def change_relationship_cyclingmode(self, volume_name,
cyclingmode='none'):
vol_attrs = self.get_vdisk_attributes(volume_name)
if vol_attrs['RC_name'] and cyclingmode:
self.ssh.ch_rcrelationship_cyclingmode(vol_attrs['RC_name'],
cyclingmode)
def change_consistgrp_cyclingmode(self, rccg_name,
cyclingmode='none'):
self.ssh.ch_rcconsistgrp_cyclingmode(rccg_name,
cyclingmode)
def delete_relationship(self, volume_name):
vol_attrs = self.get_vdisk_attributes(volume_name)
if vol_attrs['RC_name']:
@ -4011,11 +4020,20 @@ class StorwizeSVCCommonDriver(san.SanDriver,
target_helper.extend_vdisk(tgt_vol, extend_amt)
master_helper.extend_vdisk(volume.name, extend_amt)
else:
rccg_name = (
self._helpers.get_rccg_name_by_volume_name(
volume.name))
# Update gmcv volume cyclingmode to 'none'
master_helper.stop_relationship(volume.name)
master_helper.change_relationship_cyclingmode(
volume.name, 'none')
master_helper.start_relationship(volume.name)
if rccg_name:
master_helper.stop_rccg(rccg_name)
master_helper.change_consistgrp_cyclingmode(
rccg_name)
master_helper.start_rccg(rccg_name)
else:
master_helper.stop_relationship(volume.name)
master_helper.change_relationship_cyclingmode(
volume.name)
master_helper.start_relationship(volume.name)
tgt_change_vol = (
storwize_const.REPLICA_CHG_VOL_PREFIX + tgt_vol)
@ -4038,7 +4056,7 @@ class StorwizeSVCCommonDriver(san.SanDriver,
# Convert global mirror volume to GMCV volume with
# the new volume-size
self._convert_global_mirror_volume_to_gmcv(
volume, tgt_vol, new_size)
volume, tgt_vol, new_size, rccg_name=rccg_name)
except Exception as e:
msg = (_('Failed to extend a volume with remote copy '
'%(volume)s. Exception: '
@ -4052,7 +4070,8 @@ class StorwizeSVCCommonDriver(san.SanDriver,
# Convert global mirror volume to GMCV volume with
# the current volume-size
self._convert_global_mirror_volume_to_gmcv(
volume, tgt_vol, volume['size'])
volume, tgt_vol, volume['size'],
rccg_name=rccg_name)
LOG.error(msg)
raise exception.VolumeDriverException(message=msg)
@ -4077,7 +4096,8 @@ class StorwizeSVCCommonDriver(san.SanDriver,
context.get_admin_context(),
volume['id'], model_update['metadata'], False)
def _convert_global_mirror_volume_to_gmcv(self, volume, target_vol, size):
def _convert_global_mirror_volume_to_gmcv(self, volume, target_vol, size,
rccg_name=None):
master_helper = self._master_backend_helpers
target_helper = self._aux_backend_helpers
tgt_change_vol = (storwize_const.REPLICA_CHG_VOL_PREFIX + target_vol)
@ -4108,16 +4128,32 @@ class StorwizeSVCCommonDriver(san.SanDriver,
target_helper.create_vdisk(tgt_change_vol, str(int(size)), 'gb',
target_change_pool, target_change_opts)
# Update volume cyclingmode to 'multi'
master_helper.stop_relationship(volume.name)
master_helper.change_relationship_cyclingmode(volume.name, 'multi')
# Set source_change_volume and target_change_volume
master_helper.change_relationship_changevolume(volume.name,
src_change_vol, True)
target_helper.change_relationship_changevolume(target_vol,
tgt_change_vol, False)
# Start gmcv volume relationship
master_helper.start_relationship(volume.name)
if rccg_name:
# Update consistency group cyclingmode to 'multi'
master_helper.stop_rccg(rccg_name)
master_helper.change_consistgrp_cyclingmode(rccg_name, 'multi')
# Set source_change_volume and target_change_volume
master_helper.change_relationship_changevolume(volume.name,
src_change_vol,
True)
target_helper.change_relationship_changevolume(target_vol,
tgt_change_vol,
False)
# Start gmcv consistency group relationship
master_helper.start_rccg(rccg_name)
else:
# Update volume cyclingmode to 'multi'
master_helper.stop_relationship(volume.name)
master_helper.change_relationship_cyclingmode(volume.name, 'multi')
# Set source_change_volume and target_change_volume
master_helper.change_relationship_changevolume(volume.name,
src_change_vol,
True)
target_helper.change_relationship_changevolume(target_vol,
tgt_change_vol,
False)
# Start gmcv volume relationship
master_helper.start_relationship(volume.name)
def _qos_model_update(self, model_update, volume):
"""add volume wwn and IOThrottle_rate to the metadata of the volume"""

View File

@ -0,0 +1,7 @@
---
fixes:
- |
IBM Spectrum Virtualize family driver
`Bug #1960314 <https://bugs.launchpad.net/cinder/+bug/1960314>`_:
Fixed resize issue for GMCV volumes which are a part of
a consistency group(CG).