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)
(cherry picked from commit 11c8145b96)
changes/85/587685/1
Goutham Pacha Ravi 2 years ago
parent
commit
546f3c8478

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

@@ -552,6 +552,31 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
552 552
                 }
553 553
                 raise exception.NetAppException(msg % msg_args)
554 554
 
555
+    @na_utils.trace
556
+    def create_route(self, gateway, destination='0.0.0.0/0'):
557
+        try:
558
+            api_args = {
559
+                'destination': destination,
560
+                'gateway': gateway,
561
+                'return-record': 'true',
562
+            }
563
+            self.send_request('net-routes-create', api_args)
564
+        except netapp_api.NaApiError as e:
565
+            p = re.compile('.*Duplicate route exists.*', re.IGNORECASE)
566
+            if (e.code == netapp_api.EAPIERROR and re.match(p, e.message)):
567
+                LOG.debug('Route to %(destination)s via gateway %(gateway)s '
568
+                          'exists.',
569
+                          {'destination': destination, 'gateway': gateway})
570
+            else:
571
+                msg = _('Failed to create a route to %(destination)s via '
572
+                        'gateway %(gateway)s: %(err_msg)s')
573
+                msg_args = {
574
+                    'destination': destination,
575
+                    'gateway': gateway,
576
+                    'err_msg': e.message,
577
+                }
578
+                raise exception.NetAppException(msg % msg_args)
579
+
555 580
     @na_utils.trace
556 581
     def _ensure_broadcast_domain_for_port(self, node, port, mtu,
557 582
                                           ipspace=DEFAULT_IPSPACE):

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

@@ -173,6 +173,9 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
173 173
                                            network_info,
174 174
                                            ipspace_name)
175 175
 
176
+            self._create_vserver_routes(vserver_client,
177
+                                        network_info)
178
+
176 179
             vserver_client.enable_nfs(
177 180
                 self.configuration.netapp_enabled_share_protocols)
178 181
 
@@ -246,6 +249,20 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
246 249
         self._create_lif(vserver_client, vserver_name, ipspace_name,
247 250
                          node_name, lif_name, network_allocation)
248 251
 
252
+    @na_utils.trace
253
+    def _create_vserver_routes(self, vserver_client, network_info):
254
+        """Create Vserver route and set gateways."""
255
+        route_gateways = []
256
+        # NOTE(gouthamr): Use the gateway from the tenant subnet/s
257
+        # for the static routes. Do not configure a route for the admin
258
+        # subnet because fast path routing will work for incoming
259
+        # connections and there are no requirements for outgoing
260
+        # connections on the admin network yet.
261
+        for net_allocation in (network_info['network_allocations']):
262
+            if net_allocation['gateway'] not in route_gateways:
263
+                vserver_client.create_route(net_allocation['gateway'])
264
+                route_gateways.append(net_allocation['gateway'])
265
+
249 266
     @na_utils.trace
250 267
     def _get_node_data_port(self, node):
251 268
         port_names = self._client.list_node_data_ports(node)
@@ -350,7 +367,6 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
350 367
     @na_utils.trace
351 368
     def _delete_vserver_vlans(self, network_interfaces_on_vlans):
352 369
         """Delete Vserver's VLAN configuration from ports"""
353
-
354 370
         for interface in network_interfaces_on_vlans:
355 371
             try:
356 372
                 home_port = interface['home-port']

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

@@ -73,6 +73,8 @@ VLAN = '1001'
73 73
 VLAN_PORT = 'e0a-1001'
74 74
 IP_ADDRESS = '10.10.10.10'
75 75
 NETMASK = '255.255.255.0'
76
+GATEWAY = '10.10.10.1'
77
+SUBNET = '10.10.10.0/24'
76 78
 NET_ALLOCATION_ID = 'fake_allocation_id'
77 79
 LIF_NAME_TEMPLATE = 'os_%(net_allocation_id)s'
78 80
 LIF_NAME = LIF_NAME_TEMPLATE % {'net_allocation_id': NET_ALLOCATION_ID}
@@ -2079,6 +2081,23 @@ SNAPMIRROR_INITIALIZE_RESULT = etree.XML("""
2079 2081
   </results>
2080 2082
 """)
2081 2083
 
2084
+NET_ROUTES_CREATE_RESPONSE = etree.XML("""
2085
+  <results status="passed">
2086
+    <result>
2087
+      <net-vs-routes-info>
2088
+        <address-family>ipv4</address-family>
2089
+        <destination>%(subnet)s</destination>
2090
+        <gateway>%(gateway)s</gateway>
2091
+        <metric>20</metric>
2092
+        <vserver>%(vserver)s</vserver>
2093
+      </net-vs-routes-info>
2094
+    </result>
2095
+  </results>""" % {
2096
+    'gateway': GATEWAY,
2097
+    'vserver': VSERVER_NAME,
2098
+    'subnet': SUBNET,
2099
+})
2100
+
2082 2101
 FAKE_VOL_XML = """<volume-info xmlns='http://www.netapp.com/filer/admin'>
2083 2102
     <name>open123</name>
2084 2103
     <state>online</state>

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

@@ -981,6 +981,57 @@ class NetAppClientCmodeTestCase(test.TestCase):
981 981
                           fake.PORT,
982 982
                           fake.VLAN)
983 983
 
984
+    def test_create_route(self):
985
+        api_response = netapp_api.NaElement(
986
+            fake.NET_ROUTES_CREATE_RESPONSE)
987
+        expected_api_args = {
988
+            'destination': fake.SUBNET,
989
+            'gateway': fake.GATEWAY,
990
+            'return-record': 'true',
991
+        }
992
+        self.mock_object(
993
+            self.client, 'send_request', mock.Mock(return_value=api_response))
994
+
995
+        self.client.create_route(fake.GATEWAY, destination=fake.SUBNET)
996
+
997
+        self.client.send_request.assert_called_once_with(
998
+            'net-routes-create', expected_api_args)
999
+
1000
+    def test_create_route_duplicate(self):
1001
+        self.mock_object(client_cmode.LOG, 'debug')
1002
+        expected_api_args = {
1003
+            'destination': fake.SUBNET,
1004
+            'gateway': fake.GATEWAY,
1005
+            'return-record': 'true',
1006
+        }
1007
+        self.mock_object(
1008
+            self.client, 'send_request',
1009
+            mock.Mock(side_effect=self._mock_api_error(
1010
+                code=netapp_api.EAPIERROR, message='Duplicate route exists.')))
1011
+
1012
+        self.client.create_route(fake.GATEWAY, destination=fake.SUBNET)
1013
+
1014
+        self.client.send_request.assert_called_once_with(
1015
+            'net-routes-create', expected_api_args)
1016
+        self.assertEqual(1, client_cmode.LOG.debug.call_count)
1017
+
1018
+    def test_create_route_api_error(self):
1019
+        expected_api_args = {
1020
+            'destination': fake.SUBNET,
1021
+            'gateway': fake.GATEWAY,
1022
+            'return-record': 'true',
1023
+        }
1024
+        self.mock_object(
1025
+            self.client, 'send_request',
1026
+            mock.Mock(side_effect=self._mock_api_error()))
1027
+
1028
+        self.assertRaises(exception.NetAppException,
1029
+                          self.client.create_route,
1030
+                          fake.GATEWAY, destination=fake.SUBNET)
1031
+
1032
+        self.client.send_request.assert_called_once_with(
1033
+            'net-routes-create', expected_api_args)
1034
+
984 1035
     def test_ensure_broadcast_domain_for_port_domain_match(self):
985 1036
 
986 1037
         port_info = {

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

@@ -296,20 +296,24 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
296 296
                          mock.Mock(return_value=fake.IPSPACE))
297 297
         self.mock_object(self.library, '_create_vserver_lifs')
298 298
         self.mock_object(self.library, '_create_vserver_admin_lif')
299
+        self.mock_object(self.library, '_create_vserver_routes')
299 300
 
300 301
         self.library._create_vserver(vserver_name, fake.NETWORK_INFO)
301 302
 
302
-        self.library._create_ipspace.assert_called_with(fake.NETWORK_INFO)
303
-        self.library._client.create_vserver.assert_called_with(
303
+        self.library._create_ipspace.assert_called_once_with(fake.NETWORK_INFO)
304
+        self.library._client.create_vserver.assert_called_once_with(
304 305
             vserver_name, fake.ROOT_VOLUME_AGGREGATE, fake.ROOT_VOLUME,
305 306
             fake.AGGREGATES, fake.IPSPACE)
306
-        self.library._get_api_client.assert_called_with(vserver=vserver_name)
307
-        self.library._create_vserver_lifs.assert_called_with(
307
+        self.library._get_api_client.assert_called_once_with(
308
+            vserver=vserver_name)
309
+        self.library._create_vserver_lifs.assert_called_once_with(
308 310
             vserver_name, vserver_client, fake.NETWORK_INFO, fake.IPSPACE)
309
-        self.library._create_vserver_admin_lif.assert_called_with(
311
+        self.library._create_vserver_admin_lif.assert_called_once_with(
310 312
             vserver_name, vserver_client, fake.NETWORK_INFO, fake.IPSPACE)
313
+        self.library._create_vserver_routes.assert_called_once_with(
314
+            vserver_client, fake.NETWORK_INFO)
311 315
         vserver_client.enable_nfs.assert_called_once_with(versions)
312
-        self.library._client.setup_security_services.assert_called_with(
316
+        self.library._client.setup_security_services.assert_called_once_with(
313 317
             fake.NETWORK_INFO['security_services'], vserver_client,
314 318
             vserver_name)
315 319
 
@@ -509,6 +513,22 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
509 513
 
510 514
         self.assertFalse(self.library._create_lif.called)
511 515
 
516
+    @ddt.data(
517
+        fake.get_network_info(fake.USER_NETWORK_ALLOCATIONS,
518
+                              fake.ADMIN_NETWORK_ALLOCATIONS),
519
+        fake.get_network_info(fake.USER_NETWORK_ALLOCATIONS_IPV6,
520
+                              fake.ADMIN_NETWORK_ALLOCATIONS))
521
+    def test_create_vserver_routes(self, network_info):
522
+        expected_gateway = network_info['network_allocations'][0]['gateway']
523
+        vserver_client = mock.Mock()
524
+        self.mock_object(vserver_client, 'create_route')
525
+
526
+        retval = self.library._create_vserver_routes(
527
+            vserver_client, network_info)
528
+
529
+        self.assertIsNone(retval)
530
+        vserver_client.create_route.assert_called_once_with(expected_gateway)
531
+
512 532
     def test_get_node_data_port(self):
513 533
 
514 534
         self.mock_object(self.client,

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

@@ -227,6 +227,7 @@ USER_NETWORK_ALLOCATIONS = [
227 227
         'network_type': 'vlan',
228 228
         'label': 'user',
229 229
         'mtu': MTU,
230
+        'gateway': '10.10.10.1',
230 231
     },
231 232
     {
232 233
         'id': '7eabdeed-bad2-46ea-bd0f-a33884c869e0',
@@ -236,6 +237,30 @@ USER_NETWORK_ALLOCATIONS = [
236 237
         'network_type': 'vlan',
237 238
         'label': 'user',
238 239
         'mtu': MTU,
240
+        'gateway': '10.10.10.1',
241
+    }
242
+]
243
+
244
+USER_NETWORK_ALLOCATIONS_IPV6 = [
245
+    {
246
+        'id': '234dbb10-9a36-46f2-8d89-3d909830c356',
247
+        'ip_address': 'fd68:1a09:66ab:8d51:0:10:0:1',
248
+        'cidr': 'fd68:1a09:66ab:8d51::/64',
249
+        'segmentation_id': '2000',
250
+        'network_type': 'vlan',
251
+        'label': 'user',
252
+        'mtu': MTU,
253
+        'gateway': 'fd68:1a09:66ab:8d51:0:0:0:1',
254
+    },
255
+    {
256
+        'id': '6677deed-bad2-46ea-bd0f-a33884c869e0',
257
+        'ip_address': 'fd68:1a09:66ab:8d51:0:10:0:2',
258
+        'cidr': 'fd68:1a09:66ab:8d51::/64',
259
+        'segmentation_id': '2000',
260
+        'network_type': 'vlan',
261
+        'label': 'user',
262
+        'mtu': MTU,
263
+        'gateway': 'fd68:1a09:66ab:8d51:0:0:0:1',
239 264
     }
240 265
 ]
241 266
 
@@ -248,6 +273,7 @@ ADMIN_NETWORK_ALLOCATIONS = [
248 273
         'network_type': 'flat',
249 274
         'label': 'admin',
250 275
         'mtu': MTU,
276
+        'gateway': '10.10.20.1'
251 277
     },
252 278
 ]
253 279
 
@@ -611,3 +637,11 @@ def get_config_cmode():
611 637
     config.netapp_volume_snapshot_reserve_percent = 8
612 638
     config.netapp_vserver = VSERVER1
613 639
     return config
640
+
641
+
642
+def get_network_info(user_network_allocation, admin_network_allocation):
643
+    net_info = copy.deepcopy(NETWORK_INFO)
644
+    net_info['network_allocations'] = user_network_allocation
645
+    net_info['admin_network_allocations'] = admin_network_allocation
646
+
647
+    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