Merge "VMAX driver - Errors extending replicated volumes"

This commit is contained in:
Zuul 2018-01-17 16:56:46 +00:00 committed by Gerrit Code Review
commit 2f23983353
3 changed files with 55 additions and 37 deletions
cinder
tests/unit/volume/drivers/dell_emc/vmax
volume/drivers/dell_emc/vmax

@ -3072,10 +3072,17 @@ class VMAXProvisionTest(test.TestCase):
device_id = self.data.device_id
new_size = '3'
extra_specs = self.data.extra_specs
with mock.patch.object(self.provision.rest, 'extend_volume'):
with mock.patch.object(self.provision.rest, 'extend_volume'
) as mock_ex:
self.provision.extend_volume(array, device_id, new_size,
extra_specs)
self.provision.rest.extend_volume.assert_called_once_with(
mock_ex.assert_called_once_with(
array, device_id, new_size, extra_specs)
mock_ex.reset_mock()
# Pass in rdf group
self.provision.extend_volume(array, device_id, new_size,
extra_specs, self.data.rdf_group_no)
mock_ex.assert_called_once_with(
array, device_id, new_size, extra_specs)
def test_get_srp_pool_stats(self):
@ -3167,6 +3174,15 @@ class VMAXProvisionTest(test.TestCase):
target_device = self.data.device_id2
rdf_group_name = self.data.rdf_group_name
rep_extra_specs = self.data.rep_extra_specs
# State is suspended
self.provision.break_rdf_relationship(
array, device_id, target_device,
rdf_group_name, rep_extra_specs, "Suspended")
mock_mod.assert_not_called()
mock_del.assert_called_once_with(
array, device_id, rdf_group_name)
mock_del.reset_mock()
# State is synchronized
self.provision.break_rdf_relationship(
array, device_id, target_device,
rdf_group_name, rep_extra_specs, "Synchronized")

@ -2931,9 +2931,9 @@ class VMAXCommon(object):
"""Extend a replication-enabled volume.
Cannot extend volumes in a synchronization pair where the source
and/or target arrays are running HyperMax versions < 5978, or for
Metro-enabled volumes. Must first break the relationship, extend
them separately, then recreate the pair.
and/or target arrays are running HyperMax versions < 5978. Must first
break the relationship, extend them separately, then recreate the
pair. Extending Metro protected volumes is not supported.
:param array: the array serial number
:param volume: the volume objcet
:param device_id: the volume device id
@ -2949,8 +2949,7 @@ class VMAXCommon(object):
__, remote_array = self.get_rdf_details(array)
if self.rest.is_next_gen_array(remote_array):
ode_replication = True
if (self.utils.is_metro_device(self.rep_config, extra_specs)
and not self.allow_delete_metro):
if self.utils.is_metro_device(self.rep_config, extra_specs):
allow_extend = False
if allow_extend is True or ode_replication is True:
try:
@ -2960,18 +2959,16 @@ class VMAXCommon(object):
array, volume, device_id))
rep_extra_specs = self._get_replication_extra_specs(
extra_specs, self.rep_config)
lock_rdf_group = rdf_group
if not ode_replication:
# Volume must be removed from replication (storage) group
# before the replication relationship can be ended (cannot
# have a mix of replicated and non-replicated volumes as
# the SRDF groups become unmanageable), but
# leave the vol in metro management group for now
metro_grp = self.utils.get_async_rdf_managed_grp_name(
self.rep_config) if self.utils.is_metro_device(
self.rep_config, rep_extra_specs) else None
# the SRDF groups become unmanageable)
lock_rdf_group = None
self.masking.remove_and_reset_members(
array, volume, device_id, volume_name,
extra_specs, False, async_grp=metro_grp)
extra_specs, False)
# Repeat on target side
self.masking.remove_and_reset_members(
@ -2979,17 +2976,9 @@ class VMAXCommon(object):
rep_extra_specs, False)
LOG.info("Breaking replication relationship...")
if self.utils.is_metro_device(
self.rep_config, rep_extra_specs):
rep_extra_specs['allow_del_metro'] = (
self.allow_delete_metro)
self._cleanup_metro_target(
array, device_id, target_device,
rdf_group, rep_extra_specs)
else:
self.provision.break_rdf_relationship(
array, device_id, target_device, rdf_group,
rep_extra_specs, pair_state)
self.provision.break_rdf_relationship(
array, device_id, target_device, rdf_group,
rep_extra_specs, pair_state)
# Extend the target volume
LOG.info("Extending target volume...")
@ -2997,13 +2986,14 @@ class VMAXCommon(object):
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)
self.provision.extend_volume(
remote_array, target_device, new_size,
rep_extra_specs, lock_rdf_group)
# Extend the source volume
LOG.info("Extending source volume...")
self.provision.extend_volume(
array, device_id, new_size, extra_specs)
array, device_id, new_size, extra_specs, lock_rdf_group)
if not ode_replication:
# Re-create replication relationship
@ -3026,9 +3016,9 @@ class VMAXCommon(object):
else:
exception_message = (_(
"Extending a replicated volume is not "
"permitted on this backend. Please contact "
"your administrator."))
"Extending a replicated volume is not permitted on this "
"backend. Please contact your administrator. Note that "
"you cannot extend SRDF/Metro protected volumes."))
LOG.error(exception_message)
raise exception.VolumeBackendAPIException(data=exception_message)

@ -344,20 +344,29 @@ class VMAXProvision(object):
list_volume_pairs=list_device_pairs)
self.delete_volume_snap(array, snap_name, source_devices)
def extend_volume(self, array, device_id, new_size, extra_specs):
def extend_volume(self, array, device_id, new_size, extra_specs,
rdf_group=None):
"""Extend a volume.
:param array: the array serial number
:param device_id: the volume device id
:param new_size: the new size (GB)
:param extra_specs: the extra specifications
:param rdf_group: the rdf group number, if required
:returns: status_code
"""
start_time = time.time()
self.rest.extend_volume(array, device_id, new_size, extra_specs)
LOG.debug("Extend VMAX volume took: %(delta)s H:MM:SS.",
{'delta': self.utils.get_time_delta(start_time,
time.time())})
if rdf_group:
@coordination.synchronized('emc-rg-{rdf_group}')
def _extend_replicated_volume(rdf_group):
self.rest.extend_volume(array, device_id,
new_size, extra_specs)
_extend_replicated_volume(rdf_group)
else:
self.rest.extend_volume(array, device_id, new_size, extra_specs)
LOG.debug("Extend VMAX volume took: %(delta)s H:MM:SS.",
{'delta': self.utils.get_time_delta(start_time,
time.time())})
def get_srp_pool_stats(self, array, array_info):
"""Get the srp capacity stats.
@ -495,8 +504,11 @@ class VMAXProvision(object):
self.rest.wait_for_rdf_consistent_state(
array, device_id, target_device,
rep_extra_specs, state)
self.rest.modify_rdf_device_pair(
array, device_id, rdf_group, rep_extra_specs, suspend=True)
if state.lower() == utils.RDF_SUSPENDED_STATE:
LOG.info("RDF pair is already suspended")
else:
self.rest.modify_rdf_device_pair(
array, device_id, rdf_group, rep_extra_specs, suspend=True)
self.delete_rdf_pair(array, device_id, rdf_group,
target_device, rep_extra_specs)