]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Disable PUT for IPv6 subnet attributes
authorHenry Gessau <gessau@cisco.com>
Wed, 8 Oct 2014 00:38:38 +0000 (20:38 -0400)
committerHenry Gessau <gessau@cisco.com>
Wed, 8 Oct 2014 17:16:54 +0000 (13:16 -0400)
In Juno we are not ready for allowing the IPv6 attributes on a subnet
to be updated after the subnet is created, because:
- The implementation for supporting updates is incomplete.
- Perceived lack of usefulness, no good use cases known yet.
- Allowing updates causes more complexity in the code.
- Have not tested that radvd, dhcp, etc. behave OK after update.

Therefore, for now, we set 'allow_put' to False for the two IPv6
attributes, ipv6_ra_mode and ipv6_address_mode. This prevents the
modes from being updated via the PUT:subnets API.

Closes-bug: #1378952

Change-Id: Id6ce894d223c91421b62f82d266cfc15fa63ed0e

neutron/api/v2/attributes.py
neutron/db/db_base_plugin_v2.py
neutron/tests/unit/test_db_plugin.py

index 0cf1816a4209b033bb8ddbe9f933a9efee6f1a48..83471f946e68ec90f29a52b8192eca5a872404c5 100644 (file)
@@ -729,11 +729,11 @@ RESOURCE_ATTRIBUTE_MAP = {
                         'default': True,
                         'convert_to': convert_to_boolean,
                         'is_visible': True},
-        'ipv6_ra_mode': {'allow_post': True, 'allow_put': True,
+        'ipv6_ra_mode': {'allow_post': True, 'allow_put': False,
                          'default': ATTR_NOT_SPECIFIED,
                          'validate': {'type:values': constants.IPV6_MODES},
                          'is_visible': True},
-        'ipv6_address_mode': {'allow_post': True, 'allow_put': True,
+        'ipv6_address_mode': {'allow_post': True, 'allow_put': False,
                               'default': ATTR_NOT_SPECIFIED,
                               'validate': {'type:values':
                                            constants.IPV6_MODES},
index 155b9f3995d07e3449c6b4ec4e7ee62c320ffd15..9582efed3c4346a8fe8c1a48686599005a778bc8 100644 (file)
@@ -740,24 +740,17 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
             raise n_exc.InvalidSharedSetting(network=original.name)
 
     def _validate_ipv6_attributes(self, subnet, cur_subnet):
+        if cur_subnet:
+            self._validate_ipv6_update_dhcp(subnet, cur_subnet)
+            return
         ra_mode_set = attributes.is_attr_set(subnet.get('ipv6_ra_mode'))
         address_mode_set = attributes.is_attr_set(
             subnet.get('ipv6_address_mode'))
-        if cur_subnet:
-            ra_mode = (subnet['ipv6_ra_mode'] if ra_mode_set
-                       else cur_subnet['ipv6_ra_mode'])
-            addr_mode = (subnet['ipv6_address_mode'] if address_mode_set
-                         else cur_subnet['ipv6_address_mode'])
-            if ra_mode_set or address_mode_set:
-                # Check that updated subnet ipv6 attributes do not conflict
-                self._validate_ipv6_combination(ra_mode, addr_mode)
-            self._validate_ipv6_update_dhcp(subnet, cur_subnet)
-        else:
-            self._validate_ipv6_dhcp(ra_mode_set, address_mode_set,
-                                     subnet['enable_dhcp'])
-            if ra_mode_set and address_mode_set:
-                self._validate_ipv6_combination(subnet['ipv6_ra_mode'],
-                                                subnet['ipv6_address_mode'])
+        self._validate_ipv6_dhcp(ra_mode_set, address_mode_set,
+                                 subnet['enable_dhcp'])
+        if ra_mode_set and address_mode_set:
+            self._validate_ipv6_combination(subnet['ipv6_ra_mode'],
+                                            subnet['ipv6_address_mode'])
         if address_mode_set:
             self._validate_eui64_applicable(subnet)
 
index a391eefcc7dadf8bbad24d9d362fe24860389aee..f390be5afc9f851c0c42a89a2317c313b4b9740d 100644 (file)
@@ -15,6 +15,7 @@
 
 import contextlib
 import copy
+import itertools
 
 import mock
 from oslo.config import cfg
@@ -3038,15 +3039,48 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
             res = subnet_req.get_response(self.api)
             self.assertEqual(res.status_int, webob.exc.HTTPClientError.code)
 
-    def test_create_subnet_ipv6_attributes(self):
-        gateway_ip = 'fe80::1'
-        cidr = 'fe80::/64'
-
-        for mode in constants.IPV6_MODES:
-            self._test_create_subnet(gateway_ip=gateway_ip,
-                                     cidr=cidr, ip_version=6,
-                                     ipv6_ra_mode=mode,
-                                     ipv6_address_mode=mode)
+    def _test_validate_subnet_ipv6_modes(self, cur_subnet=None,
+                                         expect_success=True, **modes):
+        plugin = manager.NeutronManager.get_plugin()
+        ctx = context.get_admin_context(load_admin_roles=False)
+        new_subnet = {'ip_version': 6,
+                      'cidr': 'fe80::/64',
+                      'enable_dhcp': True}
+        for mode, value in modes.items():
+            new_subnet[mode] = value
+        if expect_success:
+            plugin._validate_subnet(ctx, new_subnet, cur_subnet)
+        else:
+            self.assertRaises(n_exc.InvalidInput, plugin._validate_subnet,
+                              ctx, new_subnet, cur_subnet)
+
+    def test_create_subnet_ipv6_ra_modes(self):
+        # Test all RA modes with no address mode specified
+        for ra_mode in constants.IPV6_MODES:
+            self._test_validate_subnet_ipv6_modes(
+                ipv6_ra_mode=ra_mode)
+
+    def test_create_subnet_ipv6_addr_modes(self):
+        # Test all address modes with no RA mode specified
+        for addr_mode in constants.IPV6_MODES:
+            self._test_validate_subnet_ipv6_modes(
+                ipv6_address_mode=addr_mode)
+
+    def test_create_subnet_ipv6_same_ra_and_addr_modes(self):
+        # Test all ipv6 modes with ra_mode==addr_mode
+        for ipv6_mode in constants.IPV6_MODES:
+            self._test_validate_subnet_ipv6_modes(
+                ipv6_ra_mode=ipv6_mode,
+                ipv6_address_mode=ipv6_mode)
+
+    def test_create_subnet_ipv6_different_ra_and_addr_modes(self):
+        # Test all ipv6 modes with ra_mode!=addr_mode
+        for ra_mode, addr_mode in itertools.permutations(
+                constants.IPV6_MODES, 2):
+            self._test_validate_subnet_ipv6_modes(
+                expect_success=not (ra_mode and addr_mode),
+                ipv6_ra_mode=ra_mode,
+                ipv6_address_mode=addr_mode)
 
     def test_create_subnet_ipv6_out_of_cidr_global(self):
         gateway_ip = '2000::1'
@@ -3108,31 +3142,6 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
         self.assertEqual(ctx_manager.exception.code,
                          webob.exc.HTTPClientError.code)
 
-    def test_create_subnet_invalid_ipv6_combination(self):
-        gateway_ip = 'fe80::1'
-        cidr = 'fe80::/80'
-        with testlib_api.ExpectedException(
-            webob.exc.HTTPClientError) as ctx_manager:
-            self._test_create_subnet(gateway_ip=gateway_ip,
-                                     cidr=cidr, ip_version=6,
-                                     ipv6_ra_mode='stateful',
-                                     ipv6_address_mode='stateless')
-        self.assertEqual(ctx_manager.exception.code,
-                         webob.exc.HTTPClientError.code)
-
-    def test_create_subnet_ipv6_single_attribute_set(self):
-        gateway_ip = 'fe80::1'
-        cidr = 'fe80::/64'
-        for mode in constants.IPV6_MODES:
-            self._test_create_subnet(gateway_ip=gateway_ip,
-                                     cidr=cidr, ip_version=6,
-                                     ipv6_ra_mode=None,
-                                     ipv6_address_mode=mode)
-            self._test_create_subnet(gateway_ip=gateway_ip,
-                                     cidr=cidr, ip_version=6,
-                                     ipv6_ra_mode=mode,
-                                     ipv6_address_mode=None)
-
     def test_create_subnet_ipv6_ra_mode_ip_version_4(self):
         cidr = '10.0.2.0/24'
         with testlib_api.ExpectedException(
@@ -3312,7 +3321,7 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
                 self.assertEqual(res.status_int,
                                  webob.exc.HTTPConflict.code)
 
-    def test_update_subnet_ipv6_attributes(self):
+    def test_update_subnet_ipv6_attributes_fails(self):
         with self.subnet(ip_version=6, cidr='fe80::/64',
                          ipv6_ra_mode=constants.IPV6_SLAAC,
                          ipv6_address_mode=constants.IPV6_SLAAC) as subnet:
@@ -3320,16 +3329,13 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
                                'ipv6_address_mode': constants.DHCPV6_STATEFUL}}
             req = self.new_update_request('subnets', data,
                                           subnet['subnet']['id'])
-            res = self.deserialize(self.fmt, req.get_response(self.api))
-            self.assertEqual(res['subnet']['ipv6_ra_mode'],
-                             data['subnet']['ipv6_ra_mode'])
-            self.assertEqual(res['subnet']['ipv6_address_mode'],
-                             data['subnet']['ipv6_address_mode'])
+            res = req.get_response(self.api)
+            self.assertEqual(res.status_int,
+                             webob.exc.HTTPClientError.code)
 
-    def test_update_subnet_ipv6_inconsistent_ra_attribute(self):
+    def test_update_subnet_ipv6_ra_mode_fails(self):
         with self.subnet(ip_version=6, cidr='fe80::/64',
-                         ipv6_ra_mode=constants.IPV6_SLAAC,
-                         ipv6_address_mode=constants.IPV6_SLAAC) as subnet:
+                         ipv6_ra_mode=constants.IPV6_SLAAC) as subnet:
             data = {'subnet': {'ipv6_ra_mode': constants.DHCPV6_STATEFUL}}
             req = self.new_update_request('subnets', data,
                                           subnet['subnet']['id'])
@@ -3337,9 +3343,8 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
             self.assertEqual(res.status_int,
                              webob.exc.HTTPClientError.code)
 
-    def test_update_subnet_ipv6_inconsistent_address_attribute(self):
+    def test_update_subnet_ipv6_ra_mode_fails(self):
         with self.subnet(ip_version=6, cidr='fe80::/64',
-                         ipv6_ra_mode=constants.IPV6_SLAAC,
                          ipv6_address_mode=constants.IPV6_SLAAC) as subnet:
             data = {'subnet': {'ipv6_address_mode': constants.DHCPV6_STATEFUL}}
             req = self.new_update_request('subnets', data,
@@ -3348,7 +3353,7 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
             self.assertEqual(res.status_int,
                              webob.exc.HTTPClientError.code)
 
-    def test_update_subnet_ipv6_inconsistent_enable_dhcp(self):
+    def test_update_subnet_ipv6_cannot_disable_dhcp(self):
         with self.subnet(ip_version=6, cidr='fe80::/64',
                          ipv6_ra_mode=constants.IPV6_SLAAC,
                          ipv6_address_mode=constants.IPV6_SLAAC) as subnet: