Merge "Big Switch: Separate L3 functions into L3 service"
This commit is contained in:
commit
206c09dd2c
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):
|
||||
|
@ -147,6 +147,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…
x
Reference in New Issue
Block a user