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 3747e2ed3e..3d161c29f9 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 @@ -332,12 +332,16 @@ class NetAppCmodeMultiSVMFileStorageLibrary( vserver_client = self._get_api_client(vserver=vserver) network_interfaces = vserver_client.get_network_interfaces() - vlan = None - if network_interfaces: - home_port = network_interfaces[0]['home-port'] - vlan = home_port.split('-')[1] + interfaces_on_vlans = [] + vlans = [] + for interface in network_interfaces: + if '-' in interface['home-port']: + interfaces_on_vlans.append(interface) + vlans.append(interface['home-port']) - @utils.synchronized('netapp-VLAN-%s' % vlan, external=True) + vlans = '-'.join(sorted(set(vlans))) if vlans else None + + @utils.synchronized('netapp-VLANs-%s' % vlans, external=True) def _delete_vserver_with_lock(): self._client.delete_vserver(vserver, vserver_client, @@ -347,15 +351,15 @@ class NetAppCmodeMultiSVMFileStorageLibrary( ipspace_name): self._client.delete_ipspace(ipspace_name) - self._delete_vserver_vlan(network_interfaces) + self._delete_vserver_vlans(interfaces_on_vlans) return _delete_vserver_with_lock() @na_utils.trace - def _delete_vserver_vlan(self, vserver_network_interfaces): + def _delete_vserver_vlans(self, network_interfaces_on_vlans): """Delete Vserver's VLAN configuration from ports""" - for interface in vserver_network_interfaces: + for interface in network_interfaces_on_vlans: try: home_port = interface['home-port'] port, vlan = home_port.split('-') diff --git a/manila/tests/share/drivers/netapp/dataontap/client/fakes.py b/manila/tests/share/drivers/netapp/dataontap/client/fakes.py index 9823761c28..4da5042583 100644 --- a/manila/tests/share/drivers/netapp/dataontap/client/fakes.py +++ b/manila/tests/share/drivers/netapp/dataontap/client/fakes.py @@ -96,6 +96,27 @@ NETWORK_INTERFACES = [{ 'home-port': VLAN_PORT }] +NETWORK_INTERFACES_MULTIPLE = [ + { + 'interface_name': 'fake_interface', + 'address': IP_ADDRESS, + 'vserver': VSERVER_NAME, + 'netmask': NETMASK, + 'role': 'data', + 'home-node': NODE_NAME, + 'home-port': VLAN_PORT, + }, + { + 'interface_name': 'fake_interface_2', + 'address': '10.10.12.10', + 'vserver': VSERVER_NAME, + 'netmask': NETMASK, + 'role': 'data', + 'home-node': NODE_NAME, + 'home-port': PORT, + } +] + IPSPACES = [{ 'uuid': 'fake_uuid', 'ipspace': IPSPACE_NAME, 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 7cf69c322a..9c225a565a 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 @@ -671,11 +671,15 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): self.mock_object(self.library, '_get_api_client', mock.Mock(return_value=vserver_client)) - mock_delete_vserver_vlan = self.mock_object(self.library, - '_delete_vserver_vlan') + mock_delete_vserver_vlans = self.mock_object(self.library, + '_delete_vserver_vlans') + + net_interfaces = copy.deepcopy(c_fake.NETWORK_INTERFACES_MULTIPLE) + net_interfaces_with_vlans = [net_interfaces[0]] + self.mock_object(vserver_client, 'get_network_interfaces', - mock.Mock(return_value=c_fake.NETWORK_INTERFACES)) + mock.Mock(return_value=net_interfaces)) security_services = fake.NETWORK_INFO['security_services'] self.library._delete_vserver(fake.VSERVER1, @@ -686,8 +690,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): self.library._client.delete_vserver.assert_called_once_with( fake.VSERVER1, vserver_client, security_services=security_services) self.assertFalse(self.library._client.delete_ipspace.called) - mock_delete_vserver_vlan.assert_called_once_with( - c_fake.NETWORK_INTERFACES) + mock_delete_vserver_vlans.assert_called_once_with( + net_interfaces_with_vlans) def test_delete_vserver_ipspace_has_data_vservers(self): @@ -701,11 +705,11 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): self.mock_object(self.library._client, 'ipspace_has_data_vservers', mock.Mock(return_value=True)) - mock_delete_vserver_vlan = self.mock_object(self.library, - '_delete_vserver_vlan') - self.mock_object(vserver_client, - 'get_network_interfaces', - mock.Mock(return_value=c_fake.NETWORK_INTERFACES)) + mock_delete_vserver_vlans = self.mock_object(self.library, + '_delete_vserver_vlans') + self.mock_object( + vserver_client, 'get_network_interfaces', + mock.Mock(return_value=c_fake.NETWORK_INTERFACES_MULTIPLE)) security_services = fake.NETWORK_INFO['security_services'] self.library._delete_vserver(fake.VSERVER1, @@ -716,8 +720,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): self.library._client.delete_vserver.assert_called_once_with( fake.VSERVER1, vserver_client, security_services=security_services) self.assertFalse(self.library._client.delete_ipspace.called) - mock_delete_vserver_vlan.assert_called_once_with( - c_fake.NETWORK_INTERFACES) + mock_delete_vserver_vlans.assert_called_once_with( + [c_fake.NETWORK_INTERFACES_MULTIPLE[0]]) @ddt.data([], c_fake.NETWORK_INTERFACES) def test_delete_vserver_with_ipspace(self, interfaces): @@ -732,8 +736,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): self.mock_object(self.library._client, 'ipspace_has_data_vservers', mock.Mock(return_value=False)) - mock_delete_vserver_vlan = self.mock_object(self.library, - '_delete_vserver_vlan') + mock_delete_vserver_vlans = self.mock_object(self.library, + '_delete_vserver_vlans') self.mock_object(vserver_client, 'get_network_interfaces', mock.Mock(return_value=interfaces)) @@ -749,11 +753,11 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): fake.VSERVER1, vserver_client, security_services=security_services) self.library._client.delete_ipspace.assert_called_once_with( fake.IPSPACE) - mock_delete_vserver_vlan.assert_called_once_with(interfaces) + mock_delete_vserver_vlans.assert_called_once_with(interfaces) - def test_delete_vserver_vlan(self): + def test_delete_vserver_vlans(self): - self.library._delete_vserver_vlan(c_fake.NETWORK_INTERFACES) + self.library._delete_vserver_vlans(c_fake.NETWORK_INTERFACES) for interface in c_fake.NETWORK_INTERFACES: home_port = interface['home-port'] port, vlan = home_port.split('-') @@ -761,7 +765,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): self.library._client.delete_vlan.assert_called_once_with( node, port, vlan) - def test_delete_vserver_vlan_client_error(self): + def test_delete_vserver_vlans_client_error(self): mock_exception_log = self.mock_object(lib_multi_svm.LOG, 'exception') self.mock_object( @@ -769,7 +773,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): 'delete_vlan', mock.Mock(side_effect=exception.NetAppException("fake error"))) - self.library._delete_vserver_vlan(c_fake.NETWORK_INTERFACES) + self.library._delete_vserver_vlans(c_fake.NETWORK_INTERFACES) for interface in c_fake.NETWORK_INTERFACES: home_port = interface['home-port'] port, vlan = home_port.split('-') diff --git a/releasenotes/notes/bug-1698250-netapp-cdot-fix-share-server-deletion-494ab3ad1c0a97c0.yaml b/releasenotes/notes/bug-1698250-netapp-cdot-fix-share-server-deletion-494ab3ad1c0a97c0.yaml new file mode 100644 index 0000000000..67fb68611e --- /dev/null +++ b/releasenotes/notes/bug-1698250-netapp-cdot-fix-share-server-deletion-494ab3ad1c0a97c0.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - The NetApp cDOT DHSS=True drivers have been fixed to not assume that share + servers are only provisioned on segmented (VLAN) networks.