From 298932c29f749e989891fd1edfea9ec864df71cb Mon Sep 17 00:00:00 2001 From: Jean-Pierre Roquesalane Date: Wed, 26 Apr 2023 12:55:33 +0200 Subject: [PATCH] Add cinder active-active support for Dell PowerMax driver Change-Id: I939bb768e004d1bc4a980dcdba932abf9f690350 --- .../dell_emc/powermax/test_powermax_common.py | 2 +- .../dell_emc/powermax/test_powermax_fc.py | 2 +- .../dell_emc/powermax/test_powermax_iscsi.py | 4 +- .../powermax/test_powermax_replication.py | 14 +++-- .../drivers/dell_emc/powermax/common.py | 53 ++++++++++++------- cinder/volume/drivers/dell_emc/powermax/fc.py | 18 ++++++- .../volume/drivers/dell_emc/powermax/iscsi.py | 18 ++++++- .../drivers/dell-emc-powermax-driver.rst | 11 ++++ doc/source/reference/support-matrix.ini | 2 +- ...ctive-active-support-bec2d96480046d82.yaml | 7 +++ 10 files changed, 99 insertions(+), 32 deletions(-) create mode 100644 releasenotes/notes/powermax-active-active-support-bec2d96480046d82.yaml diff --git a/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_common.py b/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_common.py index 04008f1f755..628fb357dd9 100644 --- a/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_common.py +++ b/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_common.py @@ -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) diff --git a/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_fc.py b/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_fc.py index a2e6ba624e2..442b319c12e 100644 --- a/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_fc.py +++ b/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_fc.py @@ -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, diff --git a/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_iscsi.py b/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_iscsi.py index b90df8b810c..aec4f420126 100644 --- a/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_iscsi.py +++ b/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_iscsi.py @@ -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) diff --git a/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_replication.py b/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_replication.py index c7f6343d4d9..2feeab1c913 100644 --- a/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_replication.py +++ b/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_replication.py @@ -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, diff --git a/cinder/volume/drivers/dell_emc/powermax/common.py b/cinder/volume/drivers/dell_emc/powermax/common.py index 159ccbfa9aa..b3fdf50486a 100644 --- a/cinder/volume/drivers/dell_emc/powermax/common.py +++ b/cinder/volume/drivers/dell_emc/powermax/common.py @@ -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) diff --git a/cinder/volume/drivers/dell_emc/powermax/fc.py b/cinder/volume/drivers/dell_emc/powermax/fc.py index 2a659acdac2..03d944c9d11 100644 --- a/cinder/volume/drivers/dell_emc/powermax/fc.py +++ b/cinder/volume/drivers/dell_emc/powermax/fc.py @@ -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. diff --git a/cinder/volume/drivers/dell_emc/powermax/iscsi.py b/cinder/volume/drivers/dell_emc/powermax/iscsi.py index 40c2af9ff23..c453f9da445 100644 --- a/cinder/volume/drivers/dell_emc/powermax/iscsi.py +++ b/cinder/volume/drivers/dell_emc/powermax/iscsi.py @@ -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. diff --git a/doc/source/configuration/block-storage/drivers/dell-emc-powermax-driver.rst b/doc/source/configuration/block-storage/drivers/dell-emc-powermax-driver.rst index d3c4c560c8d..73e9e3f697d 100644 --- a/doc/source/configuration/block-storage/drivers/dell-emc-powermax-driver.rst +++ b/doc/source/configuration/block-storage/drivers/dell-emc-powermax-driver.rst @@ -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 +.. 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 [] + 4. Remove all volumes from volume groups .. code-block:: console diff --git a/doc/source/reference/support-matrix.ini b/doc/source/reference/support-matrix.ini index be96be50493..31fe50486e9 100644 --- a/doc/source/reference/support-matrix.ini +++ b/doc/source/reference/support-matrix.ini @@ -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 diff --git a/releasenotes/notes/powermax-active-active-support-bec2d96480046d82.yaml b/releasenotes/notes/powermax-active-active-support-bec2d96480046d82.yaml new file mode 100644 index 00000000000..3a7c241f060 --- /dev/null +++ b/releasenotes/notes/powermax-active-active-support-bec2d96480046d82.yaml @@ -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. +