]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Fix IP allocation on shared networks ports.
authorSalvatore Orlando <salv.orlando@gmail.com>
Tue, 21 Aug 2012 10:53:31 +0000 (03:53 -0700)
committerSalvatore Orlando <salv.orlando@gmail.com>
Tue, 21 Aug 2012 10:53:31 +0000 (03:53 -0700)
Fixes bug 1037589

Ensure non-owner ports on shared networks get an IP address for
each subnet configured on the shared network.

Change-Id: Ib687444b7ad75f3c773b0cb41c25ac3f700fbf0f

quantum/api/v2/attributes.py
quantum/db/db_base_plugin_v2.py
quantum/db/models_v2.py
quantum/tests/unit/test_db_plugin.py

index 28694ccce8a2aab52888116f7ea660ca147e2d4c..92b29aa143323a9feb435dfc17a3f8e7ed5c84d6 100644 (file)
@@ -275,6 +275,10 @@ RESOURCE_ATTRIBUTE_MAP = {
                         'convert_to': convert_to_boolean,
                         'validate': {'type:boolean': None},
                         'is_visible': True},
+        SHARED: {'allow_post': False,
+                 'allow_put': False,
+                 'default': False,
+                 'is_visible': False},
     }
 }
 
index c4b5adff8125252c48a01b8e69b35bd5ea4d1fcf..289177b1f4a2c7949598a0d7e1ca59cb938690ab 100644 (file)
@@ -142,6 +142,13 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
         except exc.NoResultFound:
             return []
 
+    def _get_subnets_by_network(self, context, network_id):
+        try:
+            subnet_qry = context.session.query(models_v2.Subnet)
+            return subnet_qry.filter_by(network_id=network_id).all()
+        except exc.NoResultFound:
+            return []
+
     def _fields(self, resource, fields):
         if fields:
             return dict(((key, item) for key, item in resource.iteritems()
@@ -769,6 +776,10 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
             if 'shared' in n:
                 self._validate_shared_update(context, id, network, n)
             network.update(n)
+            # also update shared in all the subnets for this network
+            subnets = self._get_subnets_by_network(context, id)
+            for subnet in subnets:
+                subnet['shared'] = network['shared']
         return self._make_network_dict(network)
 
     def delete_network(self, context, id):
@@ -836,6 +847,8 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
         with context.session.begin(subtransactions=True):
             network = self._get_network(context, s["network_id"])
             self._validate_subnet_cidr(network, s['cidr'])
+            # The 'shared' attribute for subnets is for internal plugin
+            # use only. It is not exposed through the API
             subnet = models_v2.Subnet(tenant_id=tenant_id,
                                       id=s.get('id') or utils.str_uuid(),
                                       name=s['name'],
@@ -843,7 +856,8 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
                                       ip_version=s['ip_version'],
                                       cidr=s['cidr'],
                                       enable_dhcp=s['enable_dhcp'],
-                                      gateway_ip=s['gateway_ip'])
+                                      gateway_ip=s['gateway_ip'],
+                                      shared=network.shared)
 
             # perform allocate pools first, since it might raise an error
             pools = self._allocate_pools_for_subnet(context, s)
index 6be757ac2e6be047eeba1d525f798165234187e8..41654c9d5c4f9d3b106bbed0d88e073103abc922 100644 (file)
@@ -140,6 +140,7 @@ class Subnet(model_base.BASEV2, HasId, HasTenant):
     routes = orm.relationship(Route,
                               backref='subnet',
                               cascade='delete')
+    shared = sa.Column(sa.Boolean)
 
 
 class Network(model_base.BASEV2, HasId, HasTenant):
index 06ff4a0a4fc0030cf52a83587e9579a35f781826..4f13f5ae9c71a3cdf195e0338c802f32f680e7d8 100644 (file)
@@ -200,7 +200,8 @@ class QuantumDbPluginV2TestCase(unittest2.TestCase):
         for arg in ('allocation_pools',
                     'ip_version', 'tenant_id',
                     'enable_dhcp', 'allocation_pools',
-                    'dns_nameservers', 'host_routes'):
+                    'dns_nameservers', 'host_routes',
+                    'shared'):
             # Arg must be present and not null (but can be false)
             if arg in kwargs and kwargs[arg] is not None:
                 data['subnet'][arg] = kwargs[arg]
@@ -281,7 +282,7 @@ class QuantumDbPluginV2TestCase(unittest2.TestCase):
 
     def _make_subnet(self, fmt, network, gateway, cidr,
                      allocation_pools=None, ip_version=4, enable_dhcp=True,
-                     dns_nameservers=None, host_routes=None):
+                     dns_nameservers=None, host_routes=None, shared=None):
         res = self._create_subnet(fmt,
                                   net_id=network['network']['id'],
                                   cidr=cidr,
@@ -291,7 +292,8 @@ class QuantumDbPluginV2TestCase(unittest2.TestCase):
                                   ip_version=ip_version,
                                   enable_dhcp=enable_dhcp,
                                   dns_nameservers=dns_nameservers,
-                                  host_routes=host_routes)
+                                  host_routes=host_routes,
+                                  shared=shared)
         # Things can go wrong - raise HTTP exc with res code only
         # so it can be caught by unit tests
         if res.status_int >= 400:
@@ -384,7 +386,8 @@ class QuantumDbPluginV2TestCase(unittest2.TestCase):
                allocation_pools=None,
                enable_dhcp=True,
                dns_nameservers=None,
-               host_routes=None):
+               host_routes=None,
+               shared=None):
         # TODO(anyone) DRY this
         # NOTE(salvatore-orlando): we can pass the network object
         # to gen function anyway, and then avoid the repetition
@@ -398,7 +401,8 @@ class QuantumDbPluginV2TestCase(unittest2.TestCase):
                                            ip_version,
                                            enable_dhcp,
                                            dns_nameservers,
-                                           host_routes)
+                                           host_routes,
+                                           shared=shared)
                 yield subnet
                 self._delete('subnets', subnet['subnet']['id'])
         else:
@@ -410,7 +414,8 @@ class QuantumDbPluginV2TestCase(unittest2.TestCase):
                                        ip_version,
                                        enable_dhcp,
                                        dns_nameservers,
-                                       host_routes)
+                                       host_routes,
+                                       shared=shared)
             yield subnet
             self._delete('subnets', subnet['subnet']['id'])
 
@@ -573,6 +578,23 @@ class TestPortsV2(QuantumDbPluginV2TestCase):
             self.assertTrue('mac_address' in port['port'])
             self._delete('ports', port['port']['id'])
 
+    def test_create_port_public_network_with_ip(self):
+        with self.network(shared=True) as network:
+            with self.subnet(network=network, cidr='10.0.0.0/24') as subnet:
+                keys = [('admin_state_up', True), ('status', 'ACTIVE'),
+                        ('fixed_ips', [{'subnet_id': subnet['subnet']['id'],
+                                        'ip_address': '10.0.0.2'}])]
+                port_res = self._create_port('json',
+                                             network['network']['id'],
+                                             201,
+                                             tenant_id='another_tenant',
+                                             set_context=True)
+                port = self.deserialize('json', port_res)
+                for k, v in keys:
+                    self.assertEquals(port['port'][k], v)
+                self.assertTrue('mac_address' in port['port'])
+                self._delete('ports', port['port']['id'])
+
     def test_create_ports_bulk_native(self):
         if self._skip_native_bulk:
             self.skipTest("Plugin does not support native bulk port create")
@@ -1249,6 +1271,22 @@ class TestNetworksV2(QuantumDbPluginV2TestCase):
             res = self.deserialize('json', req.get_response(self.api))
             self.assertTrue(res['network']['shared'])
 
+    def test_update_network_with_subnet_set_shared(self):
+        with self.network(shared=False) as network:
+            with self.subnet(network=network) as subnet:
+                data = {'network': {'shared': True}}
+                req = self.new_update_request('networks',
+                                              data,
+                                              network['network']['id'])
+                res = self.deserialize('json', req.get_response(self.api))
+                self.assertTrue(res['network']['shared'])
+                # must query db to see whether subnet's shared attribute
+                # has been updated or not
+                ctx = context.Context('', '', is_admin=True)
+                subnet_db = QuantumManager.get_plugin()._get_subnet(
+                    ctx, subnet['subnet']['id'])
+                self.assertEqual(subnet_db['shared'], True)
+
     def test_update_network_set_not_shared_single_tenant(self):
         with self.network(shared=True) as network:
             res1 = self._create_port('json',
@@ -1751,6 +1789,13 @@ class TestSubnetsV2(QuantumDbPluginV2TestCase):
                                      allocation_pools=allocation_pools)
         self.assertEquals(ctx_manager.exception.code, 400)
 
+    def test_create_subnet_shared_returns_422(self):
+        cidr = '10.0.0.0/24'
+        with self.assertRaises(webob.exc.HTTPClientError) as ctx_manager:
+            self._test_create_subnet(cidr=cidr,
+                                     shared=True)
+        self.assertEquals(ctx_manager.exception.code, 422)
+
     def test_update_subnet(self):
         with self.subnet() as subnet:
             data = {'subnet': {'gateway_ip': '11.0.0.1'}}
@@ -1760,6 +1805,15 @@ class TestSubnetsV2(QuantumDbPluginV2TestCase):
             self.assertEqual(res['subnet']['gateway_ip'],
                              data['subnet']['gateway_ip'])
 
+    def test_update_subnet_shared_returns_422(self):
+        with self.network(shared=True) as network:
+            with self.subnet(network=network) as subnet:
+                data = {'subnet': {'shared': True}}
+                req = self.new_update_request('subnets', data,
+                                              subnet['subnet']['id'])
+                res = req.get_response(self.api)
+                self.assertEqual(res.status_int, 422)
+
     def test_show_subnet(self):
         with self.network() as network:
             with self.subnet(network=network) as subnet: