Merge "BigSwitch: Fixes floating IP backend updates"
This commit is contained in:
commit
dd3141f2bc
@ -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