]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
BigSwitch: Fixes floating IP backend updates
authorKevin Benton <blak111@gmail.com>
Thu, 19 Dec 2013 03:52:20 +0000 (03:52 +0000)
committerKevin Benton <blak111@gmail.com>
Fri, 20 Dec 2013 06:46:04 +0000 (06:46 +0000)
Changes BigSwitch plugin to correctly use
admin context on floating IP updates to the
backend controller so they correctly contain
floating IPs for all tenants.

Closes-Bug: #1262488
Change-Id: I6f2666c242e6d9b0684943db073a2284d01fa1e0

neutron/plugins/bigswitch/plugin.py
neutron/tests/unit/bigswitch/fake_server.py
neutron/tests/unit/bigswitch/test_router_db.py

index c9e8faffc6c6b5d338fa22b74d6be3d6d840bf0c..8f1a48a274915af294038186c7dcef5a68a46feb 100644 (file)
@@ -1032,12 +1032,9 @@ class NeutronRestProxyV2(db_base_plugin_v2.NeutronDbPluginV2,
             new_fl_ip = super(NeutronRestProxyV2,
                               self).create_floatingip(context, floatingip)
 
-            net_id = new_fl_ip['floating_network_id']
-            orig_net = super(NeutronRestProxyV2, self).get_network(context,
-                                                                   net_id)
             # create floatingip on the network controller
             try:
-                self._send_update_network(orig_net, context)
+                self._send_floatingip_update(context)
             except RemoteRestError as e:
                 with excutils.save_and_reraise_exception():
                     LOG.error(
@@ -1054,32 +1051,27 @@ class NeutronRestProxyV2(db_base_plugin_v2.NeutronDbPluginV2,
             new_fl_ip = super(NeutronRestProxyV2,
                               self).update_floatingip(context, id, floatingip)
 
-            net_id = new_fl_ip['floating_network_id']
-            orig_net = super(NeutronRestProxyV2, self).get_network(context,
-                                                                   net_id)
             # update network on network controller
-            self._send_update_network(orig_net, context)
+            self._send_floatingip_update(context)
             return new_fl_ip
 
     def delete_floatingip(self, context, id):
         LOG.debug(_("NeutronRestProxyV2: delete_floatingip() called"))
 
-        orig_fl_ip = super(NeutronRestProxyV2, self).get_floatingip(context,
-                                                                    id)
         with context.session.begin(subtransactions=True):
             # delete floating IP in DB
-            net_id = orig_fl_ip['floating_network_id']
             super(NeutronRestProxyV2, self).delete_floatingip(context, id)
 
-            orig_net = super(NeutronRestProxyV2, self).get_network(context,
-                                                                   net_id)
             # update network on network controller
-            self._send_update_network(orig_net, context)
+            self._send_floatingip_update(context)
 
     def disassociate_floatingips(self, context, port_id):
         LOG.debug(_("NeutronRestProxyV2: diassociate_floatingips() called"))
         super(NeutronRestProxyV2, self).disassociate_floatingips(context,
                                                                  port_id)
+        self._send_floatingip_update(context)
+
+    def _send_floatingip_update(self, context):
         try:
             ext_net_id = self.get_external_network_id(context)
             if ext_net_id:
index bc392c651e88a58c830c9ee3180d49336d093be8..6b21a1a7121a43973fcb420b0de010f3c7b34de7 100644 (file)
 # @author: Kevin Benton, <kevin.benton@bigswitch.com>
 #
 
+import json
+
+from neutron.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
+
 
 class HTTPResponseMock():
     status = 200
@@ -50,7 +56,7 @@ class HTTPResponseMock500(HTTPResponseMock):
         return "{'status': '%s'}" % self.errmsg
 
 
-class HTTPConnectionMock():
+class HTTPConnectionMock(object):
 
     def __init__(self, server, port, timeout):
         self.response = None
@@ -62,6 +68,10 @@ class HTTPConnectionMock():
             self.response = HTTPResponseMock500(None, errmsg=errmsg)
 
     def request(self, action, uri, body, headers):
+        LOG.debug(_("Request: action=%(action)s, uri=%(uri)r, "
+                    "body=%(body)s, headers=%(headers)s"),
+                  {'action': action, 'uri': uri,
+                   'body': body, 'headers': headers})
         if self.broken and "ExceptOnBadServer" in uri:
             raise Exception("Broken server got an unexpected request")
         if self.response:
@@ -94,3 +104,27 @@ class HTTPConnectionMock500(HTTPConnectionMock):
     def __init__(self, server, port, timeout):
         self.response = HTTPResponseMock500(None)
         self.broken = True
+
+
+class VerifyMultiTenantFloatingIP(HTTPConnectionMock):
+
+    def request(self, action, uri, body, headers):
+        # Only handle network update requests
+        if 'network' in uri and 'tenant' in uri and 'ports' not in uri:
+            req = json.loads(body)
+            if 'network' not in req or 'floatingips' not in req['network']:
+                msg = _("No floating IPs in request"
+                        "uri=%(uri)s, body=%(body)s") % {'uri': uri,
+                                                         'body': body}
+                raise Exception(msg)
+            distinct_tenants = []
+            for flip in req['network']['floatingips']:
+                if flip['tenant_id'] not in distinct_tenants:
+                    distinct_tenants.append(flip['tenant_id'])
+            if len(distinct_tenants) < 2:
+                msg = _("Expected floating IPs from multiple tenants."
+                        "uri=%(uri)s, body=%(body)s") % {'uri': uri,
+                                                         'body': body}
+                raise Exception(msg)
+        super(VerifyMultiTenantFloatingIP,
+              self).request(action, uri, body, headers)
index d062d3882131c0113f3f6c72ee10de530d0c41d6..5ea8e00d2e6a0e8cae7d4627f5d76cd28b66b791 100644 (file)
@@ -18,6 +18,7 @@
 # @author: Sumit Naiksatam, sumitnaiksatam@gmail.com
 #
 
+import contextlib
 import copy
 import os
 
@@ -31,6 +32,7 @@ from neutron.extensions import l3
 from neutron.manager import NeutronManager
 from neutron.openstack.common.notifier import api as notifier_api
 from neutron.openstack.common.notifier import test_notifier
+from neutron.openstack.common import uuidutils
 from neutron.plugins.bigswitch.extensions import routerrule
 from neutron.tests.unit.bigswitch import fake_server
 from neutron.tests.unit.bigswitch import test_base
@@ -39,6 +41,9 @@ from neutron.tests.unit import test_extension_extradhcpopts as test_extradhcp
 from neutron.tests.unit import test_l3_plugin
 
 
+_uuid = uuidutils.generate_uuid
+
+
 def new_L3_setUp(self):
     test_config['plugin_name_v2'] = (
         'neutron.plugins.bigswitch.plugin.NeutronRestProxyV2')
@@ -141,6 +146,70 @@ class RouterDBTestCase(test_base.BigSwitchTestBase,
                     # remove extra port created
                     self._delete('ports', p2['port']['id'])
 
+    def test_multi_tenant_flip_alllocation(self):
+        tenant1_id = _uuid()
+        tenant2_id = _uuid()
+        with contextlib.nested(
+            self.network(tenant_id=tenant1_id),
+            self.network(tenant_id=tenant2_id)) as (n1, n2):
+            with contextlib.nested(
+                self.subnet(network=n1, cidr='11.0.0.0/24'),
+                self.subnet(network=n2, cidr='12.0.0.0/24'),
+                self.subnet(cidr='13.0.0.0/24')) as (s1, s2, psub):
+                with contextlib.nested(
+                    self.router(tenant_id=tenant1_id),
+                    self.router(tenant_id=tenant2_id),
+                    self.port(subnet=s1, tenant_id=tenant1_id),
+                    self.port(subnet=s2, tenant_id=tenant2_id)) as (r1, r2,
+                                                                    p1, p2):
+                    self._set_net_external(psub['subnet']['network_id'])
+                    s1id = p1['port']['fixed_ips'][0]['subnet_id']
+                    s2id = p2['port']['fixed_ips'][0]['subnet_id']
+                    s1 = {'subnet': {'id': s1id}}
+                    s2 = {'subnet': {'id': s2id}}
+                    self._add_external_gateway_to_router(
+                        r1['router']['id'],
+                        psub['subnet']['network_id'])
+                    self._add_external_gateway_to_router(
+                        r2['router']['id'],
+                        psub['subnet']['network_id'])
+                    self._router_interface_action(
+                        'add', r1['router']['id'],
+                        s1['subnet']['id'], None)
+                    self._router_interface_action(
+                        'add', r2['router']['id'],
+                        s2['subnet']['id'], None)
+                    fl1 = self._make_floatingip_for_tenant_port(
+                        net_id=psub['subnet']['network_id'],
+                        port_id=p1['port']['id'],
+                        tenant_id=tenant1_id)
+                    multiFloatPatch = patch(
+                        'httplib.HTTPConnection',
+                        create=True,
+                        new=fake_server.VerifyMultiTenantFloatingIP)
+                    multiFloatPatch.start()
+                    fl2 = self._make_floatingip_for_tenant_port(
+                        net_id=psub['subnet']['network_id'],
+                        port_id=p2['port']['id'],
+                        tenant_id=tenant2_id)
+                    multiFloatPatch.stop()
+                    self._delete('floatingips', fl1['floatingip']['id'])
+                    self._delete('floatingips', fl2['floatingip']['id'])
+                    self._router_interface_action(
+                        'remove', r1['router']['id'],
+                        s1['subnet']['id'], None)
+                    self._router_interface_action(
+                        'remove', r2['router']['id'],
+                        s2['subnet']['id'], None)
+
+    def _make_floatingip_for_tenant_port(self, net_id, port_id, tenant_id):
+        data = {'floatingip': {'floating_network_id': net_id,
+                               'tenant_id': tenant_id,
+                               'port_id': port_id}}
+        floatingip_req = self.new_create_request('floatingips', data, self.fmt)
+        res = floatingip_req.get_response(self.ext_api)
+        return self.deserialize(self.fmt, res)
+
     def test_floatingip_with_invalid_create_port(self):
         self._test_floatingip_with_invalid_create_port(
             'neutron.plugins.bigswitch.plugin.NeutronRestProxyV2')