Merge "VMAX driver - Cannot extend volumes in a replication relationship"

This commit is contained in:
Zuul 2018-01-12 05:56:21 +00:00 committed by Gerrit Code Review
commit 4d58665b69
2 changed files with 81 additions and 48 deletions

View File

@ -3372,9 +3372,10 @@ class VMAXCommonTest(test.TestCase):
self.common._unmap_lun.assert_called_once_with( self.common._unmap_lun.assert_called_once_with(
volume, connector) volume, connector)
@mock.patch.object(rest.VMAXRest, 'is_next_gen_array', return_value=True)
@mock.patch.object(common.VMAXCommon, '_sync_check') @mock.patch.object(common.VMAXCommon, '_sync_check')
@mock.patch.object(provision.VMAXProvision, 'extend_volume') @mock.patch.object(provision.VMAXProvision, 'extend_volume')
def test_extend_volume_success(self, mock_extend, mock_sync): def test_extend_volume_success(self, mock_extend, mock_sync, mock_newgen):
volume = self.data.test_volume volume = self.data.test_volume
array = self.data.array array = self.data.array
device_id = self.data.device_id device_id = self.data.device_id
@ -3382,7 +3383,13 @@ class VMAXCommonTest(test.TestCase):
ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set) ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
ref_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f ref_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
with mock.patch.object(self.rest, 'is_vol_in_rep_session', with mock.patch.object(self.rest, 'is_vol_in_rep_session',
return_value=(False, False, None)): side_effect=[(False, False, None),
(False, True, None)]):
self.common.extend_volume(volume, new_size)
mock_extend.assert_called_once_with(
array, device_id, new_size, ref_extra_specs)
# Success, with snapshot, on new VMAX array
mock_extend.reset_mock()
self.common.extend_volume(volume, new_size) self.common.extend_volume(volume, new_size)
mock_extend.assert_called_once_with( mock_extend.assert_called_once_with(
array, device_id, new_size, ref_extra_specs) array, device_id, new_size, ref_extra_specs)
@ -6194,15 +6201,15 @@ class VMAXCommonReplicationTest(test.TestCase):
self.data.test_volume, self.data.connector) self.data.test_volume, self.data.connector)
mock_es.assert_called_once_with(extra_specs, rep_config) mock_es.assert_called_once_with(extra_specs, rep_config)
@mock.patch.object(rest.VMAXRest, 'is_vol_in_rep_session',
return_value=(False, False, None))
@mock.patch.object(common.VMAXCommon, 'extend_volume_is_replicated')
@mock.patch.object(common.VMAXCommon, '_sync_check') @mock.patch.object(common.VMAXCommon, '_sync_check')
def test_extend_volume_rep_enabled(self, mock_sync): def test_extend_volume_rep_enabled(self, mock_sync, mock_ex_re,
mock_is_re):
extra_specs = deepcopy(self.extra_specs) extra_specs = deepcopy(self.extra_specs)
extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
volume_name = self.data.test_volume.name volume_name = self.data.test_volume.name
with mock.patch.object(self.rest, 'is_vol_in_rep_session',
return_value=(False, False, None)):
with mock.patch.object(
self.common, 'extend_volume_is_replicated') as mock_ex_re:
self.common.extend_volume(self.data.test_volume, '5') self.common.extend_volume(self.data.test_volume, '5')
mock_ex_re.assert_called_once_with( mock_ex_re.assert_called_once_with(
self.data.array, self.data.test_volume, self.data.array, self.data.test_volume,
@ -6475,6 +6482,15 @@ class VMAXCommonReplicationTest(test.TestCase):
'vol1', '5', self.data.extra_specs_rep_enabled) 'vol1', '5', self.data.extra_specs_rep_enabled)
self.assertEqual(2, mock_remove.call_count) self.assertEqual(2, mock_remove.call_count)
self.assertEqual(2, mock_extend.call_count) self.assertEqual(2, mock_extend.call_count)
mock_remove.reset_mock()
mock_extend.reset_mock()
with mock.patch.object(self.rest, 'is_next_gen_array',
return_value=True):
self.common.extend_volume_is_replicated(
self.data.array, self.data.test_volume, self.data.device_id,
'vol1', '5', self.data.extra_specs_rep_enabled)
mock_remove.assert_not_called()
self.assertEqual(2, mock_extend.call_count)
def test_extend_volume_is_replicated_exception(self): def test_extend_volume_is_replicated_exception(self):
self.assertRaises(exception.VolumeBackendAPIException, self.assertRaises(exception.VolumeBackendAPIException,

View File

@ -683,12 +683,15 @@ class VMAXCommon(object):
raise exception.VolumeBackendAPIException(data=exception_message) raise exception.VolumeBackendAPIException(data=exception_message)
__, snapvx_src, __ = self.rest.is_vol_in_rep_session(array, device_id) __, snapvx_src, __ = self.rest.is_vol_in_rep_session(array, device_id)
if snapvx_src: if snapvx_src:
if not self.rest.is_next_gen_array(array):
exception_message = ( exception_message = (
_("The volume: %(volume)s is a snapshot source. Extending a " _("The volume: %(volume)s is a snapshot source. "
"volume with snapVx snapshots is not supported. Exiting...") "Extending a volume with snapVx snapshots is only "
% {'volume': volume_name}) "supported on VMAX from HyperMaxOS version 5978 "
"onwards. Exiting...") % {'volume': volume_name})
LOG.error(exception_message) LOG.error(exception_message)
raise exception.VolumeBackendAPIException(data=exception_message) raise exception.VolumeBackendAPIException(
data=exception_message)
if int(original_vol_size) > int(new_size): if int(original_vol_size) > int(new_size):
exception_message = (_( exception_message = (_(
@ -2605,22 +2608,31 @@ class VMAXCommon(object):
:param new_size: the new size the volume should be :param new_size: the new size the volume should be
:param extra_specs: extra specifications :param extra_specs: extra specifications
""" """
if self.extend_replicated_vol is True: ode_replication = False
if self.utils.is_replication_enabled(extra_specs):
if self.rest.is_next_gen_array(array):
# Check if remote array is next gen
__, remote_array = self.get_rdf_details(array)
if self.rest.is_next_gen_array(remote_array):
ode_replication = True
if self.extend_replicated_vol is True or ode_replication is True:
try: try:
(target_device, remote_array, rdf_group, (target_device, remote_array, rdf_group,
local_vol_state, pair_state) = ( local_vol_state, pair_state) = (
self.get_remote_target_device(array, volume, device_id)) self.get_remote_target_device(
array, volume, device_id))
rep_extra_specs = self._get_replication_extra_specs(
extra_specs, self.rep_config)
if not ode_replication:
# Volume must be removed from replication (storage) group # Volume must be removed from replication (storage) group
# before the replication relationship can be ended (cannot # before the replication relationship can be ended (cannot
# have a mix of replicated and non-replicated volumes as # have a mix of replicated and non-replicated volumes as
# the SRDF groups become unmanageable). # the SRDF groups become unmanageable).
self.masking.remove_and_reset_members( self.masking.remove_and_reset_members(
array, volume, device_id, volume_name, extra_specs, False) array, volume, device_id, volume_name,
extra_specs, False)
# Repeat on target side # Repeat on target side
rep_extra_specs = self._get_replication_extra_specs(
extra_specs, self.rep_config)
self.masking.remove_and_reset_members( self.masking.remove_and_reset_members(
remote_array, volume, target_device, volume_name, remote_array, volume, target_device, volume_name,
rep_extra_specs, False) rep_extra_specs, False)
@ -2630,16 +2642,21 @@ class VMAXCommon(object):
array, device_id, target_device, array, device_id, target_device,
rdf_group, rep_extra_specs, pair_state) rdf_group, rep_extra_specs, pair_state)
# Extend the target volume
LOG.info("Extending target volume...")
# Check to make sure the R2 device requires extending first...
r2_size = self.rest.get_size_of_device_on_array(
remote_array, target_device)
if int(r2_size) < int(new_size):
self.provision.extend_volume(remote_array, target_device,
new_size, rep_extra_specs)
# Extend the source volume # Extend the source volume
LOG.info("Extending source volume...") LOG.info("Extending source volume...")
self.provision.extend_volume( self.provision.extend_volume(
array, device_id, new_size, extra_specs) array, device_id, new_size, extra_specs)
# Extend the target volume if not ode_replication:
LOG.info("Extending target volume...")
self.provision.extend_volume(
remote_array, target_device, new_size, rep_extra_specs)
# Re-create replication relationship # Re-create replication relationship
LOG.info("Recreating replication relationship...") LOG.info("Recreating replication relationship...")
self.setup_volume_replication( self.setup_volume_replication(