From 11c8145b964bf2eecc16b29bf20627b73805ff2c Mon Sep 17 00:00:00 2001 From: Goutham Pacha Ravi Date: Sun, 18 Jun 2017 21:17:56 -0400 Subject: [PATCH] NetApp cDOT: Add gateway information to create static routes Add tenant routes/gateway to Vservers created by the driver. Change-Id: Id33c0e13d265d50f74f86ab8fb2c533eefa4b783 Closes-Bug: #1698258 Closes-Bug: #1612655 (cherry picked from commit f88df34e3188624ed60c69d9e159bfebe17b0f91) --- .../netapp/dataontap/client/client_cmode.py | 25 +++++++++ .../dataontap/cluster_mode/lib_multi_svm.py | 18 ++++++- .../drivers/netapp/dataontap/client/fakes.py | 19 +++++++ .../dataontap/client/test_client_cmode.py | 51 +++++++++++++++++++ .../cluster_mode/test_lib_multi_svm.py | 32 +++++++++--- .../share/drivers/netapp/dataontap/fakes.py | 34 +++++++++++++ ...ant-network-gateways-85935582e89a72a0.yaml | 7 +++ 7 files changed, 179 insertions(+), 7 deletions(-) create mode 100644 releasenotes/notes/bug-1698258-netapp-fix-tenant-network-gateways-85935582e89a72a0.yaml diff --git a/manila/share/drivers/netapp/dataontap/client/client_cmode.py b/manila/share/drivers/netapp/dataontap/client/client_cmode.py index 8ca1e2dc0d..6414e27c74 100644 --- a/manila/share/drivers/netapp/dataontap/client/client_cmode.py +++ b/manila/share/drivers/netapp/dataontap/client/client_cmode.py @@ -608,6 +608,31 @@ class NetAppCmodeClient(client_base.NetAppBaseClient): } raise exception.NetAppException(msg % msg_args) + @na_utils.trace + def create_route(self, gateway, destination='0.0.0.0/0'): + try: + api_args = { + 'destination': destination, + 'gateway': gateway, + 'return-record': 'true', + } + self.send_request('net-routes-create', api_args) + except netapp_api.NaApiError as e: + p = re.compile('.*Duplicate route exists.*', re.IGNORECASE) + if (e.code == netapp_api.EAPIERROR and re.match(p, e.message)): + LOG.debug('Route to %(destination)s via gateway %(gateway)s ' + 'exists.', + {'destination': destination, 'gateway': gateway}) + else: + msg = _('Failed to create a route to %(destination)s via ' + 'gateway %(gateway)s: %(err_msg)s') + msg_args = { + 'destination': destination, + 'gateway': gateway, + 'err_msg': e.message, + } + raise exception.NetAppException(msg % msg_args) + @na_utils.trace def _ensure_broadcast_domain_for_port(self, node, port, mtu, ipspace=DEFAULT_IPSPACE): 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 3d161c29f9..c4d4f3be46 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 @@ -181,6 +181,9 @@ class NetAppCmodeMultiSVMFileStorageLibrary( network_info, ipspace_name) + self._create_vserver_routes(vserver_client, + network_info) + vserver_client.enable_nfs( self.configuration.netapp_enabled_share_protocols) @@ -254,6 +257,20 @@ class NetAppCmodeMultiSVMFileStorageLibrary( self._create_lif(vserver_client, vserver_name, ipspace_name, node_name, lif_name, network_allocation) + @na_utils.trace + def _create_vserver_routes(self, vserver_client, network_info): + """Create Vserver route and set gateways.""" + route_gateways = [] + # NOTE(gouthamr): Use the gateway from the tenant subnet/s + # for the static routes. Do not configure a route for the admin + # subnet because fast path routing will work for incoming + # connections and there are no requirements for outgoing + # connections on the admin network yet. + for net_allocation in (network_info['network_allocations']): + if net_allocation['gateway'] not in route_gateways: + vserver_client.create_route(net_allocation['gateway']) + route_gateways.append(net_allocation['gateway']) + @na_utils.trace def _get_node_data_port(self, node): port_names = self._client.list_node_data_ports(node) @@ -358,7 +375,6 @@ class NetAppCmodeMultiSVMFileStorageLibrary( @na_utils.trace def _delete_vserver_vlans(self, network_interfaces_on_vlans): """Delete Vserver's VLAN configuration from ports""" - for interface in network_interfaces_on_vlans: try: home_port = interface['home-port'] diff --git a/manila/tests/share/drivers/netapp/dataontap/client/fakes.py b/manila/tests/share/drivers/netapp/dataontap/client/fakes.py index 4da5042583..0054b5e6ad 100644 --- a/manila/tests/share/drivers/netapp/dataontap/client/fakes.py +++ b/manila/tests/share/drivers/netapp/dataontap/client/fakes.py @@ -75,6 +75,8 @@ VLAN = '1001' VLAN_PORT = 'e0a-1001' IP_ADDRESS = '10.10.10.10' NETMASK = '255.255.255.0' +GATEWAY = '10.10.10.1' +SUBNET = '10.10.10.0/24' NET_ALLOCATION_ID = 'fake_allocation_id' LIF_NAME_TEMPLATE = 'os_%(net_allocation_id)s' LIF_NAME = LIF_NAME_TEMPLATE % {'net_allocation_id': NET_ALLOCATION_ID} @@ -2313,6 +2315,23 @@ PERF_OBJECT_INSTANCE_LIST_INFO_RESPONSE = etree.XML(""" """) +NET_ROUTES_CREATE_RESPONSE = etree.XML(""" + + + + ipv4 + %(subnet)s + %(gateway)s + 20 + %(vserver)s + + + """ % { + 'gateway': GATEWAY, + 'vserver': VSERVER_NAME, + 'subnet': SUBNET, +}) + FAKE_VOL_XML = """ open123 online diff --git a/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py b/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py index 33728b7369..b54d7574d3 100644 --- a/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py +++ b/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py @@ -1045,6 +1045,57 @@ class NetAppClientCmodeTestCase(test.TestCase): fake.PORT, fake.VLAN) + def test_create_route(self): + api_response = netapp_api.NaElement( + fake.NET_ROUTES_CREATE_RESPONSE) + expected_api_args = { + 'destination': fake.SUBNET, + 'gateway': fake.GATEWAY, + 'return-record': 'true', + } + self.mock_object( + self.client, 'send_request', mock.Mock(return_value=api_response)) + + self.client.create_route(fake.GATEWAY, destination=fake.SUBNET) + + self.client.send_request.assert_called_once_with( + 'net-routes-create', expected_api_args) + + def test_create_route_duplicate(self): + self.mock_object(client_cmode.LOG, 'debug') + expected_api_args = { + 'destination': fake.SUBNET, + 'gateway': fake.GATEWAY, + 'return-record': 'true', + } + self.mock_object( + self.client, 'send_request', + mock.Mock(side_effect=self._mock_api_error( + code=netapp_api.EAPIERROR, message='Duplicate route exists.'))) + + self.client.create_route(fake.GATEWAY, destination=fake.SUBNET) + + self.client.send_request.assert_called_once_with( + 'net-routes-create', expected_api_args) + self.assertEqual(1, client_cmode.LOG.debug.call_count) + + def test_create_route_api_error(self): + expected_api_args = { + 'destination': fake.SUBNET, + 'gateway': fake.GATEWAY, + 'return-record': 'true', + } + self.mock_object( + self.client, 'send_request', + mock.Mock(side_effect=self._mock_api_error())) + + self.assertRaises(exception.NetAppException, + self.client.create_route, + fake.GATEWAY, destination=fake.SUBNET) + + self.client.send_request.assert_called_once_with( + 'net-routes-create', expected_api_args) + def test_ensure_broadcast_domain_for_port_domain_match(self): port_info = { 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 9c225a565a..fa1c628ed4 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 @@ -314,20 +314,24 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): mock.Mock(return_value=fake.IPSPACE)) self.mock_object(self.library, '_create_vserver_lifs') self.mock_object(self.library, '_create_vserver_admin_lif') + self.mock_object(self.library, '_create_vserver_routes') self.library._create_vserver(vserver_name, fake.NETWORK_INFO) - self.library._create_ipspace.assert_called_with(fake.NETWORK_INFO) - self.library._client.create_vserver.assert_called_with( + self.library._create_ipspace.assert_called_once_with(fake.NETWORK_INFO) + self.library._client.create_vserver.assert_called_once_with( vserver_name, fake.ROOT_VOLUME_AGGREGATE, fake.ROOT_VOLUME, fake.AGGREGATES, fake.IPSPACE) - self.library._get_api_client.assert_called_with(vserver=vserver_name) - self.library._create_vserver_lifs.assert_called_with( + self.library._get_api_client.assert_called_once_with( + vserver=vserver_name) + self.library._create_vserver_lifs.assert_called_once_with( vserver_name, vserver_client, fake.NETWORK_INFO, fake.IPSPACE) - self.library._create_vserver_admin_lif.assert_called_with( + self.library._create_vserver_admin_lif.assert_called_once_with( vserver_name, vserver_client, fake.NETWORK_INFO, fake.IPSPACE) + self.library._create_vserver_routes.assert_called_once_with( + vserver_client, fake.NETWORK_INFO) vserver_client.enable_nfs.assert_called_once_with(versions) - self.library._client.setup_security_services.assert_called_with( + self.library._client.setup_security_services.assert_called_once_with( fake.NETWORK_INFO['security_services'], vserver_client, vserver_name) @@ -516,6 +520,22 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): self.assertFalse(self.library._create_lif.called) + @ddt.data( + fake.get_network_info(fake.USER_NETWORK_ALLOCATIONS, + fake.ADMIN_NETWORK_ALLOCATIONS), + fake.get_network_info(fake.USER_NETWORK_ALLOCATIONS_IPV6, + fake.ADMIN_NETWORK_ALLOCATIONS)) + def test_create_vserver_routes(self, network_info): + expected_gateway = network_info['network_allocations'][0]['gateway'] + vserver_client = mock.Mock() + self.mock_object(vserver_client, 'create_route') + + retval = self.library._create_vserver_routes( + vserver_client, network_info) + + self.assertIsNone(retval) + vserver_client.create_route.assert_called_once_with(expected_gateway) + def test_get_node_data_port(self): self.mock_object(self.client, diff --git a/manila/tests/share/drivers/netapp/dataontap/fakes.py b/manila/tests/share/drivers/netapp/dataontap/fakes.py index d8e7187986..a6caeb4ac8 100644 --- a/manila/tests/share/drivers/netapp/dataontap/fakes.py +++ b/manila/tests/share/drivers/netapp/dataontap/fakes.py @@ -230,6 +230,7 @@ USER_NETWORK_ALLOCATIONS = [ 'network_type': 'vlan', 'label': 'user', 'mtu': MTU, + 'gateway': '10.10.10.1', }, { 'id': '7eabdeed-bad2-46ea-bd0f-a33884c869e0', @@ -239,6 +240,30 @@ USER_NETWORK_ALLOCATIONS = [ 'network_type': 'vlan', 'label': 'user', 'mtu': MTU, + 'gateway': '10.10.10.1', + } +] + +USER_NETWORK_ALLOCATIONS_IPV6 = [ + { + 'id': '234dbb10-9a36-46f2-8d89-3d909830c356', + 'ip_address': 'fd68:1a09:66ab:8d51:0:10:0:1', + 'cidr': 'fd68:1a09:66ab:8d51::/64', + 'segmentation_id': '2000', + 'network_type': 'vlan', + 'label': 'user', + 'mtu': MTU, + 'gateway': 'fd68:1a09:66ab:8d51:0:0:0:1', + }, + { + 'id': '6677deed-bad2-46ea-bd0f-a33884c869e0', + 'ip_address': 'fd68:1a09:66ab:8d51:0:10:0:2', + 'cidr': 'fd68:1a09:66ab:8d51::/64', + 'segmentation_id': '2000', + 'network_type': 'vlan', + 'label': 'user', + 'mtu': MTU, + 'gateway': 'fd68:1a09:66ab:8d51:0:0:0:1', } ] @@ -251,6 +276,7 @@ ADMIN_NETWORK_ALLOCATIONS = [ 'network_type': 'flat', 'label': 'admin', 'mtu': MTU, + 'gateway': '10.10.20.1' }, ] @@ -1200,3 +1226,11 @@ def get_config_cmode(): config.netapp_volume_snapshot_reserve_percent = 8 config.netapp_vserver = VSERVER1 return config + + +def get_network_info(user_network_allocation, admin_network_allocation): + net_info = copy.deepcopy(NETWORK_INFO) + net_info['network_allocations'] = user_network_allocation + net_info['admin_network_allocations'] = admin_network_allocation + + return net_info diff --git a/releasenotes/notes/bug-1698258-netapp-fix-tenant-network-gateways-85935582e89a72a0.yaml b/releasenotes/notes/bug-1698258-netapp-fix-tenant-network-gateways-85935582e89a72a0.yaml new file mode 100644 index 0000000000..289faa08da --- /dev/null +++ b/releasenotes/notes/bug-1698258-netapp-fix-tenant-network-gateways-85935582e89a72a0.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - The NetApp DHSS=True driver now creates static routes with the gateway + specified on the tenant networks. Potential beneficiaries of this bug-fix + are deployers/users whose CIFS security service (e.g. Active Directory) + is not part of the tenant network, but a route exists via the tenant + network gateway.