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 allowedaddresspairs as addr_pair
|
||||||
from neutron.extensions import external_net
|
from neutron.extensions import external_net
|
||||||
from neutron.extensions import extra_dhcp_opt as edo_ext
|
from neutron.extensions import extra_dhcp_opt as edo_ext
|
||||||
from neutron.extensions import l3
|
|
||||||
from neutron.extensions import portbindings
|
from neutron.extensions import portbindings
|
||||||
from neutron import manager
|
from neutron import manager
|
||||||
from neutron.openstack.common import excutils
|
|
||||||
from neutron.openstack.common import importutils
|
from neutron.openstack.common import importutils
|
||||||
from neutron.openstack.common import log as logging
|
from neutron.openstack.common import log as logging
|
||||||
from neutron.plugins.bigswitch import config as pl_config
|
from neutron.plugins.bigswitch import config as pl_config
|
||||||
from neutron.plugins.bigswitch.db import porttracker_db
|
from neutron.plugins.bigswitch.db import porttracker_db
|
||||||
from neutron.plugins.bigswitch import extensions
|
from neutron.plugins.bigswitch import extensions
|
||||||
from neutron.plugins.bigswitch import routerrule_db
|
|
||||||
from neutron.plugins.bigswitch import servermanager
|
from neutron.plugins.bigswitch import servermanager
|
||||||
from neutron.plugins.bigswitch import version
|
from neutron.plugins.bigswitch import version
|
||||||
|
from neutron.plugins.common import constants as pconst
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -154,12 +152,16 @@ class SecurityGroupServerRpcMixin(sg_db_rpc.SecurityGroupServerRpcMixin):
|
|||||||
|
|
||||||
|
|
||||||
class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
|
class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
external_net_db.External_net_db_mixin,
|
external_net_db.External_net_db_mixin):
|
||||||
routerrule_db.RouterRule_db_mixin):
|
|
||||||
|
|
||||||
supported_extension_aliases = ["binding"]
|
supported_extension_aliases = ["binding"]
|
||||||
servers = None
|
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,
|
def _get_all_data(self, get_ports=True, get_floating_ips=True,
|
||||||
get_routers=True):
|
get_routers=True):
|
||||||
admin_context = qcontext.get_admin_context()
|
admin_context = qcontext.get_admin_context()
|
||||||
@ -196,9 +198,9 @@ class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
|
|
||||||
data = {'networks': networks}
|
data = {'networks': networks}
|
||||||
|
|
||||||
if get_routers:
|
if get_routers and self.l3_plugin:
|
||||||
routers = []
|
routers = []
|
||||||
all_routers = self.get_routers(admin_context) or []
|
all_routers = self.l3_plugin.get_routers(admin_context) or []
|
||||||
for router in all_routers:
|
for router in all_routers:
|
||||||
interfaces = []
|
interfaces = []
|
||||||
mapped_router = self._map_state_and_status(router)
|
mapped_router = self._map_state_and_status(router)
|
||||||
@ -242,9 +244,10 @@ class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
|
|
||||||
net_id = network['id']
|
net_id = network['id']
|
||||||
net_filter = {'floating_network_id': [net_id]}
|
net_filter = {'floating_network_id': [net_id]}
|
||||||
fl_ips = self.get_floatingips(context,
|
if self.l3_plugin:
|
||||||
filters=net_filter) or []
|
fl_ips = self.l3_plugin.get_floatingips(context,
|
||||||
network['floatingips'] = fl_ips
|
filters=net_filter) or []
|
||||||
|
network['floatingips'] = fl_ips
|
||||||
|
|
||||||
return network
|
return network
|
||||||
|
|
||||||
@ -454,8 +457,8 @@ class NeutronRestProxyV2(NeutronRestProxyV2Base,
|
|||||||
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
||||||
SecurityGroupServerRpcMixin):
|
SecurityGroupServerRpcMixin):
|
||||||
|
|
||||||
_supported_extension_aliases = ["external-net", "router", "binding",
|
_supported_extension_aliases = ["external-net", "binding",
|
||||||
"router_rules", "extra_dhcp_opt", "quotas",
|
"extra_dhcp_opt", "quotas",
|
||||||
"dhcp_agent_scheduler", "agent",
|
"dhcp_agent_scheduler", "agent",
|
||||||
"security-group", "allowed-address-pairs"]
|
"security-group", "allowed-address-pairs"]
|
||||||
|
|
||||||
@ -805,11 +808,12 @@ class NeutronRestProxyV2(NeutronRestProxyV2Base,
|
|||||||
|
|
||||||
# if needed, check to see if this is a port owned by
|
# if needed, check to see if this is a port owned by
|
||||||
# and l3-router. If so, we should prevent deletion.
|
# and l3-router. If so, we should prevent deletion.
|
||||||
if l3_port_check:
|
if l3_port_check and self.l3_plugin:
|
||||||
self.prevent_l3_port_deletion(context, port_id)
|
self.l3_plugin.prevent_l3_port_deletion(context, port_id)
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
router_ids = self.disassociate_floatingips(
|
if self.l3_plugin:
|
||||||
context, port_id, do_notify=False)
|
router_ids = self.l3_plugin.disassociate_floatingips(
|
||||||
|
context, port_id, do_notify=False)
|
||||||
self._delete_port_security_group_bindings(context, port_id)
|
self._delete_port_security_group_bindings(context, port_id)
|
||||||
port = super(NeutronRestProxyV2, self).get_port(context, port_id)
|
port = super(NeutronRestProxyV2, self).get_port(context, port_id)
|
||||||
# Tenant ID must come from network in case the network is shared
|
# 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._delete_port(context, port_id)
|
||||||
self.servers.rest_delete_port(tenid, port['network_id'], 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
|
if self.l3_plugin:
|
||||||
self.notify_routers_updated(context, router_ids)
|
# 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
|
@put_context_in_serverpool
|
||||||
def create_subnet(self, context, subnet):
|
def create_subnet(self, context, subnet):
|
||||||
@ -869,264 +874,6 @@ class NeutronRestProxyV2(NeutronRestProxyV2Base,
|
|||||||
# update network on network controller - exception will rollback
|
# update network on network controller - exception will rollback
|
||||||
self._send_update_network(orig_net, context)
|
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):
|
def _add_host_route(self, context, destination, port):
|
||||||
subnet = {}
|
subnet = {}
|
||||||
for fixed_ip in port['fixed_ips']:
|
for fixed_ip in port['fixed_ips']:
|
||||||
|
@ -228,6 +228,15 @@ class ServerProxy(object):
|
|||||||
|
|
||||||
class ServerPool(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,
|
def __init__(self, timeout=False,
|
||||||
base_uri=BASE_URI, name='NeutronRestProxy'):
|
base_uri=BASE_URI, name='NeutronRestProxy'):
|
||||||
LOG.debug(_("ServerPool: initializing"))
|
LOG.debug(_("ServerPool: initializing"))
|
||||||
@ -268,6 +277,7 @@ class ServerPool(object):
|
|||||||
]
|
]
|
||||||
eventlet.spawn(self._consistency_watchdog,
|
eventlet.spawn(self._consistency_watchdog,
|
||||||
cfg.CONF.RESTPROXY.consistency_interval)
|
cfg.CONF.RESTPROXY.consistency_interval)
|
||||||
|
ServerPool._instance = self
|
||||||
LOG.debug(_("ServerPool: initialization done"))
|
LOG.debug(_("ServerPool: initialization done"))
|
||||||
|
|
||||||
def set_context(self, context):
|
def set_context(self, context):
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
# Test config file for quantum-proxy-plugin.
|
# Test config file for quantum-proxy-plugin.
|
||||||
|
[DEFAULT]
|
||||||
|
service_plugins = bigswitch_l3
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
# This line MUST be changed to actually run the plugin.
|
# 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'
|
RESTPROXY_PKG_PATH = 'neutron.plugins.bigswitch.plugin'
|
||||||
|
L3_RESTPROXY_PKG_PATH = 'neutron.plugins.bigswitch.l3_router_plugin'
|
||||||
NOTIFIER = 'neutron.plugins.bigswitch.plugin.AgentNotifierApi'
|
NOTIFIER = 'neutron.plugins.bigswitch.plugin.AgentNotifierApi'
|
||||||
CERTFETCH = 'neutron.plugins.bigswitch.servermanager.ServerPool._fetch_cert'
|
CERTFETCH = 'neutron.plugins.bigswitch.servermanager.ServerPool._fetch_cert'
|
||||||
SERVER_MANAGER = 'neutron.plugins.bigswitch.servermanager'
|
SERVER_MANAGER = 'neutron.plugins.bigswitch.servermanager'
|
||||||
@ -36,6 +37,7 @@ CWATCH = SERVER_MANAGER + '.ServerPool._consistency_watchdog'
|
|||||||
class BigSwitchTestBase(object):
|
class BigSwitchTestBase(object):
|
||||||
|
|
||||||
_plugin_name = ('%s.NeutronRestProxyV2' % RESTPROXY_PKG_PATH)
|
_plugin_name = ('%s.NeutronRestProxyV2' % RESTPROXY_PKG_PATH)
|
||||||
|
_l3_plugin_name = ('%s.L3RestProxy' % L3_RESTPROXY_PKG_PATH)
|
||||||
|
|
||||||
def setup_config_files(self):
|
def setup_config_files(self):
|
||||||
etc_path = os.path.join(os.path.dirname(__file__), 'etc')
|
etc_path = os.path.join(os.path.dirname(__file__), 'etc')
|
||||||
@ -49,6 +51,7 @@ class BigSwitchTestBase(object):
|
|||||||
os.path.join(etc_path, 'ssl'), 'RESTPROXY')
|
os.path.join(etc_path, 'ssl'), 'RESTPROXY')
|
||||||
# The mock interferes with HTTP(S) connection caching
|
# The mock interferes with HTTP(S) connection caching
|
||||||
cfg.CONF.set_override('cache_connections', False, 'RESTPROXY')
|
cfg.CONF.set_override('cache_connections', False, 'RESTPROXY')
|
||||||
|
cfg.CONF.set_override('service_plugins', ['bigswitch_l3'])
|
||||||
|
|
||||||
def setup_patches(self):
|
def setup_patches(self):
|
||||||
self.plugin_notifier_p = mock.patch(NOTIFIER)
|
self.plugin_notifier_p = mock.patch(NOTIFIER)
|
||||||
|
@ -45,8 +45,9 @@ class BigSwitchProxyPluginV2TestCase(test_base.BigSwitchTestBase,
|
|||||||
self.setup_patches()
|
self.setup_patches()
|
||||||
if plugin_name:
|
if plugin_name:
|
||||||
self._plugin_name = plugin_name
|
self._plugin_name = plugin_name
|
||||||
|
service_plugins = {'L3_ROUTER_NAT': self._l3_plugin_name}
|
||||||
super(BigSwitchProxyPluginV2TestCase,
|
super(BigSwitchProxyPluginV2TestCase,
|
||||||
self).setUp(self._plugin_name)
|
self).setUp(self._plugin_name, service_plugins=service_plugins)
|
||||||
self.port_create_status = 'BUILD'
|
self.port_create_status = 'BUILD'
|
||||||
self.startHttpPatch()
|
self.startHttpPatch()
|
||||||
|
|
||||||
@ -310,6 +311,6 @@ class TestBigSwitchProxySync(BigSwitchProxyPluginV2TestCase):
|
|||||||
self.assertEqual(result[0], 200)
|
self.assertEqual(result[0], 200)
|
||||||
|
|
||||||
|
|
||||||
class TestBigSwitchAddressPairs(BigSwitchProxyPluginV2TestCase,
|
class TestBigSwitchAddressPairs(test_addr_pair.TestAllowedAddressPairs,
|
||||||
test_addr_pair.TestAllowedAddressPairs):
|
BigSwitchProxyPluginV2TestCase):
|
||||||
pass
|
pass
|
||||||
|
@ -70,14 +70,19 @@ class RouterDBTestBase(test_base.BigSwitchTestBase,
|
|||||||
test_l3_plugin.L3BaseForIntTests,
|
test_l3_plugin.L3BaseForIntTests,
|
||||||
test_l3_plugin.L3NatTestCaseMixin):
|
test_l3_plugin.L3NatTestCaseMixin):
|
||||||
|
|
||||||
|
mock_rescheduling = False
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.setup_patches()
|
self.setup_patches()
|
||||||
self.setup_config_files()
|
self.setup_config_files()
|
||||||
ext_mgr = RouterRulesTestExtensionManager()
|
ext_mgr = RouterRulesTestExtensionManager()
|
||||||
|
service_plugins = {'L3_ROUTER_NAT': self._l3_plugin_name}
|
||||||
super(RouterDBTestBase, self).setUp(plugin=self._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)
|
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()
|
self.startHttpPatch()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
|
@ -147,6 +147,7 @@ neutron.core_plugins =
|
|||||||
neutron.service_plugins =
|
neutron.service_plugins =
|
||||||
dummy = neutron.tests.unit.dummy_plugin:DummyServicePlugin
|
dummy = neutron.tests.unit.dummy_plugin:DummyServicePlugin
|
||||||
router = neutron.services.l3_router.l3_router_plugin:L3RouterPlugin
|
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
|
firewall = neutron.services.firewall.fwaas_plugin:FirewallPlugin
|
||||||
lbaas = neutron.services.loadbalancer.plugin:LoadBalancerPlugin
|
lbaas = neutron.services.loadbalancer.plugin:LoadBalancerPlugin
|
||||||
vpnaas = neutron.services.vpn.plugin:VPNDriverPlugin
|
vpnaas = neutron.services.vpn.plugin:VPNDriverPlugin
|
||||||
|
Loading…
x
Reference in New Issue
Block a user