Merge "VMAX driver - Cannot extend volumes in a replication relationship"
This commit is contained in:
commit
4d58665b69
@ -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,
|
||||||
|
@ -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(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user