PowerMax Driver - retype attached replication fix
Fixes for retyping attached volumes when moving from
non-replicated to replication enabled volume type.
Cases fixed:
-Retype to metro replication with existing pairs.
-Retype to non-replicated after retyping to metro.
-Retype to asynchronous replication with existing pairs present.
-Delete attached volume with asynchronous replication after
attaching to an instance.
Change-Id: Ibbf04dedade6e85649ec702574ce51ce82fc8733
Closes-Bug: #1851371
(cherry picked from commit 49b941b83a
)
This commit is contained in:
parent
89bf1d2188
commit
ad1b2d32a5
|
@ -296,6 +296,8 @@ class PowerMaxData(object):
|
||||||
rep_extra_specs4['rdf_group_label'] = rdf_group_name
|
rep_extra_specs4['rdf_group_label'] = rdf_group_name
|
||||||
rep_extra_specs5 = deepcopy(rep_extra_specs2)
|
rep_extra_specs5 = deepcopy(rep_extra_specs2)
|
||||||
rep_extra_specs5['target_array_model'] = 'VMAX250F'
|
rep_extra_specs5['target_array_model'] = 'VMAX250F'
|
||||||
|
rep_extra_specs6 = deepcopy(rep_extra_specs3)
|
||||||
|
rep_extra_specs6['target_array_model'] = 'PMAX2000'
|
||||||
|
|
||||||
rep_extra_specs_ode = deepcopy(rep_extra_specs2)
|
rep_extra_specs_ode = deepcopy(rep_extra_specs2)
|
||||||
rep_extra_specs_ode['array'] = array
|
rep_extra_specs_ode['array'] = array
|
||||||
|
|
|
@ -1514,11 +1514,12 @@ class PowerMaxCommonTest(test.TestCase):
|
||||||
mck_add_sg_to_sg.assert_called()
|
mck_add_sg_to_sg.assert_called()
|
||||||
self.assertTrue(success)
|
self.assertTrue(success)
|
||||||
|
|
||||||
@mock.patch.object(
|
@mock.patch.object(provision.PowerMaxProvision, 'create_storage_group',
|
||||||
rest.PowerMaxRest, 'get_volume',
|
return_value=None)
|
||||||
return_value=tpd.PowerMaxData.volume_details_attached)
|
@mock.patch.object(rest.PowerMaxRest, 'get_volume',
|
||||||
|
return_value=tpd.PowerMaxData.volume_details_attached)
|
||||||
@mock.patch.object(rest.PowerMaxRest, 'get_storage_group',
|
@mock.patch.object(rest.PowerMaxRest, 'get_storage_group',
|
||||||
return_value=tpd.PowerMaxData.sg_details[1])
|
side_effect=[tpd.PowerMaxData.sg_details[1], None])
|
||||||
@mock.patch.object(utils.PowerMaxUtils, 'get_child_sg_name',
|
@mock.patch.object(utils.PowerMaxUtils, 'get_child_sg_name',
|
||||||
return_value=('OS-Test-SG', '', '', ''))
|
return_value=('OS-Test-SG', '', '', ''))
|
||||||
@mock.patch.object(rest.PowerMaxRest, 'is_child_sg_in_parent_sg',
|
@mock.patch.object(rest.PowerMaxRest, 'is_child_sg_in_parent_sg',
|
||||||
|
@ -1529,7 +1530,7 @@ class PowerMaxCommonTest(test.TestCase):
|
||||||
return_value=False)
|
return_value=False)
|
||||||
def test_retype_inuse_volume_fail(self, mck_vol_in_sg, mck_sg_move,
|
def test_retype_inuse_volume_fail(self, mck_vol_in_sg, mck_sg_move,
|
||||||
mck_child_sg_in_sg, mck_get_sg_name,
|
mck_child_sg_in_sg, mck_get_sg_name,
|
||||||
mck_get_sg, mck_get_vol):
|
mck_get_sg, mck_get_vol, mck_create_sg):
|
||||||
array = self.data.array
|
array = self.data.array
|
||||||
srp = self.data.srp
|
srp = self.data.srp
|
||||||
slo = self.data.slo
|
slo = self.data.slo
|
||||||
|
@ -1688,8 +1689,13 @@ class PowerMaxCommonTest(test.TestCase):
|
||||||
return_value=True)
|
return_value=True)
|
||||||
@mock.patch.object(common.PowerMaxCommon, 'get_volume_metadata',
|
@mock.patch.object(common.PowerMaxCommon, 'get_volume_metadata',
|
||||||
return_value='')
|
return_value='')
|
||||||
def test_migrate_in_use_volume(self, mck_meta, mck_remote_retype,
|
@mock.patch.object(utils.PowerMaxUtils, 'get_async_rdf_managed_grp_name')
|
||||||
mck_setup, mck_retype, mck_cleanup):
|
@mock.patch.object(rest.PowerMaxRest, 'get_storage_group',
|
||||||
|
return_value=True)
|
||||||
|
@mock.patch.object(masking.PowerMaxMasking, 'add_volume_to_storage_group')
|
||||||
|
def test_migrate_in_use_volume(
|
||||||
|
self, mck_add_vol, mck_get_sg, mck_get_rdf_name, mck_meta,
|
||||||
|
mck_remote_retype, mck_setup, mck_retype, mck_cleanup):
|
||||||
# Array/Volume info
|
# Array/Volume info
|
||||||
array = self.data.array
|
array = self.data.array
|
||||||
srp = self.data.srp
|
srp = self.data.srp
|
||||||
|
@ -1752,6 +1758,8 @@ class PowerMaxCommonTest(test.TestCase):
|
||||||
# Scenario 3: no_rep => rep
|
# Scenario 3: no_rep => rep
|
||||||
with mock.patch.object(self.utils, 'is_replication_enabled',
|
with mock.patch.object(self.utils, 'is_replication_enabled',
|
||||||
side_effect=[False, True]):
|
side_effect=[False, True]):
|
||||||
|
tgt_extra_specs['rep_mode'] = utils.REP_METRO
|
||||||
|
self.common.rep_config['mode'] = utils.REP_METRO
|
||||||
success = self.common._migrate_volume(
|
success = self.common._migrate_volume(
|
||||||
array, volume, device_id, srp, slo, workload, volume_name,
|
array, volume, device_id, srp, slo, workload, volume_name,
|
||||||
new_type, src_extra_specs)[0]
|
new_type, src_extra_specs)[0]
|
||||||
|
@ -1763,6 +1771,9 @@ class PowerMaxCommonTest(test.TestCase):
|
||||||
mck_retype.assert_called_once_with(
|
mck_retype.assert_called_once_with(
|
||||||
array, srp, volume, device_id, src_extra_specs, slo,
|
array, srp, volume, device_id, src_extra_specs, slo,
|
||||||
workload, tgt_extra_specs, False)
|
workload, tgt_extra_specs, False)
|
||||||
|
mck_add_vol.assert_called_once()
|
||||||
|
mck_get_sg.assert_called_once()
|
||||||
|
mck_get_rdf_name.assert_called_once()
|
||||||
mck_cleanup.assert_not_called()
|
mck_cleanup.assert_not_called()
|
||||||
mck_remote_retype.assert_not_called()
|
mck_remote_retype.assert_not_called()
|
||||||
self.assertTrue(success)
|
self.assertTrue(success)
|
||||||
|
@ -1778,7 +1789,7 @@ class PowerMaxCommonTest(test.TestCase):
|
||||||
array, srp, volume, device_id, src_extra_specs, slo, workload,
|
array, srp, volume, device_id, src_extra_specs, slo, workload,
|
||||||
tgt_extra_specs, False)
|
tgt_extra_specs, False)
|
||||||
mck_remote_retype.assert_called_once_with(
|
mck_remote_retype.assert_called_once_with(
|
||||||
array, volume, device_id, volume_name, rep_mode, True,
|
array, volume, device_id, volume_name, utils.REP_METRO, True,
|
||||||
tgt_extra_specs)
|
tgt_extra_specs)
|
||||||
mck_cleanup.assert_not_called()
|
mck_cleanup.assert_not_called()
|
||||||
mck_setup.assert_not_called()
|
mck_setup.assert_not_called()
|
||||||
|
|
|
@ -32,6 +32,7 @@ from cinder.volume.drivers.dell_emc.powermax import common
|
||||||
from cinder.volume.drivers.dell_emc.powermax import fc
|
from cinder.volume.drivers.dell_emc.powermax import fc
|
||||||
from cinder.volume.drivers.dell_emc.powermax import iscsi
|
from cinder.volume.drivers.dell_emc.powermax import iscsi
|
||||||
from cinder.volume.drivers.dell_emc.powermax import masking
|
from cinder.volume.drivers.dell_emc.powermax import masking
|
||||||
|
from cinder.volume.drivers.dell_emc.powermax import metadata
|
||||||
from cinder.volume.drivers.dell_emc.powermax import provision
|
from cinder.volume.drivers.dell_emc.powermax import provision
|
||||||
from cinder.volume.drivers.dell_emc.powermax import rest
|
from cinder.volume.drivers.dell_emc.powermax import rest
|
||||||
from cinder.volume.drivers.dell_emc.powermax import utils
|
from cinder.volume.drivers.dell_emc.powermax import utils
|
||||||
|
@ -238,6 +239,7 @@ class PowerMaxReplicationTest(test.TestCase):
|
||||||
def test_unmap_lun_volume_failed_over(self, mock_fo, mock_es, mock_rm):
|
def test_unmap_lun_volume_failed_over(self, mock_fo, mock_es, mock_rm):
|
||||||
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
|
||||||
|
extra_specs[utils.IS_RE] = True
|
||||||
rep_config = self.utils.get_replication_config(
|
rep_config = self.utils.get_replication_config(
|
||||||
[self.replication_device])
|
[self.replication_device])
|
||||||
self.common._unmap_lun(self.data.test_volume, self.data.connector)
|
self.common._unmap_lun(self.data.test_volume, self.data.connector)
|
||||||
|
@ -399,32 +401,71 @@ class PowerMaxReplicationTest(test.TestCase):
|
||||||
'device_id': self.data.device_id2}, rep_data)
|
'device_id': self.data.device_id2}, rep_data)
|
||||||
mock_create.assert_not_called()
|
mock_create.assert_not_called()
|
||||||
|
|
||||||
@mock.patch.object(common.PowerMaxCommon, 'get_rdf_details',
|
@mock.patch.object(rest.PowerMaxRest, 'get_rdf_group', return_value={
|
||||||
return_value=(tpd.PowerMaxData.rdf_group_no,
|
'numDevices': 1})
|
||||||
tpd.PowerMaxData.remote_array))
|
@mock.patch.object(rest.PowerMaxRest, 'get_size_of_device_on_array')
|
||||||
@mock.patch.object(rest.PowerMaxRest, 'get_size_of_device_on_array',
|
|
||||||
return_value=2)
|
|
||||||
@mock.patch.object(common.PowerMaxCommon, '_get_replication_extra_specs',
|
@mock.patch.object(common.PowerMaxCommon, '_get_replication_extra_specs',
|
||||||
return_value=tpd.PowerMaxData.rep_extra_specs5)
|
return_value=tpd.PowerMaxData.rep_extra_specs6)
|
||||||
@mock.patch.object(common.PowerMaxCommon, '_create_volume',
|
@mock.patch.object(common.PowerMaxCommon, '_create_volume', return_value={
|
||||||
return_value=tpd.PowerMaxData.provider_location)
|
'device_id': tpd.PowerMaxData.device_id2})
|
||||||
|
@mock.patch.object(rest.PowerMaxRest, 'get_storage_group',
|
||||||
|
return_value=None)
|
||||||
|
@mock.patch.object(rest.PowerMaxRest, 'create_storage_group')
|
||||||
|
@mock.patch.object(masking.PowerMaxMasking, 'add_volume_to_storage_group')
|
||||||
@mock.patch.object(common.PowerMaxCommon, '_sync_check')
|
@mock.patch.object(common.PowerMaxCommon, '_sync_check')
|
||||||
@mock.patch.object(rest.PowerMaxRest, 'create_rdf_device_pair',
|
@mock.patch.object(rest.PowerMaxRest, 'create_rdf_device_pair',
|
||||||
return_value=tpd.PowerMaxData.rdf_group_details)
|
return_value={'rdf_dict'})
|
||||||
def test_setup_inuse_volume_replication(self, mck_create_rdf_pair,
|
@mock.patch.object(metadata.PowerMaxVolumeMetadata,
|
||||||
mck_sync_chk, mck_create_vol,
|
'gather_replication_info',
|
||||||
mck_rep_specs, mck_get_vol_size,
|
return_value={'rep_info_dict'})
|
||||||
mck_get_rdf_info):
|
def test_setup_inuse_volume_replication(
|
||||||
|
self, mck_gather_rep_info, mck_create_rdf_pair, mck_sync_check,
|
||||||
|
mck_add_vol_to_sg, mck_create_sg, mck_get_sg, mck_create_vol,
|
||||||
|
mck_get_rep_specs, mck_get_size, mck_get_rdf_grp):
|
||||||
array = self.data.array
|
array = self.data.array
|
||||||
device_id = self.data.device_id
|
|
||||||
volume = self.data.test_attached_volume
|
volume = self.data.test_attached_volume
|
||||||
extra_specs = self.data.extra_specs_migrate
|
volume_id = volume.id
|
||||||
self.rep_config = self.data.rep_extra_specs4
|
target_name = self.common.utils.get_volume_element_name(volume_id)
|
||||||
rep_status, rep_data, __ = (
|
target_device_id = tpd.PowerMaxData.device_id2
|
||||||
|
device_id = self.data.device_id
|
||||||
|
extra_specs = self.data.extra_specs_rep_enabled
|
||||||
|
self.common.rep_config['mode'] = utils.REP_METRO
|
||||||
|
rdf_group_no, remote_array = self.common.get_rdf_details(array)
|
||||||
|
rep_extra_specs = self.common._get_replication_extra_specs(
|
||||||
|
extra_specs, self.common.rep_config)
|
||||||
|
async_sg = self.common.utils.get_async_rdf_managed_grp_name(
|
||||||
|
self.common.rep_config)
|
||||||
|
status, driver_data, info_dict = (
|
||||||
self.common.setup_inuse_volume_replication(
|
self.common.setup_inuse_volume_replication(
|
||||||
array, volume, device_id, extra_specs))
|
array, volume, device_id, extra_specs))
|
||||||
self.assertEqual('enabled', rep_status)
|
self.assertEqual(status, common.REPLICATION_ENABLED)
|
||||||
self.assertEqual(self.data.rdf_group_details, rep_data)
|
self.assertEqual(driver_data, {'rdf_dict'})
|
||||||
|
self.assertEqual(info_dict, {'rep_info_dict'})
|
||||||
|
mck_get_rdf_grp.assert_called_with(array, rdf_group_no)
|
||||||
|
mck_get_size.assert_called_once_with(array, device_id)
|
||||||
|
mck_get_rep_specs.assert_called_with(
|
||||||
|
extra_specs, self.common.rep_config)
|
||||||
|
mck_create_vol.assert_called_once()
|
||||||
|
mck_get_sg.assert_called_once_with(remote_array, async_sg)
|
||||||
|
mck_create_sg.assert_called_once_with(
|
||||||
|
remote_array, async_sg, extra_specs['srp'], extra_specs['slo'],
|
||||||
|
extra_specs['workload'], rep_extra_specs)
|
||||||
|
mck_sync_check.assert_called_once_with(array, device_id, extra_specs,
|
||||||
|
tgt_only=True)
|
||||||
|
mck_add_vol_to_sg.assert_called_once_with(
|
||||||
|
remote_array, target_device_id, async_sg, target_name,
|
||||||
|
rep_extra_specs, True)
|
||||||
|
mck_create_rdf_pair.assert_called_once_with(
|
||||||
|
array, device_id, rdf_group_no, target_device_id, remote_array,
|
||||||
|
extra_specs)
|
||||||
|
mck_gather_rep_info.assert_called_with(
|
||||||
|
volume_id, 'replication', False, rdf_group_no=rdf_group_no,
|
||||||
|
target_name=target_name, remote_array=remote_array,
|
||||||
|
target_device_id=target_device_id,
|
||||||
|
replication_status=common.REPLICATION_ENABLED,
|
||||||
|
rep_mode=rep_extra_specs['rep_mode'],
|
||||||
|
rdf_group_label=self.common.rep_config['rdf_group_label'],
|
||||||
|
target_array_model=rep_extra_specs['target_array_model'])
|
||||||
|
|
||||||
@mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
|
@mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
|
||||||
return_value=('VMAX250F', False))
|
return_value=('VMAX250F', False))
|
||||||
|
|
|
@ -451,14 +451,24 @@ class PowerMaxUtilsTest(test.TestCase):
|
||||||
def test_get_child_sg_name(self):
|
def test_get_child_sg_name(self):
|
||||||
host_name = 'HostX'
|
host_name = 'HostX'
|
||||||
# Slo and rep enabled
|
# Slo and rep enabled
|
||||||
extra_specs1 = self.data.extra_specs_rep_enabled
|
extra_specs1 = {
|
||||||
extra_specs1[utils.PORTGROUPNAME] = self.data.port_group_name_f
|
'pool_name': u'Diamond+DSS+SRP_1+000197800123',
|
||||||
|
'slo': 'Diamond',
|
||||||
|
'workload': 'DSS',
|
||||||
|
'srp': 'SRP_1',
|
||||||
|
'array': self.data.array,
|
||||||
|
'interval': 3,
|
||||||
|
'retries': 120,
|
||||||
|
'replication_enabled': True,
|
||||||
|
'rep_mode': 'Synchronous',
|
||||||
|
utils.PORTGROUPNAME: self.data.port_group_name_f}
|
||||||
|
|
||||||
child_sg_name, do_disable_compression, rep_enabled, pg_name = (
|
child_sg_name, do_disable_compression, rep_enabled, pg_name = (
|
||||||
self.utils.get_child_sg_name(host_name, extra_specs1))
|
self.utils.get_child_sg_name(host_name, extra_specs1))
|
||||||
re_name = self.data.storagegroup_name_f + '-RE'
|
re_name = self.data.storagegroup_name_f + '-RE'
|
||||||
self.assertEqual(re_name, child_sg_name)
|
self.assertEqual(re_name, child_sg_name)
|
||||||
# Disable compression
|
# Disable compression
|
||||||
extra_specs2 = self.data.extra_specs_disable_compression
|
extra_specs2 = deepcopy(self.data.extra_specs_disable_compression)
|
||||||
extra_specs2[utils.PORTGROUPNAME] = self.data.port_group_name_f
|
extra_specs2[utils.PORTGROUPNAME] = self.data.port_group_name_f
|
||||||
child_sg_name, do_disable_compression, rep_enabled, pg_name = (
|
child_sg_name, do_disable_compression, rep_enabled, pg_name = (
|
||||||
self.utils.get_child_sg_name(host_name, extra_specs2))
|
self.utils.get_child_sg_name(host_name, extra_specs2))
|
||||||
|
|
|
@ -3182,6 +3182,21 @@ class PowerMaxCommon(object):
|
||||||
target_slo, target_workload, target_extra_specs,
|
target_slo, target_workload, target_extra_specs,
|
||||||
is_compression_disabled)
|
is_compression_disabled)
|
||||||
|
|
||||||
|
# Ensure that storage groups for metro volumes stay consistent
|
||||||
|
if not was_rep_enabled and is_rep_enabled and (
|
||||||
|
self.rep_config['mode'] is utils.REP_METRO):
|
||||||
|
async_sg = self.utils.get_async_rdf_managed_grp_name(
|
||||||
|
self.rep_config)
|
||||||
|
sg_exists = self.rest.get_storage_group(array, async_sg)
|
||||||
|
if not sg_exists:
|
||||||
|
self.rest.create_storage_group(
|
||||||
|
array, async_sg, extra_specs['srp'],
|
||||||
|
extra_specs['slo'], extra_specs['workload'],
|
||||||
|
extra_specs)
|
||||||
|
self.masking.add_volume_to_storage_group(
|
||||||
|
array, device_id, async_sg, volume_name, extra_specs,
|
||||||
|
True)
|
||||||
|
|
||||||
# If the volume was replication enabled both before and after
|
# If the volume was replication enabled both before and after
|
||||||
# retype, the volume needs to be retyped on the remote array also
|
# retype, the volume needs to be retyped on the remote array also
|
||||||
if was_rep_enabled and is_rep_enabled:
|
if was_rep_enabled and is_rep_enabled:
|
||||||
|
@ -3334,20 +3349,16 @@ class PowerMaxCommon(object):
|
||||||
target_sg = self.rest.get_storage_group(array, target_sg_name)
|
target_sg = self.rest.get_storage_group(array, target_sg_name)
|
||||||
|
|
||||||
if not target_sg:
|
if not target_sg:
|
||||||
self.provision.create_storage_group(array, target_sg_name, srp,
|
target_sg = self.provision.create_storage_group(
|
||||||
target_slo,
|
array, target_sg_name, srp, target_slo, target_workload,
|
||||||
target_workload,
|
target_extra_specs, is_compression_disabled)
|
||||||
target_extra_specs,
|
parent_sg = source_sg.get('parent_storage_group')
|
||||||
is_compression_disabled)
|
if parent_sg:
|
||||||
parent_sg = source_sg['parent_storage_group'][0]
|
parent_sg = parent_sg[0]
|
||||||
self.masking.add_child_sg_to_parent_sg(
|
self.masking.add_child_sg_to_parent_sg(
|
||||||
array, target_sg_name, parent_sg, target_extra_specs)
|
array, target_sg_name, parent_sg, target_extra_specs)
|
||||||
target_sg = self.rest.get_storage_group(array, target_sg_name)
|
|
||||||
|
|
||||||
target_in_parent = self.rest.is_child_sg_in_parent_sg(
|
if target_sg:
|
||||||
array, target_sg_name, target_sg['parent_storage_group'][0])
|
|
||||||
|
|
||||||
if target_sg and target_in_parent:
|
|
||||||
self.masking.move_volume_between_storage_groups(
|
self.masking.move_volume_between_storage_groups(
|
||||||
array, device_id, source_sg_name, target_sg_name,
|
array, device_id, source_sg_name, target_sg_name,
|
||||||
target_extra_specs)
|
target_extra_specs)
|
||||||
|
@ -3588,6 +3599,9 @@ class PowerMaxCommon(object):
|
||||||
rdf_group_no, remote_array = self.get_rdf_details(array)
|
rdf_group_no, remote_array = self.get_rdf_details(array)
|
||||||
extra_specs['replication_enabled'] = '<is> True'
|
extra_specs['replication_enabled'] = '<is> True'
|
||||||
extra_specs['rep_mode'] = self.rep_config['mode']
|
extra_specs['rep_mode'] = self.rep_config['mode']
|
||||||
|
group_details = self.rest.get_rdf_group(array, rdf_group_no)
|
||||||
|
volumes_in_group = group_details['numDevices']
|
||||||
|
async_sg = self.utils.get_async_rdf_managed_grp_name(self.rep_config)
|
||||||
|
|
||||||
rdf_vol_size = volume.size
|
rdf_vol_size = volume.size
|
||||||
if rdf_vol_size == 0:
|
if rdf_vol_size == 0:
|
||||||
|
@ -3598,8 +3612,24 @@ class PowerMaxCommon(object):
|
||||||
|
|
||||||
rep_extra_specs = self._get_replication_extra_specs(
|
rep_extra_specs = self._get_replication_extra_specs(
|
||||||
extra_specs, self.rep_config)
|
extra_specs, self.rep_config)
|
||||||
volume_dict = self._create_volume(
|
rep_mode = self.rep_config['mode']
|
||||||
target_name, rdf_vol_size, rep_extra_specs, in_use=True)
|
|
||||||
|
if (volumes_in_group > 0) and (rep_mode is utils.REP_METRO or
|
||||||
|
rep_mode is utils.REP_ASYNC):
|
||||||
|
volume_dict = self._create_volume(
|
||||||
|
target_name, rdf_vol_size, rep_extra_specs)
|
||||||
|
sg_exists = self.rest.get_storage_group(remote_array, async_sg)
|
||||||
|
if not sg_exists:
|
||||||
|
self.rest.create_storage_group(
|
||||||
|
remote_array, async_sg, extra_specs['srp'],
|
||||||
|
extra_specs['slo'], extra_specs['workload'],
|
||||||
|
rep_extra_specs)
|
||||||
|
self.masking.add_volume_to_storage_group(
|
||||||
|
remote_array, volume_dict['device_id'], async_sg,
|
||||||
|
target_name, rep_extra_specs, True)
|
||||||
|
else:
|
||||||
|
volume_dict = self._create_volume(
|
||||||
|
target_name, rdf_vol_size, rep_extra_specs, in_use=True)
|
||||||
target_device_id = volume_dict['device_id']
|
target_device_id = volume_dict['device_id']
|
||||||
|
|
||||||
LOG.debug("Create volume replica: Target device: %(target)s "
|
LOG.debug("Create volume replica: Target device: %(target)s "
|
||||||
|
|
|
@ -118,9 +118,10 @@ class PowerMaxFCDriver(san.SanDriver, driver.FibreChannelDriver):
|
||||||
- Debug metadata compression and service level info fix
|
- Debug metadata compression and service level info fix
|
||||||
4.1.1 - QoS calulation fix
|
4.1.1 - QoS calulation fix
|
||||||
4.1.2 - Volume group delete fix (bug #1853589)
|
4.1.2 - Volume group delete fix (bug #1853589)
|
||||||
|
4.1.3 - Retype attached replication fix (#1851371)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
VERSION = "4.1.2"
|
VERSION = "4.1.3"
|
||||||
|
|
||||||
# ThirdPartySystems wiki
|
# ThirdPartySystems wiki
|
||||||
CI_WIKI_NAME = "EMC_VMAX_CI"
|
CI_WIKI_NAME = "EMC_VMAX_CI"
|
||||||
|
|
|
@ -123,9 +123,10 @@ class PowerMaxISCSIDriver(san.SanISCSIDriver):
|
||||||
- Debug metadata compression and service level info fix
|
- Debug metadata compression and service level info fix
|
||||||
4.1.1 - QoS calulation fix
|
4.1.1 - QoS calulation fix
|
||||||
4.1.2 - Volume group delete fix (bug #1853589)
|
4.1.2 - Volume group delete fix (bug #1853589)
|
||||||
|
4.1.3 - Retype attached replication fix (#1851371)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
VERSION = "4.1.2"
|
VERSION = "4.1.3"
|
||||||
|
|
||||||
# ThirdPartySystems wiki
|
# ThirdPartySystems wiki
|
||||||
CI_WIKI_NAME = "EMC_VMAX_CI"
|
CI_WIKI_NAME = "EMC_VMAX_CI"
|
||||||
|
|
Loading…
Reference in New Issue