diff --git a/manila/share/drivers/netapp/dataontap/cluster_mode/lib_multi_svm.py b/manila/share/drivers/netapp/dataontap/cluster_mode/lib_multi_svm.py index 5ff9087c5d..87f409ae34 100644 --- a/manila/share/drivers/netapp/dataontap/cluster_mode/lib_multi_svm.py +++ b/manila/share/drivers/netapp/dataontap/cluster_mode/lib_multi_svm.py @@ -904,6 +904,18 @@ class NetAppCmodeMultiSVMFileStorageLibrary( or vserver_info.get('subtype') != 'default'): return False + if share: + share_pool = share_utils.extract_host( + share['host'], level='pool') + if self._is_flexgroup_pool(share_pool): + share_pool_list = self._get_flexgroup_aggregate_list( + share_pool) + else: + share_pool_list = [share_pool] + aggr_list = client.list_vserver_aggregates() + if not set(share_pool_list).issubset(set(aggr_list)): + return False + if self.is_nfs_config_supported: # NOTE(felipe_rodrigues): Do not check that the share nfs_config # matches with the group nfs_config, because the API guarantees diff --git a/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_multi_svm.py b/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_multi_svm.py index b27f2b5289..f96c373c7a 100644 --- a/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_multi_svm.py +++ b/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_multi_svm.py @@ -1765,11 +1765,13 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): mock_client))) self.mock_object(mock_client, 'get_vserver_info', mock.Mock(return_value=fake.VSERVER_INFO)) + self.mock_object(mock_client, 'list_vserver_aggregates', + mock.Mock(return_value=fake.AGGREGATES)) server = self.library.choose_share_server_compatible_with_share( - None, fake.SHARE_SERVERS, fake.SHARE, None, share_group) + None, fake.SHARE_SERVERS, fake.SHARE_2, None, share_group) - mock_get_extra_spec.assert_called_once_with(fake.SHARE) + mock_get_extra_spec.assert_called_once_with(fake.SHARE_2) mock_get_nfs_config.assert_called_once_with(fake.EXTRA_SPEC) self.assertEqual(expected_server, server) @@ -1803,13 +1805,15 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): mock_client))) self.mock_object(mock_client, 'get_vserver_info', mock.Mock(return_value=fake.VSERVER_INFO)) + self.mock_object(mock_client, 'list_vserver_aggregates', + mock.Mock(return_value=fake.AGGREGATES)) server = self.library.choose_share_server_compatible_with_share( - None, fake.SHARE_SERVERS, fake.SHARE, None, share_group) + None, fake.SHARE_SERVERS, fake.SHARE_2, None, share_group) self.assertEqual(expected_server, server) if nfs_config_support: - mock_get_extra_spec.assert_called_once_with(fake.SHARE) + mock_get_extra_spec.assert_called_once_with(fake.SHARE_2) mock_get_nfs_config.assert_called_once_with(fake.EMPTY_EXTRA_SPEC) @ddt.data( @@ -1843,13 +1847,15 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): mock_client))) self.mock_object(mock_client, 'get_vserver_info', mock.Mock(return_value=fake.VSERVER_INFO)) + self.mock_object(mock_client, 'list_vserver_aggregates', + mock.Mock(return_value=fake.AGGREGATES)) server = self.library.choose_share_server_compatible_with_share( - None, fake.SHARE_SERVERS, fake.SHARE) + None, fake.SHARE_SERVERS, fake.SHARE_2) self.assertEqual(expected_server, server) if nfs_config_support: - mock_get_extra_spec.assert_called_once_with(fake.SHARE) + mock_get_extra_spec.assert_called_once_with(fake.SHARE_2) mock_get_nfs_config.assert_called_once_with(fake.EXTRA_SPEC) @ddt.data( @@ -1886,13 +1892,15 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): mock_client))) self.mock_object(mock_client, 'get_vserver_info', mock.Mock(return_value=fake.VSERVER_INFO)) + self.mock_object(mock_client, 'list_vserver_aggregates', + mock.Mock(return_value=fake.AGGREGATES)) server = self.library.choose_share_server_compatible_with_share( - None, share_servers, fake.SHARE) + None, share_servers, fake.SHARE_2) self.assertEqual(expected_server, server) if nfs_config_support: - mock_get_extra_spec.assert_called_once_with(fake.SHARE) + mock_get_extra_spec.assert_called_once_with(fake.SHARE_2) mock_get_nfs_config.assert_called_once_with(fake.EMPTY_EXTRA_SPEC) def test_manage_existing_error(self): @@ -1989,6 +1997,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): self, expected_server, nfs_config, share_servers, nfs_config_supported=True): self.library.is_nfs_config_supported = nfs_config_supported + mock_client = mock.Mock() self.mock_object( share_types, "get_share_type_extra_specs", mock.Mock(return_value=fake.EXTRA_SPEC)) @@ -2000,7 +2009,6 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): self.library, '_check_nfs_config_extra_specs_validity', mock.Mock()) - mock_client = mock.Mock() self.mock_object(self.library, '_get_vserver', mock.Mock(return_value=('fake_name', mock_client))) @@ -3418,14 +3426,16 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): mock_get_provisioning_opts = self.mock_object( self.library, '_get_provisioning_options', mock.Mock(return_value={})) + self.mock_object(mock_client, 'list_vserver_aggregates', + mock.Mock(return_value=fake.AGGREGATES)) result = self.library.choose_share_server_compatible_with_share( - None, [fake.SHARE_SERVER], fake.SHARE_INSTANCE, + None, [fake.SHARE_SERVER], fake.SHARE_2, None, share_group ) expected_result = fake.SHARE_SERVER if compatible else None self.assertEqual(expected_result, result) - mock_get_extra_spec.assert_called_once_with(fake.SHARE_INSTANCE) + mock_get_extra_spec.assert_called_once_with(fake.SHARE_2) mock_get_provisioning_opts.assert_called_once_with('fake_extra_specs') if (share_group and share_group['share_server_id'] != fake.SHARE_SERVER['id']): @@ -3459,6 +3469,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): mock_client))) self.mock_object(mock_client, 'get_vserver_info', mock.Mock(return_value=fake.VSERVER_INFO)) + self.mock_object(mock_client, 'list_vserver_aggregates', + mock.Mock(return_value=fake.AGGREGATES)) mock_get_policies = self.mock_object( mock_client, 'get_fpolicy_policies_status', mock.Mock(return_value=policies)) @@ -3467,13 +3479,13 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): mock.Mock(return_value=reusable_scope)) result = self.library.choose_share_server_compatible_with_share( - None, [fake.SHARE_SERVER], fake.SHARE_INSTANCE, + None, [fake.SHARE_SERVER], fake.SHARE_2, None, None ) expected_result = fake.SHARE_SERVER if compatible else None self.assertEqual(expected_result, result) - mock_get_extra_spec.assert_called_once_with(fake.SHARE_INSTANCE) + mock_get_extra_spec.assert_called_once_with(fake.SHARE_2) mock_client.get_vserver_info.assert_called_once_with( fake.VSERVER1, ) @@ -3483,7 +3495,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): mock_get_policies.assert_called_once() if len(policies) >= self.library.FPOLICY_MAX_VSERVER_POLICIES: mock_reusable_scope.assert_called_once_with( - fake.SHARE_INSTANCE, mock_client, + fake.SHARE_2, mock_client, fpolicy_extensions_to_include=fake.FPOLICY_EXT_TO_INCLUDE, fpolicy_extensions_to_exclude=fake.FPOLICY_EXT_TO_EXCLUDE, fpolicy_file_operations=fake.FPOLICY_FILE_OPERATIONS) @@ -3518,6 +3530,71 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): fake.VSERVER1, ) + def test_choose_share_server_compatible_with_different_aggrs(self): + self.library.is_nfs_config_supported = False + mock_client = mock.Mock() + self.mock_object(self.library, '_get_vserver', + mock.Mock(return_value=(fake.VSERVER1, + mock_client))) + fake_vserver_info = { + 'operational_state': 'running', + 'state': 'running', + 'subtype': 'default' + } + self.mock_object(mock_client, 'get_vserver_info', + mock.Mock(return_value=fake_vserver_info)) + mock_get_extra_spec = self.mock_object( + share_types, 'get_extra_specs_from_share', + mock.Mock(return_value='fake_extra_specs')) + mock_get_provisioning_opts = self.mock_object( + self.library, '_get_provisioning_options', + mock.Mock(return_value={})) + self.mock_object(mock_client, 'list_vserver_aggregates', + mock.Mock(return_value=fake.AGGREGATES)) + result = self.library.choose_share_server_compatible_with_share( + None, [fake.SHARE_SERVER], fake.SHARE_INSTANCE, None) + self.assertIsNone(result) + mock_get_extra_spec.assert_called_once_with(fake.SHARE_INSTANCE) + mock_get_provisioning_opts.assert_called_once_with('fake_extra_specs') + + def test_choose_share_server_compatible_with_flexgroups(self): + self.library.is_nfs_config_supported = False + mock_client = mock.Mock() + self.mock_object(self.library, '_get_vserver', + mock.Mock(return_value=(fake.VSERVER1, + mock_client))) + fake_vserver_info = { + 'operational_state': 'running', + 'state': 'running', + 'subtype': 'default' + } + self.mock_object(mock_client, 'get_vserver_info', + mock.Mock(return_value=fake_vserver_info)) + mock_get_extra_spec = self.mock_object( + share_types, 'get_extra_specs_from_share', + mock.Mock(return_value='fake_extra_specs')) + mock_get_provisioning_opts = self.mock_object( + self.library, '_get_provisioning_options', + mock.Mock(return_value={})) + self.mock_object(mock_client, 'list_vserver_aggregates', + mock.Mock(return_value=fake.FLEXGROUP_POOL_AGGR)) + self.mock_object(self.library, '_is_flexgroup_pool', + mock.Mock(return_value=True)) + self.mock_object(self.library, '_get_flexgroup_aggregate_list', + mock.Mock(return_value=fake.FLEXGROUP_POOL_AGGR)) + result = self.library.choose_share_server_compatible_with_share( + None, [fake.SHARE_SERVER], fake.SHARE_FLEXGROUP, None) + expected_result = fake.SHARE_SERVER + self.assertEqual(expected_result, result) + self.library._get_vserver.assert_called_once_with( + fake.SHARE_SERVER, backend_name=fake.BACKEND_NAME + ) + mock_client.get_vserver_info.assert_called_once_with( + fake.VSERVER1, + ) + mock_get_extra_spec.assert_called_once_with(fake.SHARE_FLEXGROUP) + mock_get_provisioning_opts.assert_called_once_with('fake_extra_specs') + def test__create_port_and_broadcast_domain(self): self.mock_object(self.library._client, 'list_cluster_nodes', diff --git a/manila/tests/share/drivers/netapp/dataontap/fakes.py b/manila/tests/share/drivers/netapp/dataontap/fakes.py index 0c0fd2acdd..1e00106255 100644 --- a/manila/tests/share/drivers/netapp/dataontap/fakes.py +++ b/manila/tests/share/drivers/netapp/dataontap/fakes.py @@ -65,6 +65,8 @@ FREE_CAPACITY = 10000000000 TOTAL_CAPACITY = 20000000000 AGGREGATE = 'manila_aggr_1' AGGREGATES = ('manila_aggr_1', 'manila_aggr_2') +AGGR_POOL_NAME = 'manila_aggr_1' +FLEXGROUP_POOL_NAME = 'flexgroup_pool' ROOT_AGGREGATES = ('root_aggr_1', 'root_aggr_2') ROOT_VOLUME_AGGREGATE = 'manila1' ROOT_VOLUME = 'root' @@ -86,6 +88,10 @@ MANILA_HOST_NAME_2 = '%(host)s@%(backend)s#%(pool)s' % { 'host': HOST_NAME, 'backend': BACKEND_NAME, 'pool': POOL_NAME_2} MANILA_HOST_NAME_3 = '%(host)s@%(backend)s#%(pool)s' % { 'host': HOST_NAME, 'backend': BACKEND_NAME_2, 'pool': POOL_NAME_2} +MANILA_HOST_NAME_AGGR = '%(host)s@%(backend)s#%(pool)s' % { + 'host': HOST_NAME, 'backend': BACKEND_NAME, 'pool': AGGR_POOL_NAME} +MANILA_HOST_NAME_FLEXG_AGGR = '%(host)s@%(backend)s#%(pool)s' % { + 'host': HOST_NAME, 'backend': BACKEND_NAME, 'pool': FLEXGROUP_POOL_NAME} SERVER_HOST = '%(host)s@%(backend)s' % { 'host': HOST_NAME, 'backend': BACKEND_NAME} SERVER_HOST_2 = '%(host)s@%(backend)s' % { @@ -140,6 +146,46 @@ SHARE = { 'share_id': SHARE_ID, } +SHARE_2 = { + 'id': SHARE_ID, + 'host': MANILA_HOST_NAME_AGGR, + 'project_id': TENANT_ID, + 'name': SHARE_NAME, + 'size': SHARE_SIZE, + 'share_proto': 'fake', + 'share_type_id': 'fake_share_type_id', + 'share_network_id': '5dfe0898-e2a1-4740-9177-81c7d26713b0', + 'share_server_id': '7e6a2cc8-871f-4b1d-8364-5aad0f98da86', + 'network_info': { + 'network_allocations': [{'ip_address': 'ip'}] + }, + 'replica_state': constants.REPLICA_STATE_ACTIVE, + 'status': constants.STATUS_AVAILABLE, + 'share_server': None, + 'encrypt': False, + 'share_id': SHARE_ID, +} + +SHARE_FLEXGROUP = { + 'id': SHARE_ID, + 'host': MANILA_HOST_NAME_FLEXG_AGGR, + 'project_id': TENANT_ID, + 'name': SHARE_NAME, + 'size': SHARE_SIZE, + 'share_proto': 'fake', + 'share_type_id': 'fake_share_type_id', + 'share_network_id': '5dfe0898-e2a1-4740-9177-81c7d26713b0', + 'share_server_id': '7e6a2cc8-871f-4b1d-8364-5aad0f98da86', + 'network_info': { + 'network_allocations': [{'ip_address': 'ip'}] + }, + 'replica_state': constants.REPLICA_STATE_ACTIVE, + 'status': constants.STATUS_AVAILABLE, + 'share_server': None, + 'encrypt': False, + 'share_id': SHARE_ID, +} + SHARE_INSTANCE = { 'id': SHARE_INSTANCE_ID, 'share_id': SHARE_ID, @@ -871,8 +917,6 @@ AGGREGATE_CAPACITIES = { } } -FLEXGROUP_POOL_NAME = 'flexgroup_pool' - FLEXGROUP_POOL_AGGR = [AGGREGATES[0], AGGREGATES[1]] FLEXGROUP_POOL_OPT = { diff --git a/releasenotes/notes/bug-1928241-d1b48e79aceb3cc4.yaml b/releasenotes/notes/bug-1928241-d1b48e79aceb3cc4.yaml new file mode 100644 index 0000000000..20878a18fd --- /dev/null +++ b/releasenotes/notes/bug-1928241-d1b48e79aceb3cc4.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixes `bug #1928241 `_. + The NetApp ONTAP driver will now avoid reusing a share server during + the share creation in case the share server does not span the selected pool.