Big Switch: Separate L3 functions into L3 service
Separate the L3 functions from the core Big Switch plugin into an L3 service plugin. This is will allow the L3 functions to be used in ML2 deployments that use the Big Switch ML2 driver. DocImpact Implements: blueprint bsn-l3-service-plugin Change-Id: I889db0047fb9a85f02d1fb95b9c099e9243a5bb5
This commit is contained in:
parent
f3305bbd7e
commit
c9443e5662
304
neutron/plugins/bigswitch/l3_router_plugin.py
Normal file
304
neutron/plugins/bigswitch/l3_router_plugin.py
Normal file
@ -0,0 +1,304 @@
|
||||
# Copyright 2014 Big Switch Networks, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
"""
|
||||
Neutron L3 REST Proxy Plugin for Big Switch and Floodlight Controllers.
|
||||
|
||||
This plugin handles the L3 router calls for Big Switch Floodlight deployments.
|
||||
It is intended to be used in conjunction with the Big Switch ML2 driver or the
|
||||
Big Switch core plugin.
|
||||
"""
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from neutron.api import extensions as neutron_extensions
|
||||
from neutron.common import exceptions
|
||||
from neutron.common import log
|
||||
from neutron.common import utils
|
||||
from neutron.db import l3_db
|
||||
from neutron.extensions import l3
|
||||
from neutron.openstack.common import excutils
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.plugins.bigswitch import extensions
|
||||
from neutron.plugins.bigswitch import plugin as cplugin
|
||||
from neutron.plugins.bigswitch import routerrule_db
|
||||
from neutron.plugins.bigswitch import servermanager
|
||||
from neutron.plugins.common import constants
|
||||
|
||||
# number of fields in a router rule string
|
||||
ROUTER_RULE_COMPONENT_COUNT = 5
|
||||
LOG = logging.getLogger(__name__)
|
||||
put_context_in_serverpool = cplugin.put_context_in_serverpool
|
||||
|
||||
|
||||
class L3RestProxy(cplugin.NeutronRestProxyV2Base,
|
||||
routerrule_db.RouterRule_db_mixin):
|
||||
|
||||
supported_extension_aliases = ["router", "router_rules"]
|
||||
|
||||
@staticmethod
|
||||
def get_plugin_type():
|
||||
return constants.L3_ROUTER_NAT
|
||||
|
||||
@staticmethod
|
||||
def get_plugin_description():
|
||||
return _("L3 Router Service Plugin for Big Switch fabric")
|
||||
|
||||
def __init__(self):
|
||||
# Include the Big Switch Extensions path in the api_extensions
|
||||
neutron_extensions.append_api_extensions_path(extensions.__path__)
|
||||
super(L3RestProxy, self).__init__()
|
||||
self.servers = servermanager.ServerPool.get_instance()
|
||||
|
||||
@put_context_in_serverpool
|
||||
@log.log
|
||||
def create_router(self, context, router):
|
||||
self._warn_on_state_status(router['router'])
|
||||
|
||||
tenant_id = self._get_tenant_id_for_create(context, router["router"])
|
||||
|
||||
# set default router rules
|
||||
rules = self._get_tenant_default_router_rules(tenant_id)
|
||||
router['router']['router_rules'] = rules
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# create router in DB
|
||||
new_router = super(L3RestProxy, self).create_router(context,
|
||||
router)
|
||||
mapped_router = self._map_state_and_status(new_router)
|
||||
self.servers.rest_create_router(tenant_id, mapped_router)
|
||||
|
||||
# return created router
|
||||
return new_router
|
||||
|
||||
@put_context_in_serverpool
|
||||
@log.log
|
||||
def update_router(self, context, router_id, router):
|
||||
self._warn_on_state_status(router['router'])
|
||||
|
||||
orig_router = super(L3RestProxy, self).get_router(context, router_id)
|
||||
tenant_id = orig_router["tenant_id"]
|
||||
with context.session.begin(subtransactions=True):
|
||||
new_router = super(L3RestProxy,
|
||||
self).update_router(context, router_id, router)
|
||||
router = self._map_state_and_status(new_router)
|
||||
|
||||
# update router on network controller
|
||||
self.servers.rest_update_router(tenant_id, router, router_id)
|
||||
|
||||
# return updated router
|
||||
return new_router
|
||||
|
||||
# NOTE(kevinbenton): workaround for eventlet/mysql deadlock.
|
||||
# delete_router ends up calling _delete_port instead of delete_port.
|
||||
@utils.synchronized('bsn-port-barrier')
|
||||
@put_context_in_serverpool
|
||||
@log.log
|
||||
def delete_router(self, context, router_id):
|
||||
with context.session.begin(subtransactions=True):
|
||||
orig_router = self._get_router(context, router_id)
|
||||
tenant_id = orig_router["tenant_id"]
|
||||
|
||||
# Ensure that the router is not used
|
||||
router_filter = {'router_id': [router_id]}
|
||||
fips = self.get_floatingips_count(context.elevated(),
|
||||
filters=router_filter)
|
||||
if fips:
|
||||
raise l3.RouterInUse(router_id=router_id)
|
||||
|
||||
device_owner = l3_db.DEVICE_OWNER_ROUTER_INTF
|
||||
device_filter = {'device_id': [router_id],
|
||||
'device_owner': [device_owner]}
|
||||
ports = self.get_ports_count(context.elevated(),
|
||||
filters=device_filter)
|
||||
if ports:
|
||||
raise l3.RouterInUse(router_id=router_id)
|
||||
super(L3RestProxy, self).delete_router(context, router_id)
|
||||
|
||||
# delete from network controller
|
||||
self.servers.rest_delete_router(tenant_id, router_id)
|
||||
|
||||
@put_context_in_serverpool
|
||||
@log.log
|
||||
def add_router_interface(self, context, router_id, interface_info):
|
||||
# Validate args
|
||||
router = self._get_router(context, router_id)
|
||||
tenant_id = router['tenant_id']
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# create interface in DB
|
||||
new_intf_info = super(L3RestProxy,
|
||||
self).add_router_interface(context,
|
||||
router_id,
|
||||
interface_info)
|
||||
port = self._get_port(context, new_intf_info['port_id'])
|
||||
net_id = port['network_id']
|
||||
subnet_id = new_intf_info['subnet_id']
|
||||
# we will use the port's network id as interface's id
|
||||
interface_id = net_id
|
||||
intf_details = self._get_router_intf_details(context,
|
||||
interface_id,
|
||||
subnet_id)
|
||||
|
||||
# create interface on the network controller
|
||||
self.servers.rest_add_router_interface(tenant_id, router_id,
|
||||
intf_details)
|
||||
return new_intf_info
|
||||
|
||||
@put_context_in_serverpool
|
||||
@log.log
|
||||
def remove_router_interface(self, context, router_id, interface_info):
|
||||
# Validate args
|
||||
router = self._get_router(context, router_id)
|
||||
tenant_id = router['tenant_id']
|
||||
|
||||
# we will first get the interface identifier before deleting in the DB
|
||||
if not interface_info:
|
||||
msg = _("Either subnet_id or port_id must be specified")
|
||||
raise exceptions.BadRequest(resource='router', msg=msg)
|
||||
if 'port_id' in interface_info:
|
||||
port = self._get_port(context, interface_info['port_id'])
|
||||
interface_id = port['network_id']
|
||||
elif 'subnet_id' in interface_info:
|
||||
subnet = self._get_subnet(context, interface_info['subnet_id'])
|
||||
interface_id = subnet['network_id']
|
||||
else:
|
||||
msg = _("Either subnet_id or port_id must be specified")
|
||||
raise exceptions.BadRequest(resource='router', msg=msg)
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# remove router in DB
|
||||
del_ret = super(L3RestProxy,
|
||||
self).remove_router_interface(context,
|
||||
router_id,
|
||||
interface_info)
|
||||
|
||||
# create router on the network controller
|
||||
self.servers.rest_remove_router_interface(tenant_id, router_id,
|
||||
interface_id)
|
||||
return del_ret
|
||||
|
||||
@put_context_in_serverpool
|
||||
@log.log
|
||||
def create_floatingip(self, context, floatingip):
|
||||
with context.session.begin(subtransactions=True):
|
||||
# create floatingip in DB
|
||||
new_fl_ip = super(L3RestProxy,
|
||||
self).create_floatingip(context, floatingip)
|
||||
|
||||
# create floatingip on the network controller
|
||||
try:
|
||||
if 'floatingip' in self.servers.get_capabilities():
|
||||
self.servers.rest_create_floatingip(
|
||||
new_fl_ip['tenant_id'], new_fl_ip)
|
||||
else:
|
||||
self._send_floatingip_update(context)
|
||||
except servermanager.RemoteRestError as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(
|
||||
_("NeutronRestProxyV2: Unable to create remote "
|
||||
"floating IP: %s"), e)
|
||||
# return created floating IP
|
||||
return new_fl_ip
|
||||
|
||||
@put_context_in_serverpool
|
||||
@log.log
|
||||
def update_floatingip(self, context, id, floatingip):
|
||||
with context.session.begin(subtransactions=True):
|
||||
# update floatingip in DB
|
||||
new_fl_ip = super(L3RestProxy,
|
||||
self).update_floatingip(context, id, floatingip)
|
||||
|
||||
# update network on network controller
|
||||
if 'floatingip' in self.servers.get_capabilities():
|
||||
self.servers.rest_update_floatingip(new_fl_ip['tenant_id'],
|
||||
new_fl_ip, id)
|
||||
else:
|
||||
self._send_floatingip_update(context)
|
||||
return new_fl_ip
|
||||
|
||||
@put_context_in_serverpool
|
||||
@log.log
|
||||
def delete_floatingip(self, context, id):
|
||||
with context.session.begin(subtransactions=True):
|
||||
# delete floating IP in DB
|
||||
old_fip = super(L3RestProxy, self).get_floatingip(context, id)
|
||||
super(L3RestProxy, self).delete_floatingip(context, id)
|
||||
|
||||
# update network on network controller
|
||||
if 'floatingip' in self.servers.get_capabilities():
|
||||
self.servers.rest_delete_floatingip(old_fip['tenant_id'], id)
|
||||
else:
|
||||
self._send_floatingip_update(context)
|
||||
|
||||
@put_context_in_serverpool
|
||||
@log.log
|
||||
def disassociate_floatingips(self, context, port_id, do_notify=True):
|
||||
router_ids = super(L3RestProxy, self).disassociate_floatingips(
|
||||
context, port_id, do_notify=do_notify)
|
||||
self._send_floatingip_update(context)
|
||||
return router_ids
|
||||
|
||||
# overriding method from l3_db as original method calls
|
||||
# self.delete_floatingip() which in turn calls self.delete_port() which
|
||||
# is locked with 'bsn-port-barrier'
|
||||
@put_context_in_serverpool
|
||||
def delete_disassociated_floatingips(self, context, network_id):
|
||||
query = self._model_query(context, l3_db.FloatingIP)
|
||||
query = query.filter_by(floating_network_id=network_id,
|
||||
fixed_port_id=None,
|
||||
router_id=None)
|
||||
for fip in query:
|
||||
context.session.delete(fip)
|
||||
self._delete_port(context.elevated(), fip['floating_port_id'])
|
||||
|
||||
def _send_floatingip_update(self, context):
|
||||
try:
|
||||
ext_net_id = self.get_external_network_id(context)
|
||||
if ext_net_id:
|
||||
# Use the elevated state of the context for the ext_net query
|
||||
admin_context = context.elevated()
|
||||
ext_net = super(L3RestProxy,
|
||||
self).get_network(admin_context, ext_net_id)
|
||||
# update external network on network controller
|
||||
self._send_update_network(ext_net, admin_context)
|
||||
except exceptions.TooManyExternalNetworks:
|
||||
# get_external_network can raise errors when multiple external
|
||||
# networks are detected, which isn't supported by the Plugin
|
||||
LOG.error(_("NeutronRestProxyV2: too many external networks"))
|
||||
|
||||
def _get_tenant_default_router_rules(self, tenant):
|
||||
rules = cfg.CONF.ROUTER.tenant_default_router_rule
|
||||
default_set = []
|
||||
tenant_set = []
|
||||
for rule in rules:
|
||||
items = rule.split(':')
|
||||
# put an empty string on the end if nexthops wasn't specified
|
||||
if len(items) < ROUTER_RULE_COMPONENT_COUNT:
|
||||
items.append('')
|
||||
try:
|
||||
(tenant_id, source, destination, action, nexthops) = items
|
||||
except ValueError:
|
||||
continue
|
||||
parsed_rule = {'source': source,
|
||||
'destination': destination, 'action': action,
|
||||
'nexthops': [hop for hop in nexthops.split(',')
|
||||
if hop]}
|
||||
if tenant_id == '*':
|
||||
default_set.append(parsed_rule)
|
||||
if tenant_id == tenant:
|
||||
tenant_set.append(parsed_rule)
|
||||
return tenant_set if tenant_set else default_set
|
@ -77,18 +77,16 @@ from neutron.db import securitygroups_rpc_base as sg_db_rpc
|
||||
from neutron.extensions import allowedaddresspairs as addr_pair
|
||||
from neutron.extensions import external_net
|
||||
from neutron.extensions import extra_dhcp_opt as edo_ext
|
||||
from neutron.extensions import l3
|
||||
from neutron.extensions import portbindings
|
||||
from neutron import manager
|
||||
from neutron.openstack.common import excutils
|
||||
from neutron.openstack.common import importutils
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.plugins.bigswitch import config as pl_config
|
||||
from neutron.plugins.bigswitch.db import porttracker_db
|
||||
from neutron.plugins.bigswitch import extensions
|
||||
from neutron.plugins.bigswitch import routerrule_db
|
||||
from neutron.plugins.bigswitch import servermanager
|
||||
from neutron.plugins.bigswitch import version
|
||||
from neutron.plugins.common import constants as pconst
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -154,12 +152,16 @@ class SecurityGroupServerRpcMixin(sg_db_rpc.SecurityGroupServerRpcMixin):
|
||||
|
||||
|
||||
class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
external_net_db.External_net_db_mixin,
|
||||
routerrule_db.RouterRule_db_mixin):
|
||||
external_net_db.External_net_db_mixin):
|
||||
|
||||
supported_extension_aliases = ["binding"]
|
||||
servers = None
|
||||
|
||||
@property
|
||||
def l3_plugin(self):
|
||||
return manager.NeutronManager.get_service_plugins().get(
|
||||
pconst.L3_ROUTER_NAT)
|
||||
|
||||
def _get_all_data(self, get_ports=True, get_floating_ips=True,
|
||||
get_routers=True):
|
||||
admin_context = qcontext.get_admin_context()
|
||||
@ -196,9 +198,9 @@ class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
|
||||
data = {'networks': networks}
|
||||
|
||||
if get_routers:
|
||||
if get_routers and self.l3_plugin:
|
||||
routers = []
|
||||
all_routers = self.get_routers(admin_context) or []
|
||||
all_routers = self.l3_plugin.get_routers(admin_context) or []
|
||||
for router in all_routers:
|
||||
interfaces = []
|
||||
mapped_router = self._map_state_and_status(router)
|
||||
@ -242,9 +244,10 @@ class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
|
||||
net_id = network['id']
|
||||
net_filter = {'floating_network_id': [net_id]}
|
||||
fl_ips = self.get_floatingips(context,
|
||||
filters=net_filter) or []
|
||||
network['floatingips'] = fl_ips
|
||||
if self.l3_plugin:
|
||||
fl_ips = self.l3_plugin.get_floatingips(context,
|
||||
filters=net_filter) or []
|
||||
network['floatingips'] = fl_ips
|
||||
|
||||
return network
|
||||
|
||||
@ -454,8 +457,8 @@ class NeutronRestProxyV2(NeutronRestProxyV2Base,
|
||||
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
||||
SecurityGroupServerRpcMixin):
|
||||
|
||||
_supported_extension_aliases = ["external-net", "router", "binding",
|
||||
"router_rules", "extra_dhcp_opt", "quotas",
|
||||
_supported_extension_aliases = ["external-net", "binding",
|
||||
"extra_dhcp_opt", "quotas",
|
||||
"dhcp_agent_scheduler", "agent",
|
||||
"security-group", "allowed-address-pairs"]
|
||||
|
||||
@ -805,11 +808,12 @@ class NeutronRestProxyV2(NeutronRestProxyV2Base,
|
||||
|
||||
# if needed, check to see if this is a port owned by
|
||||
# and l3-router. If so, we should prevent deletion.
|
||||
if l3_port_check:
|
||||
self.prevent_l3_port_deletion(context, port_id)
|
||||
if l3_port_check and self.l3_plugin:
|
||||
self.l3_plugin.prevent_l3_port_deletion(context, port_id)
|
||||
with context.session.begin(subtransactions=True):
|
||||
router_ids = self.disassociate_floatingips(
|
||||
context, port_id, do_notify=False)
|
||||
if self.l3_plugin:
|
||||
router_ids = self.l3_plugin.disassociate_floatingips(
|
||||
context, port_id, do_notify=False)
|
||||
self._delete_port_security_group_bindings(context, port_id)
|
||||
port = super(NeutronRestProxyV2, self).get_port(context, port_id)
|
||||
# Tenant ID must come from network in case the network is shared
|
||||
@ -817,8 +821,9 @@ class NeutronRestProxyV2(NeutronRestProxyV2Base,
|
||||
self._delete_port(context, port_id)
|
||||
self.servers.rest_delete_port(tenid, port['network_id'], port_id)
|
||||
|
||||
# now that we've left db transaction, we are safe to notify
|
||||
self.notify_routers_updated(context, router_ids)
|
||||
if self.l3_plugin:
|
||||
# now that we've left db transaction, we are safe to notify
|
||||
self.l3_plugin.notify_routers_updated(context, router_ids)
|
||||
|
||||
@put_context_in_serverpool
|
||||
def create_subnet(self, context, subnet):
|
||||
@ -869,264 +874,6 @@ class NeutronRestProxyV2(NeutronRestProxyV2Base,
|
||||
# update network on network controller - exception will rollback
|
||||
self._send_update_network(orig_net, context)
|
||||
|
||||
def _get_tenant_default_router_rules(self, tenant):
|
||||
rules = cfg.CONF.ROUTER.tenant_default_router_rule
|
||||
defaultset = []
|
||||
tenantset = []
|
||||
for rule in rules:
|
||||
items = rule.split(':')
|
||||
if len(items) == 5:
|
||||
(tenantid, source, destination, action, nexthops) = items
|
||||
elif len(items) == 4:
|
||||
(tenantid, source, destination, action) = items
|
||||
nexthops = ''
|
||||
else:
|
||||
continue
|
||||
parsedrule = {'source': source,
|
||||
'destination': destination, 'action': action,
|
||||
'nexthops': nexthops.split(',')}
|
||||
if parsedrule['nexthops'][0] == '':
|
||||
parsedrule['nexthops'] = []
|
||||
if tenantid == '*':
|
||||
defaultset.append(parsedrule)
|
||||
if tenantid == tenant:
|
||||
tenantset.append(parsedrule)
|
||||
if tenantset:
|
||||
return tenantset
|
||||
return defaultset
|
||||
|
||||
@put_context_in_serverpool
|
||||
def create_router(self, context, router):
|
||||
LOG.debug(_("NeutronRestProxyV2: create_router() called"))
|
||||
|
||||
self._warn_on_state_status(router['router'])
|
||||
|
||||
tenant_id = self._get_tenant_id_for_create(context, router["router"])
|
||||
|
||||
# set default router rules
|
||||
rules = self._get_tenant_default_router_rules(tenant_id)
|
||||
router['router']['router_rules'] = rules
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# create router in DB
|
||||
new_router = super(NeutronRestProxyV2, self).create_router(context,
|
||||
router)
|
||||
mapped_router = self._map_state_and_status(new_router)
|
||||
self.servers.rest_create_router(tenant_id, mapped_router)
|
||||
|
||||
# return created router
|
||||
return new_router
|
||||
|
||||
@put_context_in_serverpool
|
||||
def update_router(self, context, router_id, router):
|
||||
|
||||
LOG.debug(_("NeutronRestProxyV2.update_router() called"))
|
||||
|
||||
self._warn_on_state_status(router['router'])
|
||||
|
||||
orig_router = super(NeutronRestProxyV2, self).get_router(context,
|
||||
router_id)
|
||||
tenant_id = orig_router["tenant_id"]
|
||||
with context.session.begin(subtransactions=True):
|
||||
new_router = super(NeutronRestProxyV2,
|
||||
self).update_router(context, router_id, router)
|
||||
router = self._map_state_and_status(new_router)
|
||||
|
||||
# update router on network controller
|
||||
self.servers.rest_update_router(tenant_id, router, router_id)
|
||||
|
||||
# return updated router
|
||||
return new_router
|
||||
|
||||
# NOTE(kevinbenton): workaround for eventlet/mysql deadlock.
|
||||
# delete_router ends up calling _delete_port instead of delete_port.
|
||||
@utils.synchronized('bsn-port-barrier')
|
||||
@put_context_in_serverpool
|
||||
def delete_router(self, context, router_id):
|
||||
LOG.debug(_("NeutronRestProxyV2: delete_router() called"))
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
orig_router = self._get_router(context, router_id)
|
||||
tenant_id = orig_router["tenant_id"]
|
||||
|
||||
# Ensure that the router is not used
|
||||
router_filter = {'router_id': [router_id]}
|
||||
fips = self.get_floatingips_count(context.elevated(),
|
||||
filters=router_filter)
|
||||
if fips:
|
||||
raise l3.RouterInUse(router_id=router_id)
|
||||
|
||||
device_owner = l3_db.DEVICE_OWNER_ROUTER_INTF
|
||||
device_filter = {'device_id': [router_id],
|
||||
'device_owner': [device_owner]}
|
||||
ports = self.get_ports_count(context.elevated(),
|
||||
filters=device_filter)
|
||||
if ports:
|
||||
raise l3.RouterInUse(router_id=router_id)
|
||||
ret_val = super(NeutronRestProxyV2,
|
||||
self).delete_router(context, router_id)
|
||||
|
||||
# delete from network ctrl
|
||||
self.servers.rest_delete_router(tenant_id, router_id)
|
||||
return ret_val
|
||||
|
||||
@put_context_in_serverpool
|
||||
def add_router_interface(self, context, router_id, interface_info):
|
||||
|
||||
LOG.debug(_("NeutronRestProxyV2: add_router_interface() called"))
|
||||
|
||||
# Validate args
|
||||
router = self._get_router(context, router_id)
|
||||
tenant_id = router['tenant_id']
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# create interface in DB
|
||||
new_intf_info = super(NeutronRestProxyV2,
|
||||
self).add_router_interface(context,
|
||||
router_id,
|
||||
interface_info)
|
||||
port = self._get_port(context, new_intf_info['port_id'])
|
||||
net_id = port['network_id']
|
||||
subnet_id = new_intf_info['subnet_id']
|
||||
# we will use the port's network id as interface's id
|
||||
interface_id = net_id
|
||||
intf_details = self._get_router_intf_details(context,
|
||||
interface_id,
|
||||
subnet_id)
|
||||
|
||||
# create interface on the network controller
|
||||
self.servers.rest_add_router_interface(tenant_id, router_id,
|
||||
intf_details)
|
||||
return new_intf_info
|
||||
|
||||
@put_context_in_serverpool
|
||||
def remove_router_interface(self, context, router_id, interface_info):
|
||||
|
||||
LOG.debug(_("NeutronRestProxyV2: remove_router_interface() called"))
|
||||
|
||||
# Validate args
|
||||
router = self._get_router(context, router_id)
|
||||
tenant_id = router['tenant_id']
|
||||
|
||||
# we will first get the interface identifier before deleting in the DB
|
||||
if not interface_info:
|
||||
msg = _("Either subnet_id or port_id must be specified")
|
||||
raise exceptions.BadRequest(resource='router', msg=msg)
|
||||
if 'port_id' in interface_info:
|
||||
port = self._get_port(context, interface_info['port_id'])
|
||||
interface_id = port['network_id']
|
||||
elif 'subnet_id' in interface_info:
|
||||
subnet = self._get_subnet(context, interface_info['subnet_id'])
|
||||
interface_id = subnet['network_id']
|
||||
else:
|
||||
msg = _("Either subnet_id or port_id must be specified")
|
||||
raise exceptions.BadRequest(resource='router', msg=msg)
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# remove router in DB
|
||||
del_ret = super(NeutronRestProxyV2,
|
||||
self).remove_router_interface(context,
|
||||
router_id,
|
||||
interface_info)
|
||||
|
||||
# create router on the network controller
|
||||
self.servers.rest_remove_router_interface(tenant_id, router_id,
|
||||
interface_id)
|
||||
return del_ret
|
||||
|
||||
@put_context_in_serverpool
|
||||
def create_floatingip(self, context, floatingip):
|
||||
LOG.debug(_("NeutronRestProxyV2: create_floatingip() called"))
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# create floatingip in DB
|
||||
new_fl_ip = super(NeutronRestProxyV2,
|
||||
self).create_floatingip(context, floatingip)
|
||||
|
||||
# create floatingip on the network controller
|
||||
try:
|
||||
if 'floatingip' in self.servers.get_capabilities():
|
||||
self.servers.rest_create_floatingip(
|
||||
new_fl_ip['tenant_id'], new_fl_ip)
|
||||
else:
|
||||
self._send_floatingip_update(context)
|
||||
except servermanager.RemoteRestError as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(
|
||||
_("NeutronRestProxyV2: Unable to create remote "
|
||||
"floating IP: %s"), e)
|
||||
# return created floating IP
|
||||
return new_fl_ip
|
||||
|
||||
@put_context_in_serverpool
|
||||
def update_floatingip(self, context, id, floatingip):
|
||||
LOG.debug(_("NeutronRestProxyV2: update_floatingip() called"))
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# update floatingip in DB
|
||||
new_fl_ip = super(NeutronRestProxyV2,
|
||||
self).update_floatingip(context, id, floatingip)
|
||||
|
||||
# update network on network controller
|
||||
if 'floatingip' in self.servers.get_capabilities():
|
||||
self.servers.rest_update_floatingip(new_fl_ip['tenant_id'],
|
||||
new_fl_ip, id)
|
||||
else:
|
||||
self._send_floatingip_update(context)
|
||||
return new_fl_ip
|
||||
|
||||
@put_context_in_serverpool
|
||||
def delete_floatingip(self, context, id):
|
||||
LOG.debug(_("NeutronRestProxyV2: delete_floatingip() called"))
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# delete floating IP in DB
|
||||
old_fip = super(NeutronRestProxyV2, self).get_floatingip(context,
|
||||
id)
|
||||
super(NeutronRestProxyV2, self).delete_floatingip(context, id)
|
||||
|
||||
# update network on network controller
|
||||
if 'floatingip' in self.servers.get_capabilities():
|
||||
self.servers.rest_delete_floatingip(old_fip['tenant_id'], id)
|
||||
else:
|
||||
self._send_floatingip_update(context)
|
||||
|
||||
@put_context_in_serverpool
|
||||
def disassociate_floatingips(self, context, port_id, do_notify=True):
|
||||
LOG.debug(_("NeutronRestProxyV2: diassociate_floatingips() called"))
|
||||
router_ids = super(NeutronRestProxyV2, self).disassociate_floatingips(
|
||||
context, port_id, do_notify=do_notify)
|
||||
self._send_floatingip_update(context)
|
||||
return router_ids
|
||||
|
||||
# overriding method from l3_db as original method calls
|
||||
# self.delete_floatingip() which in turn calls self.delete_port() which
|
||||
# is locked with 'bsn-port-barrier'
|
||||
@put_context_in_serverpool
|
||||
def delete_disassociated_floatingips(self, context, network_id):
|
||||
query = self._model_query(context, l3_db.FloatingIP)
|
||||
query = query.filter_by(floating_network_id=network_id,
|
||||
fixed_port_id=None,
|
||||
router_id=None)
|
||||
for fip in query:
|
||||
context.session.delete(fip)
|
||||
self._delete_port(context.elevated(), fip['floating_port_id'])
|
||||
|
||||
def _send_floatingip_update(self, context):
|
||||
try:
|
||||
ext_net_id = self.get_external_network_id(context)
|
||||
if ext_net_id:
|
||||
# Use the elevated state of the context for the ext_net query
|
||||
admin_context = context.elevated()
|
||||
ext_net = super(NeutronRestProxyV2,
|
||||
self).get_network(admin_context, ext_net_id)
|
||||
# update external network on network controller
|
||||
self._send_update_network(ext_net, admin_context)
|
||||
except exceptions.TooManyExternalNetworks:
|
||||
# get_external_network can raise errors when multiple external
|
||||
# networks are detected, which isn't supported by the Plugin
|
||||
LOG.error(_("NeutronRestProxyV2: too many external networks"))
|
||||
|
||||
def _add_host_route(self, context, destination, port):
|
||||
subnet = {}
|
||||
for fixed_ip in port['fixed_ips']:
|
||||
|
@ -228,6 +228,15 @@ class ServerProxy(object):
|
||||
|
||||
class ServerPool(object):
|
||||
|
||||
_instance = None
|
||||
|
||||
@classmethod
|
||||
def get_instance(cls):
|
||||
if cls._instance:
|
||||
return cls._instance
|
||||
cls._instance = cls()
|
||||
return cls._instance
|
||||
|
||||
def __init__(self, timeout=False,
|
||||
base_uri=BASE_URI, name='NeutronRestProxy'):
|
||||
LOG.debug(_("ServerPool: initializing"))
|
||||
@ -268,6 +277,7 @@ class ServerPool(object):
|
||||
]
|
||||
eventlet.spawn(self._consistency_watchdog,
|
||||
cfg.CONF.RESTPROXY.consistency_interval)
|
||||
ServerPool._instance = self
|
||||
LOG.debug(_("ServerPool: initialization done"))
|
||||
|
||||
def set_context(self, context):
|
||||
|
@ -1,4 +1,6 @@
|
||||
# Test config file for quantum-proxy-plugin.
|
||||
[DEFAULT]
|
||||
service_plugins = bigswitch_l3
|
||||
|
||||
[database]
|
||||
# This line MUST be changed to actually run the plugin.
|
||||
|
@ -25,6 +25,7 @@ from neutron.tests.unit.bigswitch import fake_server
|
||||
|
||||
|
||||
RESTPROXY_PKG_PATH = 'neutron.plugins.bigswitch.plugin'
|
||||
L3_RESTPROXY_PKG_PATH = 'neutron.plugins.bigswitch.l3_router_plugin'
|
||||
NOTIFIER = 'neutron.plugins.bigswitch.plugin.AgentNotifierApi'
|
||||
CERTFETCH = 'neutron.plugins.bigswitch.servermanager.ServerPool._fetch_cert'
|
||||
SERVER_MANAGER = 'neutron.plugins.bigswitch.servermanager'
|
||||
@ -36,6 +37,7 @@ CWATCH = SERVER_MANAGER + '.ServerPool._consistency_watchdog'
|
||||
class BigSwitchTestBase(object):
|
||||
|
||||
_plugin_name = ('%s.NeutronRestProxyV2' % RESTPROXY_PKG_PATH)
|
||||
_l3_plugin_name = ('%s.L3RestProxy' % L3_RESTPROXY_PKG_PATH)
|
||||
|
||||
def setup_config_files(self):
|
||||
etc_path = os.path.join(os.path.dirname(__file__), 'etc')
|
||||
@ -49,6 +51,7 @@ class BigSwitchTestBase(object):
|
||||
os.path.join(etc_path, 'ssl'), 'RESTPROXY')
|
||||
# The mock interferes with HTTP(S) connection caching
|
||||
cfg.CONF.set_override('cache_connections', False, 'RESTPROXY')
|
||||
cfg.CONF.set_override('service_plugins', ['bigswitch_l3'])
|
||||
|
||||
def setup_patches(self):
|
||||
self.plugin_notifier_p = mock.patch(NOTIFIER)
|
||||
|
@ -45,8 +45,9 @@ class BigSwitchProxyPluginV2TestCase(test_base.BigSwitchTestBase,
|
||||
self.setup_patches()
|
||||
if plugin_name:
|
||||
self._plugin_name = plugin_name
|
||||
service_plugins = {'L3_ROUTER_NAT': self._l3_plugin_name}
|
||||
super(BigSwitchProxyPluginV2TestCase,
|
||||
self).setUp(self._plugin_name)
|
||||
self).setUp(self._plugin_name, service_plugins=service_plugins)
|
||||
self.port_create_status = 'BUILD'
|
||||
self.startHttpPatch()
|
||||
|
||||
@ -310,6 +311,6 @@ class TestBigSwitchProxySync(BigSwitchProxyPluginV2TestCase):
|
||||
self.assertEqual(result[0], 200)
|
||||
|
||||
|
||||
class TestBigSwitchAddressPairs(BigSwitchProxyPluginV2TestCase,
|
||||
test_addr_pair.TestAllowedAddressPairs):
|
||||
class TestBigSwitchAddressPairs(test_addr_pair.TestAllowedAddressPairs,
|
||||
BigSwitchProxyPluginV2TestCase):
|
||||
pass
|
||||
|
@ -70,14 +70,19 @@ class RouterDBTestBase(test_base.BigSwitchTestBase,
|
||||
test_l3_plugin.L3BaseForIntTests,
|
||||
test_l3_plugin.L3NatTestCaseMixin):
|
||||
|
||||
mock_rescheduling = False
|
||||
|
||||
def setUp(self):
|
||||
self.setup_patches()
|
||||
self.setup_config_files()
|
||||
ext_mgr = RouterRulesTestExtensionManager()
|
||||
service_plugins = {'L3_ROUTER_NAT': self._l3_plugin_name}
|
||||
super(RouterDBTestBase, self).setUp(plugin=self._plugin_name,
|
||||
ext_mgr=ext_mgr)
|
||||
ext_mgr=ext_mgr,
|
||||
service_plugins=service_plugins)
|
||||
cfg.CONF.set_default('allow_overlapping_ips', False)
|
||||
self.plugin_obj = manager.NeutronManager.get_plugin()
|
||||
self.plugin_obj = manager.NeutronManager.get_service_plugins().get(
|
||||
'L3_ROUTER_NAT')
|
||||
self.startHttpPatch()
|
||||
|
||||
def tearDown(self):
|
||||
|
@ -148,6 +148,7 @@ neutron.core_plugins =
|
||||
neutron.service_plugins =
|
||||
dummy = neutron.tests.unit.dummy_plugin:DummyServicePlugin
|
||||
router = neutron.services.l3_router.l3_router_plugin:L3RouterPlugin
|
||||
bigswitch_l3 = neutron.plugins.bigswitch.l3_router_plugin:L3RestProxy
|
||||
firewall = neutron.services.firewall.fwaas_plugin:FirewallPlugin
|
||||
lbaas = neutron.services.loadbalancer.plugin:LoadBalancerPlugin
|
||||
vpnaas = neutron.services.vpn.plugin:VPNDriverPlugin
|
||||
|
Loading…
Reference in New Issue
Block a user