diff --git a/manila/share/drivers/netapp/dataontap/cluster_mode/lib_base.py b/manila/share/drivers/netapp/dataontap/cluster_mode/lib_base.py index 3b21f2113d..5ce228d31b 100644 --- a/manila/share/drivers/netapp/dataontap/cluster_mode/lib_base.py +++ b/manila/share/drivers/netapp/dataontap/cluster_mode/lib_base.py @@ -1618,6 +1618,12 @@ class NetAppCmodeFileStorageLibrary(object): replica_list) new_replica_list.append(r) + # Unmount the original active replica. + orig_active_vserver = dm_session.get_vserver_from_share( + orig_active_replica) + self._unmount_orig_active_replica(orig_active_replica, + orig_active_vserver) + self._handle_qos_on_replication_change(dm_session, new_active_replica, orig_active_replica, @@ -1625,6 +1631,25 @@ class NetAppCmodeFileStorageLibrary(object): return new_replica_list + def _unmount_orig_active_replica(self, orig_active_replica, + orig_active_vserver=None): + orig_active_replica_backend = ( + share_utils.extract_host(orig_active_replica['host'], + level='backend_name')) + orig_active_vserver_client = data_motion.get_client_for_backend( + orig_active_replica_backend, + vserver_name=orig_active_vserver) + share_name = self._get_backend_share_name( + orig_active_replica['id']) + try: + orig_active_vserver_client.unmount_volume(share_name, + force=True) + LOG.info("Unmount of the original active replica %s successful.", + orig_active_replica['id']) + except exception.StorageCommunicationException: + LOG.exception("Could not unmount the original active replica %s.", + orig_active_replica['id']) + def _handle_qos_on_replication_change(self, dm_session, new_active_replica, orig_active_replica, share_server=None): diff --git a/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_base.py b/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_base.py index 323bdbf568..a4742e1c03 100644 --- a/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_base.py +++ b/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_base.py @@ -2921,13 +2921,20 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): mock.Mock(return_value=mock.Mock())) self.mock_object(self.library, '_create_export', mock.Mock(return_value='fake_export_location')) + self.mock_object(self.library, '_unmount_orig_active_replica') self.mock_object(self.library, '_handle_qos_on_replication_change') + mock_dm_session = mock.Mock() + self.mock_object(data_motion, "DataMotionSession", + mock.Mock(return_value=mock_dm_session)) + self.mock_object(mock_dm_session, 'get_vserver_from_share', + mock.Mock(return_value=fake.VSERVER1)) + replicas = self.library.promote_replica( None, [self.fake_replica, self.fake_replica_2], self.fake_replica_2, [], share_server=None) - self.mock_dm_session.change_snapmirror_source.assert_called_once_with( + mock_dm_session.change_snapmirror_source.assert_called_once_with( self.fake_replica, self.fake_replica, self.fake_replica_2, mock.ANY ) @@ -2944,6 +2951,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): actual_replica_2['export_locations']) self.assertEqual(constants.STATUS_ACTIVE, actual_replica_2['access_rules_status']) + self.library._unmount_orig_active_replica.assert_called_once_with( + self.fake_replica, fake.VSERVER1) self.library._handle_qos_on_replication_change.assert_called_once() def test_promote_replica_destination_unreachable(self): @@ -2954,6 +2963,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): self.mock_object(self.library, '_get_helper', mock.Mock(return_value=mock.Mock())) + self.mock_object(self.library, '_unmount_orig_active_replica') self.mock_object(self.library, '_handle_qos_on_replication_change') self.mock_object(self.library, '_create_export', @@ -2972,6 +2982,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): actual_replica['replica_state']) self.assertEqual(constants.STATUS_ERROR, actual_replica['status']) + self.assertFalse( + self.library._unmount_orig_active_replica.called) self.assertFalse( self.library._handle_qos_on_replication_change.called) @@ -2983,6 +2995,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): '_get_vserver', mock.Mock(return_value=(fake.VSERVER1, mock.Mock()))) + self.mock_object(self.library, '_unmount_orig_active_replica') self.mock_object(self.library, '_handle_qos_on_replication_change') self.mock_object(self.library, '_get_helper', @@ -2990,12 +3003,17 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): self.mock_object(self.library, '_create_export', mock.Mock(return_value='fake_export_location')) + mock_dm_session = mock.Mock() + self.mock_object(data_motion, "DataMotionSession", + mock.Mock(return_value=mock_dm_session)) + self.mock_object(mock_dm_session, 'get_vserver_from_share', + mock.Mock(return_value=fake.VSERVER1)) replicas = self.library.promote_replica( None, [self.fake_replica, self.fake_replica_2, fake_replica_3], self.fake_replica_2, [], share_server=None) - self.mock_dm_session.change_snapmirror_source.assert_has_calls([ + mock_dm_session.change_snapmirror_source.assert_has_calls([ mock.call(fake_replica_3, self.fake_replica, self.fake_replica_2, mock.ANY), mock.call(self.fake_replica, self.fake_replica, @@ -3017,6 +3035,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): lambda x: x['id'] == fake_replica_3['id'], replicas))[0] self.assertEqual(constants.REPLICA_STATE_OUT_OF_SYNC, actual_replica_3['replica_state']) + self.library._unmount_orig_active_replica.assert_called_once_with( + self.fake_replica, fake.VSERVER1) self.library._handle_qos_on_replication_change.assert_called_once() def test_promote_replica_with_access_rules(self): @@ -3024,6 +3044,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): '_get_vserver', mock.Mock(return_value=(fake.VSERVER1, mock.Mock()))) + self.mock_object(self.library, '_unmount_orig_active_replica') self.mock_object(self.library, '_handle_qos_on_replication_change') mock_helper = mock.Mock() self.mock_object(self.library, @@ -3032,11 +3053,17 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): self.mock_object(self.library, '_create_export', mock.Mock(return_value='fake_export_location')) + mock_dm_session = mock.Mock() + self.mock_object(data_motion, "DataMotionSession", + mock.Mock(return_value=mock_dm_session)) + self.mock_object(mock_dm_session, 'get_vserver_from_share', + mock.Mock(return_value=fake.VSERVER1)) + replicas = self.library.promote_replica( None, [self.fake_replica, self.fake_replica_2], self.fake_replica_2, [fake.SHARE_ACCESS], share_server=None) - self.mock_dm_session.change_snapmirror_source.assert_has_calls([ + mock_dm_session.change_snapmirror_source.assert_has_calls([ mock.call(self.fake_replica, self.fake_replica, self.fake_replica_2, mock.ANY) ], any_order=True) @@ -3046,8 +3073,20 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): mock_helper.update_access.assert_called_once_with(self.fake_replica_2, share_name, [fake.SHARE_ACCESS]) + self.library._unmount_orig_active_replica.assert_called_once_with( + self.fake_replica, fake.VSERVER1) self.library._handle_qos_on_replication_change.assert_called_once() + def test_unmount_orig_active_replica(self): + self.mock_object(share_utils, 'extract_host', mock.Mock( + return_value=fake.MANILA_HOST_NAME)) + self.mock_object(data_motion, 'get_client_for_backend') + self.mock_object(self.library, '_get_backend_share_name', mock.Mock( + return_value=fake.SHARE_NAME)) + + result = self.library._unmount_orig_active_replica(fake.SHARE) + self.assertIsNone(result) + @ddt.data({'extra_specs': {'netapp:snapshot_policy': 'none'}, 'have_cluster_creds': True}, # Test Case 2 isn't possible input diff --git a/releasenotes/notes/bug-1634278-unmount-orig-active-after-promote-8e24c099ddc1e564.yaml b/releasenotes/notes/bug-1634278-unmount-orig-active-after-promote-8e24c099ddc1e564.yaml new file mode 100644 index 0000000000..107a64128a --- /dev/null +++ b/releasenotes/notes/bug-1634278-unmount-orig-active-after-promote-8e24c099ddc1e564.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - The NetApp ONTAP driver is now fixed to unmount + the original active share volume after one of its + replica gets promoted.