Browse Source

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 f88df34e31)
Goutham Pacha Ravi 1 year ago
parent
commit
11c8145b96

+ 25
- 0
manila/share/drivers/netapp/dataontap/client/client_cmode.py View File

@@ -608,6 +608,31 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
608 608
                 }
609 609
                 raise exception.NetAppException(msg % msg_args)
610 610
 
611
+    @na_utils.trace
612
+    def create_route(self, gateway, destination='0.0.0.0/0'):
613
+        try:
614
+            api_args = {
615
+                'destination': destination,
616
+                'gateway': gateway,
617
+                'return-record': 'true',
618
+            }
619
+            self.send_request('net-routes-create', api_args)
620
+        except netapp_api.NaApiError as e:
621
+            p = re.compile('.*Duplicate route exists.*', re.IGNORECASE)
622
+            if (e.code == netapp_api.EAPIERROR and re.match(p, e.message)):
623
+                LOG.debug('Route to %(destination)s via gateway %(gateway)s '
624
+                          'exists.',
625
+                          {'destination': destination, 'gateway': gateway})
626
+            else:
627
+                msg = _('Failed to create a route to %(destination)s via '
628
+                        'gateway %(gateway)s: %(err_msg)s')
629
+                msg_args = {
630
+                    'destination': destination,
631
+                    'gateway': gateway,
632
+                    'err_msg': e.message,
633
+                }
634
+                raise exception.NetAppException(msg % msg_args)
635
+
611 636
     @na_utils.trace
612 637
     def _ensure_broadcast_domain_for_port(self, node, port, mtu,
613 638
                                           ipspace=DEFAULT_IPSPACE):

+ 17
- 1
manila/share/drivers/netapp/dataontap/cluster_mode/lib_multi_svm.py View File

@@ -181,6 +181,9 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
181 181
                                            network_info,
182 182
                                            ipspace_name)
183 183
 
184
+            self._create_vserver_routes(vserver_client,
185
+                                        network_info)
186
+
184 187
             vserver_client.enable_nfs(
185 188
                 self.configuration.netapp_enabled_share_protocols)
186 189
 
@@ -254,6 +257,20 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
254 257
         self._create_lif(vserver_client, vserver_name, ipspace_name,
255 258
                          node_name, lif_name, network_allocation)
256 259
 
260
+    @na_utils.trace
261
+    def _create_vserver_routes(self, vserver_client, network_info):
262
+        """Create Vserver route and set gateways."""
263
+        route_gateways = []
264
+        # NOTE(gouthamr): Use the gateway from the tenant subnet/s
265
+        # for the static routes. Do not configure a route for the admin
266
+        # subnet because fast path routing will work for incoming
267
+        # connections and there are no requirements for outgoing
268
+        # connections on the admin network yet.
269
+        for net_allocation in (network_info['network_allocations']):
270
+            if net_allocation['gateway'] not in route_gateways:
271
+                vserver_client.create_route(net_allocation['gateway'])
272
+                route_gateways.append(net_allocation['gateway'])
273
+
257 274
     @na_utils.trace
258 275
     def _get_node_data_port(self, node):
259 276
         port_names = self._client.list_node_data_ports(node)
@@ -358,7 +375,6 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
358 375
     @na_utils.trace
359 376
     def _delete_vserver_vlans(self, network_interfaces_on_vlans):
360 377
         """Delete Vserver's VLAN configuration from ports"""
361
-
362 378
         for interface in network_interfaces_on_vlans:
363 379
             try:
364 380
                 home_port = interface['home-port']

+ 19
- 0
manila/tests/share/drivers/netapp/dataontap/client/fakes.py View File

@@ -75,6 +75,8 @@ VLAN = '1001'
75 75
 VLAN_PORT = 'e0a-1001'
76 76
 IP_ADDRESS = '10.10.10.10'
77 77
 NETMASK = '255.255.255.0'
78
+GATEWAY = '10.10.10.1'
79
+SUBNET = '10.10.10.0/24'
78 80
 NET_ALLOCATION_ID = 'fake_allocation_id'
79 81
 LIF_NAME_TEMPLATE = 'os_%(net_allocation_id)s'
80 82
 LIF_NAME = LIF_NAME_TEMPLATE % {'net_allocation_id': NET_ALLOCATION_ID}
@@ -2313,6 +2315,23 @@ PERF_OBJECT_INSTANCE_LIST_INFO_RESPONSE = etree.XML("""
2313 2315
     </instances>
2314 2316
   </results>""")
2315 2317
 
2318
+NET_ROUTES_CREATE_RESPONSE = etree.XML("""
2319
+  <results status="passed">
2320
+    <result>
2321
+      <net-vs-routes-info>
2322
+        <address-family>ipv4</address-family>
2323
+        <destination>%(subnet)s</destination>
2324
+        <gateway>%(gateway)s</gateway>
2325
+        <metric>20</metric>
2326
+        <vserver>%(vserver)s</vserver>
2327
+      </net-vs-routes-info>
2328
+    </result>
2329
+  </results>""" % {
2330
+    'gateway': GATEWAY,
2331
+    'vserver': VSERVER_NAME,
2332
+    'subnet': SUBNET,
2333
+})
2334
+
2316 2335
 FAKE_VOL_XML = """<volume-info xmlns='http://www.netapp.com/filer/admin'>
2317 2336
     <name>open123</name>
2318 2337
     <state>online</state>

+ 51
- 0
manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py View File

@@ -1045,6 +1045,57 @@ class NetAppClientCmodeTestCase(test.TestCase):
1045 1045
                           fake.PORT,
1046 1046
                           fake.VLAN)
1047 1047
 
1048
+    def test_create_route(self):
1049
+        api_response = netapp_api.NaElement(
1050
+            fake.NET_ROUTES_CREATE_RESPONSE)
1051
+        expected_api_args = {
1052
+            'destination': fake.SUBNET,
1053
+            'gateway': fake.GATEWAY,
1054
+            'return-record': 'true',
1055
+        }
1056
+        self.mock_object(
1057
+            self.client, 'send_request', mock.Mock(return_value=api_response))
1058
+
1059
+        self.client.create_route(fake.GATEWAY, destination=fake.SUBNET)
1060
+
1061
+        self.client.send_request.assert_called_once_with(
1062
+            'net-routes-create', expected_api_args)
1063
+
1064
+    def test_create_route_duplicate(self):
1065
+        self.mock_object(client_cmode.LOG, 'debug')
1066
+        expected_api_args = {
1067
+            'destination': fake.SUBNET,
1068
+            'gateway': fake.GATEWAY,
1069
+            'return-record': 'true',
1070
+        }
1071
+        self.mock_object(
1072
+            self.client, 'send_request',
1073
+            mock.Mock(side_effect=self._mock_api_error(
1074
+                code=netapp_api.EAPIERROR, message='Duplicate route exists.')))
1075
+
1076
+        self.client.create_route(fake.GATEWAY, destination=fake.SUBNET)
1077
+
1078
+        self.client.send_request.assert_called_once_with(
1079
+            'net-routes-create', expected_api_args)
1080
+        self.assertEqual(1, client_cmode.LOG.debug.call_count)
1081
+
1082
+    def test_create_route_api_error(self):
1083
+        expected_api_args = {
1084
+            'destination': fake.SUBNET,
1085
+            'gateway': fake.GATEWAY,
1086
+            'return-record': 'true',
1087
+        }
1088
+        self.mock_object(
1089
+            self.client, 'send_request',
1090
+            mock.Mock(side_effect=self._mock_api_error()))
1091
+
1092
+        self.assertRaises(exception.NetAppException,
1093
+                          self.client.create_route,
1094
+                          fake.GATEWAY, destination=fake.SUBNET)
1095
+
1096
+        self.client.send_request.assert_called_once_with(
1097
+            'net-routes-create', expected_api_args)
1098
+
1048 1099
     def test_ensure_broadcast_domain_for_port_domain_match(self):
1049 1100
 
1050 1101
         port_info = {

+ 26
- 6
manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_multi_svm.py View File

@@ -314,20 +314,24 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
314 314
                          mock.Mock(return_value=fake.IPSPACE))
315 315
         self.mock_object(self.library, '_create_vserver_lifs')
316 316
         self.mock_object(self.library, '_create_vserver_admin_lif')
317
+        self.mock_object(self.library, '_create_vserver_routes')
317 318
 
318 319
         self.library._create_vserver(vserver_name, fake.NETWORK_INFO)
319 320
 
320
-        self.library._create_ipspace.assert_called_with(fake.NETWORK_INFO)
321
-        self.library._client.create_vserver.assert_called_with(
321
+        self.library._create_ipspace.assert_called_once_with(fake.NETWORK_INFO)
322
+        self.library._client.create_vserver.assert_called_once_with(
322 323
             vserver_name, fake.ROOT_VOLUME_AGGREGATE, fake.ROOT_VOLUME,
323 324
             fake.AGGREGATES, fake.IPSPACE)
324
-        self.library._get_api_client.assert_called_with(vserver=vserver_name)
325
-        self.library._create_vserver_lifs.assert_called_with(
325
+        self.library._get_api_client.assert_called_once_with(
326
+            vserver=vserver_name)
327
+        self.library._create_vserver_lifs.assert_called_once_with(
326 328
             vserver_name, vserver_client, fake.NETWORK_INFO, fake.IPSPACE)
327
-        self.library._create_vserver_admin_lif.assert_called_with(
329
+        self.library._create_vserver_admin_lif.assert_called_once_with(
328 330
             vserver_name, vserver_client, fake.NETWORK_INFO, fake.IPSPACE)
331
+        self.library._create_vserver_routes.assert_called_once_with(
332
+            vserver_client, fake.NETWORK_INFO)
329 333
         vserver_client.enable_nfs.assert_called_once_with(versions)
330
-        self.library._client.setup_security_services.assert_called_with(
334
+        self.library._client.setup_security_services.assert_called_once_with(
331 335
             fake.NETWORK_INFO['security_services'], vserver_client,
332 336
             vserver_name)
333 337
 
@@ -516,6 +520,22 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
516 520
 
517 521
         self.assertFalse(self.library._create_lif.called)
518 522
 
523
+    @ddt.data(
524
+        fake.get_network_info(fake.USER_NETWORK_ALLOCATIONS,
525
+                              fake.ADMIN_NETWORK_ALLOCATIONS),
526
+        fake.get_network_info(fake.USER_NETWORK_ALLOCATIONS_IPV6,
527
+                              fake.ADMIN_NETWORK_ALLOCATIONS))
528
+    def test_create_vserver_routes(self, network_info):
529
+        expected_gateway = network_info['network_allocations'][0]['gateway']
530
+        vserver_client = mock.Mock()
531
+        self.mock_object(vserver_client, 'create_route')
532
+
533
+        retval = self.library._create_vserver_routes(
534
+            vserver_client, network_info)
535
+
536
+        self.assertIsNone(retval)
537
+        vserver_client.create_route.assert_called_once_with(expected_gateway)
538
+
519 539
     def test_get_node_data_port(self):
520 540
 
521 541
         self.mock_object(self.client,

+ 34
- 0
manila/tests/share/drivers/netapp/dataontap/fakes.py View File

@@ -230,6 +230,7 @@ USER_NETWORK_ALLOCATIONS = [
230 230
         'network_type': 'vlan',
231 231
         'label': 'user',
232 232
         'mtu': MTU,
233
+        'gateway': '10.10.10.1',
233 234
     },
234 235
     {
235 236
         'id': '7eabdeed-bad2-46ea-bd0f-a33884c869e0',
@@ -239,6 +240,30 @@ USER_NETWORK_ALLOCATIONS = [
239 240
         'network_type': 'vlan',
240 241
         'label': 'user',
241 242
         'mtu': MTU,
243
+        'gateway': '10.10.10.1',
244
+    }
245
+]
246
+
247
+USER_NETWORK_ALLOCATIONS_IPV6 = [
248
+    {
249
+        'id': '234dbb10-9a36-46f2-8d89-3d909830c356',
250
+        'ip_address': 'fd68:1a09:66ab:8d51:0:10:0:1',
251
+        'cidr': 'fd68:1a09:66ab:8d51::/64',
252
+        'segmentation_id': '2000',
253
+        'network_type': 'vlan',
254
+        'label': 'user',
255
+        'mtu': MTU,
256
+        'gateway': 'fd68:1a09:66ab:8d51:0:0:0:1',
257
+    },
258
+    {
259
+        'id': '6677deed-bad2-46ea-bd0f-a33884c869e0',
260
+        'ip_address': 'fd68:1a09:66ab:8d51:0:10:0:2',
261
+        'cidr': 'fd68:1a09:66ab:8d51::/64',
262
+        'segmentation_id': '2000',
263
+        'network_type': 'vlan',
264
+        'label': 'user',
265
+        'mtu': MTU,
266
+        'gateway': 'fd68:1a09:66ab:8d51:0:0:0:1',
242 267
     }
243 268
 ]
244 269
 
@@ -251,6 +276,7 @@ ADMIN_NETWORK_ALLOCATIONS = [
251 276
         'network_type': 'flat',
252 277
         'label': 'admin',
253 278
         'mtu': MTU,
279
+        'gateway': '10.10.20.1'
254 280
     },
255 281
 ]
256 282
 
@@ -1200,3 +1226,11 @@ def get_config_cmode():
1200 1226
     config.netapp_volume_snapshot_reserve_percent = 8
1201 1227
     config.netapp_vserver = VSERVER1
1202 1228
     return config
1229
+
1230
+
1231
+def get_network_info(user_network_allocation, admin_network_allocation):
1232
+    net_info = copy.deepcopy(NETWORK_INFO)
1233
+    net_info['network_allocations'] = user_network_allocation
1234
+    net_info['admin_network_allocations'] = admin_network_allocation
1235
+
1236
+    return net_info

+ 7
- 0
releasenotes/notes/bug-1698258-netapp-fix-tenant-network-gateways-85935582e89a72a0.yaml View File

@@ -0,0 +1,7 @@
1
+---
2
+fixes:
3
+  - The NetApp DHSS=True driver now creates static routes with the gateway
4
+    specified on the tenant networks. Potential beneficiaries of this bug-fix
5
+    are deployers/users whose CIFS security service (e.g. Active Directory)
6
+    is not part of the tenant network, but a route exists via the tenant
7
+    network gateway.

Loading…
Cancel
Save