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:
parent
b0c83077aa
commit
a77d24d155
@ -1032,12 +1032,9 @@ class NeutronRestProxyV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
new_fl_ip = super(NeutronRestProxyV2,
|
new_fl_ip = super(NeutronRestProxyV2,
|
||||||
self).create_floatingip(context, floatingip)
|
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
|
# create floatingip on the network controller
|
||||||
try:
|
try:
|
||||||
self._send_update_network(orig_net, context)
|
self._send_floatingip_update(context)
|
||||||
except RemoteRestError as e:
|
except RemoteRestError as e:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
LOG.error(
|
LOG.error(
|
||||||
@ -1054,32 +1051,27 @@ class NeutronRestProxyV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
new_fl_ip = super(NeutronRestProxyV2,
|
new_fl_ip = super(NeutronRestProxyV2,
|
||||||
self).update_floatingip(context, id, floatingip)
|
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
|
# update network on network controller
|
||||||
self._send_update_network(orig_net, context)
|
self._send_floatingip_update(context)
|
||||||
return new_fl_ip
|
return new_fl_ip
|
||||||
|
|
||||||
def delete_floatingip(self, context, id):
|
def delete_floatingip(self, context, id):
|
||||||
LOG.debug(_("NeutronRestProxyV2: delete_floatingip() called"))
|
LOG.debug(_("NeutronRestProxyV2: delete_floatingip() called"))
|
||||||
|
|
||||||
orig_fl_ip = super(NeutronRestProxyV2, self).get_floatingip(context,
|
|
||||||
id)
|
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
# delete floating IP in DB
|
# delete floating IP in DB
|
||||||
net_id = orig_fl_ip['floating_network_id']
|
|
||||||
super(NeutronRestProxyV2, self).delete_floatingip(context, id)
|
super(NeutronRestProxyV2, self).delete_floatingip(context, id)
|
||||||
|
|
||||||
orig_net = super(NeutronRestProxyV2, self).get_network(context,
|
|
||||||
net_id)
|
|
||||||
# update network on network controller
|
# update network on network controller
|
||||||
self._send_update_network(orig_net, context)
|
self._send_floatingip_update(context)
|
||||||
|
|
||||||
def disassociate_floatingips(self, context, port_id):
|
def disassociate_floatingips(self, context, port_id):
|
||||||
LOG.debug(_("NeutronRestProxyV2: diassociate_floatingips() called"))
|
LOG.debug(_("NeutronRestProxyV2: diassociate_floatingips() called"))
|
||||||
super(NeutronRestProxyV2, self).disassociate_floatingips(context,
|
super(NeutronRestProxyV2, self).disassociate_floatingips(context,
|
||||||
port_id)
|
port_id)
|
||||||
|
self._send_floatingip_update(context)
|
||||||
|
|
||||||
|
def _send_floatingip_update(self, context):
|
||||||
try:
|
try:
|
||||||
ext_net_id = self.get_external_network_id(context)
|
ext_net_id = self.get_external_network_id(context)
|
||||||
if ext_net_id:
|
if ext_net_id:
|
||||||
|
@ -17,6 +17,12 @@
|
|||||||
# @author: Kevin Benton, <kevin.benton@bigswitch.com>
|
# @author: Kevin Benton, <kevin.benton@bigswitch.com>
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from neutron.openstack.common import log as logging
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class HTTPResponseMock():
|
class HTTPResponseMock():
|
||||||
status = 200
|
status = 200
|
||||||
@ -50,7 +56,7 @@ class HTTPResponseMock500(HTTPResponseMock):
|
|||||||
return "{'status': '%s'}" % self.errmsg
|
return "{'status': '%s'}" % self.errmsg
|
||||||
|
|
||||||
|
|
||||||
class HTTPConnectionMock():
|
class HTTPConnectionMock(object):
|
||||||
|
|
||||||
def __init__(self, server, port, timeout):
|
def __init__(self, server, port, timeout):
|
||||||
self.response = None
|
self.response = None
|
||||||
@ -62,6 +68,10 @@ class HTTPConnectionMock():
|
|||||||
self.response = HTTPResponseMock500(None, errmsg=errmsg)
|
self.response = HTTPResponseMock500(None, errmsg=errmsg)
|
||||||
|
|
||||||
def request(self, action, uri, body, headers):
|
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:
|
if self.broken and "ExceptOnBadServer" in uri:
|
||||||
raise Exception("Broken server got an unexpected request")
|
raise Exception("Broken server got an unexpected request")
|
||||||
if self.response:
|
if self.response:
|
||||||
@ -94,3 +104,27 @@ class HTTPConnectionMock500(HTTPConnectionMock):
|
|||||||
def __init__(self, server, port, timeout):
|
def __init__(self, server, port, timeout):
|
||||||
self.response = HTTPResponseMock500(None)
|
self.response = HTTPResponseMock500(None)
|
||||||
self.broken = True
|
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)
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
# @author: Sumit Naiksatam, sumitnaiksatam@gmail.com
|
# @author: Sumit Naiksatam, sumitnaiksatam@gmail.com
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import contextlib
|
||||||
import copy
|
import copy
|
||||||
import os
|
import os
|
||||||
|
|
||||||
@ -31,6 +32,7 @@ from neutron.extensions import l3
|
|||||||
from neutron.manager import NeutronManager
|
from neutron.manager import NeutronManager
|
||||||
from neutron.openstack.common.notifier import api as notifier_api
|
from neutron.openstack.common.notifier import api as notifier_api
|
||||||
from neutron.openstack.common.notifier import test_notifier
|
from neutron.openstack.common.notifier import test_notifier
|
||||||
|
from neutron.openstack.common import uuidutils
|
||||||
from neutron.plugins.bigswitch.extensions import routerrule
|
from neutron.plugins.bigswitch.extensions import routerrule
|
||||||
from neutron.tests.unit.bigswitch import fake_server
|
from neutron.tests.unit.bigswitch import fake_server
|
||||||
from neutron.tests.unit.bigswitch import test_base
|
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
|
from neutron.tests.unit import test_l3_plugin
|
||||||
|
|
||||||
|
|
||||||
|
_uuid = uuidutils.generate_uuid
|
||||||
|
|
||||||
|
|
||||||
def new_L3_setUp(self):
|
def new_L3_setUp(self):
|
||||||
test_config['plugin_name_v2'] = (
|
test_config['plugin_name_v2'] = (
|
||||||
'neutron.plugins.bigswitch.plugin.NeutronRestProxyV2')
|
'neutron.plugins.bigswitch.plugin.NeutronRestProxyV2')
|
||||||
@ -141,6 +146,70 @@ class RouterDBTestCase(test_base.BigSwitchTestBase,
|
|||||||
# remove extra port created
|
# remove extra port created
|
||||||
self._delete('ports', p2['port']['id'])
|
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):
|
def test_floatingip_with_invalid_create_port(self):
|
||||||
self._test_floatingip_with_invalid_create_port(
|
self._test_floatingip_with_invalid_create_port(
|
||||||
'neutron.plugins.bigswitch.plugin.NeutronRestProxyV2')
|
'neutron.plugins.bigswitch.plugin.NeutronRestProxyV2')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user