BigSwitch: Fixes floating IP backend updates

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
This commit is contained in:
Kevin Benton 2013-12-19 03:52:20 +00:00
parent b0c83077aa
commit a77d24d155
3 changed files with 110 additions and 15 deletions

View 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:

View File

@ -17,6 +17,12 @@
# @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)

View 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')