[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:
parent
85387cae8b
commit
f8f9bfabf9
@ -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',
|
||||
|
@ -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"""
|
||||
|
@ -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).
|
Loading…
Reference in New Issue
Block a user