From 053b2fe63cdbddaccb8002b91d11065e9ce22af4 Mon Sep 17 00:00:00 2001 From: Saikumar Pulluri Date: Mon, 5 Aug 2024 22:40:51 +0530 Subject: [PATCH] Added support to Active/Active mode in ISCSI/FC drivers [NetApp ONTAP] This patch enables Active/Active support in NetApp ISCSI/FC drivers. To support replication in A/A mode, the method failover_host was splitted in two phases (failover and failover_completed) as required by the spec [1]. [1] https://specs.openstack.org/openstack/cinder-specs/specs/ocata/ha-aa-replication.html Change-Id: I4e38d592abf1d36dedda97a17710746b4037c779 --- .../netapp/dataontap/test_block_cmode.py | 64 +++++++++++++++++++ .../drivers/netapp/dataontap/block_cmode.py | 22 ++++++- .../drivers/netapp/dataontap/fc_cmode.py | 11 +++- .../drivers/netapp/dataontap/iscsi_cmode.py | 11 +++- doc/source/reference/support-matrix.ini | 39 +++++++---- ...app-iscsi-aa-support-eff8ed19a30e87c0.yaml | 5 ++ 6 files changed, 133 insertions(+), 19 deletions(-) create mode 100644 releasenotes/notes/feature-netapp-iscsi-aa-support-eff8ed19a30e87c0.yaml diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_cmode.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_cmode.py index 13a8b77d51e..56216940498 100644 --- a/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_cmode.py +++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_cmode.py @@ -783,6 +783,70 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase): self.assertEqual('dev1', actual_active) self.assertEqual([], vol_updates) + @ddt.data({'secondary_id': 'dev0', 'configured_targets': ['dev1']}, + {'secondary_id': 'dev3', 'configured_targets': ['dev1', 'dev2']}, + {'secondary_id': 'dev1', 'configured_targets': []}, + {'secondary_id': None, 'configured_targets': []}) + @ddt.unpack + def test_failover_invalid_replication_target(self, secondary_id, + configured_targets): + """This tests executes a method in the DataMotionMixin.""" + self.library.backend_name = 'dev0' + self.mock_object(data_motion.DataMotionMixin, + 'get_replication_backend_names', + return_value=configured_targets) + complete_failover_call = self.mock_object( + data_motion.DataMotionMixin, '_complete_failover') + + self.assertRaises(exception.InvalidReplicationTarget, + self.library.failover, 'fake_context', [], + secondary_id=secondary_id) + self.assertFalse(complete_failover_call.called) + + def test_failover_unable_to_failover(self): + """This tests executes a method in the DataMotionMixin.""" + self.library.backend_name = 'dev0' + self.mock_object(data_motion.DataMotionMixin, '_complete_failover', + side_effect=na_utils.NetAppDriverException) + self.mock_object(data_motion.DataMotionMixin, + 'get_replication_backend_names', + return_value=['dev1', 'dev2']) + self.mock_object(self.library.ssc_library, 'get_ssc_flexvol_names', + return_value=fake_utils.SSC.keys()) + self.mock_object(self.library, '_update_zapi_client') + + self.assertRaises(exception.UnableToFailOver, + self.library.failover, 'fake_context', [], + secondary_id='dev1') + data_motion.DataMotionMixin._complete_failover.assert_called_once_with( + 'dev0', ['dev1', 'dev2'], fake_utils.SSC.keys(), [], + failover_target='dev1') + self.assertFalse(self.library._update_zapi_client.called) + + def test_failover(self): + """This tests executes a method in the DataMotionMixin.""" + self.library.backend_name = 'dev0' + self.mock_object(data_motion.DataMotionMixin, '_complete_failover', + return_value=('dev1', [])) + self.mock_object(data_motion.DataMotionMixin, + 'get_replication_backend_names', + return_value=['dev1', 'dev2']) + self.mock_object(self.library.ssc_library, 'get_ssc_flexvol_names', + return_value=fake_utils.SSC.keys()) + self.mock_object(self.library, '_update_zapi_client') + + actual_active, vol_updates, __ = self.library.failover( + 'fake_context', [], secondary_id='dev1', groups=[]) + + data_motion.DataMotionMixin._complete_failover.assert_called_once_with( + 'dev0', ['dev1', 'dev2'], fake_utils.SSC.keys(), [], + failover_target='dev1') + + def test_failover_completed(self): + self.mock_object(self.library, '_update_zapi_client') + self.library.failover_completed('fake_context', secondary_id='dev1') + self.library._update_zapi_client.assert_called_once_with('dev1') + def test_add_looping_tasks(self): mock_update_ssc = self.mock_object(self.library, '_update_ssc') mock_handle_housekeeping = self.mock_object( diff --git a/cinder/volume/drivers/netapp/dataontap/block_cmode.py b/cinder/volume/drivers/netapp/dataontap/block_cmode.py index 5aa24b55ef0..d684ef10aea 100644 --- a/cinder/volume/drivers/netapp/dataontap/block_cmode.py +++ b/cinder/volume/drivers/netapp/dataontap/block_cmode.py @@ -61,10 +61,12 @@ class NetAppBlockStorageCmodeLibrary( Add support for dynamic Adaptive QoS policy group creation 3.0.0 - Add support for Intra-cluster Storage assisted volume migration Add support for revert to snapshot + 4.0.0 - Add Cinder Active/Active support (High Availability) + Implement Active/Active replication support """ - VERSION = "3.0.0" + VERSION = "4.0.0" REQUIRED_CMODE_FLAGS = ['netapp_vserver'] @@ -454,9 +456,23 @@ class NetAppBlockStorageCmodeLibrary( super(NetAppBlockStorageCmodeLibrary, self).unmanage(volume) def failover_host(self, context, volumes, secondary_id=None, groups=None): - """Failover a backend to a secondary replication target.""" + """Failover a backend to a secondary replication target. - return self._failover_host(volumes, secondary_id=secondary_id) + This function combines failover() and failover_completed() + to perform failover when Active/Active is not enabled. + """ + active_backend_name, volume_updates, group_updates = ( + self._failover(context, volumes, secondary_id, groups)) + self._failover_completed(context, active_backend_name) + return active_backend_name, volume_updates, group_updates + + def failover(self, context, volumes, secondary_id=None, groups=None): + """Failover to replication target.""" + return self._failover(context, volumes, secondary_id, groups) + + def failover_completed(self, context, secondary_id=None): + """Update volume node when `failover` is completed.""" + return self._failover_completed(context, secondary_id) def _get_backing_flexvol_names(self): """Returns a list of backing flexvol names.""" diff --git a/cinder/volume/drivers/netapp/dataontap/fc_cmode.py b/cinder/volume/drivers/netapp/dataontap/fc_cmode.py index cfb64ff159a..b82b441d264 100644 --- a/cinder/volume/drivers/netapp/dataontap/fc_cmode.py +++ b/cinder/volume/drivers/netapp/dataontap/fc_cmode.py @@ -36,12 +36,15 @@ class NetAppCmodeFibreChannelDriver(driver.BaseVD, 2.0.0 - Wallaby driver version bump 3.0.0 - Add support for Intra-cluster Storage assisted volume migration Add support for revert to snapshot + 4.0.0 - Add Cinder Active/Active support (High Availability) + Implement Active/Active replication support """ - VERSION = "3.0.0" + VERSION = "4.0.0" DRIVER_NAME = 'NetApp_FibreChannel_Cluster_direct' + SUPPORTS_ACTIVE_ACTIVE = True # ThirdPartySystems wiki page CI_WIKI_NAME = "NetApp_CI" @@ -154,6 +157,12 @@ class NetAppCmodeFibreChannelDriver(driver.BaseVD, return self.library.failover_host( context, volumes, secondary_id=secondary_id) + def failover(self, context, volumes, secondary_id=None, groups=None): + return self.library.failover(context, volumes, secondary_id) + + def failover_completed(self, context, secondary_id=None): + return self.library.failover_completed(context, secondary_id) + def migrate_volume(self, context, volume, host): return self.library.migrate_volume(context, volume, host) diff --git a/cinder/volume/drivers/netapp/dataontap/iscsi_cmode.py b/cinder/volume/drivers/netapp/dataontap/iscsi_cmode.py index f581ec3dad7..4bbb9921fc3 100644 --- a/cinder/volume/drivers/netapp/dataontap/iscsi_cmode.py +++ b/cinder/volume/drivers/netapp/dataontap/iscsi_cmode.py @@ -32,6 +32,7 @@ class NetAppCmodeISCSIDriver(driver.BaseVD, # ThirdPartySystems wiki page CI_WIKI_NAME = "NetApp_CI" VERSION = block_cmode.NetAppBlockStorageCmodeLibrary.VERSION + SUPPORTS_ACTIVE_ACTIVE = True def __init__(self, *args, **kwargs): super(NetAppCmodeISCSIDriver, self).__init__(*args, **kwargs) @@ -133,8 +134,14 @@ class NetAppCmodeISCSIDriver(driver.BaseVD, source_group=source_group, source_vols=source_vols) def failover_host(self, context, volumes, secondary_id=None, groups=None): - return self.library.failover_host( - context, volumes, secondary_id=secondary_id) + return self.library.failover_host(context, volumes, + secondary_id=secondary_id) + + def failover(self, context, volumes, secondary_id=None, groups=None): + return self.library.failover(context, volumes, secondary_id) + + def failover_completed(self, context, secondary_id=None): + return self.library.failover_completed(context, secondary_id) def migrate_volume(self, context, volume, host): return self.library.migrate_volume(context, volume, host) diff --git a/doc/source/reference/support-matrix.ini b/doc/source/reference/support-matrix.ini index 0d7a6c11db3..6a4fcfdceea 100644 --- a/doc/source/reference/support-matrix.ini +++ b/doc/source/reference/support-matrix.ini @@ -156,8 +156,11 @@ title=NEC Storage M Series Driver (iSCSI, FC) [driver.nec_v] title=NEC Storage V Series Driver (iSCSI, FC) -[driver.netapp_ontap] -title=NetApp Data ONTAP Driver (iSCSI, FC, NVMe/TCP) +[driver.netapp_ontap_nvme_tcp] +title=NetApp Data ONTAP Driver (NVMe/TCP) + +[driver.netapp_ontap_iscsi_fc] +title=NetApp Data ONTAP Driver (iSCSI,FC) [driver.netapp_ontap_nfs] title=NetApp Data ONTAP Driver (NFS) @@ -291,7 +294,8 @@ driver.lvm=complete driver.macrosan=complete driver.nec=complete driver.nec_v=complete -driver.netapp_ontap=complete +driver.netapp_ontap_nvme_tcp=complete +driver.netapp_ontap_iscsi_fc=complete driver.netapp_ontap_nfs=complete driver.netapp_solidfire=complete driver.nexenta=complete @@ -370,7 +374,8 @@ driver.lvm=complete driver.macrosan=complete driver.nec=complete driver.nec_v=complete -driver.netapp_ontap=complete +driver.netapp_ontap_nvme_tcp=complete +driver.netapp_ontap_iscsi_fc=complete driver.netapp_ontap_nfs=complete driver.netapp_solidfire=complete driver.nexenta=complete @@ -452,7 +457,8 @@ driver.lvm=missing driver.macrosan=complete driver.nec=complete driver.nec_v=missing -driver.netapp_ontap=complete +driver.netapp_ontap_nvme_tcp=complete +driver.netapp_ontap_iscsi_fc=complete driver.netapp_ontap_nfs=complete driver.netapp_solidfire=complete driver.nexenta=missing @@ -533,7 +539,8 @@ driver.lvm=missing driver.macrosan=complete driver.nec=missing driver.nec_v=missing -driver.netapp_ontap=complete +driver.netapp_ontap_nvme_tcp=complete +driver.netapp_ontap_iscsi_fc=complete driver.netapp_ontap_nfs=complete driver.netapp_solidfire=complete driver.nexenta=missing @@ -615,7 +622,8 @@ driver.lvm=missing driver.macrosan=missing driver.nec=missing driver.nec_v=complete -driver.netapp_ontap=complete +driver.netapp_ontap_nvme_tcp=complete +driver.netapp_ontap_iscsi_fc=complete driver.netapp_ontap_nfs=complete driver.netapp_solidfire=complete driver.nexenta=missing @@ -696,7 +704,8 @@ driver.lvm=complete driver.macrosan=complete driver.nec=complete driver.nec_v=complete -driver.netapp_ontap=complete +driver.netapp_ontap_nvme_tcp=complete +driver.netapp_ontap_iscsi_fc=complete driver.netapp_ontap_nfs=complete driver.netapp_solidfire=complete driver.nexenta=missing @@ -778,7 +787,8 @@ driver.lvm=missing driver.macrosan=complete driver.nec=complete driver.nec_v=missing -driver.netapp_ontap=complete +driver.netapp_ontap_nvme_tcp=complete +driver.netapp_ontap_iscsi_fc=complete driver.netapp_ontap_nfs=complete driver.netapp_solidfire=complete driver.nexenta=missing @@ -860,7 +870,8 @@ driver.lvm=complete driver.macrosan=missing driver.nec=complete driver.nec_v=complete -driver.netapp_ontap=complete +driver.netapp_ontap_nvme_tcp=complete +driver.netapp_ontap_iscsi_fc=complete driver.netapp_ontap_nfs=complete driver.netapp_solidfire=complete driver.nexenta=missing @@ -905,7 +916,7 @@ driver.dell_emc_vmax_3=complete driver.dell_emc_vnx=complete driver.dell_emc_powerflex=complete driver.dell_emc_xtremio=missing -driver.fujitsu_eternus=complete +driver.fujitsu_eternus=missing driver.fungible=missing driver.hitachi_vsp=complete driver.hpe_3par=complete @@ -939,7 +950,8 @@ driver.lvm=complete driver.macrosan=missing driver.nec=complete driver.nec_v=complete -driver.netapp_ontap=complete +driver.netapp_ontap_nvme_tcp=complete +driver.netapp_ontap_iscsi_fc=complete driver.netapp_ontap_nfs=complete driver.netapp_solidfire=complete driver.nexenta=missing @@ -1022,7 +1034,8 @@ driver.lvm=missing driver.macrosan=complete driver.nec=missing driver.nec_v=missing -driver.netapp_ontap=missing +driver.netapp_ontap_nvme_tcp=missing +driver.netapp_ontap_iscsi_fc=complete driver.netapp_ontap_nfs=complete driver.netapp_solidfire=complete driver.nexenta=missing diff --git a/releasenotes/notes/feature-netapp-iscsi-aa-support-eff8ed19a30e87c0.yaml b/releasenotes/notes/feature-netapp-iscsi-aa-support-eff8ed19a30e87c0.yaml new file mode 100644 index 00000000000..2af9b8fb24c --- /dev/null +++ b/releasenotes/notes/feature-netapp-iscsi-aa-support-eff8ed19a30e87c0.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + NetApp ONTAP ISCSI/FC drivers: Enabled support for Active/Active environments + in the NetApp ISCSI/FC drivers (including replication).