Add cinder active-active support for Dell PowerMax driver

Change-Id: I939bb768e004d1bc4a980dcdba932abf9f690350
This commit is contained in:
Jean-Pierre Roquesalane 2023-04-26 12:55:33 +02:00 committed by Yian Zong
parent 5ea10b2ecc
commit 298932c29f
10 changed files with 99 additions and 32 deletions

View File

@ -2937,7 +2937,7 @@ class PowerMaxCommonTest(test.TestCase):
group = self.data.test_group_1
add_vols = []
remove_vols = [self.data.test_volume_group_member]
self.mock_object(self.common, 'failover', True)
self.mock_object(self.common, 'failedover', True)
self.assertRaises(
exception.VolumeBackendAPIException, self.common.update_group,
group, add_vols, remove_vols)

View File

@ -315,7 +315,7 @@ class PowerMaxFCTest(test.TestCase):
def test_failover_host(self):
with mock.patch.object(
self.common, 'failover_host',
self.common, 'failover',
return_value=(self.data.remote_array, [], [])) as mock_fo:
self.driver.failover_host(self.data.ctx, [self.data.test_volume])
mock_fo.assert_called_once_with([self.data.test_volume], None,

View File

@ -359,8 +359,8 @@ class PowerMaxISCSITest(test.TestCase):
self.data.test_volume, new_type, host)
def test_failover_host(self):
with mock.patch.object(self.common, 'failover_host',
return_value={}) as mock_fo:
with mock.patch.object(self.common, 'failover',
return_value=(None, [], [])) as mock_fo:
self.driver.failover_host({}, [self.data.test_volume])
mock_fo.assert_called_once_with([self.data.test_volume], None,
None)

View File

@ -297,7 +297,8 @@ class PowerMaxReplicationTest(test.TestCase):
backend_id = self.data.rep_backend_id_sync
rep_configs = self.common.rep_configs
secondary_id, volume_update_list, group_update_list = (
self.common.failover_host(volumes, backend_id, groups))
self.common.failover(volumes, backend_id, groups))
self.common.failover_completed(backend_id)
mck_validate.assert_called_once_with(
False, backend_id, rep_configs, self.data.array, ['123'], False)
mck_populate.assert_called_once_with(volumes, groups, None)
@ -314,7 +315,7 @@ class PowerMaxReplicationTest(test.TestCase):
backend_id = self.data.rep_backend_id_sync
rep_configs = self.common.rep_configs
self.assertRaises(exception.InvalidReplicationTarget,
self.common.failover_host, volumes, backend_id)
self.common.failover, volumes, backend_id)
mck_validate.assert_called_once_with(
False, backend_id, rep_configs, self.data.array, ['123'], False)
@ -331,7 +332,8 @@ class PowerMaxReplicationTest(test.TestCase):
backend_id = utils.PMAX_FAILOVER_START_ARRAY_PROMOTION
rep_configs = self.common.rep_configs
secondary_id, volume_update_list, group_update_list = (
self.common.failover_host(volumes, backend_id, groups))
self.common.failover(volumes, backend_id, groups))
self.common.failover_completed(backend_id)
self.assertEqual(0, mck_populate.call_count)
self.assertEqual(backend_id, secondary_id)
self.assertEqual(list(), volume_update_list)
@ -358,7 +360,8 @@ class PowerMaxReplicationTest(test.TestCase):
rep_configs = self.common.rep_configs
self.common.promotion = True
secondary_id, volume_update_list, group_update_list = (
self.common.failover_host(volumes, backend_id, groups))
self.common.failover(volumes, backend_id, groups))
self.common.failover_completed(backend_id)
mck_populate.assert_called_once_with(volumes, groups, None)
mck_validate.assert_called_once_with(
False, backend_id, rep_configs, self.data.array, ['123'], True)
@ -497,7 +500,8 @@ class PowerMaxReplicationTest(test.TestCase):
extra_specs['rep_mode'] = utils.REP_ASYNC
with mock.patch.object(common.PowerMaxCommon, '_initial_setup',
return_value=extra_specs):
self.async_driver.common.failover_host(volumes, None, [])
self.async_driver.common.failover(volumes, None, [])
self.common.failover_completed(None)
mock_fg.assert_called_once()
@mock.patch.object(rest.PowerMaxRest,

View File

@ -204,7 +204,7 @@ class PowerMaxCommon(object):
self.next_gen = False
self.replication_enabled = False
self.rep_devices = []
self.failover = True if active_backend_id else False
self.failedover = True if active_backend_id else False
self.promotion = False
self.powermax_array_tag_list = None
self.powermax_short_host_name_template = None
@ -1350,7 +1350,7 @@ class PowerMaxCommon(object):
array_info_list = self.pool_info['arrays_info']
already_queried = False
for array_info in array_info_list:
if self.failover:
if self.failedover:
rep_config = self.rep_configs[0]
array_info = self.get_secondary_stats_info(
rep_config, array_info)
@ -5540,7 +5540,7 @@ class PowerMaxCommon(object):
return rdf_group_no, remote_array
def failover_host(self, volumes, secondary_id=None, groups=None):
def failover(self, volumes, secondary_id=None, groups=None):
"""Fails over the volumes on a host back and forth.
Driver needs to update following info for failed-over volume:
@ -5557,36 +5557,53 @@ class PowerMaxCommon(object):
primary_array = self.configuration.safe_get(utils.POWERMAX_ARRAY)
array_list = self.rest.get_arrays_list()
is_valid, msg = self.utils.validate_failover_request(
self.failover, secondary_id, self.rep_configs, primary_array,
self.failedover, secondary_id, self.rep_configs, primary_array,
array_list, self.promotion)
if not is_valid:
LOG.error(msg)
raise exception.InvalidReplicationTarget(msg)
group_fo = None
if not self.failover:
self.failover = True
if not self.failedover:
self.failedover = True
if not secondary_id:
secondary_id = utils.RDF_FAILEDOVER_STATE
elif secondary_id == 'default':
self.failover = False
self.failedover = False
group_fo = 'default'
if secondary_id == utils.PMAX_FAILOVER_START_ARRAY_PROMOTION:
self.promotion = True
LOG.info("Enabled array promotion.")
else:
if secondary_id != utils.PMAX_FAILOVER_START_ARRAY_PROMOTION:
volume_update_list, group_update_list = (
self._populate_volume_and_group_update_lists(
volumes, groups, group_fo))
if secondary_id == 'default' and self.promotion:
self.promotion = False
LOG.info("Disabled array promotion.")
LOG.info("Failover host complete.")
LOG.info("Failover host completed.")
return secondary_id, volume_update_list, group_update_list
def failover_completed(self, secondary_id=None, isAA=False):
"""This method is called after failover for clustered backends."""
if secondary_id == utils.PMAX_FAILOVER_START_ARRAY_PROMOTION:
self.promotion = True
LOG.info("Enabled array promotion.")
else:
if isAA:
if secondary_id == 'failed over':
self.failedover = True
elif not secondary_id:
self.failedover = False
if self.promotion:
self.promotion = False
LOG.info("Disabled array promotion.")
else:
if not secondary_id:
self.failedover = True
elif secondary_id == 'default':
self.failedover = False
if self.promotion:
self.promotion = False
LOG.info("Disabled array promotion.")
LOG.info('Failover completion completed.')
def _populate_volume_and_group_update_lists(
self, volumes, groups, group_fo):
"""Populate volume and group update lists
@ -5675,7 +5692,7 @@ class PowerMaxCommon(object):
'volume_id': vol.id,
'updates': {
'replication_status': REPLICATION_DISABLED}})
elif self.failover:
elif self.failedover:
# Since the array has been failed-over,
# volumes without replication should be in error.
for vol in non_rep_vol_list:
@ -6347,7 +6364,7 @@ class PowerMaxCommon(object):
if self.promotion:
self._update_group_promotion(
group, add_volumes, remove_volumes)
elif self.failover:
elif self.failedover:
msg = _('Cannot perform group updates during failover, please '
'either failback or perform a promotion operation.')
raise exception.VolumeBackendAPIException(msg)

View File

@ -132,9 +132,12 @@ class PowerMaxFCDriver(san.SanDriver, driver.FibreChannelDriver):
- Support for Failover Abilities (bp/powermax-failover-abilities)
4.4.0 - Early check for status of port
4.4.1 - Report trim/discard support
4.5.0 - Add PowerMax v4 support
4.5.1 - Add active/active compliance
"""
VERSION = "4.4.1"
VERSION = "4.5.1"
SUPPORTS_ACTIVE_ACTIVE = True
# ThirdPartySystems wiki
CI_WIKI_NAME = "DellEMC_PowerMAX_CI"
@ -661,7 +664,18 @@ class PowerMaxFCDriver(san.SanDriver, driver.FibreChannelDriver):
:param groups: replication groups
:returns: secondary_id, volume_update_list, group_update_list
"""
return self.common.failover_host(volumes, secondary_id, groups)
active_backend_id, volume_update_list, group_update_list = (
self.common.failover(volumes, secondary_id, groups))
self.common.failover_completed(secondary_id, False)
return active_backend_id, volume_update_list, group_update_list
def failover(self, context, volumes, secondary_id=None, groups=None):
"""Like failover but for a host that is clustered."""
return self.common.failover(volumes, secondary_id, groups)
def failover_completed(self, context, active_backend_id=None):
"""This method is called after failover for clustered backends."""
return self.common.failover_completed(active_backend_id, True)
def create_group(self, context, group):
"""Creates a generic volume group.

View File

@ -137,9 +137,12 @@ class PowerMaxISCSIDriver(san.SanISCSIDriver):
- Support for Failover Abilities (bp/powermax-failover-abilities)
4.4.0 - Early check for status of port
4.4.1 - Report trim/discard support
4.5.0 - Add PowerMax v4 support
4.5.1 - Add active/active compliance
"""
VERSION = "4.4.1"
VERSION = "4.5.1"
SUPPORTS_ACTIVE_ACTIVE = True
# ThirdPartySystems wiki
CI_WIKI_NAME = "DellEMC_PowerMAX_CI"
@ -571,7 +574,18 @@ class PowerMaxISCSIDriver(san.SanISCSIDriver):
:param groups: replication groups
:returns: secondary_id, volume_update_list, group_update_list
"""
return self.common.failover_host(volumes, secondary_id, groups)
active_backend_id, volume_update_list, group_update_list = (
self.common.failover(volumes, secondary_id, groups))
self.common.failover_completed(secondary_id, False)
return active_backend_id, volume_update_list, group_update_list
def failover(self, context, volumes, secondary_id=None, groups=None):
"""Like failover but for a host that is clustered."""
return self.common.failover(volumes, secondary_id, groups)
def failover_completed(self, context, active_backend_id=None):
"""This method is called after failover for clustered backends."""
return self.common.failover_completed(active_backend_id, True)
def create_group(self, context, group):
"""Creates a generic volume group.

View File

@ -251,6 +251,7 @@ PowerMax drivers also support the following features:
- Snap id support
- Seamless Live Migration from SMI-S support
- Port group & port performance load balancing
- Cinder volume active/active support
.. note::
@ -2418,6 +2419,16 @@ failover promotion.
# cinder service-list
# cinder service-enable <host> <binary>
.. note::
With Cinder volume active/active deployment, use the following commands to
view and enable the cluster as well.
.. code-block:: console
# cinder --os-volume-api-version 3.17 cluster-list
# cinder --os-volume-api-version 3.17 cluster-enable [<binary>] <cluster-name>
4. Remove all volumes from volume groups
.. code-block:: console

View File

@ -977,7 +977,7 @@ notes=Vendor drivers that support running in an active/active
a configuration.
driver.datacore=missing
driver.datera=missing
driver.dell_emc_powermax=missing
driver.dell_emc_powermax=complete
driver.dell_emc_powerstore=missing
driver.dell_emc_powerstore_nfs=missing
driver.dell_emc_powervault=missing

View File

@ -0,0 +1,7 @@
---
features:
- |
Dell PowerMax driver: Enabled support for Active/Active
to both FC and iSCSI driver. This allows users to configure
Dell PowerMax backends in clustered environments.