Merge "Add cinder active-active support for Dell PowerMax driver"
This commit is contained in:
commit
38cd59cd0a
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user