Adds support for L3 routing/NAT as a service plugin
- Adds L3 routing/NAT service plugin - Removes L3 routing/NAT from ML2 plugin - Moves "router:external" attribute to new extension "External-net" - Introduces separate RPC topic for L3 callbacks from L3 agent Implements: blueprint quantum-l3-routing-plugin Change-Id: Id9af10c2910f9a1730b163203a68d101ffc3b282
This commit is contained in:
parent
39ef7594bd
commit
715b16aca7
@ -208,7 +208,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback, manager.Manager):
|
|||||||
raise SystemExit(msg)
|
raise SystemExit(msg)
|
||||||
|
|
||||||
self.context = context.get_admin_context_without_session()
|
self.context = context.get_admin_context_without_session()
|
||||||
self.plugin_rpc = L3PluginApi(topics.PLUGIN, host)
|
self.plugin_rpc = L3PluginApi(topics.L3PLUGIN, host)
|
||||||
self.fullsync = True
|
self.fullsync = True
|
||||||
self.updated_routers = set()
|
self.updated_routers = set()
|
||||||
self.removed_routers = set()
|
self.removed_routers = set()
|
||||||
|
@ -169,6 +169,18 @@ class ExtensionDescriptor(object):
|
|||||||
if extended_attrs:
|
if extended_attrs:
|
||||||
attrs.update(extended_attrs)
|
attrs.update(extended_attrs)
|
||||||
|
|
||||||
|
def get_alias_namespace_compatibility_map(self):
|
||||||
|
"""Returns mappings between extension aliases and XML namespaces.
|
||||||
|
|
||||||
|
The mappings are XML namespaces that should, for backward compatibility
|
||||||
|
reasons, be added to the XML serialization of extended attributes.
|
||||||
|
This allows an established extended attribute to be provided by
|
||||||
|
another extension than the original one while keeping its old alias
|
||||||
|
in the name.
|
||||||
|
:return: A dictionary of extension_aliases and namespace strings.
|
||||||
|
"""
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
class ActionExtensionController(wsgi.Controller):
|
class ActionExtensionController(wsgi.Controller):
|
||||||
|
|
||||||
@ -468,6 +480,13 @@ class ExtensionManager(object):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
LOG.exception(_("Error fetching extended attributes for "
|
LOG.exception(_("Error fetching extended attributes for "
|
||||||
"extension '%s'"), ext.get_name())
|
"extension '%s'"), ext.get_name())
|
||||||
|
try:
|
||||||
|
comp_map = ext.get_alias_namespace_compatibility_map()
|
||||||
|
attributes.EXT_NSES_BC.update(comp_map)
|
||||||
|
except AttributeError:
|
||||||
|
LOG.info(_("Extension '%s' provides no backward "
|
||||||
|
"compatibility map for extended attributes"),
|
||||||
|
ext.get_name())
|
||||||
processed_exts.add(ext_name)
|
processed_exts.add(ext_name)
|
||||||
del exts_to_process[ext_name]
|
del exts_to_process[ext_name]
|
||||||
if len(processed_exts) == processed_ext_count:
|
if len(processed_exts) == processed_ext_count:
|
||||||
|
@ -19,6 +19,7 @@ from neutron.common import utils
|
|||||||
from neutron import manager
|
from neutron import manager
|
||||||
from neutron.openstack.common import log as logging
|
from neutron.openstack.common import log as logging
|
||||||
from neutron.openstack.common.rpc import proxy
|
from neutron.openstack.common.rpc import proxy
|
||||||
|
from neutron.plugins.common import constants as service_constants
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -46,7 +47,8 @@ class L3AgentNotifyAPI(proxy.RpcProxy):
|
|||||||
operation, data):
|
operation, data):
|
||||||
"""Notify changed routers to hosting l3 agents."""
|
"""Notify changed routers to hosting l3 agents."""
|
||||||
adminContext = context.is_admin and context or context.elevated()
|
adminContext = context.is_admin and context or context.elevated()
|
||||||
plugin = manager.NeutronManager.get_plugin()
|
plugin = manager.NeutronManager.get_service_plugins().get(
|
||||||
|
service_constants.L3_ROUTER_NAT)
|
||||||
for router_id in router_ids:
|
for router_id in router_ids:
|
||||||
l3_agents = plugin.get_l3_agents_hosting_routers(
|
l3_agents = plugin.get_l3_agents_hosting_routers(
|
||||||
adminContext, [router_id],
|
adminContext, [router_id],
|
||||||
@ -66,9 +68,14 @@ class L3AgentNotifyAPI(proxy.RpcProxy):
|
|||||||
|
|
||||||
def _notification(self, context, method, router_ids, operation, data):
|
def _notification(self, context, method, router_ids, operation, data):
|
||||||
"""Notify all the agents that are hosting the routers."""
|
"""Notify all the agents that are hosting the routers."""
|
||||||
plugin = manager.NeutronManager.get_plugin()
|
plugin = manager.NeutronManager.get_service_plugins().get(
|
||||||
|
service_constants.L3_ROUTER_NAT)
|
||||||
|
if not plugin:
|
||||||
|
LOG.error(_('No plugin for L3 routing registered. Cannot notify '
|
||||||
|
'agents with the message %s'), method)
|
||||||
|
return
|
||||||
if utils.is_extension_supported(
|
if utils.is_extension_supported(
|
||||||
plugin, constants.L3_AGENT_SCHEDULER_EXT_ALIAS):
|
plugin, constants.L3_AGENT_SCHEDULER_EXT_ALIAS):
|
||||||
adminContext = (context.is_admin and
|
adminContext = (context.is_admin and
|
||||||
context or context.elevated())
|
context or context.elevated())
|
||||||
plugin.schedule_routers(adminContext, router_ids)
|
plugin.schedule_routers(adminContext, router_ids)
|
||||||
|
@ -704,8 +704,14 @@ PLURALS = {NETWORKS: NETWORK,
|
|||||||
'extensions': 'extension'}
|
'extensions': 'extension'}
|
||||||
EXT_NSES = {}
|
EXT_NSES = {}
|
||||||
|
|
||||||
|
# Namespaces to be added for backward compatibility
|
||||||
|
# when existing extended resource attributes are
|
||||||
|
# provided by other extension than original one.
|
||||||
|
EXT_NSES_BC = {}
|
||||||
|
|
||||||
|
|
||||||
def get_attr_metadata():
|
def get_attr_metadata():
|
||||||
return {'plurals': PLURALS,
|
return {'plurals': PLURALS,
|
||||||
'xmlns': constants.XML_NS_V20,
|
'xmlns': constants.XML_NS_V20,
|
||||||
constants.EXT_NS: EXT_NSES}
|
constants.EXT_NS: EXT_NSES,
|
||||||
|
constants.EXT_NS_COMP: EXT_NSES_BC}
|
||||||
|
@ -45,6 +45,7 @@ DHCP_RESPONSE_PORT = 68
|
|||||||
MIN_VLAN_TAG = 1
|
MIN_VLAN_TAG = 1
|
||||||
MAX_VLAN_TAG = 4094
|
MAX_VLAN_TAG = 4094
|
||||||
|
|
||||||
|
EXT_NS_COMP = '_backward_comp_e_ns'
|
||||||
EXT_NS = '_extension_ns'
|
EXT_NS = '_extension_ns'
|
||||||
XML_NS_V20 = 'http://openstack.org/quantum/api/v2.0'
|
XML_NS_V20 = 'http://openstack.org/quantum/api/v2.0'
|
||||||
XSI_NAMESPACE = "http://www.w3.org/2001/XMLSchema-instance"
|
XSI_NAMESPACE = "http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
@ -24,6 +24,7 @@ UPDATE = 'update'
|
|||||||
|
|
||||||
AGENT = 'q-agent-notifier'
|
AGENT = 'q-agent-notifier'
|
||||||
PLUGIN = 'q-plugin'
|
PLUGIN = 'q-plugin'
|
||||||
|
L3PLUGIN = 'q-l3-plugin'
|
||||||
DHCP = 'q-dhcp-notifer'
|
DHCP = 'q-dhcp-notifer'
|
||||||
FIREWALL_PLUGIN = 'q-firewall-plugin'
|
FIREWALL_PLUGIN = 'q-firewall-plugin'
|
||||||
METERING_PLUGIN = 'q-metering-plugin'
|
METERING_PLUGIN = 'q-metering-plugin'
|
||||||
|
@ -24,9 +24,7 @@ from sqlalchemy.orm import joinedload
|
|||||||
from neutron.common import constants
|
from neutron.common import constants
|
||||||
from neutron.db import agents_db
|
from neutron.db import agents_db
|
||||||
from neutron.db import model_base
|
from neutron.db import model_base
|
||||||
from neutron.db import models_v2
|
|
||||||
from neutron.extensions import dhcpagentscheduler
|
from neutron.extensions import dhcpagentscheduler
|
||||||
from neutron.extensions import l3agentscheduler
|
|
||||||
from neutron.openstack.common import log as logging
|
from neutron.openstack.common import log as logging
|
||||||
|
|
||||||
|
|
||||||
@ -37,14 +35,8 @@ AGENTS_SCHEDULER_OPTS = [
|
|||||||
default='neutron.scheduler.'
|
default='neutron.scheduler.'
|
||||||
'dhcp_agent_scheduler.ChanceScheduler',
|
'dhcp_agent_scheduler.ChanceScheduler',
|
||||||
help=_('Driver to use for scheduling network to DHCP agent')),
|
help=_('Driver to use for scheduling network to DHCP agent')),
|
||||||
cfg.StrOpt('router_scheduler_driver',
|
|
||||||
default='neutron.scheduler.l3_agent_scheduler.ChanceScheduler',
|
|
||||||
help=_('Driver to use for scheduling '
|
|
||||||
'router to a default L3 agent')),
|
|
||||||
cfg.BoolOpt('network_auto_schedule', default=True,
|
cfg.BoolOpt('network_auto_schedule', default=True,
|
||||||
help=_('Allow auto scheduling networks to DHCP agent.')),
|
help=_('Allow auto scheduling networks to DHCP agent.')),
|
||||||
cfg.BoolOpt('router_auto_schedule', default=True,
|
|
||||||
help=_('Allow auto scheduling routers to L3 agent.')),
|
|
||||||
cfg.IntOpt('dhcp_agents_per_network', default=1,
|
cfg.IntOpt('dhcp_agents_per_network', default=1,
|
||||||
help=_('Number of DHCP agents scheduled to host a network.')),
|
help=_('Number of DHCP agents scheduled to host a network.')),
|
||||||
]
|
]
|
||||||
@ -65,17 +57,6 @@ class NetworkDhcpAgentBinding(model_base.BASEV2):
|
|||||||
primary_key=True)
|
primary_key=True)
|
||||||
|
|
||||||
|
|
||||||
class RouterL3AgentBinding(model_base.BASEV2, models_v2.HasId):
|
|
||||||
"""Represents binding between neutron routers and L3 agents."""
|
|
||||||
|
|
||||||
router_id = sa.Column(sa.String(36),
|
|
||||||
sa.ForeignKey("routers.id", ondelete='CASCADE'))
|
|
||||||
l3_agent = orm.relation(agents_db.Agent)
|
|
||||||
l3_agent_id = sa.Column(sa.String(36),
|
|
||||||
sa.ForeignKey("agents.id",
|
|
||||||
ondelete='CASCADE'))
|
|
||||||
|
|
||||||
|
|
||||||
class AgentSchedulerDbMixin(agents_db.AgentDbMixin):
|
class AgentSchedulerDbMixin(agents_db.AgentDbMixin):
|
||||||
"""Common class for agent scheduler mixins."""
|
"""Common class for agent scheduler mixins."""
|
||||||
|
|
||||||
@ -115,203 +96,6 @@ class AgentSchedulerDbMixin(agents_db.AgentDbMixin):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
class L3AgentSchedulerDbMixin(l3agentscheduler.L3AgentSchedulerPluginBase,
|
|
||||||
AgentSchedulerDbMixin):
|
|
||||||
"""Mixin class to add l3 agent scheduler extension to db_plugin_base_v2."""
|
|
||||||
|
|
||||||
router_scheduler = None
|
|
||||||
|
|
||||||
def add_router_to_l3_agent(self, context, id, router_id):
|
|
||||||
"""Add a l3 agent to host a router."""
|
|
||||||
router = self.get_router(context, router_id)
|
|
||||||
with context.session.begin(subtransactions=True):
|
|
||||||
agent_db = self._get_agent(context, id)
|
|
||||||
if (agent_db['agent_type'] != constants.AGENT_TYPE_L3 or
|
|
||||||
not agent_db['admin_state_up'] or
|
|
||||||
not self.get_l3_agent_candidates(router, [agent_db])):
|
|
||||||
raise l3agentscheduler.InvalidL3Agent(id=id)
|
|
||||||
query = context.session.query(RouterL3AgentBinding)
|
|
||||||
try:
|
|
||||||
binding = query.filter_by(router_id=router_id).one()
|
|
||||||
|
|
||||||
raise l3agentscheduler.RouterHostedByL3Agent(
|
|
||||||
router_id=router_id,
|
|
||||||
agent_id=binding.l3_agent_id)
|
|
||||||
except exc.NoResultFound:
|
|
||||||
pass
|
|
||||||
|
|
||||||
result = self.auto_schedule_routers(context,
|
|
||||||
agent_db.host,
|
|
||||||
[router_id])
|
|
||||||
if not result:
|
|
||||||
raise l3agentscheduler.RouterSchedulingFailed(
|
|
||||||
router_id=router_id, agent_id=id)
|
|
||||||
|
|
||||||
l3_notifier = self.agent_notifiers.get(constants.AGENT_TYPE_L3)
|
|
||||||
if l3_notifier:
|
|
||||||
l3_notifier.router_added_to_agent(
|
|
||||||
context, [router_id], agent_db.host)
|
|
||||||
|
|
||||||
def remove_router_from_l3_agent(self, context, id, router_id):
|
|
||||||
"""Remove the router from l3 agent.
|
|
||||||
|
|
||||||
After it, the router will be non-hosted until there is update which
|
|
||||||
lead to re schedule or be added to another agent manually.
|
|
||||||
"""
|
|
||||||
agent = self._get_agent(context, id)
|
|
||||||
with context.session.begin(subtransactions=True):
|
|
||||||
query = context.session.query(RouterL3AgentBinding)
|
|
||||||
query = query.filter(
|
|
||||||
RouterL3AgentBinding.router_id == router_id,
|
|
||||||
RouterL3AgentBinding.l3_agent_id == id)
|
|
||||||
try:
|
|
||||||
binding = query.one()
|
|
||||||
except exc.NoResultFound:
|
|
||||||
raise l3agentscheduler.RouterNotHostedByL3Agent(
|
|
||||||
router_id=router_id, agent_id=id)
|
|
||||||
context.session.delete(binding)
|
|
||||||
l3_notifier = self.agent_notifiers.get(constants.AGENT_TYPE_L3)
|
|
||||||
if l3_notifier:
|
|
||||||
l3_notifier.router_removed_from_agent(
|
|
||||||
context, router_id, agent.host)
|
|
||||||
|
|
||||||
def list_routers_on_l3_agent(self, context, id):
|
|
||||||
query = context.session.query(RouterL3AgentBinding.router_id)
|
|
||||||
query = query.filter(RouterL3AgentBinding.l3_agent_id == id)
|
|
||||||
|
|
||||||
router_ids = [item[0] for item in query]
|
|
||||||
if router_ids:
|
|
||||||
return {'routers':
|
|
||||||
self.get_routers(context, filters={'id': router_ids})}
|
|
||||||
else:
|
|
||||||
return {'routers': []}
|
|
||||||
|
|
||||||
def list_active_sync_routers_on_active_l3_agent(
|
|
||||||
self, context, host, router_ids):
|
|
||||||
agent = self._get_agent_by_type_and_host(
|
|
||||||
context, constants.AGENT_TYPE_L3, host)
|
|
||||||
if not agent.admin_state_up:
|
|
||||||
return []
|
|
||||||
query = context.session.query(RouterL3AgentBinding.router_id)
|
|
||||||
query = query.filter(
|
|
||||||
RouterL3AgentBinding.l3_agent_id == agent.id)
|
|
||||||
|
|
||||||
if not router_ids:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
query = query.filter(
|
|
||||||
RouterL3AgentBinding.router_id.in_(router_ids))
|
|
||||||
router_ids = [item[0] for item in query]
|
|
||||||
if router_ids:
|
|
||||||
return self.get_sync_data(context, router_ids=router_ids,
|
|
||||||
active=True)
|
|
||||||
else:
|
|
||||||
return []
|
|
||||||
|
|
||||||
def get_l3_agents_hosting_routers(self, context, router_ids,
|
|
||||||
admin_state_up=None,
|
|
||||||
active=None):
|
|
||||||
if not router_ids:
|
|
||||||
return []
|
|
||||||
query = context.session.query(RouterL3AgentBinding)
|
|
||||||
if len(router_ids) > 1:
|
|
||||||
query = query.options(joinedload('l3_agent')).filter(
|
|
||||||
RouterL3AgentBinding.router_id.in_(router_ids))
|
|
||||||
else:
|
|
||||||
query = query.options(joinedload('l3_agent')).filter(
|
|
||||||
RouterL3AgentBinding.router_id == router_ids[0])
|
|
||||||
if admin_state_up is not None:
|
|
||||||
query = (query.filter(agents_db.Agent.admin_state_up ==
|
|
||||||
admin_state_up))
|
|
||||||
l3_agents = [binding.l3_agent for binding in query]
|
|
||||||
if active is not None:
|
|
||||||
l3_agents = [l3_agent for l3_agent in
|
|
||||||
l3_agents if not
|
|
||||||
agents_db.AgentDbMixin.is_agent_down(
|
|
||||||
l3_agent['heartbeat_timestamp'])]
|
|
||||||
return l3_agents
|
|
||||||
|
|
||||||
def _get_l3_bindings_hosting_routers(self, context, router_ids):
|
|
||||||
if not router_ids:
|
|
||||||
return []
|
|
||||||
query = context.session.query(RouterL3AgentBinding)
|
|
||||||
if len(router_ids) > 1:
|
|
||||||
query = query.options(joinedload('l3_agent')).filter(
|
|
||||||
RouterL3AgentBinding.router_id.in_(router_ids))
|
|
||||||
else:
|
|
||||||
query = query.options(joinedload('l3_agent')).filter(
|
|
||||||
RouterL3AgentBinding.router_id == router_ids[0])
|
|
||||||
return query.all()
|
|
||||||
|
|
||||||
def list_l3_agents_hosting_router(self, context, router_id):
|
|
||||||
with context.session.begin(subtransactions=True):
|
|
||||||
bindings = self._get_l3_bindings_hosting_routers(
|
|
||||||
context, [router_id])
|
|
||||||
results = []
|
|
||||||
for binding in bindings:
|
|
||||||
l3_agent_dict = self._make_agent_dict(binding.l3_agent)
|
|
||||||
results.append(l3_agent_dict)
|
|
||||||
if results:
|
|
||||||
return {'agents': results}
|
|
||||||
else:
|
|
||||||
return {'agents': []}
|
|
||||||
|
|
||||||
def get_l3_agents(self, context, active=None, filters=None):
|
|
||||||
query = context.session.query(agents_db.Agent)
|
|
||||||
query = query.filter(
|
|
||||||
agents_db.Agent.agent_type == constants.AGENT_TYPE_L3)
|
|
||||||
if active is not None:
|
|
||||||
query = (query.filter(agents_db.Agent.admin_state_up == active))
|
|
||||||
if filters:
|
|
||||||
for key, value in filters.iteritems():
|
|
||||||
column = getattr(agents_db.Agent, key, None)
|
|
||||||
if column:
|
|
||||||
query = query.filter(column.in_(value))
|
|
||||||
|
|
||||||
return [l3_agent
|
|
||||||
for l3_agent in query
|
|
||||||
if AgentSchedulerDbMixin.is_eligible_agent(active, l3_agent)]
|
|
||||||
|
|
||||||
def get_l3_agent_candidates(self, sync_router, l3_agents):
|
|
||||||
"""Get the valid l3 agents for the router from a list of l3_agents."""
|
|
||||||
candidates = []
|
|
||||||
for l3_agent in l3_agents:
|
|
||||||
if not l3_agent.admin_state_up:
|
|
||||||
continue
|
|
||||||
agent_conf = self.get_configuration_dict(l3_agent)
|
|
||||||
router_id = agent_conf.get('router_id', None)
|
|
||||||
use_namespaces = agent_conf.get('use_namespaces', True)
|
|
||||||
handle_internal_only_routers = agent_conf.get(
|
|
||||||
'handle_internal_only_routers', True)
|
|
||||||
gateway_external_network_id = agent_conf.get(
|
|
||||||
'gateway_external_network_id', None)
|
|
||||||
if not use_namespaces and router_id != sync_router['id']:
|
|
||||||
continue
|
|
||||||
ex_net_id = (sync_router['external_gateway_info'] or {}).get(
|
|
||||||
'network_id')
|
|
||||||
if ((not ex_net_id and not handle_internal_only_routers) or
|
|
||||||
(ex_net_id and gateway_external_network_id and
|
|
||||||
ex_net_id != gateway_external_network_id)):
|
|
||||||
continue
|
|
||||||
candidates.append(l3_agent)
|
|
||||||
return candidates
|
|
||||||
|
|
||||||
def auto_schedule_routers(self, context, host, router_ids):
|
|
||||||
if self.router_scheduler:
|
|
||||||
return self.router_scheduler.auto_schedule_routers(
|
|
||||||
self, context, host, router_ids)
|
|
||||||
|
|
||||||
def schedule_router(self, context, router):
|
|
||||||
if self.router_scheduler:
|
|
||||||
return self.router_scheduler.schedule(
|
|
||||||
self, context, router)
|
|
||||||
|
|
||||||
def schedule_routers(self, context, routers):
|
|
||||||
"""Schedule the routers to l3 agents."""
|
|
||||||
for router in routers:
|
|
||||||
self.schedule_router(context, router)
|
|
||||||
|
|
||||||
|
|
||||||
class DhcpAgentSchedulerDbMixin(dhcpagentscheduler
|
class DhcpAgentSchedulerDbMixin(dhcpagentscheduler
|
||||||
.DhcpAgentSchedulerPluginBase,
|
.DhcpAgentSchedulerPluginBase,
|
||||||
AgentSchedulerDbMixin):
|
AgentSchedulerDbMixin):
|
||||||
|
@ -59,6 +59,11 @@ class CommonDbMixin(object):
|
|||||||
# from this class should be invoked
|
# from this class should be invoked
|
||||||
_model_query_hooks = {}
|
_model_query_hooks = {}
|
||||||
|
|
||||||
|
# This dictionary will store methods for extending attributes of
|
||||||
|
# api resources. Mixins can use this dict for adding their own methods
|
||||||
|
# TODO(salvatore-orlando): Avoid using class-level variables
|
||||||
|
_dict_extend_functions = {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def register_model_query_hook(cls, model, name, query_hook, filter_hook,
|
def register_model_query_hook(cls, model, name, query_hook, filter_hook,
|
||||||
result_filters=None):
|
result_filters=None):
|
||||||
@ -218,11 +223,6 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
|||||||
__native_pagination_support = True
|
__native_pagination_support = True
|
||||||
__native_sorting_support = True
|
__native_sorting_support = True
|
||||||
|
|
||||||
# This dictionary will store methods for extending attributes of
|
|
||||||
# api resources. Mixins can use this dict for adding their own methods
|
|
||||||
# TODO(salvatore-orlando): Avoid using class-level variables
|
|
||||||
_dict_extend_functions = {}
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# NOTE(jkoelker) This is an incomplete implementation. Subclasses
|
# NOTE(jkoelker) This is an incomplete implementation. Subclasses
|
||||||
# must override __init__ and setup the database
|
# must override __init__ and setup the database
|
||||||
|
157
neutron/db/external_net_db.py
Normal file
157
neutron/db/external_net_db.py
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright (c) 2013 OpenStack Foundation.
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy import orm
|
||||||
|
from sqlalchemy.orm import exc
|
||||||
|
from sqlalchemy.sql import expression as expr
|
||||||
|
|
||||||
|
from neutron.api.v2 import attributes
|
||||||
|
from neutron.common import constants as l3_constants
|
||||||
|
from neutron.common import exceptions as q_exc
|
||||||
|
from neutron.db import db_base_plugin_v2
|
||||||
|
from neutron.db import model_base
|
||||||
|
from neutron.db import models_v2
|
||||||
|
from neutron.extensions import external_net
|
||||||
|
|
||||||
|
|
||||||
|
DEVICE_OWNER_ROUTER_GW = l3_constants.DEVICE_OWNER_ROUTER_GW
|
||||||
|
|
||||||
|
|
||||||
|
class ExternalNetwork(model_base.BASEV2):
|
||||||
|
network_id = sa.Column(sa.String(36),
|
||||||
|
sa.ForeignKey('networks.id', ondelete="CASCADE"),
|
||||||
|
primary_key=True)
|
||||||
|
|
||||||
|
# Add a relationship to the Network model in order to instruct
|
||||||
|
# SQLAlchemy to eagerly load this association
|
||||||
|
network = orm.relationship(
|
||||||
|
models_v2.Network,
|
||||||
|
backref=orm.backref("external", lazy='joined',
|
||||||
|
uselist=False, cascade='delete'))
|
||||||
|
|
||||||
|
|
||||||
|
class External_net_db_mixin(object):
|
||||||
|
"""Mixin class to add external network methods to db_plugin_base_v2."""
|
||||||
|
|
||||||
|
def _network_model_hook(self, context, original_model, query):
|
||||||
|
query = query.outerjoin(ExternalNetwork,
|
||||||
|
(original_model.id ==
|
||||||
|
ExternalNetwork.network_id))
|
||||||
|
return query
|
||||||
|
|
||||||
|
def _network_filter_hook(self, context, original_model, conditions):
|
||||||
|
if conditions is not None and not hasattr(conditions, '__iter__'):
|
||||||
|
conditions = (conditions, )
|
||||||
|
# Apply the external network filter only in non-admin context
|
||||||
|
if not context.is_admin and hasattr(original_model, 'tenant_id'):
|
||||||
|
conditions = expr.or_(ExternalNetwork.network_id != expr.null(),
|
||||||
|
*conditions)
|
||||||
|
return conditions
|
||||||
|
|
||||||
|
def _network_result_filter_hook(self, query, filters):
|
||||||
|
vals = filters and filters.get(external_net.EXTERNAL, [])
|
||||||
|
if not vals:
|
||||||
|
return query
|
||||||
|
if vals[0]:
|
||||||
|
return query.filter((ExternalNetwork.network_id != expr.null()))
|
||||||
|
return query.filter((ExternalNetwork.network_id == expr.null()))
|
||||||
|
|
||||||
|
# TODO(salvatore-orlando): Perform this operation without explicitly
|
||||||
|
# referring to db_base_plugin_v2, as plugins that do not extend from it
|
||||||
|
# might exist in the future
|
||||||
|
db_base_plugin_v2.NeutronDbPluginV2.register_model_query_hook(
|
||||||
|
models_v2.Network,
|
||||||
|
"external_net",
|
||||||
|
'_network_model_hook',
|
||||||
|
'_network_filter_hook',
|
||||||
|
'_network_result_filter_hook')
|
||||||
|
|
||||||
|
def _network_is_external(self, context, net_id):
|
||||||
|
try:
|
||||||
|
context.session.query(ExternalNetwork).filter_by(
|
||||||
|
network_id=net_id).one()
|
||||||
|
return True
|
||||||
|
except exc.NoResultFound:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _extend_network_dict_l3(self, network_res, network_db):
|
||||||
|
# Comparing with None for converting uuid into bool
|
||||||
|
network_res[external_net.EXTERNAL] = network_db.external is not None
|
||||||
|
return network_res
|
||||||
|
|
||||||
|
# Register dict extend functions for networks
|
||||||
|
db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
|
||||||
|
attributes.NETWORKS, ['_extend_network_dict_l3'])
|
||||||
|
|
||||||
|
def _process_l3_create(self, context, net_data, req_data):
|
||||||
|
external = req_data.get(external_net.EXTERNAL)
|
||||||
|
external_set = attributes.is_attr_set(external)
|
||||||
|
|
||||||
|
if not external_set:
|
||||||
|
return
|
||||||
|
|
||||||
|
if external:
|
||||||
|
# expects to be called within a plugin's session
|
||||||
|
context.session.add(ExternalNetwork(network_id=net_data['id']))
|
||||||
|
net_data[external_net.EXTERNAL] = external
|
||||||
|
|
||||||
|
def _process_l3_update(self, context, net_data, req_data):
|
||||||
|
|
||||||
|
new_value = req_data.get(external_net.EXTERNAL)
|
||||||
|
net_id = net_data['id']
|
||||||
|
if not attributes.is_attr_set(new_value):
|
||||||
|
return
|
||||||
|
|
||||||
|
if net_data.get(external_net.EXTERNAL) == new_value:
|
||||||
|
return
|
||||||
|
|
||||||
|
if new_value:
|
||||||
|
context.session.add(ExternalNetwork(network_id=net_id))
|
||||||
|
net_data[external_net.EXTERNAL] = True
|
||||||
|
else:
|
||||||
|
# must make sure we do not have any external gateway ports
|
||||||
|
# (and thus, possible floating IPs) on this network before
|
||||||
|
# allow it to be update to external=False
|
||||||
|
port = context.session.query(models_v2.Port).filter_by(
|
||||||
|
device_owner=DEVICE_OWNER_ROUTER_GW,
|
||||||
|
network_id=net_data['id']).first()
|
||||||
|
if port:
|
||||||
|
raise external_net.ExternalNetworkInUse(net_id=net_id)
|
||||||
|
|
||||||
|
context.session.query(ExternalNetwork).filter_by(
|
||||||
|
network_id=net_id).delete()
|
||||||
|
net_data[external_net.EXTERNAL] = False
|
||||||
|
|
||||||
|
def _filter_nets_l3(self, context, nets, filters):
|
||||||
|
vals = filters and filters.get(external_net.EXTERNAL, [])
|
||||||
|
if not vals:
|
||||||
|
return nets
|
||||||
|
|
||||||
|
ext_nets = set(en['network_id']
|
||||||
|
for en in context.session.query(ExternalNetwork))
|
||||||
|
if vals[0]:
|
||||||
|
return [n for n in nets if n['id'] in ext_nets]
|
||||||
|
else:
|
||||||
|
return [n for n in nets if n['id'] not in ext_nets]
|
||||||
|
|
||||||
|
def get_external_network_id(self, context):
|
||||||
|
nets = self.get_networks(context, {external_net.EXTERNAL: [True]})
|
||||||
|
if len(nets) > 1:
|
||||||
|
raise q_exc.TooManyExternalNetworks()
|
||||||
|
else:
|
||||||
|
return nets[0]['id'] if nets else None
|
@ -91,8 +91,8 @@ class ExtraRoute_db_mixin(l3_db.L3_NAT_db_mixin):
|
|||||||
# nexthop belongs to one of cidrs of the router ports
|
# nexthop belongs to one of cidrs of the router ports
|
||||||
cidrs = []
|
cidrs = []
|
||||||
for port in ports:
|
for port in ports:
|
||||||
cidrs += [self._get_subnet(context,
|
cidrs += [self._core_plugin._get_subnet(context,
|
||||||
ip['subnet_id'])['cidr']
|
ip['subnet_id'])['cidr']
|
||||||
for ip in port['fixed_ips']]
|
for ip in port['fixed_ips']]
|
||||||
if not netaddr.all_matching_cidrs(nexthop, cidrs):
|
if not netaddr.all_matching_cidrs(nexthop, cidrs):
|
||||||
raise extraroute.InvalidRoutes(
|
raise extraroute.InvalidRoutes(
|
||||||
@ -114,7 +114,7 @@ class ExtraRoute_db_mixin(l3_db.L3_NAT_db_mixin):
|
|||||||
quota=cfg.CONF.max_routes)
|
quota=cfg.CONF.max_routes)
|
||||||
|
|
||||||
filters = {'device_id': [router_id]}
|
filters = {'device_id': [router_id]}
|
||||||
ports = self.get_ports(context, filters)
|
ports = self._core_plugin.get_ports(context, filters)
|
||||||
for route in routes:
|
for route in routes:
|
||||||
self._validate_routes_nexthop(
|
self._validate_routes_nexthop(
|
||||||
context, ports, routes, route['nexthop'])
|
context, ports, routes, route['nexthop'])
|
||||||
@ -171,7 +171,7 @@ class ExtraRoute_db_mixin(l3_db.L3_NAT_db_mixin):
|
|||||||
subnet_id):
|
subnet_id):
|
||||||
super(ExtraRoute_db_mixin, self)._confirm_router_interface_not_in_use(
|
super(ExtraRoute_db_mixin, self)._confirm_router_interface_not_in_use(
|
||||||
context, router_id, subnet_id)
|
context, router_id, subnet_id)
|
||||||
subnet_db = self._get_subnet(context, subnet_id)
|
subnet_db = self._core_plugin._get_subnet(context, subnet_id)
|
||||||
subnet_cidr = netaddr.IPNetwork(subnet_db['cidr'])
|
subnet_cidr = netaddr.IPNetwork(subnet_db['cidr'])
|
||||||
extra_routes = self._get_extra_routes_by_router_id(context, router_id)
|
extra_routes = self._get_extra_routes_by_router_id(context, router_id)
|
||||||
for route in extra_routes:
|
for route in extra_routes:
|
||||||
|
251
neutron/db/l3_agentschedulers_db.py
Normal file
251
neutron/db/l3_agentschedulers_db.py
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright (c) 2013 OpenStack Foundation.
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
from oslo.config import cfg
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy import orm
|
||||||
|
from sqlalchemy.orm import exc
|
||||||
|
from sqlalchemy.orm import joinedload
|
||||||
|
|
||||||
|
from neutron.common import constants
|
||||||
|
from neutron.db import agents_db
|
||||||
|
from neutron.db.agentschedulers_db import AgentSchedulerDbMixin
|
||||||
|
from neutron.db import model_base
|
||||||
|
from neutron.db import models_v2
|
||||||
|
from neutron.extensions import l3agentscheduler
|
||||||
|
|
||||||
|
|
||||||
|
L3_AGENTS_SCHEDULER_OPTS = [
|
||||||
|
cfg.StrOpt('router_scheduler_driver',
|
||||||
|
default='neutron.scheduler.l3_agent_scheduler.ChanceScheduler',
|
||||||
|
help=_('Driver to use for scheduling '
|
||||||
|
'router to a default L3 agent')),
|
||||||
|
cfg.BoolOpt('router_auto_schedule', default=True,
|
||||||
|
help=_('Allow auto scheduling of routers to L3 agent.')),
|
||||||
|
]
|
||||||
|
|
||||||
|
cfg.CONF.register_opts(L3_AGENTS_SCHEDULER_OPTS)
|
||||||
|
|
||||||
|
|
||||||
|
class RouterL3AgentBinding(model_base.BASEV2, models_v2.HasId):
|
||||||
|
"""Represents binding between neutron routers and L3 agents."""
|
||||||
|
|
||||||
|
router_id = sa.Column(sa.String(36),
|
||||||
|
sa.ForeignKey("routers.id", ondelete='CASCADE'))
|
||||||
|
l3_agent = orm.relation(agents_db.Agent)
|
||||||
|
l3_agent_id = sa.Column(sa.String(36),
|
||||||
|
sa.ForeignKey("agents.id",
|
||||||
|
ondelete='CASCADE'))
|
||||||
|
|
||||||
|
|
||||||
|
class L3AgentSchedulerDbMixin(l3agentscheduler.L3AgentSchedulerPluginBase,
|
||||||
|
AgentSchedulerDbMixin):
|
||||||
|
"""Mixin class to add l3 agent scheduler extension to plugins
|
||||||
|
using the l3 agent for routing.
|
||||||
|
"""
|
||||||
|
|
||||||
|
router_scheduler = None
|
||||||
|
|
||||||
|
def add_router_to_l3_agent(self, context, agent_id, router_id):
|
||||||
|
"""Add a l3 agent to host a router."""
|
||||||
|
router = self.get_router(context, router_id)
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
agent_db = self._get_agent(context, agent_id)
|
||||||
|
if (agent_db['agent_type'] != constants.AGENT_TYPE_L3 or
|
||||||
|
not agent_db['admin_state_up'] or
|
||||||
|
not self.get_l3_agent_candidates(router, [agent_db])):
|
||||||
|
raise l3agentscheduler.InvalidL3Agent(id=agent_id)
|
||||||
|
query = context.session.query(RouterL3AgentBinding)
|
||||||
|
try:
|
||||||
|
binding = query.filter_by(router_id=router_id).one()
|
||||||
|
|
||||||
|
raise l3agentscheduler.RouterHostedByL3Agent(
|
||||||
|
router_id=router_id,
|
||||||
|
agent_id=binding.l3_agent_id)
|
||||||
|
except exc.NoResultFound:
|
||||||
|
pass
|
||||||
|
|
||||||
|
result = self.auto_schedule_routers(context,
|
||||||
|
agent_db.host,
|
||||||
|
[router_id])
|
||||||
|
if not result:
|
||||||
|
raise l3agentscheduler.RouterSchedulingFailed(
|
||||||
|
router_id=router_id, agent_id=agent_id)
|
||||||
|
|
||||||
|
l3_notifier = self.agent_notifiers.get(constants.AGENT_TYPE_L3)
|
||||||
|
if l3_notifier:
|
||||||
|
l3_notifier.router_added_to_agent(
|
||||||
|
context, [router_id], agent_db.host)
|
||||||
|
|
||||||
|
def remove_router_from_l3_agent(self, context, agent_id, router_id):
|
||||||
|
"""Remove the router from l3 agent.
|
||||||
|
|
||||||
|
After removal, the router will be non-hosted until there is update
|
||||||
|
which leads to re-schedule or be added to another agent manually.
|
||||||
|
"""
|
||||||
|
agent = self._get_agent(context, agent_id)
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
query = context.session.query(RouterL3AgentBinding)
|
||||||
|
query = query.filter(
|
||||||
|
RouterL3AgentBinding.router_id == router_id,
|
||||||
|
RouterL3AgentBinding.l3_agent_id == agent_id)
|
||||||
|
try:
|
||||||
|
binding = query.one()
|
||||||
|
except exc.NoResultFound:
|
||||||
|
raise l3agentscheduler.RouterNotHostedByL3Agent(
|
||||||
|
router_id=router_id, agent_id=agent_id)
|
||||||
|
context.session.delete(binding)
|
||||||
|
l3_notifier = self.agent_notifiers.get(constants.AGENT_TYPE_L3)
|
||||||
|
if l3_notifier:
|
||||||
|
l3_notifier.router_removed_from_agent(
|
||||||
|
context, router_id, agent.host)
|
||||||
|
|
||||||
|
def list_routers_on_l3_agent(self, context, agent_id):
|
||||||
|
query = context.session.query(RouterL3AgentBinding.router_id)
|
||||||
|
query = query.filter(RouterL3AgentBinding.l3_agent_id == agent_id)
|
||||||
|
|
||||||
|
router_ids = [item[0] for item in query]
|
||||||
|
if router_ids:
|
||||||
|
return {'routers':
|
||||||
|
self.get_routers(context, filters={'id': router_ids})}
|
||||||
|
else:
|
||||||
|
return {'routers': []}
|
||||||
|
|
||||||
|
def list_active_sync_routers_on_active_l3_agent(
|
||||||
|
self, context, host, router_ids):
|
||||||
|
agent = self._get_agent_by_type_and_host(
|
||||||
|
context, constants.AGENT_TYPE_L3, host)
|
||||||
|
if not agent.admin_state_up:
|
||||||
|
return []
|
||||||
|
query = context.session.query(RouterL3AgentBinding.router_id)
|
||||||
|
query = query.filter(
|
||||||
|
RouterL3AgentBinding.l3_agent_id == agent.id)
|
||||||
|
|
||||||
|
if not router_ids:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
query = query.filter(
|
||||||
|
RouterL3AgentBinding.router_id.in_(router_ids))
|
||||||
|
router_ids = [item[0] for item in query]
|
||||||
|
if router_ids:
|
||||||
|
return self.get_sync_data(context, router_ids=router_ids,
|
||||||
|
active=True)
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_l3_agents_hosting_routers(self, context, router_ids,
|
||||||
|
admin_state_up=None,
|
||||||
|
active=None):
|
||||||
|
if not router_ids:
|
||||||
|
return []
|
||||||
|
query = context.session.query(RouterL3AgentBinding)
|
||||||
|
if len(router_ids) > 1:
|
||||||
|
query = query.options(joinedload('l3_agent')).filter(
|
||||||
|
RouterL3AgentBinding.router_id.in_(router_ids))
|
||||||
|
else:
|
||||||
|
query = query.options(joinedload('l3_agent')).filter(
|
||||||
|
RouterL3AgentBinding.router_id == router_ids[0])
|
||||||
|
if admin_state_up is not None:
|
||||||
|
query = (query.filter(agents_db.Agent.admin_state_up ==
|
||||||
|
admin_state_up))
|
||||||
|
l3_agents = [binding.l3_agent for binding in query]
|
||||||
|
if active is not None:
|
||||||
|
l3_agents = [l3_agent for l3_agent in
|
||||||
|
l3_agents if not
|
||||||
|
agents_db.AgentDbMixin.is_agent_down(
|
||||||
|
l3_agent['heartbeat_timestamp'])]
|
||||||
|
return l3_agents
|
||||||
|
|
||||||
|
def _get_l3_bindings_hosting_routers(self, context, router_ids):
|
||||||
|
if not router_ids:
|
||||||
|
return []
|
||||||
|
query = context.session.query(RouterL3AgentBinding)
|
||||||
|
if len(router_ids) > 1:
|
||||||
|
query = query.options(joinedload('l3_agent')).filter(
|
||||||
|
RouterL3AgentBinding.router_id.in_(router_ids))
|
||||||
|
else:
|
||||||
|
query = query.options(joinedload('l3_agent')).filter(
|
||||||
|
RouterL3AgentBinding.router_id == router_ids[0])
|
||||||
|
return query.all()
|
||||||
|
|
||||||
|
def list_l3_agents_hosting_router(self, context, router_id):
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
bindings = self._get_l3_bindings_hosting_routers(
|
||||||
|
context, [router_id])
|
||||||
|
results = []
|
||||||
|
for binding in bindings:
|
||||||
|
l3_agent_dict = self._make_agent_dict(binding.l3_agent)
|
||||||
|
results.append(l3_agent_dict)
|
||||||
|
if results:
|
||||||
|
return {'agents': results}
|
||||||
|
else:
|
||||||
|
return {'agents': []}
|
||||||
|
|
||||||
|
def get_l3_agents(self, context, active=None, filters=None):
|
||||||
|
query = context.session.query(agents_db.Agent)
|
||||||
|
query = query.filter(
|
||||||
|
agents_db.Agent.agent_type == constants.AGENT_TYPE_L3)
|
||||||
|
if active is not None:
|
||||||
|
query = (query.filter(agents_db.Agent.admin_state_up == active))
|
||||||
|
if filters:
|
||||||
|
for key, value in filters.iteritems():
|
||||||
|
column = getattr(agents_db.Agent, key, None)
|
||||||
|
if column:
|
||||||
|
query = query.filter(column.in_(value))
|
||||||
|
|
||||||
|
return [l3_agent
|
||||||
|
for l3_agent in query
|
||||||
|
if AgentSchedulerDbMixin.is_eligible_agent(active, l3_agent)]
|
||||||
|
|
||||||
|
def get_l3_agent_candidates(self, sync_router, l3_agents):
|
||||||
|
"""Get the valid l3 agents for the router from a list of l3_agents."""
|
||||||
|
candidates = []
|
||||||
|
for l3_agent in l3_agents:
|
||||||
|
if not l3_agent.admin_state_up:
|
||||||
|
continue
|
||||||
|
agent_conf = self.get_configuration_dict(l3_agent)
|
||||||
|
router_id = agent_conf.get('router_id', None)
|
||||||
|
use_namespaces = agent_conf.get('use_namespaces', True)
|
||||||
|
handle_internal_only_routers = agent_conf.get(
|
||||||
|
'handle_internal_only_routers', True)
|
||||||
|
gateway_external_network_id = agent_conf.get(
|
||||||
|
'gateway_external_network_id', None)
|
||||||
|
if not use_namespaces and router_id != sync_router['id']:
|
||||||
|
continue
|
||||||
|
ex_net_id = (sync_router['external_gateway_info'] or {}).get(
|
||||||
|
'network_id')
|
||||||
|
if ((not ex_net_id and not handle_internal_only_routers) or
|
||||||
|
(ex_net_id and gateway_external_network_id and
|
||||||
|
ex_net_id != gateway_external_network_id)):
|
||||||
|
continue
|
||||||
|
candidates.append(l3_agent)
|
||||||
|
return candidates
|
||||||
|
|
||||||
|
def auto_schedule_routers(self, context, host, router_ids):
|
||||||
|
if self.router_scheduler:
|
||||||
|
return self.router_scheduler.auto_schedule_routers(
|
||||||
|
self, context, host, router_ids)
|
||||||
|
|
||||||
|
def schedule_router(self, context, router):
|
||||||
|
if self.router_scheduler:
|
||||||
|
return self.router_scheduler.schedule(
|
||||||
|
self, context, router)
|
||||||
|
|
||||||
|
def schedule_routers(self, context, routers):
|
||||||
|
"""Schedule the routers to l3 agents."""
|
||||||
|
for router in routers:
|
||||||
|
self.schedule_router(context, router)
|
@ -21,16 +21,15 @@ import netaddr
|
|||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from sqlalchemy import orm
|
from sqlalchemy import orm
|
||||||
from sqlalchemy.orm import exc
|
from sqlalchemy.orm import exc
|
||||||
from sqlalchemy.sql import expression as expr
|
|
||||||
|
|
||||||
from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
|
from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
|
||||||
from neutron.api.v2 import attributes
|
from neutron.api.v2 import attributes
|
||||||
from neutron.common import constants as l3_constants
|
from neutron.common import constants as l3_constants
|
||||||
from neutron.common import exceptions as q_exc
|
from neutron.common import exceptions as q_exc
|
||||||
from neutron.db import db_base_plugin_v2
|
|
||||||
from neutron.db import model_base
|
from neutron.db import model_base
|
||||||
from neutron.db import models_v2
|
from neutron.db import models_v2
|
||||||
from neutron.extensions import l3
|
from neutron.extensions import l3
|
||||||
|
from neutron import manager
|
||||||
from neutron.openstack.common import log as logging
|
from neutron.openstack.common import log as logging
|
||||||
from neutron.openstack.common.notifier import api as notifier_api
|
from neutron.openstack.common.notifier import api as notifier_api
|
||||||
from neutron.openstack.common import uuidutils
|
from neutron.openstack.common import uuidutils
|
||||||
@ -59,19 +58,6 @@ class Router(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
|
|||||||
gw_port = orm.relationship(models_v2.Port)
|
gw_port = orm.relationship(models_v2.Port)
|
||||||
|
|
||||||
|
|
||||||
class ExternalNetwork(model_base.BASEV2):
|
|
||||||
network_id = sa.Column(sa.String(36),
|
|
||||||
sa.ForeignKey('networks.id', ondelete="CASCADE"),
|
|
||||||
primary_key=True)
|
|
||||||
|
|
||||||
# Add a relationship to the Network model in order to instruct
|
|
||||||
# SQLAlchemy to eagerly load this association
|
|
||||||
network = orm.relationship(
|
|
||||||
models_v2.Network,
|
|
||||||
backref=orm.backref("external", lazy='joined',
|
|
||||||
uselist=False, cascade='delete'))
|
|
||||||
|
|
||||||
|
|
||||||
class FloatingIP(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
|
class FloatingIP(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
|
||||||
"""Represents a floating IP address.
|
"""Represents a floating IP address.
|
||||||
|
|
||||||
@ -93,38 +79,9 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
|
|
||||||
l3_rpc_notifier = l3_rpc_agent_api.L3AgentNotify
|
l3_rpc_notifier = l3_rpc_agent_api.L3AgentNotify
|
||||||
|
|
||||||
def _network_model_hook(self, context, original_model, query):
|
@property
|
||||||
query = query.outerjoin(ExternalNetwork,
|
def _core_plugin(self):
|
||||||
(original_model.id ==
|
return manager.NeutronManager.get_plugin()
|
||||||
ExternalNetwork.network_id))
|
|
||||||
return query
|
|
||||||
|
|
||||||
def _network_filter_hook(self, context, original_model, conditions):
|
|
||||||
if conditions is not None and not hasattr(conditions, '__iter__'):
|
|
||||||
conditions = (conditions, )
|
|
||||||
# Apply the external network filter only in non-admin context
|
|
||||||
if not context.is_admin and hasattr(original_model, 'tenant_id'):
|
|
||||||
conditions = expr.or_(ExternalNetwork.network_id != expr.null(),
|
|
||||||
*conditions)
|
|
||||||
return conditions
|
|
||||||
|
|
||||||
def _network_result_filter_hook(self, query, filters):
|
|
||||||
vals = filters and filters.get('router:external', [])
|
|
||||||
if not vals:
|
|
||||||
return query
|
|
||||||
if vals[0]:
|
|
||||||
return query.filter((ExternalNetwork.network_id != expr.null()))
|
|
||||||
return query.filter((ExternalNetwork.network_id == expr.null()))
|
|
||||||
|
|
||||||
# TODO(salvatore-orlando): Perform this operation without explicitly
|
|
||||||
# referring to db_base_plugin_v2, as plugins that do not extend from it
|
|
||||||
# might exist in the future
|
|
||||||
db_base_plugin_v2.NeutronDbPluginV2.register_model_query_hook(
|
|
||||||
models_v2.Network,
|
|
||||||
"external_net",
|
|
||||||
'_network_model_hook',
|
|
||||||
'_network_filter_hook',
|
|
||||||
'_network_result_filter_hook')
|
|
||||||
|
|
||||||
def _get_router(self, context, id):
|
def _get_router(self, context, id):
|
||||||
try:
|
try:
|
||||||
@ -194,7 +151,7 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
|
|
||||||
def _create_router_gw_port(self, context, router, network_id):
|
def _create_router_gw_port(self, context, router, network_id):
|
||||||
# Port has no 'tenant-id', as it is hidden from user
|
# Port has no 'tenant-id', as it is hidden from user
|
||||||
gw_port = self.create_port(context.elevated(), {
|
gw_port = self._core_plugin.create_port(context.elevated(), {
|
||||||
'port': {'tenant_id': '', # intentionally not set
|
'port': {'tenant_id': '', # intentionally not set
|
||||||
'network_id': network_id,
|
'network_id': network_id,
|
||||||
'mac_address': attributes.ATTR_NOT_SPECIFIED,
|
'mac_address': attributes.ATTR_NOT_SPECIFIED,
|
||||||
@ -205,15 +162,15 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
'name': ''}})
|
'name': ''}})
|
||||||
|
|
||||||
if not gw_port['fixed_ips']:
|
if not gw_port['fixed_ips']:
|
||||||
self.delete_port(context.elevated(), gw_port['id'],
|
self._core_plugin.delete_port(context.elevated(), gw_port['id'],
|
||||||
l3_port_check=False)
|
l3_port_check=False)
|
||||||
msg = (_('No IPs available for external network %s') %
|
msg = (_('No IPs available for external network %s') %
|
||||||
network_id)
|
network_id)
|
||||||
raise q_exc.BadRequest(resource='router', msg=msg)
|
raise q_exc.BadRequest(resource='router', msg=msg)
|
||||||
|
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
router.gw_port = self._get_port(context.elevated(),
|
router.gw_port = self._core_plugin._get_port(context.elevated(),
|
||||||
gw_port['id'])
|
gw_port['id'])
|
||||||
context.session.add(router)
|
context.session.add(router)
|
||||||
|
|
||||||
def _update_router_gw_info(self, context, router_id, info, router=None):
|
def _update_router_gw_info(self, context, router_id, info, router=None):
|
||||||
@ -225,7 +182,7 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
# network_id attribute is required by API, so it must be present
|
# network_id attribute is required by API, so it must be present
|
||||||
network_id = info['network_id'] if info else None
|
network_id = info['network_id'] if info else None
|
||||||
if network_id:
|
if network_id:
|
||||||
network_db = self._get_network(context, network_id)
|
network_db = self._core_plugin._get_network(context, network_id)
|
||||||
if not network_db.external:
|
if not network_db.external:
|
||||||
msg = _("Network %s is not a valid external "
|
msg = _("Network %s is not a valid external "
|
||||||
"network") % network_id
|
"network") % network_id
|
||||||
@ -242,13 +199,14 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
router.gw_port = None
|
router.gw_port = None
|
||||||
context.session.add(router)
|
context.session.add(router)
|
||||||
self.delete_port(context.elevated(), gw_port['id'],
|
self._core_plugin.delete_port(context.elevated(),
|
||||||
l3_port_check=False)
|
gw_port['id'],
|
||||||
|
l3_port_check=False)
|
||||||
|
|
||||||
if network_id is not None and (gw_port is None or
|
if network_id is not None and (gw_port is None or
|
||||||
gw_port['network_id'] != network_id):
|
gw_port['network_id'] != network_id):
|
||||||
subnets = self._get_subnets_by_network(context,
|
subnets = self._core_plugin._get_subnets_by_network(context,
|
||||||
network_id)
|
network_id)
|
||||||
for subnet in subnets:
|
for subnet in subnets:
|
||||||
self._check_for_dup_router_subnet(context, router_id,
|
self._check_for_dup_router_subnet(context, router_id,
|
||||||
network_id, subnet['id'],
|
network_id, subnet['id'],
|
||||||
@ -267,17 +225,19 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
|
|
||||||
device_filter = {'device_id': [id],
|
device_filter = {'device_id': [id],
|
||||||
'device_owner': [DEVICE_OWNER_ROUTER_INTF]}
|
'device_owner': [DEVICE_OWNER_ROUTER_INTF]}
|
||||||
ports = self.get_ports_count(context.elevated(),
|
ports = self._core_plugin.get_ports_count(context.elevated(),
|
||||||
filters=device_filter)
|
filters=device_filter)
|
||||||
if ports:
|
if ports:
|
||||||
raise l3.RouterInUse(router_id=id)
|
raise l3.RouterInUse(router_id=id)
|
||||||
|
|
||||||
# delete any gw port
|
# delete any gw port
|
||||||
device_filter = {'device_id': [id],
|
device_filter = {'device_id': [id],
|
||||||
'device_owner': [DEVICE_OWNER_ROUTER_GW]}
|
'device_owner': [DEVICE_OWNER_ROUTER_GW]}
|
||||||
ports = self.get_ports(context.elevated(), filters=device_filter)
|
ports = self._core_plugin.get_ports(context.elevated(),
|
||||||
|
filters=device_filter)
|
||||||
if ports:
|
if ports:
|
||||||
self._delete_port(context.elevated(), ports[0]['id'])
|
self._core_plugin._delete_port(context.elevated(),
|
||||||
|
ports[0]['id'])
|
||||||
|
|
||||||
context.session.delete(router)
|
context.session.delete(router)
|
||||||
self.l3_rpc_notifier.router_deleted(context, id)
|
self.l3_rpc_notifier.router_deleted(context, id)
|
||||||
@ -317,8 +277,8 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
% subnet_id)
|
% subnet_id)
|
||||||
raise q_exc.BadRequest(resource='router', msg=msg)
|
raise q_exc.BadRequest(resource='router', msg=msg)
|
||||||
sub_id = ip['subnet_id']
|
sub_id = ip['subnet_id']
|
||||||
cidr = self._get_subnet(context.elevated(),
|
cidr = self._core_plugin._get_subnet(context.elevated(),
|
||||||
sub_id)['cidr']
|
sub_id)['cidr']
|
||||||
ipnet = netaddr.IPNetwork(cidr)
|
ipnet = netaddr.IPNetwork(cidr)
|
||||||
match1 = netaddr.all_matching_cidrs(new_ipnet, [cidr])
|
match1 = netaddr.all_matching_cidrs(new_ipnet, [cidr])
|
||||||
match2 = netaddr.all_matching_cidrs(ipnet, [subnet_cidr])
|
match2 = netaddr.all_matching_cidrs(ipnet, [subnet_cidr])
|
||||||
@ -346,7 +306,8 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
msg = _("Cannot specify both subnet-id and port-id")
|
msg = _("Cannot specify both subnet-id and port-id")
|
||||||
raise q_exc.BadRequest(resource='router', msg=msg)
|
raise q_exc.BadRequest(resource='router', msg=msg)
|
||||||
|
|
||||||
port = self._get_port(context, interface_info['port_id'])
|
port = self._core_plugin._get_port(context,
|
||||||
|
interface_info['port_id'])
|
||||||
if port['device_id']:
|
if port['device_id']:
|
||||||
raise q_exc.PortInUse(net_id=port['network_id'],
|
raise q_exc.PortInUse(net_id=port['network_id'],
|
||||||
port_id=port['id'],
|
port_id=port['id'],
|
||||||
@ -356,7 +317,7 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
msg = _('Router port must have exactly one fixed IP')
|
msg = _('Router port must have exactly one fixed IP')
|
||||||
raise q_exc.BadRequest(resource='router', msg=msg)
|
raise q_exc.BadRequest(resource='router', msg=msg)
|
||||||
subnet_id = fixed_ips[0]['subnet_id']
|
subnet_id = fixed_ips[0]['subnet_id']
|
||||||
subnet = self._get_subnet(context, subnet_id)
|
subnet = self._core_plugin._get_subnet(context, subnet_id)
|
||||||
self._check_for_dup_router_subnet(context, router_id,
|
self._check_for_dup_router_subnet(context, router_id,
|
||||||
port['network_id'],
|
port['network_id'],
|
||||||
subnet['id'],
|
subnet['id'],
|
||||||
@ -365,7 +326,7 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
'device_owner': DEVICE_OWNER_ROUTER_INTF})
|
'device_owner': DEVICE_OWNER_ROUTER_INTF})
|
||||||
elif 'subnet_id' in interface_info:
|
elif 'subnet_id' in interface_info:
|
||||||
subnet_id = interface_info['subnet_id']
|
subnet_id = interface_info['subnet_id']
|
||||||
subnet = self._get_subnet(context, subnet_id)
|
subnet = self._core_plugin._get_subnet(context, subnet_id)
|
||||||
# Ensure the subnet has a gateway
|
# Ensure the subnet has a gateway
|
||||||
if not subnet['gateway_ip']:
|
if not subnet['gateway_ip']:
|
||||||
msg = _('Subnet for router interface must have a gateway IP')
|
msg = _('Subnet for router interface must have a gateway IP')
|
||||||
@ -376,7 +337,7 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
subnet['cidr'])
|
subnet['cidr'])
|
||||||
fixed_ip = {'ip_address': subnet['gateway_ip'],
|
fixed_ip = {'ip_address': subnet['gateway_ip'],
|
||||||
'subnet_id': subnet['id']}
|
'subnet_id': subnet['id']}
|
||||||
port = self.create_port(context, {
|
port = self._core_plugin.create_port(context, {
|
||||||
'port':
|
'port':
|
||||||
{'tenant_id': subnet['tenant_id'],
|
{'tenant_id': subnet['tenant_id'],
|
||||||
'network_id': subnet['network_id'],
|
'network_id': subnet['network_id'],
|
||||||
@ -402,7 +363,7 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
|
|
||||||
def _confirm_router_interface_not_in_use(self, context, router_id,
|
def _confirm_router_interface_not_in_use(self, context, router_id,
|
||||||
subnet_id):
|
subnet_id):
|
||||||
subnet_db = self._get_subnet(context, subnet_id)
|
subnet_db = self._core_plugin._get_subnet(context, subnet_id)
|
||||||
subnet_cidr = netaddr.IPNetwork(subnet_db['cidr'])
|
subnet_cidr = netaddr.IPNetwork(subnet_db['cidr'])
|
||||||
fip_qry = context.session.query(FloatingIP)
|
fip_qry = context.session.query(FloatingIP)
|
||||||
for fip_db in fip_qry.filter_by(router_id=router_id):
|
for fip_db in fip_qry.filter_by(router_id=router_id):
|
||||||
@ -416,7 +377,7 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
raise q_exc.BadRequest(resource='router', msg=msg)
|
raise q_exc.BadRequest(resource='router', msg=msg)
|
||||||
if 'port_id' in interface_info:
|
if 'port_id' in interface_info:
|
||||||
port_id = interface_info['port_id']
|
port_id = interface_info['port_id']
|
||||||
port_db = self._get_port(context, port_id)
|
port_db = self._core_plugin._get_port(context, port_id)
|
||||||
if not (port_db['device_owner'] == DEVICE_OWNER_ROUTER_INTF and
|
if not (port_db['device_owner'] == DEVICE_OWNER_ROUTER_INTF and
|
||||||
port_db['device_id'] == router_id):
|
port_db['device_id'] == router_id):
|
||||||
raise l3.RouterInterfaceNotFound(router_id=router_id,
|
raise l3.RouterInterfaceNotFound(router_id=router_id,
|
||||||
@ -428,16 +389,17 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
port_id=port_id,
|
port_id=port_id,
|
||||||
subnet_id=interface_info['subnet_id'])
|
subnet_id=interface_info['subnet_id'])
|
||||||
subnet_id = port_db['fixed_ips'][0]['subnet_id']
|
subnet_id = port_db['fixed_ips'][0]['subnet_id']
|
||||||
subnet = self._get_subnet(context, subnet_id)
|
subnet = self._core_plugin._get_subnet(context, subnet_id)
|
||||||
self._confirm_router_interface_not_in_use(
|
self._confirm_router_interface_not_in_use(
|
||||||
context, router_id, subnet_id)
|
context, router_id, subnet_id)
|
||||||
self.delete_port(context, port_db['id'], l3_port_check=False)
|
self._core_plugin.delete_port(context, port_db['id'],
|
||||||
|
l3_port_check=False)
|
||||||
elif 'subnet_id' in interface_info:
|
elif 'subnet_id' in interface_info:
|
||||||
subnet_id = interface_info['subnet_id']
|
subnet_id = interface_info['subnet_id']
|
||||||
self._confirm_router_interface_not_in_use(context, router_id,
|
self._confirm_router_interface_not_in_use(context, router_id,
|
||||||
subnet_id)
|
subnet_id)
|
||||||
|
|
||||||
subnet = self._get_subnet(context, subnet_id)
|
subnet = self._core_plugin._get_subnet(context, subnet_id)
|
||||||
found = False
|
found = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -450,7 +412,8 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
for p in ports:
|
for p in ports:
|
||||||
if p['fixed_ips'][0]['subnet_id'] == subnet_id:
|
if p['fixed_ips'][0]['subnet_id'] == subnet_id:
|
||||||
port_id = p['id']
|
port_id = p['id']
|
||||||
self.delete_port(context, p['id'], l3_port_check=False)
|
self._core_plugin.delete_port(context, p['id'],
|
||||||
|
l3_port_check=False)
|
||||||
found = True
|
found = True
|
||||||
break
|
break
|
||||||
except exc.NoResultFound:
|
except exc.NoResultFound:
|
||||||
@ -492,7 +455,8 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
def _get_router_for_floatingip(self, context, internal_port,
|
def _get_router_for_floatingip(self, context, internal_port,
|
||||||
internal_subnet_id,
|
internal_subnet_id,
|
||||||
external_network_id):
|
external_network_id):
|
||||||
subnet_db = self._get_subnet(context, internal_subnet_id)
|
subnet_db = self._core_plugin._get_subnet(context,
|
||||||
|
internal_subnet_id)
|
||||||
if not subnet_db['gateway_ip']:
|
if not subnet_db['gateway_ip']:
|
||||||
msg = (_('Cannot add floating IP to port on subnet %s '
|
msg = (_('Cannot add floating IP to port on subnet %s '
|
||||||
'which has no gateway_ip') % internal_subnet_id)
|
'which has no gateway_ip') % internal_subnet_id)
|
||||||
@ -526,7 +490,7 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
Retrieve information concerning the internal port where
|
Retrieve information concerning the internal port where
|
||||||
the floating IP should be associated to.
|
the floating IP should be associated to.
|
||||||
"""
|
"""
|
||||||
internal_port = self._get_port(context, fip['port_id'])
|
internal_port = self._core_plugin._get_port(context, fip['port_id'])
|
||||||
if not internal_port['tenant_id'] == fip['tenant_id']:
|
if not internal_port['tenant_id'] == fip['tenant_id']:
|
||||||
port_id = fip['port_id']
|
port_id = fip['port_id']
|
||||||
if 'id' in fip:
|
if 'id' in fip:
|
||||||
@ -633,7 +597,7 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
fip_id = uuidutils.generate_uuid()
|
fip_id = uuidutils.generate_uuid()
|
||||||
|
|
||||||
f_net_id = fip['floating_network_id']
|
f_net_id = fip['floating_network_id']
|
||||||
if not self._network_is_external(context, f_net_id):
|
if not self._core_plugin._network_is_external(context, f_net_id):
|
||||||
msg = _("Network %s is not a valid external network") % f_net_id
|
msg = _("Network %s is not a valid external network") % f_net_id
|
||||||
raise q_exc.BadRequest(resource='floatingip', msg=msg)
|
raise q_exc.BadRequest(resource='floatingip', msg=msg)
|
||||||
|
|
||||||
@ -641,7 +605,7 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
# This external port is never exposed to the tenant.
|
# This external port is never exposed to the tenant.
|
||||||
# it is used purely for internal system and admin use when
|
# it is used purely for internal system and admin use when
|
||||||
# managing floating IPs.
|
# managing floating IPs.
|
||||||
external_port = self.create_port(context.elevated(), {
|
external_port = self._core_plugin.create_port(context.elevated(), {
|
||||||
'port':
|
'port':
|
||||||
{'tenant_id': '', # tenant intentionally not set
|
{'tenant_id': '', # tenant intentionally not set
|
||||||
'network_id': f_net_id,
|
'network_id': f_net_id,
|
||||||
@ -686,8 +650,8 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
fip_port_id = floatingip_db['floating_port_id']
|
fip_port_id = floatingip_db['floating_port_id']
|
||||||
before_router_id = floatingip_db['router_id']
|
before_router_id = floatingip_db['router_id']
|
||||||
self._update_fip_assoc(context, fip, floatingip_db,
|
self._update_fip_assoc(context, fip, floatingip_db,
|
||||||
self.get_port(context.elevated(),
|
self._core_plugin.get_port(
|
||||||
fip_port_id))
|
context.elevated(), fip_port_id))
|
||||||
router_ids = []
|
router_ids = []
|
||||||
if before_router_id:
|
if before_router_id:
|
||||||
router_ids.append(before_router_id)
|
router_ids.append(before_router_id)
|
||||||
@ -704,9 +668,9 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
router_id = floatingip['router_id']
|
router_id = floatingip['router_id']
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
context.session.delete(floatingip)
|
context.session.delete(floatingip)
|
||||||
self.delete_port(context.elevated(),
|
self._core_plugin.delete_port(context.elevated(),
|
||||||
floatingip['floating_port_id'],
|
floatingip['floating_port_id'],
|
||||||
l3_port_check=False)
|
l3_port_check=False)
|
||||||
if router_id:
|
if router_id:
|
||||||
self.l3_rpc_notifier.routers_updated(
|
self.l3_rpc_notifier.routers_updated(
|
||||||
context, [router_id],
|
context, [router_id],
|
||||||
@ -747,7 +711,7 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
to /ports, but rather via other API calls that perform the proper
|
to /ports, but rather via other API calls that perform the proper
|
||||||
deletion checks.
|
deletion checks.
|
||||||
"""
|
"""
|
||||||
port_db = self._get_port(context, port_id)
|
port_db = self._core_plugin._get_port(context, port_id)
|
||||||
if port_db['device_owner'] in [DEVICE_OWNER_ROUTER_INTF,
|
if port_db['device_owner'] in [DEVICE_OWNER_ROUTER_INTF,
|
||||||
DEVICE_OWNER_ROUTER_GW,
|
DEVICE_OWNER_ROUTER_GW,
|
||||||
DEVICE_OWNER_FLOATINGIP]:
|
DEVICE_OWNER_FLOATINGIP]:
|
||||||
@ -782,74 +746,6 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
self.l3_rpc_notifier.routers_updated(
|
self.l3_rpc_notifier.routers_updated(
|
||||||
context, [router_id])
|
context, [router_id])
|
||||||
|
|
||||||
def _network_is_external(self, context, net_id):
|
|
||||||
try:
|
|
||||||
context.session.query(ExternalNetwork).filter_by(
|
|
||||||
network_id=net_id).one()
|
|
||||||
return True
|
|
||||||
except exc.NoResultFound:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _extend_network_dict_l3(self, network_res, network_db):
|
|
||||||
# Comparing with None for converting uuid into bool
|
|
||||||
network_res[l3.EXTERNAL] = network_db.external is not None
|
|
||||||
return network_res
|
|
||||||
|
|
||||||
# Register dict extend functions for networks
|
|
||||||
db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
|
|
||||||
attributes.NETWORKS, ['_extend_network_dict_l3'])
|
|
||||||
|
|
||||||
def _process_l3_create(self, context, net_data, req_data):
|
|
||||||
external = req_data.get(l3.EXTERNAL)
|
|
||||||
external_set = attributes.is_attr_set(external)
|
|
||||||
|
|
||||||
if not external_set:
|
|
||||||
return
|
|
||||||
|
|
||||||
if external:
|
|
||||||
# expects to be called within a plugin's session
|
|
||||||
context.session.add(ExternalNetwork(network_id=net_data['id']))
|
|
||||||
net_data[l3.EXTERNAL] = external
|
|
||||||
|
|
||||||
def _process_l3_update(self, context, net_data, req_data):
|
|
||||||
|
|
||||||
new_value = req_data.get(l3.EXTERNAL)
|
|
||||||
net_id = net_data['id']
|
|
||||||
if not attributes.is_attr_set(new_value):
|
|
||||||
return
|
|
||||||
|
|
||||||
if net_data.get(l3.EXTERNAL) == new_value:
|
|
||||||
return
|
|
||||||
|
|
||||||
if new_value:
|
|
||||||
context.session.add(ExternalNetwork(network_id=net_id))
|
|
||||||
net_data[l3.EXTERNAL] = True
|
|
||||||
else:
|
|
||||||
# must make sure we do not have any external gateway ports
|
|
||||||
# (and thus, possible floating IPs) on this network before
|
|
||||||
# allow it to be update to external=False
|
|
||||||
port = context.session.query(models_v2.Port).filter_by(
|
|
||||||
device_owner=DEVICE_OWNER_ROUTER_GW,
|
|
||||||
network_id=net_data['id']).first()
|
|
||||||
if port:
|
|
||||||
raise l3.ExternalNetworkInUse(net_id=net_id)
|
|
||||||
|
|
||||||
context.session.query(ExternalNetwork).filter_by(
|
|
||||||
network_id=net_id).delete()
|
|
||||||
net_data[l3.EXTERNAL] = False
|
|
||||||
|
|
||||||
def _filter_nets_l3(self, context, nets, filters):
|
|
||||||
vals = filters and filters.get('router:external', [])
|
|
||||||
if not vals:
|
|
||||||
return nets
|
|
||||||
|
|
||||||
ext_nets = set(en['network_id']
|
|
||||||
for en in context.session.query(ExternalNetwork))
|
|
||||||
if vals[0]:
|
|
||||||
return [n for n in nets if n['id'] in ext_nets]
|
|
||||||
else:
|
|
||||||
return [n for n in nets if n['id'] not in ext_nets]
|
|
||||||
|
|
||||||
def _build_routers_list(self, routers, gw_ports):
|
def _build_routers_list(self, routers, gw_ports):
|
||||||
gw_port_id_gw_port_dict = dict((gw_port['id'], gw_port)
|
gw_port_id_gw_port_dict = dict((gw_port['id'], gw_port)
|
||||||
for gw_port in gw_ports)
|
for gw_port in gw_ports)
|
||||||
@ -898,7 +794,7 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
if not gw_port_ids:
|
if not gw_port_ids:
|
||||||
return []
|
return []
|
||||||
filters = {'id': gw_port_ids}
|
filters = {'id': gw_port_ids}
|
||||||
gw_ports = self.get_ports(context, filters)
|
gw_ports = self._core_plugin.get_ports(context, filters)
|
||||||
if gw_ports:
|
if gw_ports:
|
||||||
self._populate_subnet_for_ports(context, gw_ports)
|
self._populate_subnet_for_ports(context, gw_ports)
|
||||||
return gw_ports
|
return gw_ports
|
||||||
@ -910,7 +806,7 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
return []
|
return []
|
||||||
filters = {'device_id': router_ids,
|
filters = {'device_id': router_ids,
|
||||||
'device_owner': [device_owner]}
|
'device_owner': [device_owner]}
|
||||||
interfaces = self.get_ports(context, filters)
|
interfaces = self._core_plugin.get_ports(context, filters)
|
||||||
if interfaces:
|
if interfaces:
|
||||||
self._populate_subnet_for_ports(context, interfaces)
|
self._populate_subnet_for_ports(context, interfaces)
|
||||||
return interfaces
|
return interfaces
|
||||||
@ -943,7 +839,7 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
return
|
return
|
||||||
filters = {'id': subnet_id_ports_dict.keys()}
|
filters = {'id': subnet_id_ports_dict.keys()}
|
||||||
fields = ['id', 'cidr', 'gateway_ip']
|
fields = ['id', 'cidr', 'gateway_ip']
|
||||||
subnet_dicts = self.get_subnets(context, filters, fields)
|
subnet_dicts = self._core_plugin.get_subnets(context, filters, fields)
|
||||||
for subnet_dict in subnet_dicts:
|
for subnet_dict in subnet_dicts:
|
||||||
ports = subnet_id_ports_dict.get(subnet_dict['id'], [])
|
ports = subnet_id_ports_dict.get(subnet_dict['id'], [])
|
||||||
for port in ports:
|
for port in ports:
|
||||||
@ -982,10 +878,3 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
floating_ips = self._get_sync_floating_ips(context, router_ids)
|
floating_ips = self._get_sync_floating_ips(context, router_ids)
|
||||||
interfaces = self.get_sync_interfaces(context, router_ids)
|
interfaces = self.get_sync_interfaces(context, router_ids)
|
||||||
return self._process_sync_data(routers, interfaces, floating_ips)
|
return self._process_sync_data(routers, interfaces, floating_ips)
|
||||||
|
|
||||||
def get_external_network_id(self, context):
|
|
||||||
nets = self.get_networks(context, {'router:external': [True]})
|
|
||||||
if len(nets) > 1:
|
|
||||||
raise q_exc.TooManyExternalNetworks()
|
|
||||||
else:
|
|
||||||
return nets[0]['id'] if nets else None
|
|
||||||
|
@ -22,6 +22,7 @@ from neutron.extensions import portbindings
|
|||||||
from neutron import manager
|
from neutron import manager
|
||||||
from neutron.openstack.common import jsonutils
|
from neutron.openstack.common import jsonutils
|
||||||
from neutron.openstack.common import log as logging
|
from neutron.openstack.common import log as logging
|
||||||
|
from neutron.plugins.common import constants as plugin_constants
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -41,15 +42,21 @@ class L3RpcCallbackMixin(object):
|
|||||||
router_ids = kwargs.get('router_ids')
|
router_ids = kwargs.get('router_ids')
|
||||||
host = kwargs.get('host')
|
host = kwargs.get('host')
|
||||||
context = neutron_context.get_admin_context()
|
context = neutron_context.get_admin_context()
|
||||||
plugin = manager.NeutronManager.get_plugin()
|
l3plugin = manager.NeutronManager.get_service_plugins()[
|
||||||
if utils.is_extension_supported(
|
plugin_constants.L3_ROUTER_NAT]
|
||||||
plugin, constants.L3_AGENT_SCHEDULER_EXT_ALIAS):
|
if not l3plugin:
|
||||||
|
routers = {}
|
||||||
|
LOG.error(_('No plugin for L3 routing registered! Will reply '
|
||||||
|
'to l3 agent with empty router dictionary.'))
|
||||||
|
elif utils.is_extension_supported(
|
||||||
|
l3plugin, constants.L3_AGENT_SCHEDULER_EXT_ALIAS):
|
||||||
if cfg.CONF.router_auto_schedule:
|
if cfg.CONF.router_auto_schedule:
|
||||||
plugin.auto_schedule_routers(context, host, router_ids)
|
l3plugin.auto_schedule_routers(context, host, router_ids)
|
||||||
routers = plugin.list_active_sync_routers_on_active_l3_agent(
|
routers = l3plugin.list_active_sync_routers_on_active_l3_agent(
|
||||||
context, host, router_ids)
|
context, host, router_ids)
|
||||||
else:
|
else:
|
||||||
routers = plugin.get_sync_data(context, router_ids)
|
routers = l3plugin.get_sync_data(context, router_ids)
|
||||||
|
plugin = manager.NeutronManager.get_plugin()
|
||||||
if utils.is_extension_supported(
|
if utils.is_extension_supported(
|
||||||
plugin, constants.PORT_BINDING_EXT_ALIAS):
|
plugin, constants.PORT_BINDING_EXT_ALIAS):
|
||||||
self._ensure_host_set_on_ports(context, plugin, host, routers)
|
self._ensure_host_set_on_ports(context, plugin, host, routers)
|
||||||
|
@ -23,9 +23,9 @@ from sqlalchemy import orm
|
|||||||
from sqlalchemy.orm import exc
|
from sqlalchemy.orm import exc
|
||||||
|
|
||||||
from neutron.common import constants as n_constants
|
from neutron.common import constants as n_constants
|
||||||
from neutron.db import agentschedulers_db as agent_db
|
|
||||||
from neutron.db import api as qdbapi
|
from neutron.db import api as qdbapi
|
||||||
from neutron.db import db_base_plugin_v2 as base_db
|
from neutron.db import db_base_plugin_v2 as base_db
|
||||||
|
from neutron.db import l3_agentschedulers_db as l3_agent_db
|
||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
from neutron.db import model_base
|
from neutron.db import model_base
|
||||||
from neutron.db import models_v2
|
from neutron.db import models_v2
|
||||||
@ -597,11 +597,11 @@ class VPNPluginRpcDbMixin():
|
|||||||
query = query.join(IKEPolicy)
|
query = query.join(IKEPolicy)
|
||||||
query = query.join(IPsecPolicy)
|
query = query.join(IPsecPolicy)
|
||||||
query = query.join(IPsecPeerCidr)
|
query = query.join(IPsecPeerCidr)
|
||||||
query = query.join(agent_db.RouterL3AgentBinding,
|
query = query.join(l3_agent_db.RouterL3AgentBinding,
|
||||||
agent_db.RouterL3AgentBinding.router_id ==
|
l3_agent_db.RouterL3AgentBinding.router_id ==
|
||||||
VPNService.router_id)
|
VPNService.router_id)
|
||||||
query = query.filter(
|
query = query.filter(
|
||||||
agent_db.RouterL3AgentBinding.l3_agent_id == agent.id)
|
l3_agent_db.RouterL3AgentBinding.l3_agent_id == agent.id)
|
||||||
return query
|
return query
|
||||||
|
|
||||||
def update_status_by_agent(self, context, service_status_info_list):
|
def update_status_by_agent(self, context, service_status_info_list):
|
||||||
|
70
neutron/extensions/external_net.py
Normal file
70
neutron/extensions/external_net.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright (c) 2013 OpenStack Foundation.
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
from neutron.api import extensions
|
||||||
|
from neutron.api.v2 import attributes as attr
|
||||||
|
from neutron.common import exceptions as qexception
|
||||||
|
from neutron.extensions import l3
|
||||||
|
|
||||||
|
|
||||||
|
class ExternalNetworkInUse(qexception.InUse):
|
||||||
|
message = _("External network %(net_id)s cannot be updated to be made "
|
||||||
|
"non-external, since it has existing gateway ports")
|
||||||
|
|
||||||
|
|
||||||
|
# For backward compatibility the 'router' prefix is kept.
|
||||||
|
EXTERNAL = 'router:external'
|
||||||
|
EXTENDED_ATTRIBUTES_2_0 = {
|
||||||
|
'networks': {EXTERNAL: {'allow_post': True,
|
||||||
|
'allow_put': True,
|
||||||
|
'default': attr.ATTR_NOT_SPECIFIED,
|
||||||
|
'is_visible': True,
|
||||||
|
'convert_to': attr.convert_to_boolean,
|
||||||
|
'enforce_policy': True,
|
||||||
|
'required_by_policy': True}}}
|
||||||
|
|
||||||
|
|
||||||
|
class External_net(extensions.ExtensionDescriptor):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_name(cls):
|
||||||
|
return "Neutron external network"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_alias(cls):
|
||||||
|
return "external-net"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_description(cls):
|
||||||
|
return _("Adds external network attribute to network resource.")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_namespace(cls):
|
||||||
|
return "http://docs.openstack.org/ext/neutron/external_net/api/v1.0"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_updated(cls):
|
||||||
|
return "2013-01-14T10:00:00-00:00"
|
||||||
|
|
||||||
|
def get_extended_resources(self, version):
|
||||||
|
if version == "2.0":
|
||||||
|
return EXTENDED_ATTRIBUTES_2_0
|
||||||
|
else:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def get_alias_namespace_compatibility_map(self):
|
||||||
|
return {l3.L3.get_alias(): l3.L3.get_namespace()}
|
@ -27,6 +27,7 @@ from neutron.api.v2 import attributes as attr
|
|||||||
from neutron.api.v2 import base
|
from neutron.api.v2 import base
|
||||||
from neutron.common import exceptions as qexception
|
from neutron.common import exceptions as qexception
|
||||||
from neutron import manager
|
from neutron import manager
|
||||||
|
from neutron.plugins.common import constants
|
||||||
from neutron import quota
|
from neutron import quota
|
||||||
|
|
||||||
|
|
||||||
@ -77,11 +78,6 @@ class L3PortInUse(qexception.InUse):
|
|||||||
" cannot be deleted directly via the port API.")
|
" cannot be deleted directly via the port API.")
|
||||||
|
|
||||||
|
|
||||||
class ExternalNetworkInUse(qexception.InUse):
|
|
||||||
message = _("External network %(net_id)s cannot be updated to be made "
|
|
||||||
"non-external, since it has existing gateway ports")
|
|
||||||
|
|
||||||
|
|
||||||
class RouterExternalGatewayInUseByFloatingIp(qexception.InUse):
|
class RouterExternalGatewayInUseByFloatingIp(qexception.InUse):
|
||||||
message = _("Gateway cannot be updated for router %(router_id)s, since a "
|
message = _("Gateway cannot be updated for router %(router_id)s, since a "
|
||||||
"gateway to external network %(net_id)s is required by one or "
|
"gateway to external network %(net_id)s is required by one or "
|
||||||
@ -140,16 +136,6 @@ RESOURCE_ATTRIBUTE_MAP = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
EXTERNAL = 'router:external'
|
|
||||||
EXTENDED_ATTRIBUTES_2_0 = {
|
|
||||||
'networks': {EXTERNAL: {'allow_post': True,
|
|
||||||
'allow_put': True,
|
|
||||||
'default': attr.ATTR_NOT_SPECIFIED,
|
|
||||||
'is_visible': True,
|
|
||||||
'convert_to': attr.convert_to_boolean,
|
|
||||||
'enforce_policy': True,
|
|
||||||
'required_by_policy': True}}}
|
|
||||||
|
|
||||||
l3_quota_opts = [
|
l3_quota_opts = [
|
||||||
cfg.IntOpt('quota_router',
|
cfg.IntOpt('quota_router',
|
||||||
default=10,
|
default=10,
|
||||||
@ -193,7 +179,8 @@ class L3(extensions.ExtensionDescriptor):
|
|||||||
my_plurals = [(key, key[:-1]) for key in RESOURCE_ATTRIBUTE_MAP.keys()]
|
my_plurals = [(key, key[:-1]) for key in RESOURCE_ATTRIBUTE_MAP.keys()]
|
||||||
attr.PLURALS.update(dict(my_plurals))
|
attr.PLURALS.update(dict(my_plurals))
|
||||||
exts = []
|
exts = []
|
||||||
plugin = manager.NeutronManager.get_plugin()
|
plugin = manager.NeutronManager.get_service_plugins()[
|
||||||
|
constants.L3_ROUTER_NAT]
|
||||||
for resource_name in ['router', 'floatingip']:
|
for resource_name in ['router', 'floatingip']:
|
||||||
collection_name = resource_name + "s"
|
collection_name = resource_name + "s"
|
||||||
params = RESOURCE_ATTRIBUTE_MAP.get(collection_name, dict())
|
params = RESOURCE_ATTRIBUTE_MAP.get(collection_name, dict())
|
||||||
@ -225,8 +212,7 @@ class L3(extensions.ExtensionDescriptor):
|
|||||||
|
|
||||||
def get_extended_resources(self, version):
|
def get_extended_resources(self, version):
|
||||||
if version == "2.0":
|
if version == "2.0":
|
||||||
return dict(EXTENDED_ATTRIBUTES_2_0.items() +
|
return RESOURCE_ATTRIBUTE_MAP
|
||||||
RESOURCE_ATTRIBUTE_MAP.items())
|
|
||||||
else:
|
else:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
|
|
||||||
|
import webob.exc
|
||||||
|
|
||||||
from neutron.api import extensions
|
from neutron.api import extensions
|
||||||
from neutron.api.v2 import base
|
from neutron.api.v2 import base
|
||||||
from neutron.api.v2 import resource
|
from neutron.api.v2 import resource
|
||||||
@ -24,9 +26,15 @@ from neutron.common import constants
|
|||||||
from neutron.common import exceptions
|
from neutron.common import exceptions
|
||||||
from neutron.extensions import agent
|
from neutron.extensions import agent
|
||||||
from neutron import manager
|
from neutron import manager
|
||||||
|
from neutron.openstack.common import log as logging
|
||||||
|
from neutron.plugins.common import constants as service_constants
|
||||||
from neutron import policy
|
from neutron import policy
|
||||||
from neutron import wsgi
|
from neutron import wsgi
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
L3_ROUTER = 'l3-router'
|
L3_ROUTER = 'l3-router'
|
||||||
L3_ROUTERS = L3_ROUTER + 's'
|
L3_ROUTERS = L3_ROUTER + 's'
|
||||||
L3_AGENT = 'l3-agent'
|
L3_AGENT = 'l3-agent'
|
||||||
@ -34,8 +42,18 @@ L3_AGENTS = L3_AGENT + 's'
|
|||||||
|
|
||||||
|
|
||||||
class RouterSchedulerController(wsgi.Controller):
|
class RouterSchedulerController(wsgi.Controller):
|
||||||
|
def get_plugin(self):
|
||||||
|
plugin = manager.NeutronManager.get_service_plugins().get(
|
||||||
|
service_constants.L3_ROUTER_NAT)
|
||||||
|
if not plugin:
|
||||||
|
LOG.error(_('No plugin for L3 routing registered to handle '
|
||||||
|
'router scheduling'))
|
||||||
|
msg = _('The resource could not be found.')
|
||||||
|
raise webob.exc.HTTPNotFound(msg)
|
||||||
|
return plugin
|
||||||
|
|
||||||
def index(self, request, **kwargs):
|
def index(self, request, **kwargs):
|
||||||
plugin = manager.NeutronManager.get_plugin()
|
plugin = self.get_plugin()
|
||||||
policy.enforce(request.context,
|
policy.enforce(request.context,
|
||||||
"get_%s" % L3_ROUTERS,
|
"get_%s" % L3_ROUTERS,
|
||||||
{})
|
{})
|
||||||
@ -43,7 +61,7 @@ class RouterSchedulerController(wsgi.Controller):
|
|||||||
request.context, kwargs['agent_id'])
|
request.context, kwargs['agent_id'])
|
||||||
|
|
||||||
def create(self, request, body, **kwargs):
|
def create(self, request, body, **kwargs):
|
||||||
plugin = manager.NeutronManager.get_plugin()
|
plugin = self.get_plugin()
|
||||||
policy.enforce(request.context,
|
policy.enforce(request.context,
|
||||||
"create_%s" % L3_ROUTER,
|
"create_%s" % L3_ROUTER,
|
||||||
{})
|
{})
|
||||||
@ -53,7 +71,7 @@ class RouterSchedulerController(wsgi.Controller):
|
|||||||
body['router_id'])
|
body['router_id'])
|
||||||
|
|
||||||
def delete(self, request, id, **kwargs):
|
def delete(self, request, id, **kwargs):
|
||||||
plugin = manager.NeutronManager.get_plugin()
|
plugin = self.get_plugin()
|
||||||
policy.enforce(request.context,
|
policy.enforce(request.context,
|
||||||
"delete_%s" % L3_ROUTER,
|
"delete_%s" % L3_ROUTER,
|
||||||
{})
|
{})
|
||||||
@ -62,8 +80,19 @@ class RouterSchedulerController(wsgi.Controller):
|
|||||||
|
|
||||||
|
|
||||||
class L3AgentsHostingRouterController(wsgi.Controller):
|
class L3AgentsHostingRouterController(wsgi.Controller):
|
||||||
|
def get_plugin(self):
|
||||||
|
plugin = manager.NeutronManager.get_service_plugins().get(
|
||||||
|
service_constants.L3_ROUTER_NAT)
|
||||||
|
if not plugin:
|
||||||
|
LOG.error(_('No plugin for L3 routing registered to handle '
|
||||||
|
'router scheduling'))
|
||||||
|
msg = _('The resource could not be found.')
|
||||||
|
raise webob.exc.HTTPNotFound(msg)
|
||||||
|
return plugin
|
||||||
|
|
||||||
def index(self, request, **kwargs):
|
def index(self, request, **kwargs):
|
||||||
plugin = manager.NeutronManager.get_plugin()
|
plugin = manager.NeutronManager.get_service_plugins().get(
|
||||||
|
service_constants.L3_ROUTER_NAT)
|
||||||
policy.enforce(request.context,
|
policy.enforce(request.context,
|
||||||
"get_%s" % L3_AGENTS,
|
"get_%s" % L3_AGENTS,
|
||||||
{})
|
{})
|
||||||
|
@ -63,8 +63,10 @@ from neutron import context as qcontext
|
|||||||
from neutron.db import api as db
|
from neutron.db import api as db
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
from neutron.db import dhcp_rpc_base
|
from neutron.db import dhcp_rpc_base
|
||||||
|
from neutron.db import external_net_db
|
||||||
from neutron.db import extradhcpopt_db
|
from neutron.db import extradhcpopt_db
|
||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
|
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 l3
|
||||||
from neutron.extensions import portbindings
|
from neutron.extensions import portbindings
|
||||||
@ -428,11 +430,12 @@ class RpcProxy(dhcp_rpc_base.DhcpRpcCallbackMixin):
|
|||||||
|
|
||||||
|
|
||||||
class NeutronRestProxyV2(db_base_plugin_v2.NeutronDbPluginV2,
|
class NeutronRestProxyV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
|
external_net_db.External_net_db_mixin,
|
||||||
routerrule_db.RouterRule_db_mixin,
|
routerrule_db.RouterRule_db_mixin,
|
||||||
extradhcpopt_db.ExtraDhcpOptMixin):
|
extradhcpopt_db.ExtraDhcpOptMixin):
|
||||||
|
|
||||||
supported_extension_aliases = ["router", "binding", "router_rules",
|
supported_extension_aliases = ["external-net", "router", "binding",
|
||||||
"extra_dhcp_opt"]
|
"router_rules", "extra_dhcp_opt"]
|
||||||
|
|
||||||
def __init__(self, server_timeout=None):
|
def __init__(self, server_timeout=None):
|
||||||
LOG.info(_('NeutronRestProxy: Starting plugin. Version=%s'),
|
LOG.info(_('NeutronRestProxy: Starting plugin. Version=%s'),
|
||||||
@ -1192,8 +1195,8 @@ class NeutronRestProxyV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
network['gateway'] = ''
|
network['gateway'] = ''
|
||||||
network[l3.EXTERNAL] = self._network_is_external(context,
|
network[external_net.EXTERNAL] = self._network_is_external(
|
||||||
network['id'])
|
context, network['id'])
|
||||||
|
|
||||||
return network
|
return network
|
||||||
|
|
||||||
|
@ -39,7 +39,9 @@ from neutron.db import agentschedulers_db
|
|||||||
from neutron.db import api as db
|
from neutron.db import api as db
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
from neutron.db import dhcp_rpc_base
|
from neutron.db import dhcp_rpc_base
|
||||||
|
from neutron.db import external_net_db
|
||||||
from neutron.db import extraroute_db
|
from neutron.db import extraroute_db
|
||||||
|
from neutron.db import l3_agentschedulers_db
|
||||||
from neutron.db import l3_rpc_base
|
from neutron.db import l3_rpc_base
|
||||||
from neutron.db import portbindings_base
|
from neutron.db import portbindings_base
|
||||||
from neutron.db import securitygroups_rpc_base as sg_db_rpc
|
from neutron.db import securitygroups_rpc_base as sg_db_rpc
|
||||||
@ -52,6 +54,7 @@ from neutron.openstack.common import rpc
|
|||||||
from neutron.openstack.common.rpc import proxy
|
from neutron.openstack.common.rpc import proxy
|
||||||
from neutron.plugins.brocade.db import models as brocade_db
|
from neutron.plugins.brocade.db import models as brocade_db
|
||||||
from neutron.plugins.brocade import vlanbm as vbm
|
from neutron.plugins.brocade import vlanbm as vbm
|
||||||
|
from neutron.plugins.common import constants as svc_constants
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -203,9 +206,10 @@ class AgentNotifierApi(proxy.RpcProxy,
|
|||||||
|
|
||||||
|
|
||||||
class BrocadePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
class BrocadePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
|
external_net_db.External_net_db_mixin,
|
||||||
extraroute_db.ExtraRoute_db_mixin,
|
extraroute_db.ExtraRoute_db_mixin,
|
||||||
sg_db_rpc.SecurityGroupServerRpcMixin,
|
sg_db_rpc.SecurityGroupServerRpcMixin,
|
||||||
agentschedulers_db.L3AgentSchedulerDbMixin,
|
l3_agentschedulers_db.L3AgentSchedulerDbMixin,
|
||||||
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
||||||
portbindings_base.PortBindingBaseMixin):
|
portbindings_base.PortBindingBaseMixin):
|
||||||
"""BrocadePluginV2 is a Neutron plugin.
|
"""BrocadePluginV2 is a Neutron plugin.
|
||||||
@ -222,8 +226,9 @@ class BrocadePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
self.supported_extension_aliases = ["binding", "security-group",
|
self.supported_extension_aliases = ["binding", "security-group",
|
||||||
"router", "extraroute",
|
"external-net", "router",
|
||||||
"agent", "l3_agent_scheduler",
|
"extraroute", "agent",
|
||||||
|
"l3_agent_scheduler",
|
||||||
"dhcp_agent_scheduler"]
|
"dhcp_agent_scheduler"]
|
||||||
|
|
||||||
self.physical_interface = (cfg.CONF.PHYSICAL_INTERFACE.
|
self.physical_interface = (cfg.CONF.PHYSICAL_INTERFACE.
|
||||||
@ -254,14 +259,15 @@ class BrocadePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
|
|
||||||
def _setup_rpc(self):
|
def _setup_rpc(self):
|
||||||
# RPC support
|
# RPC support
|
||||||
self.topic = topics.PLUGIN
|
self.service_topics = {svc_constants.CORE: topics.PLUGIN,
|
||||||
|
svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN}
|
||||||
self.rpc_context = context.RequestContext('neutron', 'neutron',
|
self.rpc_context = context.RequestContext('neutron', 'neutron',
|
||||||
is_admin=False)
|
is_admin=False)
|
||||||
self.conn = rpc.create_connection(new=True)
|
self.conn = rpc.create_connection(new=True)
|
||||||
self.callbacks = BridgeRpcCallbacks()
|
self.callbacks = BridgeRpcCallbacks()
|
||||||
self.dispatcher = self.callbacks.create_rpc_dispatcher()
|
self.dispatcher = self.callbacks.create_rpc_dispatcher()
|
||||||
self.conn.create_consumer(self.topic, self.dispatcher,
|
for svc_topic in self.service_topics.values():
|
||||||
fanout=False)
|
self.conn.create_consumer(svc_topic, self.dispatcher, fanout=False)
|
||||||
# Consume from all consumers in a thread
|
# Consume from all consumers in a thread
|
||||||
self.conn.consume_in_thread()
|
self.conn.consume_in_thread()
|
||||||
self.notifier = AgentNotifierApi(topics.AGENT)
|
self.notifier = AgentNotifierApi(topics.AGENT)
|
||||||
|
@ -35,6 +35,7 @@ from neutron.db import agents_db
|
|||||||
from neutron.db import agentschedulers_db
|
from neutron.db import agentschedulers_db
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
from neutron.db import dhcp_rpc_base
|
from neutron.db import dhcp_rpc_base
|
||||||
|
from neutron.db import external_net_db
|
||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
from neutron.db import l3_rpc_base
|
from neutron.db import l3_rpc_base
|
||||||
from neutron.db import securitygroups_rpc_base as sg_db_rpc
|
from neutron.db import securitygroups_rpc_base as sg_db_rpc
|
||||||
@ -51,6 +52,7 @@ from neutron.plugins.cisco.db import n1kv_db_v2
|
|||||||
from neutron.plugins.cisco.db import network_db_v2
|
from neutron.plugins.cisco.db import network_db_v2
|
||||||
from neutron.plugins.cisco.extensions import n1kv_profile
|
from neutron.plugins.cisco.extensions import n1kv_profile
|
||||||
from neutron.plugins.cisco.n1kv import n1kv_client
|
from neutron.plugins.cisco.n1kv import n1kv_client
|
||||||
|
from neutron.plugins.common import constants as svc_constants
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -127,6 +129,7 @@ class AgentNotifierApi(proxy.RpcProxy,
|
|||||||
|
|
||||||
|
|
||||||
class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
|
external_net_db.External_net_db_mixin,
|
||||||
l3_db.L3_NAT_db_mixin,
|
l3_db.L3_NAT_db_mixin,
|
||||||
n1kv_db_v2.NetworkProfile_db_mixin,
|
n1kv_db_v2.NetworkProfile_db_mixin,
|
||||||
n1kv_db_v2.PolicyProfile_db_mixin,
|
n1kv_db_v2.PolicyProfile_db_mixin,
|
||||||
@ -148,7 +151,8 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
"policy_profile_binding",
|
"policy_profile_binding",
|
||||||
"network_profile_binding",
|
"network_profile_binding",
|
||||||
"n1kv_profile", "network_profile",
|
"n1kv_profile", "network_profile",
|
||||||
"policy_profile", "router", "credential"]
|
"policy_profile", "external-net", "router",
|
||||||
|
"credential"]
|
||||||
|
|
||||||
def __init__(self, configfile=None):
|
def __init__(self, configfile=None):
|
||||||
"""
|
"""
|
||||||
@ -170,13 +174,14 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
|
|
||||||
def _setup_rpc(self):
|
def _setup_rpc(self):
|
||||||
# RPC support
|
# RPC support
|
||||||
self.topic = topics.PLUGIN
|
self.service_topics = {svc_constants.CORE: topics.PLUGIN,
|
||||||
|
svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN}
|
||||||
self.conn = rpc.create_connection(new=True)
|
self.conn = rpc.create_connection(new=True)
|
||||||
self.notifier = AgentNotifierApi(topics.AGENT)
|
self.notifier = AgentNotifierApi(topics.AGENT)
|
||||||
self.callbacks = N1kvRpcCallbacks(self.notifier)
|
self.callbacks = N1kvRpcCallbacks(self.notifier)
|
||||||
self.dispatcher = self.callbacks.create_rpc_dispatcher()
|
self.dispatcher = self.callbacks.create_rpc_dispatcher()
|
||||||
self.conn.create_consumer(self.topic, self.dispatcher,
|
for svc_topic in self.service_topics.values():
|
||||||
fanout=False)
|
self.conn.create_consumer(svc_topic, self.dispatcher, fanout=False)
|
||||||
# Consume from all consumers in a thread
|
# Consume from all consumers in a thread
|
||||||
self.dhcp_agent_notifier = dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
|
self.dhcp_agent_notifier = dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
|
||||||
self.l3_agent_notifier = l3_rpc_agent_api.L3AgentNotify
|
self.l3_agent_notifier = l3_rpc_agent_api.L3AgentNotify
|
||||||
|
@ -22,6 +22,8 @@ LOADBALANCER = "LOADBALANCER"
|
|||||||
FIREWALL = "FIREWALL"
|
FIREWALL = "FIREWALL"
|
||||||
VPN = "VPN"
|
VPN = "VPN"
|
||||||
METERING = "METERING"
|
METERING = "METERING"
|
||||||
|
L3_ROUTER_NAT = "L3_ROUTER_NAT"
|
||||||
|
|
||||||
|
|
||||||
#maps extension alias to service type
|
#maps extension alias to service type
|
||||||
EXT_TO_SERVICE_MAPPING = {
|
EXT_TO_SERVICE_MAPPING = {
|
||||||
@ -30,10 +32,12 @@ EXT_TO_SERVICE_MAPPING = {
|
|||||||
'fwaas': FIREWALL,
|
'fwaas': FIREWALL,
|
||||||
'vpnaas': VPN,
|
'vpnaas': VPN,
|
||||||
'metering': METERING,
|
'metering': METERING,
|
||||||
|
'router': L3_ROUTER_NAT
|
||||||
}
|
}
|
||||||
|
|
||||||
# TODO(salvatore-orlando): Move these (or derive them) from conf file
|
# TODO(salvatore-orlando): Move these (or derive them) from conf file
|
||||||
ALLOWED_SERVICES = [CORE, DUMMY, LOADBALANCER, FIREWALL, VPN, METERING]
|
ALLOWED_SERVICES = [CORE, DUMMY, LOADBALANCER, FIREWALL, VPN, METERING,
|
||||||
|
L3_ROUTER_NAT]
|
||||||
|
|
||||||
COMMON_PREFIXES = {
|
COMMON_PREFIXES = {
|
||||||
CORE: "",
|
CORE: "",
|
||||||
@ -42,6 +46,7 @@ COMMON_PREFIXES = {
|
|||||||
FIREWALL: "/fw",
|
FIREWALL: "/fw",
|
||||||
VPN: "/vpn",
|
VPN: "/vpn",
|
||||||
METERING: "/metering",
|
METERING: "/metering",
|
||||||
|
L3_ROUTER_NAT: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Service operation status constants
|
# Service operation status constants
|
||||||
|
@ -22,6 +22,7 @@ from neutron.api.v2 import attributes
|
|||||||
from neutron.common import exceptions as q_exc
|
from neutron.common import exceptions as q_exc
|
||||||
from neutron.common import topics
|
from neutron.common import topics
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
|
from neutron.db import external_net_db
|
||||||
from neutron.db import l3_gwmode_db
|
from neutron.db import l3_gwmode_db
|
||||||
from neutron.db import portbindings_base
|
from neutron.db import portbindings_base
|
||||||
from neutron.db import quota_db # noqa
|
from neutron.db import quota_db # noqa
|
||||||
@ -29,6 +30,7 @@ from neutron.extensions import portbindings
|
|||||||
from neutron.extensions import providernet as provider
|
from neutron.extensions import providernet as provider
|
||||||
from neutron.openstack.common import log as logging
|
from neutron.openstack.common import log as logging
|
||||||
from neutron.openstack.common import rpc
|
from neutron.openstack.common import rpc
|
||||||
|
from neutron.plugins.common import constants as svc_constants
|
||||||
from neutron.plugins.common import utils as plugin_utils
|
from neutron.plugins.common import utils as plugin_utils
|
||||||
from neutron.plugins.hyperv import agent_notifier_api
|
from neutron.plugins.hyperv import agent_notifier_api
|
||||||
from neutron.plugins.hyperv.common import constants
|
from neutron.plugins.hyperv.common import constants
|
||||||
@ -142,6 +144,7 @@ class VlanNetworkProvider(BaseNetworkProvider):
|
|||||||
|
|
||||||
|
|
||||||
class HyperVNeutronPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
class HyperVNeutronPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
|
external_net_db.External_net_db_mixin,
|
||||||
l3_gwmode_db.L3_NAT_db_mixin,
|
l3_gwmode_db.L3_NAT_db_mixin,
|
||||||
portbindings_base.PortBindingBaseMixin):
|
portbindings_base.PortBindingBaseMixin):
|
||||||
|
|
||||||
@ -149,8 +152,8 @@ class HyperVNeutronPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
# bulk operations. Name mangling is used in order to ensure it
|
# bulk operations. Name mangling is used in order to ensure it
|
||||||
# is qualified by class
|
# is qualified by class
|
||||||
__native_bulk_support = True
|
__native_bulk_support = True
|
||||||
supported_extension_aliases = ["provider", "router", "ext-gw-mode",
|
supported_extension_aliases = ["provider", "external-net", "router",
|
||||||
"binding", "quotas"]
|
"ext-gw-mode", "binding", "quotas"]
|
||||||
|
|
||||||
def __init__(self, configfile=None):
|
def __init__(self, configfile=None):
|
||||||
self._db = hyperv_db.HyperVPluginDB()
|
self._db = hyperv_db.HyperVPluginDB()
|
||||||
@ -181,14 +184,15 @@ class HyperVNeutronPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
|
|
||||||
def _setup_rpc(self):
|
def _setup_rpc(self):
|
||||||
# RPC support
|
# RPC support
|
||||||
self.topic = topics.PLUGIN
|
self.service_topics = {svc_constants.CORE: topics.PLUGIN,
|
||||||
|
svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN}
|
||||||
self.conn = rpc.create_connection(new=True)
|
self.conn = rpc.create_connection(new=True)
|
||||||
self.notifier = agent_notifier_api.AgentNotifierApi(
|
self.notifier = agent_notifier_api.AgentNotifierApi(
|
||||||
topics.AGENT)
|
topics.AGENT)
|
||||||
self.callbacks = rpc_callbacks.HyperVRpcCallbacks(self.notifier)
|
self.callbacks = rpc_callbacks.HyperVRpcCallbacks(self.notifier)
|
||||||
self.dispatcher = self.callbacks.create_rpc_dispatcher()
|
self.dispatcher = self.callbacks.create_rpc_dispatcher()
|
||||||
self.conn.create_consumer(self.topic, self.dispatcher,
|
for svc_topic in self.service_topics.values():
|
||||||
fanout=False)
|
self.conn.create_consumer(svc_topic, self.dispatcher, fanout=False)
|
||||||
# Consume from all consumers in a thread
|
# Consume from all consumers in a thread
|
||||||
self.conn.consume_in_thread()
|
self.conn.consume_in_thread()
|
||||||
|
|
||||||
|
@ -31,7 +31,9 @@ from neutron.db import agentschedulers_db
|
|||||||
from neutron.db import api as db_api
|
from neutron.db import api as db_api
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
from neutron.db import dhcp_rpc_base
|
from neutron.db import dhcp_rpc_base
|
||||||
|
from neutron.db import external_net_db
|
||||||
from neutron.db import extraroute_db
|
from neutron.db import extraroute_db
|
||||||
|
from neutron.db import l3_agentschedulers_db
|
||||||
from neutron.db import l3_gwmode_db
|
from neutron.db import l3_gwmode_db
|
||||||
from neutron.db import l3_rpc_base
|
from neutron.db import l3_rpc_base
|
||||||
from neutron.db import portbindings_db
|
from neutron.db import portbindings_db
|
||||||
@ -43,6 +45,7 @@ from neutron.openstack.common import importutils
|
|||||||
from neutron.openstack.common import log as logging
|
from neutron.openstack.common import log as logging
|
||||||
from neutron.openstack.common import rpc
|
from neutron.openstack.common import rpc
|
||||||
from neutron.openstack.common.rpc import proxy
|
from neutron.openstack.common.rpc import proxy
|
||||||
|
from neutron.plugins.common import constants as svc_constants
|
||||||
from neutron.plugins.common import utils as plugin_utils
|
from neutron.plugins.common import utils as plugin_utils
|
||||||
from neutron.plugins.linuxbridge.common import constants
|
from neutron.plugins.linuxbridge.common import constants
|
||||||
from neutron.plugins.linuxbridge.db import l2network_db_v2 as db
|
from neutron.plugins.linuxbridge.db import l2network_db_v2 as db
|
||||||
@ -188,10 +191,11 @@ class AgentNotifierApi(proxy.RpcProxy,
|
|||||||
|
|
||||||
|
|
||||||
class LinuxBridgePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
class LinuxBridgePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
|
external_net_db.External_net_db_mixin,
|
||||||
extraroute_db.ExtraRoute_db_mixin,
|
extraroute_db.ExtraRoute_db_mixin,
|
||||||
l3_gwmode_db.L3_NAT_db_mixin,
|
l3_gwmode_db.L3_NAT_db_mixin,
|
||||||
sg_db_rpc.SecurityGroupServerRpcMixin,
|
sg_db_rpc.SecurityGroupServerRpcMixin,
|
||||||
agentschedulers_db.L3AgentSchedulerDbMixin,
|
l3_agentschedulers_db.L3AgentSchedulerDbMixin,
|
||||||
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
||||||
portbindings_db.PortBindingMixin):
|
portbindings_db.PortBindingMixin):
|
||||||
"""Implement the Neutron abstractions using Linux bridging.
|
"""Implement the Neutron abstractions using Linux bridging.
|
||||||
@ -217,9 +221,9 @@ class LinuxBridgePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
__native_pagination_support = True
|
__native_pagination_support = True
|
||||||
__native_sorting_support = True
|
__native_sorting_support = True
|
||||||
|
|
||||||
_supported_extension_aliases = ["provider", "router", "ext-gw-mode",
|
_supported_extension_aliases = ["provider", "external-net", "router",
|
||||||
"binding", "quotas", "security-group",
|
"ext-gw-mode", "binding", "quotas",
|
||||||
"agent", "extraroute",
|
"security-group", "agent", "extraroute",
|
||||||
"l3_agent_scheduler",
|
"l3_agent_scheduler",
|
||||||
"dhcp_agent_scheduler"]
|
"dhcp_agent_scheduler"]
|
||||||
|
|
||||||
@ -259,12 +263,13 @@ class LinuxBridgePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
|
|
||||||
def _setup_rpc(self):
|
def _setup_rpc(self):
|
||||||
# RPC support
|
# RPC support
|
||||||
self.topic = topics.PLUGIN
|
self.service_topics = {svc_constants.CORE: topics.PLUGIN,
|
||||||
|
svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN}
|
||||||
self.conn = rpc.create_connection(new=True)
|
self.conn = rpc.create_connection(new=True)
|
||||||
self.callbacks = LinuxBridgeRpcCallbacks()
|
self.callbacks = LinuxBridgeRpcCallbacks()
|
||||||
self.dispatcher = self.callbacks.create_rpc_dispatcher()
|
self.dispatcher = self.callbacks.create_rpc_dispatcher()
|
||||||
self.conn.create_consumer(self.topic, self.dispatcher,
|
for svc_topic in self.service_topics.values():
|
||||||
fanout=False)
|
self.conn.create_consumer(svc_topic, self.dispatcher, fanout=False)
|
||||||
# Consume from all consumers in a thread
|
# Consume from all consumers in a thread
|
||||||
self.conn.consume_in_thread()
|
self.conn.consume_in_thread()
|
||||||
self.notifier = AgentNotifierApi(topics.AGENT)
|
self.notifier = AgentNotifierApi(topics.AGENT)
|
||||||
|
@ -20,6 +20,7 @@ from oslo.config import cfg
|
|||||||
from neutron.common import exceptions as exc
|
from neutron.common import exceptions as exc
|
||||||
from neutron.db import api as db
|
from neutron.db import api as db
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
|
from neutron.db import external_net_db
|
||||||
from neutron.db import extraroute_db
|
from neutron.db import extraroute_db
|
||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
from neutron.db import models_v2
|
from neutron.db import models_v2
|
||||||
@ -45,14 +46,16 @@ class FaildToAddFlavorBinding(exc.NeutronException):
|
|||||||
|
|
||||||
|
|
||||||
class MetaPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
class MetaPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
|
external_net_db.External_net_db_mixin,
|
||||||
extraroute_db.ExtraRoute_db_mixin):
|
extraroute_db.ExtraRoute_db_mixin):
|
||||||
|
|
||||||
def __init__(self, configfile=None):
|
def __init__(self, configfile=None):
|
||||||
LOG.debug(_("Start initializing metaplugin"))
|
LOG.debug(_("Start initializing metaplugin"))
|
||||||
self.supported_extension_aliases = \
|
self.supported_extension_aliases = \
|
||||||
cfg.CONF.META.supported_extension_aliases.split(',')
|
cfg.CONF.META.supported_extension_aliases.split(',')
|
||||||
self.supported_extension_aliases += ['flavor', 'router',
|
self.supported_extension_aliases += ['flavor', 'external-net',
|
||||||
'ext-gw-mode', 'extraroute']
|
'router', 'ext-gw-mode',
|
||||||
|
'extraroute']
|
||||||
|
|
||||||
# Ignore config option overapping
|
# Ignore config option overapping
|
||||||
def _is_opt_registered(opts, opt):
|
def _is_opt_registered(opts, opt):
|
||||||
|
@ -19,6 +19,7 @@ from oslo.config import cfg
|
|||||||
|
|
||||||
from neutron.db import api as db
|
from neutron.db import api as db
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
|
from neutron.db import external_net_db
|
||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
from neutron.openstack.common import log as logging
|
from neutron.openstack.common import log as logging
|
||||||
from neutronclient.common import exceptions
|
from neutronclient.common import exceptions
|
||||||
@ -29,8 +30,9 @@ LOG = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class ProxyPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
class ProxyPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
|
external_net_db.External_net_db_mixin,
|
||||||
l3_db.L3_NAT_db_mixin):
|
l3_db.L3_NAT_db_mixin):
|
||||||
supported_extension_aliases = ["router"]
|
supported_extension_aliases = ["external-net", "router"]
|
||||||
|
|
||||||
def __init__(self, configfile=None):
|
def __init__(self, configfile=None):
|
||||||
db.configure_db()
|
db.configure_db()
|
||||||
|
@ -33,6 +33,7 @@ from neutron.db import agentschedulers_db
|
|||||||
from neutron.db import api as db
|
from neutron.db import api as db
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
from neutron.db import dhcp_rpc_base
|
from neutron.db import dhcp_rpc_base
|
||||||
|
from neutron.db import external_net_db
|
||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
from neutron.db import models_v2
|
from neutron.db import models_v2
|
||||||
from neutron.db import securitygroups_db
|
from neutron.db import securitygroups_db
|
||||||
@ -188,12 +189,13 @@ class MidonetPluginException(n_exc.NeutronException):
|
|||||||
|
|
||||||
|
|
||||||
class MidonetPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
class MidonetPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
|
external_net_db.External_net_db_mixin,
|
||||||
l3_db.L3_NAT_db_mixin,
|
l3_db.L3_NAT_db_mixin,
|
||||||
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
||||||
securitygroups_db.SecurityGroupDbMixin):
|
securitygroups_db.SecurityGroupDbMixin):
|
||||||
|
|
||||||
supported_extension_aliases = ['router', 'security-group', 'agent',
|
supported_extension_aliases = ['external-net', 'router', 'security-group',
|
||||||
'dhcp_agent_scheduler']
|
'agent' 'dhcp_agent_scheduler']
|
||||||
__native_bulk_support = False
|
__native_bulk_support = False
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -17,7 +17,6 @@ from oslo.config import cfg
|
|||||||
|
|
||||||
from neutron.agent import securitygroups_rpc as sg_rpc
|
from neutron.agent import securitygroups_rpc as sg_rpc
|
||||||
from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
|
from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
|
||||||
from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
|
|
||||||
from neutron.api.v2 import attributes
|
from neutron.api.v2 import attributes
|
||||||
from neutron.common import constants as const
|
from neutron.common import constants as const
|
||||||
from neutron.common import exceptions as exc
|
from neutron.common import exceptions as exc
|
||||||
@ -25,8 +24,7 @@ from neutron.common import topics
|
|||||||
from neutron.db import agentschedulers_db
|
from neutron.db import agentschedulers_db
|
||||||
from neutron.db import allowedaddresspairs_db as addr_pair_db
|
from neutron.db import allowedaddresspairs_db as addr_pair_db
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
from neutron.db import extraroute_db
|
from neutron.db import external_net_db
|
||||||
from neutron.db import l3_gwmode_db
|
|
||||||
from neutron.db import models_v2
|
from neutron.db import models_v2
|
||||||
from neutron.db import quota_db # noqa
|
from neutron.db import quota_db # noqa
|
||||||
from neutron.db import securitygroups_rpc_base as sg_db_rpc
|
from neutron.db import securitygroups_rpc_base as sg_db_rpc
|
||||||
@ -34,10 +32,12 @@ from neutron.extensions import allowedaddresspairs as addr_pair
|
|||||||
from neutron.extensions import multiprovidernet as mpnet
|
from neutron.extensions import multiprovidernet as mpnet
|
||||||
from neutron.extensions import portbindings
|
from neutron.extensions import portbindings
|
||||||
from neutron.extensions import providernet as provider
|
from neutron.extensions import providernet as provider
|
||||||
|
from neutron import manager
|
||||||
from neutron.openstack.common import excutils
|
from neutron.openstack.common import excutils
|
||||||
from neutron.openstack.common import importutils
|
from neutron.openstack.common import importutils
|
||||||
from neutron.openstack.common import log
|
from neutron.openstack.common import log
|
||||||
from neutron.openstack.common import rpc as c_rpc
|
from neutron.openstack.common import rpc as c_rpc
|
||||||
|
from neutron.plugins.common import constants as service_constants
|
||||||
from neutron.plugins.ml2.common import exceptions as ml2_exc
|
from neutron.plugins.ml2.common import exceptions as ml2_exc
|
||||||
from neutron.plugins.ml2 import config # noqa
|
from neutron.plugins.ml2 import config # noqa
|
||||||
from neutron.plugins.ml2 import db
|
from neutron.plugins.ml2 import db
|
||||||
@ -55,12 +55,11 @@ TYPE_MULTI_SEGMENT = 'multi-segment'
|
|||||||
|
|
||||||
|
|
||||||
class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
extraroute_db.ExtraRoute_db_mixin,
|
external_net_db.External_net_db_mixin,
|
||||||
l3_gwmode_db.L3_NAT_db_mixin,
|
|
||||||
sg_db_rpc.SecurityGroupServerRpcMixin,
|
sg_db_rpc.SecurityGroupServerRpcMixin,
|
||||||
agentschedulers_db.L3AgentSchedulerDbMixin,
|
|
||||||
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
||||||
addr_pair_db.AllowedAddressPairsMixin):
|
addr_pair_db.AllowedAddressPairsMixin):
|
||||||
|
|
||||||
"""Implement the Neutron L2 abstractions using modules.
|
"""Implement the Neutron L2 abstractions using modules.
|
||||||
|
|
||||||
Ml2Plugin is a Neutron plugin based on separately extensible sets
|
Ml2Plugin is a Neutron plugin based on separately extensible sets
|
||||||
@ -78,10 +77,9 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
__native_sorting_support = True
|
__native_sorting_support = True
|
||||||
|
|
||||||
# List of supported extensions
|
# List of supported extensions
|
||||||
_supported_extension_aliases = ["provider", "router", "extraroute",
|
_supported_extension_aliases = ["provider", "external-net", "binding",
|
||||||
"binding", "quotas", "security-group",
|
"quotas", "security-group", "agent",
|
||||||
"agent", "l3_agent_scheduler",
|
"dhcp_agent_scheduler",
|
||||||
"dhcp_agent_scheduler", "ext-gw-mode",
|
|
||||||
"multi-provider", "allowed-address-pairs"]
|
"multi-provider", "allowed-address-pairs"]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -106,9 +104,6 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
self.network_scheduler = importutils.import_object(
|
self.network_scheduler = importutils.import_object(
|
||||||
cfg.CONF.network_scheduler_driver
|
cfg.CONF.network_scheduler_driver
|
||||||
)
|
)
|
||||||
self.router_scheduler = importutils.import_object(
|
|
||||||
cfg.CONF.router_scheduler_driver
|
|
||||||
)
|
|
||||||
|
|
||||||
LOG.info(_("Modular L2 Plugin initialization complete"))
|
LOG.info(_("Modular L2 Plugin initialization complete"))
|
||||||
|
|
||||||
@ -117,9 +112,6 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
self.agent_notifiers[const.AGENT_TYPE_DHCP] = (
|
self.agent_notifiers[const.AGENT_TYPE_DHCP] = (
|
||||||
dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
|
dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
|
||||||
)
|
)
|
||||||
self.agent_notifiers[const.AGENT_TYPE_L3] = (
|
|
||||||
l3_rpc_agent_api.L3AgentNotify
|
|
||||||
)
|
|
||||||
self.callbacks = rpc.RpcCallbacks(self.notifier, self.type_manager)
|
self.callbacks = rpc.RpcCallbacks(self.notifier, self.type_manager)
|
||||||
self.topic = topics.PLUGIN
|
self.topic = topics.PLUGIN
|
||||||
self.conn = c_rpc.create_connection(new=True)
|
self.conn = c_rpc.create_connection(new=True)
|
||||||
@ -514,12 +506,15 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
return updated_port
|
return updated_port
|
||||||
|
|
||||||
def delete_port(self, context, id, l3_port_check=True):
|
def delete_port(self, context, id, l3_port_check=True):
|
||||||
if l3_port_check:
|
l3plugin = manager.NeutronManager.get_service_plugins().get(
|
||||||
self.prevent_l3_port_deletion(context, id)
|
service_constants.L3_ROUTER_NAT)
|
||||||
|
if l3plugin and l3_port_check:
|
||||||
|
l3plugin.prevent_l3_port_deletion(context, id)
|
||||||
|
|
||||||
session = context.session
|
session = context.session
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
self.disassociate_floatingips(context, id)
|
if l3plugin:
|
||||||
|
l3plugin.disassociate_floatingips(context, id)
|
||||||
port = self.get_port(context, id)
|
port = self.get_port(context, id)
|
||||||
network = self.get_network(context, port['network_id'])
|
network = self.get_network(context, port['network_id'])
|
||||||
mech_context = driver_context.PortContext(self, context, port,
|
mech_context = driver_context.PortContext(self, context, port,
|
||||||
|
@ -20,7 +20,6 @@ from neutron.common import topics
|
|||||||
from neutron.db import agents_db
|
from neutron.db import agents_db
|
||||||
from neutron.db import api as db_api
|
from neutron.db import api as db_api
|
||||||
from neutron.db import dhcp_rpc_base
|
from neutron.db import dhcp_rpc_base
|
||||||
from neutron.db import l3_rpc_base
|
|
||||||
from neutron.db import securitygroups_rpc_base as sg_db_rpc
|
from neutron.db import securitygroups_rpc_base as sg_db_rpc
|
||||||
from neutron.openstack.common import log
|
from neutron.openstack.common import log
|
||||||
from neutron.openstack.common.rpc import proxy
|
from neutron.openstack.common.rpc import proxy
|
||||||
@ -37,7 +36,6 @@ TAP_DEVICE_PREFIX_LENGTH = 3
|
|||||||
|
|
||||||
|
|
||||||
class RpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin,
|
class RpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin,
|
||||||
l3_rpc_base.L3RpcCallbackMixin,
|
|
||||||
sg_db_rpc.SecurityGroupServerRpcCallbackMixin,
|
sg_db_rpc.SecurityGroupServerRpcCallbackMixin,
|
||||||
type_tunnel.TunnelRpcCallbackMixin):
|
type_tunnel.TunnelRpcCallbackMixin):
|
||||||
|
|
||||||
|
@ -29,7 +29,9 @@ from neutron.common import topics
|
|||||||
from neutron.common import utils
|
from neutron.common import utils
|
||||||
from neutron.db import agentschedulers_db
|
from neutron.db import agentschedulers_db
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
|
from neutron.db import external_net_db
|
||||||
from neutron.db import extraroute_db
|
from neutron.db import extraroute_db
|
||||||
|
from neutron.db import l3_agentschedulers_db
|
||||||
from neutron.db import l3_gwmode_db
|
from neutron.db import l3_gwmode_db
|
||||||
from neutron.db import portbindings_db
|
from neutron.db import portbindings_db
|
||||||
from neutron.db import quota_db # noqa
|
from neutron.db import quota_db # noqa
|
||||||
@ -39,6 +41,7 @@ from neutron.extensions import providernet as provider
|
|||||||
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.openstack.common import rpc
|
from neutron.openstack.common import rpc
|
||||||
|
from neutron.plugins.common import constants as svc_constants
|
||||||
from neutron.plugins.common import utils as plugin_utils
|
from neutron.plugins.common import utils as plugin_utils
|
||||||
from neutron.plugins.mlnx import agent_notify_api
|
from neutron.plugins.mlnx import agent_notify_api
|
||||||
from neutron.plugins.mlnx.common import constants
|
from neutron.plugins.mlnx.common import constants
|
||||||
@ -49,10 +52,11 @@ LOG = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
|
external_net_db.External_net_db_mixin,
|
||||||
extraroute_db.ExtraRoute_db_mixin,
|
extraroute_db.ExtraRoute_db_mixin,
|
||||||
l3_gwmode_db.L3_NAT_db_mixin,
|
l3_gwmode_db.L3_NAT_db_mixin,
|
||||||
sg_db_rpc.SecurityGroupServerRpcMixin,
|
sg_db_rpc.SecurityGroupServerRpcMixin,
|
||||||
agentschedulers_db.L3AgentSchedulerDbMixin,
|
l3_agentschedulers_db.L3AgentSchedulerDbMixin,
|
||||||
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
||||||
portbindings_db.PortBindingMixin):
|
portbindings_db.PortBindingMixin):
|
||||||
"""Realization of Neutron API on Mellanox HCA embedded switch technology.
|
"""Realization of Neutron API on Mellanox HCA embedded switch technology.
|
||||||
@ -75,9 +79,9 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
# is qualified by class
|
# is qualified by class
|
||||||
__native_bulk_support = True
|
__native_bulk_support = True
|
||||||
|
|
||||||
_supported_extension_aliases = ["provider", "router", "ext-gw-mode",
|
_supported_extension_aliases = ["provider", "external-net", "router",
|
||||||
"binding", "quotas", "security-group",
|
"ext-gw-mode", "binding", "quotas",
|
||||||
"agent", "extraroute",
|
"security-group", "agent", "extraroute",
|
||||||
"l3_agent_scheduler",
|
"l3_agent_scheduler",
|
||||||
"dhcp_agent_scheduler"]
|
"dhcp_agent_scheduler"]
|
||||||
|
|
||||||
@ -112,12 +116,13 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
|
|
||||||
def _setup_rpc(self):
|
def _setup_rpc(self):
|
||||||
# RPC support
|
# RPC support
|
||||||
self.topic = topics.PLUGIN
|
self.service_topics = {svc_constants.CORE: topics.PLUGIN,
|
||||||
|
svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN}
|
||||||
self.conn = rpc.create_connection(new=True)
|
self.conn = rpc.create_connection(new=True)
|
||||||
self.callbacks = rpc_callbacks.MlnxRpcCallbacks()
|
self.callbacks = rpc_callbacks.MlnxRpcCallbacks()
|
||||||
self.dispatcher = self.callbacks.create_rpc_dispatcher()
|
self.dispatcher = self.callbacks.create_rpc_dispatcher()
|
||||||
self.conn.create_consumer(self.topic, self.dispatcher,
|
for svc_topic in self.service_topics.values():
|
||||||
fanout=False)
|
self.conn.create_consumer(svc_topic, self.dispatcher, fanout=False)
|
||||||
# Consume from all consumers in a thread
|
# Consume from all consumers in a thread
|
||||||
self.conn.consume_in_thread()
|
self.conn.consume_in_thread()
|
||||||
self.notifier = agent_notify_api.AgentNotifierApi(topics.AGENT)
|
self.notifier = agent_notify_api.AgentNotifierApi(topics.AGENT)
|
||||||
|
@ -27,6 +27,7 @@ from neutron.db import agents_db
|
|||||||
from neutron.db import agentschedulers_db
|
from neutron.db import agentschedulers_db
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
from neutron.db import dhcp_rpc_base
|
from neutron.db import dhcp_rpc_base
|
||||||
|
from neutron.db import external_net_db
|
||||||
from neutron.db import l3_rpc_base
|
from neutron.db import l3_rpc_base
|
||||||
from neutron.db import portbindings_base
|
from neutron.db import portbindings_base
|
||||||
from neutron.db import portbindings_db
|
from neutron.db import portbindings_db
|
||||||
@ -38,6 +39,7 @@ from neutron.openstack.common import log as logging
|
|||||||
from neutron.openstack.common import rpc
|
from neutron.openstack.common import rpc
|
||||||
from neutron.openstack.common.rpc import proxy
|
from neutron.openstack.common.rpc import proxy
|
||||||
from neutron.openstack.common import uuidutils
|
from neutron.openstack.common import uuidutils
|
||||||
|
from neutron.plugins.common import constants as svc_constants
|
||||||
from neutron.plugins.nec.common import config
|
from neutron.plugins.nec.common import config
|
||||||
from neutron.plugins.nec.common import exceptions as nexc
|
from neutron.plugins.nec.common import exceptions as nexc
|
||||||
from neutron.plugins.nec.db import api as ndb
|
from neutron.plugins.nec.db import api as ndb
|
||||||
@ -50,6 +52,7 @@ LOG = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
|
external_net_db.External_net_db_mixin,
|
||||||
nec_router.RouterMixin,
|
nec_router.RouterMixin,
|
||||||
sg_db_rpc.SecurityGroupServerRpcMixin,
|
sg_db_rpc.SecurityGroupServerRpcMixin,
|
||||||
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
||||||
@ -71,6 +74,7 @@ class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
_supported_extension_aliases = ["agent",
|
_supported_extension_aliases = ["agent",
|
||||||
"binding",
|
"binding",
|
||||||
"dhcp_agent_scheduler",
|
"dhcp_agent_scheduler",
|
||||||
|
"external-net",
|
||||||
"ext-gw-mode",
|
"ext-gw-mode",
|
||||||
"extraroute",
|
"extraroute",
|
||||||
"l3_agent_scheduler",
|
"l3_agent_scheduler",
|
||||||
@ -127,7 +131,8 @@ class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
}
|
}
|
||||||
|
|
||||||
def setup_rpc(self):
|
def setup_rpc(self):
|
||||||
self.topic = topics.PLUGIN
|
self.service_topics = {svc_constants.CORE: topics.PLUGIN,
|
||||||
|
svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN}
|
||||||
self.conn = rpc.create_connection(new=True)
|
self.conn = rpc.create_connection(new=True)
|
||||||
self.notifier = NECPluginV2AgentNotifierApi(topics.AGENT)
|
self.notifier = NECPluginV2AgentNotifierApi(topics.AGENT)
|
||||||
self.agent_notifiers[const.AGENT_TYPE_DHCP] = (
|
self.agent_notifiers[const.AGENT_TYPE_DHCP] = (
|
||||||
@ -145,7 +150,8 @@ class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
self.callback_sg,
|
self.callback_sg,
|
||||||
agents_db.AgentExtRpcCallback()]
|
agents_db.AgentExtRpcCallback()]
|
||||||
self.dispatcher = q_rpc.PluginRpcDispatcher(callbacks)
|
self.dispatcher = q_rpc.PluginRpcDispatcher(callbacks)
|
||||||
self.conn.create_consumer(self.topic, self.dispatcher, fanout=False)
|
for svc_topic in self.service_topics.values():
|
||||||
|
self.conn.create_consumer(svc_topic, self.dispatcher, fanout=False)
|
||||||
# Consume from all consumers in a thread
|
# Consume from all consumers in a thread
|
||||||
self.conn.consume_in_thread()
|
self.conn.consume_in_thread()
|
||||||
|
|
||||||
|
@ -19,9 +19,9 @@
|
|||||||
from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
|
from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
|
||||||
from neutron.api.v2 import attributes as attr
|
from neutron.api.v2 import attributes as attr
|
||||||
from neutron.common import exceptions as q_exc
|
from neutron.common import exceptions as q_exc
|
||||||
from neutron.db import agentschedulers_db
|
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
from neutron.db import extraroute_db
|
from neutron.db import extraroute_db
|
||||||
|
from neutron.db import l3_agentschedulers_db
|
||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
from neutron.db import l3_gwmode_db
|
from neutron.db import l3_gwmode_db
|
||||||
from neutron.db import models_v2
|
from neutron.db import models_v2
|
||||||
@ -260,7 +260,7 @@ class RouterMixin(extraroute_db.ExtraRoute_db_mixin,
|
|||||||
l3.ROUTERS, [extend_router_dict_provider])
|
l3.ROUTERS, [extend_router_dict_provider])
|
||||||
|
|
||||||
|
|
||||||
class L3AgentSchedulerDbMixin(agentschedulers_db.L3AgentSchedulerDbMixin):
|
class L3AgentSchedulerDbMixin(l3_agentschedulers_db.L3AgentSchedulerDbMixin):
|
||||||
|
|
||||||
def auto_schedule_routers(self, context, host, router_ids):
|
def auto_schedule_routers(self, context, host, router_ids):
|
||||||
router_ids = rdb.get_routers_by_provider(
|
router_ids = rdb.get_routers_by_provider(
|
||||||
|
@ -37,6 +37,7 @@ from neutron.db import agentschedulers_db
|
|||||||
from neutron.db import allowedaddresspairs_db as addr_pair_db
|
from neutron.db import allowedaddresspairs_db as addr_pair_db
|
||||||
from neutron.db import api as db
|
from neutron.db import api as db
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
|
from neutron.db import external_net_db
|
||||||
from neutron.db import extraroute_db
|
from neutron.db import extraroute_db
|
||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
from neutron.db import l3_gwmode_db
|
from neutron.db import l3_gwmode_db
|
||||||
@ -46,6 +47,7 @@ from neutron.db import portsecurity_db
|
|||||||
from neutron.db import quota_db # noqa
|
from neutron.db import quota_db # noqa
|
||||||
from neutron.db import securitygroups_db
|
from neutron.db import securitygroups_db
|
||||||
from neutron.extensions import allowedaddresspairs as addr_pair
|
from neutron.extensions import allowedaddresspairs as addr_pair
|
||||||
|
from neutron.extensions import external_net as ext_net_extn
|
||||||
from neutron.extensions import extraroute
|
from neutron.extensions import extraroute
|
||||||
from neutron.extensions import l3
|
from neutron.extensions import l3
|
||||||
from neutron.extensions import multiprovidernet as mpnet
|
from neutron.extensions import multiprovidernet as mpnet
|
||||||
@ -117,6 +119,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
|||||||
db_base_plugin_v2.NeutronDbPluginV2,
|
db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
dhcpmeta_modes.DhcpMetadataAccess,
|
dhcpmeta_modes.DhcpMetadataAccess,
|
||||||
dist_rtr.DistributedRouter_mixin,
|
dist_rtr.DistributedRouter_mixin,
|
||||||
|
external_net_db.External_net_db_mixin,
|
||||||
extraroute_db.ExtraRoute_db_mixin,
|
extraroute_db.ExtraRoute_db_mixin,
|
||||||
l3_gwmode_db.L3_NAT_db_mixin,
|
l3_gwmode_db.L3_NAT_db_mixin,
|
||||||
mac_db.MacLearningDbMixin,
|
mac_db.MacLearningDbMixin,
|
||||||
@ -146,6 +149,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
|||||||
"port-security",
|
"port-security",
|
||||||
"provider",
|
"provider",
|
||||||
"quotas",
|
"quotas",
|
||||||
|
"external-net",
|
||||||
"router",
|
"router",
|
||||||
"security-group"]
|
"security-group"]
|
||||||
|
|
||||||
@ -965,7 +969,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
|||||||
"network %s"), net_data.get('name', '<unknown>'))
|
"network %s"), net_data.get('name', '<unknown>'))
|
||||||
transport_zone_config = self._convert_to_nvp_transport_zones(
|
transport_zone_config = self._convert_to_nvp_transport_zones(
|
||||||
self.cluster, net_data)
|
self.cluster, net_data)
|
||||||
external = net_data.get(l3.EXTERNAL)
|
external = net_data.get(ext_net_extn.EXTERNAL)
|
||||||
if (not attr.is_attr_set(external) or
|
if (not attr.is_attr_set(external) or
|
||||||
attr.is_attr_set(external) and not external):
|
attr.is_attr_set(external) and not external):
|
||||||
lswitch = nvplib.create_lswitch(
|
lswitch = nvplib.create_lswitch(
|
||||||
@ -1213,7 +1217,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
|||||||
# being updated or not
|
# being updated or not
|
||||||
old_mac_learning_state = ret_port.get(mac_ext.MAC_LEARNING)
|
old_mac_learning_state = ret_port.get(mac_ext.MAC_LEARNING)
|
||||||
# copy values over - except fixed_ips as
|
# copy values over - except fixed_ips as
|
||||||
# they've alreaby been processed
|
# they've already been processed
|
||||||
port['port'].pop('fixed_ips', None)
|
port['port'].pop('fixed_ips', None)
|
||||||
ret_port.update(port['port'])
|
ret_port.update(port['port'])
|
||||||
tenant_id = self._get_tenant_id_for_create(context, ret_port)
|
tenant_id = self._get_tenant_id_for_create(context, ret_port)
|
||||||
|
@ -18,6 +18,7 @@ import random
|
|||||||
from neutron.common import constants
|
from neutron.common import constants
|
||||||
from neutron.common import exceptions
|
from neutron.common import exceptions
|
||||||
from neutron import context
|
from neutron import context
|
||||||
|
from neutron.db import external_net_db
|
||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
from neutron.db import models_v2
|
from neutron.db import models_v2
|
||||||
from neutron.openstack.common import jsonutils
|
from neutron.openstack.common import jsonutils
|
||||||
@ -363,9 +364,9 @@ class NvpSynchronizer():
|
|||||||
if not ext_networks:
|
if not ext_networks:
|
||||||
ext_networks = [net['id'] for net in context.session.query(
|
ext_networks = [net['id'] for net in context.session.query(
|
||||||
models_v2.Network).join(
|
models_v2.Network).join(
|
||||||
l3_db.ExternalNetwork,
|
external_net_db.ExternalNetwork,
|
||||||
(models_v2.Network.id ==
|
(models_v2.Network.id ==
|
||||||
l3_db.ExternalNetwork.network_id))]
|
external_net_db.ExternalNetwork.network_id))]
|
||||||
if neutron_port_data['network_id'] in ext_networks:
|
if neutron_port_data['network_id'] in ext_networks:
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
neutron_port_data['status'] = constants.PORT_STATUS_ACTIVE
|
neutron_port_data['status'] = constants.PORT_STATUS_ACTIVE
|
||||||
@ -430,9 +431,9 @@ class NvpSynchronizer():
|
|||||||
# this query
|
# this query
|
||||||
ext_nets = [net['id'] for net in ctx.session.query(
|
ext_nets = [net['id'] for net in ctx.session.query(
|
||||||
models_v2.Network).join(
|
models_v2.Network).join(
|
||||||
l3_db.ExternalNetwork,
|
external_net_db.ExternalNetwork,
|
||||||
(models_v2.Network.id ==
|
(models_v2.Network.id ==
|
||||||
l3_db.ExternalNetwork.network_id))]
|
external_net_db.ExternalNetwork.network_id))]
|
||||||
for port in self._plugin._get_collection_query(
|
for port in self._plugin._get_collection_query(
|
||||||
ctx, models_v2.Port, filters=filters):
|
ctx, models_v2.Port, filters=filters):
|
||||||
lswitchport = neutron_port_mappings.get(port['id'])
|
lswitchport = neutron_port_mappings.get(port['id'])
|
||||||
|
@ -39,8 +39,10 @@ from neutron.db import agentschedulers_db
|
|||||||
from neutron.db import allowedaddresspairs_db as addr_pair_db
|
from neutron.db import allowedaddresspairs_db as addr_pair_db
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
from neutron.db import dhcp_rpc_base
|
from neutron.db import dhcp_rpc_base
|
||||||
|
from neutron.db import external_net_db
|
||||||
from neutron.db import extradhcpopt_db
|
from neutron.db import extradhcpopt_db
|
||||||
from neutron.db import extraroute_db
|
from neutron.db import extraroute_db
|
||||||
|
from neutron.db import l3_agentschedulers_db
|
||||||
from neutron.db import l3_gwmode_db
|
from neutron.db import l3_gwmode_db
|
||||||
from neutron.db import l3_rpc_base
|
from neutron.db import l3_rpc_base
|
||||||
from neutron.db import portbindings_db
|
from neutron.db import portbindings_db
|
||||||
@ -54,6 +56,7 @@ from neutron.openstack.common import importutils
|
|||||||
from neutron.openstack.common import log as logging
|
from neutron.openstack.common import log as logging
|
||||||
from neutron.openstack.common import rpc
|
from neutron.openstack.common import rpc
|
||||||
from neutron.openstack.common.rpc import proxy
|
from neutron.openstack.common.rpc import proxy
|
||||||
|
from neutron.plugins.common import constants as svc_constants
|
||||||
from neutron.plugins.common import utils as plugin_utils
|
from neutron.plugins.common import utils as plugin_utils
|
||||||
from neutron.plugins.openvswitch.common import config # noqa
|
from neutron.plugins.openvswitch.common import config # noqa
|
||||||
from neutron.plugins.openvswitch.common import constants
|
from neutron.plugins.openvswitch.common import constants
|
||||||
@ -221,10 +224,11 @@ class AgentNotifierApi(proxy.RpcProxy,
|
|||||||
|
|
||||||
|
|
||||||
class OVSNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
class OVSNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
|
external_net_db.External_net_db_mixin,
|
||||||
extraroute_db.ExtraRoute_db_mixin,
|
extraroute_db.ExtraRoute_db_mixin,
|
||||||
l3_gwmode_db.L3_NAT_db_mixin,
|
l3_gwmode_db.L3_NAT_db_mixin,
|
||||||
sg_db_rpc.SecurityGroupServerRpcMixin,
|
sg_db_rpc.SecurityGroupServerRpcMixin,
|
||||||
agentschedulers_db.L3AgentSchedulerDbMixin,
|
l3_agentschedulers_db.L3AgentSchedulerDbMixin,
|
||||||
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
||||||
portbindings_db.PortBindingMixin,
|
portbindings_db.PortBindingMixin,
|
||||||
extradhcpopt_db.ExtraDhcpOptMixin,
|
extradhcpopt_db.ExtraDhcpOptMixin,
|
||||||
@ -254,9 +258,9 @@ class OVSNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
__native_pagination_support = True
|
__native_pagination_support = True
|
||||||
__native_sorting_support = True
|
__native_sorting_support = True
|
||||||
|
|
||||||
_supported_extension_aliases = ["provider", "router", "ext-gw-mode",
|
_supported_extension_aliases = ["provider", "external-net", "router",
|
||||||
"binding", "quotas", "security-group",
|
"ext-gw-mode", "binding", "quotas",
|
||||||
"agent", "extraroute",
|
"security-group", "agent", "extraroute",
|
||||||
"l3_agent_scheduler",
|
"l3_agent_scheduler",
|
||||||
"dhcp_agent_scheduler",
|
"dhcp_agent_scheduler",
|
||||||
"extra_dhcp_opt",
|
"extra_dhcp_opt",
|
||||||
@ -314,7 +318,8 @@ class OVSNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
|
|
||||||
def setup_rpc(self):
|
def setup_rpc(self):
|
||||||
# RPC support
|
# RPC support
|
||||||
self.topic = topics.PLUGIN
|
self.service_topics = {svc_constants.CORE: topics.PLUGIN,
|
||||||
|
svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN}
|
||||||
self.conn = rpc.create_connection(new=True)
|
self.conn = rpc.create_connection(new=True)
|
||||||
self.notifier = AgentNotifierApi(topics.AGENT)
|
self.notifier = AgentNotifierApi(topics.AGENT)
|
||||||
self.agent_notifiers[q_const.AGENT_TYPE_DHCP] = (
|
self.agent_notifiers[q_const.AGENT_TYPE_DHCP] = (
|
||||||
@ -325,8 +330,8 @@ class OVSNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
)
|
)
|
||||||
self.callbacks = OVSRpcCallbacks(self.notifier, self.tunnel_type)
|
self.callbacks = OVSRpcCallbacks(self.notifier, self.tunnel_type)
|
||||||
self.dispatcher = self.callbacks.create_rpc_dispatcher()
|
self.dispatcher = self.callbacks.create_rpc_dispatcher()
|
||||||
self.conn.create_consumer(self.topic, self.dispatcher,
|
for svc_topic in self.service_topics.values():
|
||||||
fanout=False)
|
self.conn.create_consumer(svc_topic, self.dispatcher, fanout=False)
|
||||||
# Consume from all consumers in a thread
|
# Consume from all consumers in a thread
|
||||||
self.conn.consume_in_thread()
|
self.conn.consume_in_thread()
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ from oslo.config import cfg
|
|||||||
from neutron.api.v2 import attributes
|
from neutron.api.v2 import attributes
|
||||||
from neutron.db import api as db
|
from neutron.db import api as db
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
|
from neutron.db import external_net_db
|
||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
from neutron.db import portbindings_db
|
from neutron.db import portbindings_db
|
||||||
from neutron.extensions import portbindings
|
from neutron.extensions import portbindings
|
||||||
@ -56,9 +57,10 @@ cfg.CONF.register_opts(director_server_opts, "PLUMgridDirector")
|
|||||||
|
|
||||||
class NeutronPluginPLUMgridV2(db_base_plugin_v2.NeutronDbPluginV2,
|
class NeutronPluginPLUMgridV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
portbindings_db.PortBindingMixin,
|
portbindings_db.PortBindingMixin,
|
||||||
|
external_net_db.External_net_db_mixin,
|
||||||
l3_db.L3_NAT_db_mixin):
|
l3_db.L3_NAT_db_mixin):
|
||||||
|
|
||||||
supported_extension_aliases = ["router", "binding"]
|
supported_extension_aliases = ["external-net", "router", "binding"]
|
||||||
|
|
||||||
binding_view = "extension:port_binding:view"
|
binding_view = "extension:port_binding:view"
|
||||||
binding_set = "extension:port_binding:set"
|
binding_set = "extension:port_binding:set"
|
||||||
|
@ -28,6 +28,7 @@ from neutron.common import topics
|
|||||||
from neutron.db import api as db
|
from neutron.db import api as db
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
from neutron.db import dhcp_rpc_base
|
from neutron.db import dhcp_rpc_base
|
||||||
|
from neutron.db import external_net_db
|
||||||
from neutron.db import extraroute_db
|
from neutron.db import extraroute_db
|
||||||
from neutron.db import l3_gwmode_db
|
from neutron.db import l3_gwmode_db
|
||||||
from neutron.db import l3_rpc_base
|
from neutron.db import l3_rpc_base
|
||||||
@ -88,12 +89,13 @@ class AgentNotifierApi(proxy.RpcProxy,
|
|||||||
|
|
||||||
|
|
||||||
class RyuNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
class RyuNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
|
external_net_db.External_net_db_mixin,
|
||||||
extraroute_db.ExtraRoute_db_mixin,
|
extraroute_db.ExtraRoute_db_mixin,
|
||||||
l3_gwmode_db.L3_NAT_db_mixin,
|
l3_gwmode_db.L3_NAT_db_mixin,
|
||||||
sg_db_rpc.SecurityGroupServerRpcMixin,
|
sg_db_rpc.SecurityGroupServerRpcMixin,
|
||||||
portbindings_base.PortBindingBaseMixin):
|
portbindings_base.PortBindingBaseMixin):
|
||||||
|
|
||||||
_supported_extension_aliases = ["router", "ext-gw-mode",
|
_supported_extension_aliases = ["external-net", "router", "ext-gw-mode",
|
||||||
"extraroute", "security-group",
|
"extraroute", "security-group",
|
||||||
"binding"]
|
"binding"]
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ from sqlalchemy.sql import exists
|
|||||||
|
|
||||||
from neutron.common import constants
|
from neutron.common import constants
|
||||||
from neutron.db import agents_db
|
from neutron.db import agents_db
|
||||||
from neutron.db import agentschedulers_db
|
from neutron.db import l3_agentschedulers_db
|
||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
from neutron.openstack.common import log as logging
|
from neutron.openstack.common import log as logging
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ class ChanceScheduler(object):
|
|||||||
#TODO(gongysh) consider the disabled agent's router
|
#TODO(gongysh) consider the disabled agent's router
|
||||||
stmt = ~exists().where(
|
stmt = ~exists().where(
|
||||||
l3_db.Router.id ==
|
l3_db.Router.id ==
|
||||||
agentschedulers_db.RouterL3AgentBinding.router_id)
|
l3_agentschedulers_db.RouterL3AgentBinding.router_id)
|
||||||
unscheduled_router_ids = [router_id_[0] for router_id_ in
|
unscheduled_router_ids = [router_id_[0] for router_id_ in
|
||||||
context.session.query(
|
context.session.query(
|
||||||
l3_db.Router.id).filter(stmt)]
|
l3_db.Router.id).filter(stmt)]
|
||||||
@ -106,7 +106,7 @@ class ChanceScheduler(object):
|
|||||||
|
|
||||||
# binding
|
# binding
|
||||||
for router_id in router_ids:
|
for router_id in router_ids:
|
||||||
binding = agentschedulers_db.RouterL3AgentBinding()
|
binding = l3_agentschedulers_db.RouterL3AgentBinding()
|
||||||
binding.l3_agent = l3_agent
|
binding.l3_agent = l3_agent
|
||||||
binding.router_id = router_id
|
binding.router_id = router_id
|
||||||
binding.default = True
|
binding.default = True
|
||||||
@ -144,7 +144,7 @@ class ChanceScheduler(object):
|
|||||||
return
|
return
|
||||||
|
|
||||||
chosen_agent = random.choice(candidates)
|
chosen_agent = random.choice(candidates)
|
||||||
binding = agentschedulers_db.RouterL3AgentBinding()
|
binding = l3_agentschedulers_db.RouterL3AgentBinding()
|
||||||
binding.l3_agent = chosen_agent
|
binding.l3_agent = chosen_agent
|
||||||
binding.router_id = sync_router['id']
|
binding.router_id = sync_router['id']
|
||||||
context.session.add(binding)
|
context.session.add(binding)
|
||||||
|
30
neutron/services/l3_router/README
Normal file
30
neutron/services/l3_router/README
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
This service plugin implements the L3 routing functionality (resources router
|
||||||
|
and floatingip) that in earlier releases before Havana was provided by core
|
||||||
|
plugins (openvswitch, linuxbridge, ... etc).
|
||||||
|
|
||||||
|
Core plugins can now choose not to implement L3 routing functionality and
|
||||||
|
instead delegate that to the L3 routing service plugin.
|
||||||
|
|
||||||
|
The required changes to a core plugin are in that case:
|
||||||
|
- Do not inherit 'l3_db.L3_NAT_db_mixin' (or its descendants like extraroute)
|
||||||
|
anymore.
|
||||||
|
- Remove "router" from 'supported_extension_aliases'.
|
||||||
|
- Modify any 'self' references to members in L3_NAT_db_mixin to instead use
|
||||||
|
'manager.NeutronManager.get_service_plugins().get(constants.L3_ROUTER_NAT)'
|
||||||
|
For example,
|
||||||
|
self.prevent_l3_port_deletion(...)
|
||||||
|
becomes something like
|
||||||
|
plugin = manager.NeutronManager.get_service_plugins().get(
|
||||||
|
constants.L3_ROUTER_NAT)
|
||||||
|
if plugin:
|
||||||
|
plugin.prevent_l3_port_deletion(...)
|
||||||
|
|
||||||
|
If the core plugin has relied on the L3Agent the following must also be changed:
|
||||||
|
- Do not inherit 'l3_rpc_base.L3RpcCallbackMixin' in any '*RpcCallbacks' class.
|
||||||
|
- Do not be a consumer of the topics.L3PLUGIN topic for RPC.
|
||||||
|
|
||||||
|
To use the L3 routing service plugin, add
|
||||||
|
'neutron.services.l3_router.l3_router_plugin.L3RouterPlugin'
|
||||||
|
to 'service_plugins' in '/etc/neutron/neutron.conf'.
|
||||||
|
That is,
|
||||||
|
service_plugins = neutron.services.l3_router.l3_router_plugin.L3RouterPlugin
|
16
neutron/services/l3_router/__init__.py
Normal file
16
neutron/services/l3_router/__init__.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright (c) 2013 OpenStack Foundation.
|
||||||
|
# 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.
|
93
neutron/services/l3_router/l3_router_plugin.py
Normal file
93
neutron/services/l3_router/l3_router_plugin.py
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright (c) 2013 OpenStack Foundation.
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# @author: Bob Melander, Cisco Systems, Inc.
|
||||||
|
|
||||||
|
from oslo.config import cfg
|
||||||
|
|
||||||
|
from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
|
||||||
|
from neutron.common import constants as q_const
|
||||||
|
from neutron.common import rpc as q_rpc
|
||||||
|
from neutron.common import topics
|
||||||
|
from neutron.db import api as qdbapi
|
||||||
|
from neutron.db import db_base_plugin_v2
|
||||||
|
from neutron.db import extraroute_db
|
||||||
|
from neutron.db import l3_agentschedulers_db
|
||||||
|
from neutron.db import l3_gwmode_db
|
||||||
|
from neutron.db import l3_rpc_base
|
||||||
|
from neutron.db import model_base
|
||||||
|
from neutron.openstack.common import importutils
|
||||||
|
from neutron.openstack.common import rpc
|
||||||
|
from neutron.plugins.common import constants
|
||||||
|
|
||||||
|
|
||||||
|
class L3RouterPluginRpcCallbacks(l3_rpc_base.L3RpcCallbackMixin):
|
||||||
|
|
||||||
|
# Set RPC API version to 1.0 by default.
|
||||||
|
RPC_API_VERSION = '1.0'
|
||||||
|
|
||||||
|
def create_rpc_dispatcher(self):
|
||||||
|
"""Get the rpc dispatcher for this manager.
|
||||||
|
|
||||||
|
If a manager would like to set an rpc API version, or support more than
|
||||||
|
one class as the target of rpc messages, override this method.
|
||||||
|
"""
|
||||||
|
return q_rpc.PluginRpcDispatcher([self])
|
||||||
|
|
||||||
|
|
||||||
|
class L3RouterPlugin(db_base_plugin_v2.CommonDbMixin,
|
||||||
|
extraroute_db.ExtraRoute_db_mixin,
|
||||||
|
l3_gwmode_db.L3_NAT_db_mixin,
|
||||||
|
l3_agentschedulers_db.L3AgentSchedulerDbMixin):
|
||||||
|
|
||||||
|
"""Implementation of the Neutron L3 Router Service Plugin.
|
||||||
|
|
||||||
|
This class implements a L3 service plugin that provides
|
||||||
|
router and floatingip resources and manages associated
|
||||||
|
request/response.
|
||||||
|
All DB related work is implemented in classes
|
||||||
|
l3_db.L3_NAT_db_mixin and extraroute_db.ExtraRoute_db_mixin.
|
||||||
|
"""
|
||||||
|
supported_extension_aliases = ["router", "ext-gw-mode",
|
||||||
|
"extraroute", "l3_agent_scheduler"]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
qdbapi.register_models(base=model_base.BASEV2)
|
||||||
|
self.setup_rpc()
|
||||||
|
self.router_scheduler = importutils.import_object(
|
||||||
|
cfg.CONF.router_scheduler_driver)
|
||||||
|
|
||||||
|
def setup_rpc(self):
|
||||||
|
# RPC support
|
||||||
|
self.topic = topics.L3PLUGIN
|
||||||
|
self.conn = rpc.create_connection(new=True)
|
||||||
|
self.agent_notifiers.update(
|
||||||
|
{q_const.AGENT_TYPE_L3: l3_rpc_agent_api.L3AgentNotify})
|
||||||
|
self.callbacks = L3RouterPluginRpcCallbacks()
|
||||||
|
self.dispatcher = self.callbacks.create_rpc_dispatcher()
|
||||||
|
self.conn.create_consumer(self.topic, self.dispatcher,
|
||||||
|
fanout=False)
|
||||||
|
self.conn.consume_in_thread()
|
||||||
|
|
||||||
|
def get_plugin_type(self):
|
||||||
|
return constants.L3_ROUTER_NAT
|
||||||
|
|
||||||
|
def get_plugin_description(self):
|
||||||
|
"""returns string description of the plugin."""
|
||||||
|
return ("L3 Router Service Plugin for basic L3 forwarding"
|
||||||
|
" between (L2) Neutron networks and access to external"
|
||||||
|
" networks via a NAT gateway.")
|
@ -47,14 +47,14 @@ def new_L3_setUp(self):
|
|||||||
cfg.CONF.set_default('allow_overlapping_ips', False)
|
cfg.CONF.set_default('allow_overlapping_ips', False)
|
||||||
ext_mgr = RouterRulesTestExtensionManager()
|
ext_mgr = RouterRulesTestExtensionManager()
|
||||||
test_config['extension_manager'] = ext_mgr
|
test_config['extension_manager'] = ext_mgr
|
||||||
super(test_l3_plugin.L3NatTestCaseBase, self).setUp()
|
super(test_l3_plugin.L3BaseForIntTests, self).setUp()
|
||||||
|
|
||||||
# Set to None to reload the drivers
|
# Set to None to reload the drivers
|
||||||
notifier_api._drivers = None
|
notifier_api._drivers = None
|
||||||
cfg.CONF.set_override("notification_driver", [test_notifier.__name__])
|
cfg.CONF.set_override("notification_driver", [test_notifier.__name__])
|
||||||
|
|
||||||
|
|
||||||
origSetUp = test_l3_plugin.L3NatDBTestCase.setUp
|
origSetUp = test_l3_plugin.L3NatDBIntTestCase.setUp
|
||||||
|
|
||||||
|
|
||||||
class RouterRulesTestExtensionManager(object):
|
class RouterRulesTestExtensionManager(object):
|
||||||
@ -82,13 +82,13 @@ class DHCPOptsTestCase(test_extradhcp.TestExtraDhcpOpt):
|
|||||||
super(test_extradhcp.ExtraDhcpOptDBTestCase, self).setUp(plugin=p_path)
|
super(test_extradhcp.ExtraDhcpOptDBTestCase, self).setUp(plugin=p_path)
|
||||||
|
|
||||||
|
|
||||||
class RouterDBTestCase(test_l3_plugin.L3NatDBTestCase):
|
class RouterDBTestCase(test_l3_plugin.L3NatDBIntTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.httpPatch = patch('httplib.HTTPConnection', create=True,
|
self.httpPatch = patch('httplib.HTTPConnection', create=True,
|
||||||
new=fake_server.HTTPConnectionMock)
|
new=fake_server.HTTPConnectionMock)
|
||||||
self.httpPatch.start()
|
self.httpPatch.start()
|
||||||
test_l3_plugin.L3NatDBTestCase.setUp = new_L3_setUp
|
test_l3_plugin.L3NatDBIntTestCase.setUp = new_L3_setUp
|
||||||
super(RouterDBTestCase, self).setUp()
|
super(RouterDBTestCase, self).setUp()
|
||||||
self.plugin_obj = NeutronManager.get_plugin()
|
self.plugin_obj = NeutronManager.get_plugin()
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ class RouterDBTestCase(test_l3_plugin.L3NatDBTestCase):
|
|||||||
del test_config['plugin_name_v2']
|
del test_config['plugin_name_v2']
|
||||||
del test_config['config_files']
|
del test_config['config_files']
|
||||||
cfg.CONF.reset()
|
cfg.CONF.reset()
|
||||||
test_l3_plugin.L3NatDBTestCase.setUp = origSetUp
|
test_l3_plugin.L3NatDBIntTestCase.setUp = origSetUp
|
||||||
|
|
||||||
def test_router_remove_router_interface_wrong_subnet_returns_400(self):
|
def test_router_remove_router_interface_wrong_subnet_returns_400(self):
|
||||||
with self.router() as r:
|
with self.router() as r:
|
||||||
|
@ -27,6 +27,7 @@ from neutron.api.extensions import PluginAwareExtensionManager
|
|||||||
from neutron.common import config
|
from neutron.common import config
|
||||||
from neutron import context
|
from neutron import context
|
||||||
from neutron.db import agentschedulers_db
|
from neutron.db import agentschedulers_db
|
||||||
|
from neutron.db import l3_agentschedulers_db
|
||||||
from neutron.db.vpn import vpn_db
|
from neutron.db.vpn import vpn_db
|
||||||
from neutron import extensions
|
from neutron import extensions
|
||||||
from neutron.extensions import vpnaas
|
from neutron.extensions import vpnaas
|
||||||
@ -46,8 +47,8 @@ ROOTDIR = os.path.normpath(os.path.join(
|
|||||||
extensions_path = ':'.join(extensions.__path__)
|
extensions_path = ':'.join(extensions.__path__)
|
||||||
|
|
||||||
|
|
||||||
class TestVpnCorePlugin(test_l3_plugin.TestL3NatPlugin,
|
class TestVpnCorePlugin(test_l3_plugin.TestL3NatIntPlugin,
|
||||||
agentschedulers_db.L3AgentSchedulerDbMixin,
|
l3_agentschedulers_db.L3AgentSchedulerDbMixin,
|
||||||
agentschedulers_db.DhcpAgentSchedulerDbMixin):
|
agentschedulers_db.DhcpAgentSchedulerDbMixin):
|
||||||
def __init__(self, configfile=None):
|
def __init__(self, configfile=None):
|
||||||
super(TestVpnCorePlugin, self).__init__()
|
super(TestVpnCorePlugin, self).__init__()
|
||||||
|
@ -32,7 +32,7 @@ PLUGIN_NAME = ('neutron.plugins.embrane.plugins.embrane_fake_plugin.'
|
|||||||
sys.modules["heleosapi"] = mock.Mock()
|
sys.modules["heleosapi"] = mock.Mock()
|
||||||
|
|
||||||
|
|
||||||
class TestEmbraneL3NatDBTestCase(router_test.L3NatDBTestCase):
|
class TestEmbraneL3NatDBTestCase(router_test.L3NatDBIntTestCase):
|
||||||
_plugin_name = PLUGIN_NAME
|
_plugin_name = PLUGIN_NAME
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -42,5 +42,5 @@ class TestEmbraneL3NatDBTestCase(router_test.L3NatDBTestCase):
|
|||||||
super(TestEmbraneL3NatDBTestCase, self).setUp()
|
super(TestEmbraneL3NatDBTestCase, self).setUp()
|
||||||
|
|
||||||
|
|
||||||
class ExtraRouteDBTestCase(extraroute_test.ExtraRouteDBTestCase):
|
class ExtraRouteDBTestCase(extraroute_test.ExtraRouteDBIntTestCase):
|
||||||
_plugin_name = PLUGIN_NAME
|
_plugin_name = PLUGIN_NAME
|
||||||
|
@ -20,11 +20,13 @@ from neutron.tests.unit.openvswitch import test_agent_scheduler
|
|||||||
class LbAgentSchedulerTestCase(
|
class LbAgentSchedulerTestCase(
|
||||||
test_agent_scheduler.OvsAgentSchedulerTestCase):
|
test_agent_scheduler.OvsAgentSchedulerTestCase):
|
||||||
plugin_str = test_linuxbridge_plugin.PLUGIN_NAME
|
plugin_str = test_linuxbridge_plugin.PLUGIN_NAME
|
||||||
|
l3_plugin = None
|
||||||
|
|
||||||
|
|
||||||
class LbL3AgentNotifierTestCase(
|
class LbL3AgentNotifierTestCase(
|
||||||
test_agent_scheduler.OvsL3AgentNotifierTestCase):
|
test_agent_scheduler.OvsL3AgentNotifierTestCase):
|
||||||
plugin_str = test_linuxbridge_plugin.PLUGIN_NAME
|
plugin_str = test_linuxbridge_plugin.PLUGIN_NAME
|
||||||
|
l3_plugin = None
|
||||||
|
|
||||||
|
|
||||||
class LbDhcpAgentNotifierTestCase(
|
class LbDhcpAgentNotifierTestCase(
|
||||||
|
@ -15,12 +15,14 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
|
from neutron.db import external_net_db
|
||||||
from neutron.db import l3_gwmode_db
|
from neutron.db import l3_gwmode_db
|
||||||
|
|
||||||
|
|
||||||
class Fake1(db_base_plugin_v2.NeutronDbPluginV2,
|
class Fake1(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
|
external_net_db.External_net_db_mixin,
|
||||||
l3_gwmode_db.L3_NAT_db_mixin):
|
l3_gwmode_db.L3_NAT_db_mixin):
|
||||||
supported_extension_aliases = ['router']
|
supported_extension_aliases = ['external-net', 'router']
|
||||||
|
|
||||||
def fake_func(self):
|
def fake_func(self):
|
||||||
return 'fake1'
|
return 'fake1'
|
||||||
|
@ -72,6 +72,6 @@ class TestMetaSubnetsV2(test_plugin.TestSubnetsV2,
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TestMetaL3NatDBTestCase(test_l3_plugin.L3NatDBTestCase,
|
class TestMetaL3NatDBTestCase(test_l3_plugin.L3NatDBIntTestCase,
|
||||||
MetaPluginV2DBTestCase):
|
MetaPluginV2DBTestCase):
|
||||||
pass
|
pass
|
||||||
|
@ -20,11 +20,15 @@ from neutron.tests.unit.openvswitch import test_agent_scheduler
|
|||||||
class Ml2AgentSchedulerTestCase(
|
class Ml2AgentSchedulerTestCase(
|
||||||
test_agent_scheduler.OvsAgentSchedulerTestCase):
|
test_agent_scheduler.OvsAgentSchedulerTestCase):
|
||||||
plugin_str = test_ml2_plugin.PLUGIN_NAME
|
plugin_str = test_ml2_plugin.PLUGIN_NAME
|
||||||
|
l3_plugin = ('neutron.services.l3_router.'
|
||||||
|
'l3_router_plugin.L3RouterPlugin')
|
||||||
|
|
||||||
|
|
||||||
class Ml2L3AgentNotifierTestCase(
|
class Ml2L3AgentNotifierTestCase(
|
||||||
test_agent_scheduler.OvsL3AgentNotifierTestCase):
|
test_agent_scheduler.OvsL3AgentNotifierTestCase):
|
||||||
plugin_str = test_ml2_plugin.PLUGIN_NAME
|
plugin_str = test_ml2_plugin.PLUGIN_NAME
|
||||||
|
l3_plugin = ('neutron.services.l3_router.'
|
||||||
|
'l3_router_plugin.L3RouterPlugin')
|
||||||
|
|
||||||
|
|
||||||
class Ml2DhcpAgentNotifierTestCase(
|
class Ml2DhcpAgentNotifierTestCase(
|
||||||
|
@ -19,7 +19,6 @@ from neutron.extensions import providernet as pnet
|
|||||||
from neutron.plugins.ml2 import config
|
from neutron.plugins.ml2 import config
|
||||||
from neutron.tests.unit import _test_extension_portbindings as test_bindings
|
from neutron.tests.unit import _test_extension_portbindings as test_bindings
|
||||||
from neutron.tests.unit import test_db_plugin as test_plugin
|
from neutron.tests.unit import test_db_plugin as test_plugin
|
||||||
from neutron.tests.unit import test_extension_ext_gw_mode
|
|
||||||
from neutron.tests.unit import test_security_groups_rpc as test_sg_rpc
|
from neutron.tests.unit import test_security_groups_rpc as test_sg_rpc
|
||||||
|
|
||||||
|
|
||||||
@ -31,6 +30,10 @@ class Ml2PluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
|
|||||||
_plugin_name = PLUGIN_NAME
|
_plugin_name = PLUGIN_NAME
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
# We need a L3 service plugin
|
||||||
|
l3_plugin = ('neutron.tests.unit.test_l3_plugin.'
|
||||||
|
'TestL3NatServicePlugin')
|
||||||
|
service_plugins = {'l3_plugin_name': l3_plugin}
|
||||||
# Enable the test mechanism driver to ensure that
|
# Enable the test mechanism driver to ensure that
|
||||||
# we can successfully call through to all mechanism
|
# we can successfully call through to all mechanism
|
||||||
# driver apis.
|
# driver apis.
|
||||||
@ -43,7 +46,8 @@ class Ml2PluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
|
|||||||
config.cfg.CONF.set_override('network_vlan_ranges', [self.phys_vrange],
|
config.cfg.CONF.set_override('network_vlan_ranges', [self.phys_vrange],
|
||||||
group='ml2_type_vlan')
|
group='ml2_type_vlan')
|
||||||
self.addCleanup(config.cfg.CONF.reset)
|
self.addCleanup(config.cfg.CONF.reset)
|
||||||
super(Ml2PluginV2TestCase, self).setUp(PLUGIN_NAME)
|
super(Ml2PluginV2TestCase, self).setUp(PLUGIN_NAME,
|
||||||
|
service_plugins=service_plugins)
|
||||||
self.port_create_status = 'DOWN'
|
self.port_create_status = 'DOWN'
|
||||||
|
|
||||||
|
|
||||||
@ -93,11 +97,6 @@ class TestMl2PortBindingHost(Ml2PluginV2TestCase,
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TestMl2ExtGwModeSupport(Ml2PluginV2TestCase,
|
|
||||||
test_extension_ext_gw_mode.ExtGwModeTestCase):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class TestMultiSegmentNetworks(Ml2PluginV2TestCase):
|
class TestMultiSegmentNetworks(Ml2PluginV2TestCase):
|
||||||
|
|
||||||
def setUp(self, plugin=None):
|
def setUp(self, plugin=None):
|
||||||
|
@ -20,11 +20,13 @@ from neutron.tests.unit.openvswitch import test_agent_scheduler
|
|||||||
class MlnxAgentSchedulerTestCase(
|
class MlnxAgentSchedulerTestCase(
|
||||||
test_agent_scheduler.OvsAgentSchedulerTestCase):
|
test_agent_scheduler.OvsAgentSchedulerTestCase):
|
||||||
plugin_str = test_mlnx_plugin.PLUGIN_NAME
|
plugin_str = test_mlnx_plugin.PLUGIN_NAME
|
||||||
|
l3_plugin = None
|
||||||
|
|
||||||
|
|
||||||
class MlnxL3AgentNotifierTestCase(
|
class MlnxL3AgentNotifierTestCase(
|
||||||
test_agent_scheduler.OvsL3AgentNotifierTestCase):
|
test_agent_scheduler.OvsL3AgentNotifierTestCase):
|
||||||
plugin_str = test_mlnx_plugin.PLUGIN_NAME
|
plugin_str = test_mlnx_plugin.PLUGIN_NAME
|
||||||
|
l3_plugin = None
|
||||||
|
|
||||||
|
|
||||||
class MlnxDhcpAgentNotifierTestCase(
|
class MlnxDhcpAgentNotifierTestCase(
|
||||||
|
@ -31,6 +31,7 @@ class NecAgentSchedulerTestCase(
|
|||||||
test_nec_plugin.NecPluginV2TestCaseBase):
|
test_nec_plugin.NecPluginV2TestCaseBase):
|
||||||
|
|
||||||
plugin_str = test_nec_plugin.PLUGIN_NAME
|
plugin_str = test_nec_plugin.PLUGIN_NAME
|
||||||
|
l3_plugin = None
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.setup_nec_plugin_base()
|
self.setup_nec_plugin_base()
|
||||||
@ -54,6 +55,7 @@ class NecL3AgentNotifierTestCase(
|
|||||||
test_nec_plugin.NecPluginV2TestCaseBase):
|
test_nec_plugin.NecPluginV2TestCaseBase):
|
||||||
|
|
||||||
plugin_str = test_nec_plugin.PLUGIN_NAME
|
plugin_str = test_nec_plugin.PLUGIN_NAME
|
||||||
|
l3_plugin = None
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
# OvsDhcpAgentNotifierTestCase uses stop() for each mock.
|
# OvsDhcpAgentNotifierTestCase uses stop() for each mock.
|
||||||
|
@ -21,7 +21,7 @@ from neutron.tests.unit.nec import test_nec_plugin
|
|||||||
from neutron.tests.unit import test_extension_extraroute as test_ext_route
|
from neutron.tests.unit import test_extension_extraroute as test_ext_route
|
||||||
|
|
||||||
|
|
||||||
class NecRouterL3AgentTestCase(test_ext_route.ExtraRouteDBTestCase):
|
class NecRouterL3AgentTestCase(test_ext_route.ExtraRouteDBIntTestCase):
|
||||||
|
|
||||||
_plugin_name = test_nec_plugin.PLUGIN_NAME
|
_plugin_name = test_nec_plugin.PLUGIN_NAME
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ from neutron.common import constants
|
|||||||
from neutron.common import exceptions as ntn_exc
|
from neutron.common import exceptions as ntn_exc
|
||||||
import neutron.common.test_lib as test_lib
|
import neutron.common.test_lib as test_lib
|
||||||
from neutron import context
|
from neutron import context
|
||||||
|
from neutron.extensions import external_net
|
||||||
from neutron.extensions import l3
|
from neutron.extensions import l3
|
||||||
from neutron.extensions import l3_ext_gw_mode
|
from neutron.extensions import l3_ext_gw_mode
|
||||||
from neutron.extensions import multiprovidernet as mpnet
|
from neutron.extensions import multiprovidernet as mpnet
|
||||||
@ -73,6 +74,13 @@ class NiciraPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
|
|||||||
data = {'network': {'name': name,
|
data = {'network': {'name': name,
|
||||||
'admin_state_up': admin_state_up,
|
'admin_state_up': admin_state_up,
|
||||||
'tenant_id': self._tenant_id}}
|
'tenant_id': self._tenant_id}}
|
||||||
|
# Fix to allow the router:external attribute and any other
|
||||||
|
# attributes containing a colon to be passed with
|
||||||
|
# a double underscore instead
|
||||||
|
kwargs = dict((k.replace('__', ':'), v) for k, v in kwargs.items())
|
||||||
|
if external_net.EXTERNAL in kwargs:
|
||||||
|
arg_list = (external_net.EXTERNAL, ) + (arg_list or ())
|
||||||
|
|
||||||
attrs = kwargs
|
attrs = kwargs
|
||||||
if providernet_args:
|
if providernet_args:
|
||||||
attrs.update(providernet_args)
|
attrs.update(providernet_args)
|
||||||
@ -427,7 +435,7 @@ class TestNiciraL3ExtensionManager(object):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
class TestNiciraL3NatTestCase(test_l3_plugin.L3NatDBTestCase,
|
class TestNiciraL3NatTestCase(test_l3_plugin.L3NatDBIntTestCase,
|
||||||
NiciraPluginV2TestCase):
|
NiciraPluginV2TestCase):
|
||||||
|
|
||||||
def _restore_l3_attribute_map(self):
|
def _restore_l3_attribute_map(self):
|
||||||
@ -465,7 +473,7 @@ class TestNiciraL3NatTestCase(test_l3_plugin.L3NatDBTestCase,
|
|||||||
net_type = NeutronPlugin.NetworkTypes.L3_EXT
|
net_type = NeutronPlugin.NetworkTypes.L3_EXT
|
||||||
expected = [('subnets', []), ('name', name), ('admin_state_up', True),
|
expected = [('subnets', []), ('name', name), ('admin_state_up', True),
|
||||||
('status', 'ACTIVE'), ('shared', False),
|
('status', 'ACTIVE'), ('shared', False),
|
||||||
(l3.EXTERNAL, True),
|
(external_net.EXTERNAL, True),
|
||||||
(pnet.NETWORK_TYPE, net_type),
|
(pnet.NETWORK_TYPE, net_type),
|
||||||
(pnet.PHYSICAL_NETWORK, 'l3_gw_uuid'),
|
(pnet.PHYSICAL_NETWORK, 'l3_gw_uuid'),
|
||||||
(pnet.SEGMENTATION_ID, vlan_id)]
|
(pnet.SEGMENTATION_ID, vlan_id)]
|
||||||
@ -1137,14 +1145,16 @@ class TestNiciraQoSQueue(NiciraPluginV2TestCase):
|
|||||||
|
|
||||||
|
|
||||||
class NiciraExtGwModeTestCase(NiciraPluginV2TestCase,
|
class NiciraExtGwModeTestCase(NiciraPluginV2TestCase,
|
||||||
test_ext_gw_mode.ExtGwModeTestCase):
|
test_ext_gw_mode.ExtGwModeIntTestCase):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class NiciraNeutronNVPOutOfSync(NiciraPluginV2TestCase,
|
class NiciraNeutronNVPOutOfSync(NiciraPluginV2TestCase,
|
||||||
test_l3_plugin.L3NatTestCaseBase):
|
test_l3_plugin.L3NatTestCaseMixin):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
ext_mgr = test_l3_plugin.L3TestExtensionManager()
|
||||||
|
test_lib.test_config['extension_manager'] = ext_mgr
|
||||||
super(NiciraNeutronNVPOutOfSync, self).setUp()
|
super(NiciraNeutronNVPOutOfSync, self).setUp()
|
||||||
|
|
||||||
def test_delete_network_not_in_nvp(self):
|
def test_delete_network_not_in_nvp(self):
|
||||||
@ -1246,7 +1256,7 @@ class NiciraNeutronNVPOutOfSync(NiciraPluginV2TestCase,
|
|||||||
net_id = net['network']['id']
|
net_id = net['network']['id']
|
||||||
if external:
|
if external:
|
||||||
self._update('networks', net_id,
|
self._update('networks', net_id,
|
||||||
{'network': {l3.EXTERNAL: True}})
|
{'network': {external_net.EXTERNAL: True}})
|
||||||
sub_res = self._create_subnet('json', net_id, cidr)
|
sub_res = self._create_subnet('json', net_id, cidr)
|
||||||
sub = self.deserialize('json', sub_res)
|
sub = self.deserialize('json', sub_res)
|
||||||
return net_id, sub['subnet']['id']
|
return net_id, sub['subnet']['id']
|
||||||
|
@ -288,10 +288,15 @@ class NvpSyncTestCase(base.BaseTestCase):
|
|||||||
'--config-file', get_fake_conf('nvp.ini.test')]
|
'--config-file', get_fake_conf('nvp.ini.test')]
|
||||||
config.parse(args=args)
|
config.parse(args=args)
|
||||||
self._plugin = NeutronPlugin.NvpPluginV2()
|
self._plugin = NeutronPlugin.NvpPluginV2()
|
||||||
|
mock_nm_get_plugin = mock.patch('neutron.manager.NeutronManager.'
|
||||||
|
'get_plugin')
|
||||||
|
self.mock_nm_get_plugin = mock_nm_get_plugin.start()
|
||||||
|
self.mock_nm_get_plugin.return_value = self._plugin
|
||||||
super(NvpSyncTestCase, self).setUp()
|
super(NvpSyncTestCase, self).setUp()
|
||||||
self.addCleanup(self.fc.reset_all)
|
self.addCleanup(self.fc.reset_all)
|
||||||
self.addCleanup(patch_sync.stop)
|
self.addCleanup(patch_sync.stop)
|
||||||
self.addCleanup(mock_nvpapi.stop)
|
self.addCleanup(mock_nvpapi.stop)
|
||||||
|
self.addCleanup(mock_nm_get_plugin.stop)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
cfg.CONF.reset()
|
cfg.CONF.reset()
|
||||||
|
@ -34,6 +34,7 @@ from neutron.extensions import l3agentscheduler
|
|||||||
from neutron import manager
|
from neutron import manager
|
||||||
from neutron.openstack.common import timeutils
|
from neutron.openstack.common import timeutils
|
||||||
from neutron.openstack.common import uuidutils
|
from neutron.openstack.common import uuidutils
|
||||||
|
from neutron.plugins.common import constants as service_constants
|
||||||
from neutron.tests.unit import test_agent_ext_plugin
|
from neutron.tests.unit import test_agent_ext_plugin
|
||||||
from neutron.tests.unit import test_db_plugin as test_plugin
|
from neutron.tests.unit import test_db_plugin as test_plugin
|
||||||
from neutron.tests.unit import test_extensions
|
from neutron.tests.unit import test_extensions
|
||||||
@ -196,13 +197,19 @@ class OvsAgentSchedulerTestCaseBase(test_l3_plugin.L3NatTestCaseMixin,
|
|||||||
fmt = 'json'
|
fmt = 'json'
|
||||||
plugin_str = ('neutron.plugins.openvswitch.'
|
plugin_str = ('neutron.plugins.openvswitch.'
|
||||||
'ovs_neutron_plugin.OVSNeutronPluginV2')
|
'ovs_neutron_plugin.OVSNeutronPluginV2')
|
||||||
|
l3_plugin = None
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
# Save the global RESOURCE_ATTRIBUTE_MAP
|
# Save the global RESOURCE_ATTRIBUTE_MAP
|
||||||
self.saved_attr_map = {}
|
self.saved_attr_map = {}
|
||||||
for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.iteritems():
|
for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.iteritems():
|
||||||
self.saved_attr_map[resource] = attrs.copy()
|
self.saved_attr_map[resource] = attrs.copy()
|
||||||
super(OvsAgentSchedulerTestCaseBase, self).setUp(self.plugin_str)
|
if self.l3_plugin:
|
||||||
|
service_plugins = {'l3_plugin_name': self.l3_plugin}
|
||||||
|
else:
|
||||||
|
service_plugins = None
|
||||||
|
super(OvsAgentSchedulerTestCaseBase, self).setUp(
|
||||||
|
self.plugin_str, service_plugins=service_plugins)
|
||||||
ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
|
ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
|
||||||
self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)
|
self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)
|
||||||
self.adminContext = context.get_admin_context()
|
self.adminContext = context.get_admin_context()
|
||||||
@ -213,7 +220,9 @@ class OvsAgentSchedulerTestCaseBase(test_l3_plugin.L3NatTestCaseMixin,
|
|||||||
attributes.RESOURCE_ATTRIBUTE_MAP.update(
|
attributes.RESOURCE_ATTRIBUTE_MAP.update(
|
||||||
agent.RESOURCE_ATTRIBUTE_MAP)
|
agent.RESOURCE_ATTRIBUTE_MAP)
|
||||||
self.addCleanup(self.restore_attribute_map)
|
self.addCleanup(self.restore_attribute_map)
|
||||||
self.agentscheduler_dbMinxin = manager.NeutronManager.get_plugin()
|
self.l3agentscheduler_dbMinxin = (
|
||||||
|
manager.NeutronManager.get_service_plugins().get(
|
||||||
|
service_constants.L3_ROUTER_NAT))
|
||||||
|
|
||||||
def restore_attribute_map(self):
|
def restore_attribute_map(self):
|
||||||
# Restore the original RESOURCE_ATTRIBUTE_MAP
|
# Restore the original RESOURCE_ATTRIBUTE_MAP
|
||||||
@ -822,7 +831,7 @@ class OvsAgentSchedulerTestCase(OvsAgentSchedulerTestCaseBase):
|
|||||||
res = router_req.get_response(self.ext_api)
|
res = router_req.get_response(self.ext_api)
|
||||||
router = self.deserialize(self.fmt, res)
|
router = self.deserialize(self.fmt, res)
|
||||||
l3agents = (
|
l3agents = (
|
||||||
self.agentscheduler_dbMinxin.get_l3_agents_hosting_routers(
|
self.l3agentscheduler_dbMinxin.get_l3_agents_hosting_routers(
|
||||||
self.adminContext, [router['router']['id']]))
|
self.adminContext, [router['router']['id']]))
|
||||||
self._delete('routers', router['router']['id'])
|
self._delete('routers', router['router']['id'])
|
||||||
self.assertEqual(0, len(l3agents))
|
self.assertEqual(0, len(l3agents))
|
||||||
@ -960,7 +969,12 @@ class OvsAgentSchedulerTestCase(OvsAgentSchedulerTestCaseBase):
|
|||||||
admin_context=False)
|
admin_context=False)
|
||||||
|
|
||||||
|
|
||||||
class OvsDhcpAgentNotifierTestCase(OvsAgentSchedulerTestCaseBase):
|
class OvsDhcpAgentNotifierTestCase(test_l3_plugin.L3NatTestCaseMixin,
|
||||||
|
test_agent_ext_plugin.AgentDBTestMixIn,
|
||||||
|
AgentSchedulerTestMixIn,
|
||||||
|
test_plugin.NeutronDbPluginV2TestCase):
|
||||||
|
plugin_str = ('neutron.plugins.openvswitch.'
|
||||||
|
'ovs_neutron_plugin.OVSNeutronPluginV2')
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.dhcp_notifier = dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
|
self.dhcp_notifier = dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
|
||||||
@ -969,8 +983,26 @@ class OvsDhcpAgentNotifierTestCase(OvsAgentSchedulerTestCaseBase):
|
|||||||
'DhcpAgentNotifyAPI')
|
'DhcpAgentNotifyAPI')
|
||||||
self.dhcp_notifier_cls = self.dhcp_notifier_cls_p.start()
|
self.dhcp_notifier_cls = self.dhcp_notifier_cls_p.start()
|
||||||
self.dhcp_notifier_cls.return_value = self.dhcp_notifier
|
self.dhcp_notifier_cls.return_value = self.dhcp_notifier
|
||||||
super(OvsDhcpAgentNotifierTestCase, self).setUp()
|
# Save the global RESOURCE_ATTRIBUTE_MAP
|
||||||
|
self.saved_attr_map = {}
|
||||||
|
for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.iteritems():
|
||||||
|
self.saved_attr_map[resource] = attrs.copy()
|
||||||
|
super(OvsDhcpAgentNotifierTestCase, self).setUp(self.plugin_str)
|
||||||
|
ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
|
||||||
|
self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)
|
||||||
|
self.adminContext = context.get_admin_context()
|
||||||
|
# Add the resources to the global attribute map
|
||||||
|
# This is done here as the setup process won't
|
||||||
|
# initialize the main API router which extends
|
||||||
|
# the global attribute map
|
||||||
|
attributes.RESOURCE_ATTRIBUTE_MAP.update(
|
||||||
|
agent.RESOURCE_ATTRIBUTE_MAP)
|
||||||
self.addCleanup(self.dhcp_notifier_cls_p.stop)
|
self.addCleanup(self.dhcp_notifier_cls_p.stop)
|
||||||
|
self.addCleanup(self.restore_attribute_map)
|
||||||
|
|
||||||
|
def restore_attribute_map(self):
|
||||||
|
# Restore the original RESOURCE_ATTRIBUTE_MAP
|
||||||
|
attributes.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
|
||||||
|
|
||||||
def test_network_add_to_dhcp_agent_notification(self):
|
def test_network_add_to_dhcp_agent_notification(self):
|
||||||
with mock.patch.object(self.dhcp_notifier, 'cast') as mock_dhcp:
|
with mock.patch.object(self.dhcp_notifier, 'cast') as mock_dhcp:
|
||||||
@ -1081,7 +1113,13 @@ class OvsDhcpAgentNotifierTestCase(OvsAgentSchedulerTestCaseBase):
|
|||||||
self.assertIn(expected, mock_dhcp.call_args_list)
|
self.assertIn(expected, mock_dhcp.call_args_list)
|
||||||
|
|
||||||
|
|
||||||
class OvsL3AgentNotifierTestCase(OvsAgentSchedulerTestCaseBase):
|
class OvsL3AgentNotifierTestCase(test_l3_plugin.L3NatTestCaseMixin,
|
||||||
|
test_agent_ext_plugin.AgentDBTestMixIn,
|
||||||
|
AgentSchedulerTestMixIn,
|
||||||
|
test_plugin.NeutronDbPluginV2TestCase):
|
||||||
|
plugin_str = ('neutron.plugins.openvswitch.'
|
||||||
|
'ovs_neutron_plugin.OVSNeutronPluginV2')
|
||||||
|
l3_plugin = None
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.dhcp_notifier_cls_p = mock.patch(
|
self.dhcp_notifier_cls_p = mock.patch(
|
||||||
@ -1090,8 +1128,31 @@ class OvsL3AgentNotifierTestCase(OvsAgentSchedulerTestCaseBase):
|
|||||||
self.dhcp_notifier = mock.Mock(name='dhcp_notifier')
|
self.dhcp_notifier = mock.Mock(name='dhcp_notifier')
|
||||||
self.dhcp_notifier_cls = self.dhcp_notifier_cls_p.start()
|
self.dhcp_notifier_cls = self.dhcp_notifier_cls_p.start()
|
||||||
self.dhcp_notifier_cls.return_value = self.dhcp_notifier
|
self.dhcp_notifier_cls.return_value = self.dhcp_notifier
|
||||||
super(OvsL3AgentNotifierTestCase, self).setUp()
|
# Save the global RESOURCE_ATTRIBUTE_MAP
|
||||||
|
self.saved_attr_map = {}
|
||||||
|
for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.iteritems():
|
||||||
|
self.saved_attr_map[resource] = attrs.copy()
|
||||||
|
if self.l3_plugin:
|
||||||
|
service_plugins = {'l3_plugin_name': self.l3_plugin}
|
||||||
|
else:
|
||||||
|
service_plugins = None
|
||||||
|
super(OvsL3AgentNotifierTestCase, self).setUp(
|
||||||
|
self.plugin_str, service_plugins=service_plugins)
|
||||||
|
ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
|
||||||
|
self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)
|
||||||
|
self.adminContext = context.get_admin_context()
|
||||||
|
# Add the resources to the global attribute map
|
||||||
|
# This is done here as the setup process won't
|
||||||
|
# initialize the main API router which extends
|
||||||
|
# the global attribute map
|
||||||
|
attributes.RESOURCE_ATTRIBUTE_MAP.update(
|
||||||
|
agent.RESOURCE_ATTRIBUTE_MAP)
|
||||||
self.addCleanup(self.dhcp_notifier_cls_p.stop)
|
self.addCleanup(self.dhcp_notifier_cls_p.stop)
|
||||||
|
self.addCleanup(self.restore_attribute_map)
|
||||||
|
|
||||||
|
def restore_attribute_map(self):
|
||||||
|
# Restore the original RESOURCE_ATTRIBUTE_MAP
|
||||||
|
attributes.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
|
||||||
|
|
||||||
def test_router_add_to_l3_agent_notification(self):
|
def test_router_add_to_l3_agent_notification(self):
|
||||||
plugin = manager.NeutronManager.get_plugin()
|
plugin = manager.NeutronManager.get_plugin()
|
||||||
|
@ -20,7 +20,7 @@ from neutron.api.v2 import attributes as attr
|
|||||||
from neutron.common.test_lib import test_config
|
from neutron.common.test_lib import test_config
|
||||||
from neutron import context
|
from neutron import context
|
||||||
from neutron.db import agents_db
|
from neutron.db import agents_db
|
||||||
from neutron.db import agentschedulers_db
|
from neutron.db import l3_agentschedulers_db
|
||||||
from neutron.extensions import l3 as ext_l3
|
from neutron.extensions import l3 as ext_l3
|
||||||
from neutron.extensions import metering as ext_metering
|
from neutron.extensions import metering as ext_metering
|
||||||
from neutron.openstack.common import uuidutils
|
from neutron.openstack.common import uuidutils
|
||||||
@ -68,7 +68,7 @@ class TestMeteringPlugin(test_db_plugin.NeutronDbPluginV2TestCase,
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
service_plugins = {'metering_plugin_name': DB_METERING_PLUGIN_KLASS}
|
service_plugins = {'metering_plugin_name': DB_METERING_PLUGIN_KLASS}
|
||||||
test_config['plugin_name_v2'] = ('neutron.tests.unit.test_l3_plugin.'
|
test_config['plugin_name_v2'] = ('neutron.tests.unit.test_l3_plugin.'
|
||||||
'TestL3NatPlugin')
|
'TestL3NatIntPlugin')
|
||||||
ext_mgr = MeteringTestExtensionManager()
|
ext_mgr = MeteringTestExtensionManager()
|
||||||
test_config['extension_manager'] = ext_mgr
|
test_config['extension_manager'] = ext_mgr
|
||||||
super(TestMeteringPlugin, self).setUp(service_plugins=service_plugins)
|
super(TestMeteringPlugin, self).setUp(service_plugins=service_plugins)
|
||||||
@ -249,8 +249,8 @@ class TestMeteringPlugin(test_db_plugin.NeutronDbPluginV2TestCase,
|
|||||||
topic=self.topic)
|
topic=self.topic)
|
||||||
|
|
||||||
|
|
||||||
class TestRoutePlugin(agentschedulers_db.L3AgentSchedulerDbMixin,
|
class TestRouteIntPlugin(l3_agentschedulers_db.L3AgentSchedulerDbMixin,
|
||||||
test_l3_plugin.TestL3NatPlugin):
|
test_l3_plugin.TestL3NatIntPlugin):
|
||||||
supported_extension_aliases = ["router", "l3_agent_scheduler"]
|
supported_extension_aliases = ["router", "l3_agent_scheduler"]
|
||||||
|
|
||||||
|
|
||||||
@ -268,7 +268,7 @@ class TestMeteringPluginL3AgentScheduler(
|
|||||||
service_plugins = {'metering_plugin_name': DB_METERING_PLUGIN_KLASS}
|
service_plugins = {'metering_plugin_name': DB_METERING_PLUGIN_KLASS}
|
||||||
|
|
||||||
plugin_str = ('neutron.tests.unit.services.metering.'
|
plugin_str = ('neutron.tests.unit.services.metering.'
|
||||||
'test_metering_plugin.TestRoutePlugin')
|
'test_metering_plugin.TestRouteIntPlugin')
|
||||||
test_config['plugin_name_v2'] = plugin_str
|
test_config['plugin_name_v2'] = plugin_str
|
||||||
|
|
||||||
ext_mgr = MeteringTestExtensionManager()
|
ext_mgr = MeteringTestExtensionManager()
|
||||||
|
@ -27,6 +27,7 @@ from webob import exc
|
|||||||
|
|
||||||
from neutron.common import constants
|
from neutron.common import constants
|
||||||
from neutron.db import api as db_api
|
from neutron.db import api as db_api
|
||||||
|
from neutron.db import external_net_db
|
||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
from neutron.db import l3_gwmode_db
|
from neutron.db import l3_gwmode_db
|
||||||
from neutron.db import models_v2
|
from neutron.db import models_v2
|
||||||
@ -84,8 +85,17 @@ class TestExtensionManager(object):
|
|||||||
|
|
||||||
|
|
||||||
# A simple class for making a concrete class out of the mixin
|
# A simple class for making a concrete class out of the mixin
|
||||||
class TestDbPlugin(test_l3_plugin.TestL3NatPlugin,
|
# for the case of a plugin that integrates l3 routing.
|
||||||
l3_gwmode_db.L3_NAT_db_mixin):
|
class TestDbIntPlugin(test_l3_plugin.TestL3NatIntPlugin,
|
||||||
|
l3_gwmode_db.L3_NAT_db_mixin):
|
||||||
|
|
||||||
|
supported_extension_aliases = ["external-net", "router", "ext-gw-mode"]
|
||||||
|
|
||||||
|
|
||||||
|
# A simple class for making a concrete class out of the mixin
|
||||||
|
# for the case of a l3 router service plugin
|
||||||
|
class TestDbSepPlugin(test_l3_plugin.TestL3NatServicePlugin,
|
||||||
|
l3_gwmode_db.L3_NAT_db_mixin):
|
||||||
|
|
||||||
supported_extension_aliases = ["router", "ext-gw-mode"]
|
supported_extension_aliases = ["router", "ext-gw-mode"]
|
||||||
|
|
||||||
@ -96,7 +106,7 @@ class TestL3GwModeMixin(base.BaseTestCase):
|
|||||||
super(TestL3GwModeMixin, self).setUp()
|
super(TestL3GwModeMixin, self).setUp()
|
||||||
stubout_fixture = self.useFixture(StuboutFixture())
|
stubout_fixture = self.useFixture(StuboutFixture())
|
||||||
self.stubs = stubout_fixture.stubs
|
self.stubs = stubout_fixture.stubs
|
||||||
self.target_object = TestDbPlugin()
|
self.target_object = TestDbIntPlugin()
|
||||||
# Patch the context
|
# Patch the context
|
||||||
ctx_patcher = mock.patch('neutron.context', autospec=True)
|
ctx_patcher = mock.patch('neutron.context', autospec=True)
|
||||||
mock_context = ctx_patcher.start()
|
mock_context = ctx_patcher.start()
|
||||||
@ -116,7 +126,8 @@ class TestL3GwModeMixin(base.BaseTestCase):
|
|||||||
tenant_id=self.tenant_id,
|
tenant_id=self.tenant_id,
|
||||||
admin_state_up=True,
|
admin_state_up=True,
|
||||||
status=constants.NET_STATUS_ACTIVE)
|
status=constants.NET_STATUS_ACTIVE)
|
||||||
self.net_ext = l3_db.ExternalNetwork(network_id=self.ext_net_id)
|
self.net_ext = external_net_db.ExternalNetwork(
|
||||||
|
network_id=self.ext_net_id)
|
||||||
self.context.session.add(self.network)
|
self.context.session.add(self.network)
|
||||||
# The following is to avoid complains from sqlite on
|
# The following is to avoid complains from sqlite on
|
||||||
# foreign key violations
|
# foreign key violations
|
||||||
@ -297,29 +308,30 @@ class TestL3GwModeMixin(base.BaseTestCase):
|
|||||||
self.assertFalse(router.get('enable_snat'))
|
self.assertFalse(router.get('enable_snat'))
|
||||||
|
|
||||||
|
|
||||||
class ExtGwModeTestCase(test_db_plugin.NeutronDbPluginV2TestCase,
|
class ExtGwModeIntTestCase(test_db_plugin.NeutronDbPluginV2TestCase,
|
||||||
test_l3_plugin.L3NatTestCaseMixin):
|
test_l3_plugin.L3NatTestCaseMixin):
|
||||||
|
|
||||||
def setUp(self, plugin=None, ext_mgr=None):
|
def setUp(self, plugin=None, svc_plugins=None, ext_mgr=None):
|
||||||
# Store l3 resource attribute map as it will be updated
|
# Store l3 resource attribute map as it will be updated
|
||||||
self._l3_attribute_map_bk = {}
|
self._l3_attribute_map_bk = {}
|
||||||
for item in l3.RESOURCE_ATTRIBUTE_MAP:
|
for item in l3.RESOURCE_ATTRIBUTE_MAP:
|
||||||
self._l3_attribute_map_bk[item] = (
|
self._l3_attribute_map_bk[item] = (
|
||||||
l3.RESOURCE_ATTRIBUTE_MAP[item].copy())
|
l3.RESOURCE_ATTRIBUTE_MAP[item].copy())
|
||||||
plugin = plugin or (
|
plugin = plugin or (
|
||||||
'neutron.tests.unit.test_extension_ext_gw_mode.TestDbPlugin')
|
'neutron.tests.unit.test_extension_ext_gw_mode.TestDbIntPlugin')
|
||||||
# for these tests we need to enable overlapping ips
|
# for these tests we need to enable overlapping ips
|
||||||
cfg.CONF.set_default('allow_overlapping_ips', True)
|
cfg.CONF.set_default('allow_overlapping_ips', True)
|
||||||
ext_mgr = ext_mgr or TestExtensionManager()
|
ext_mgr = ext_mgr or TestExtensionManager()
|
||||||
super(ExtGwModeTestCase, self).setUp(plugin=plugin,
|
super(ExtGwModeIntTestCase, self).setUp(plugin=plugin,
|
||||||
ext_mgr=ext_mgr)
|
ext_mgr=ext_mgr,
|
||||||
|
service_plugins=svc_plugins)
|
||||||
self.addCleanup(self.restore_l3_attribute_map)
|
self.addCleanup(self.restore_l3_attribute_map)
|
||||||
|
|
||||||
def restore_l3_attribute_map(self):
|
def restore_l3_attribute_map(self):
|
||||||
l3.RESOURCE_ATTRIBUTE_MAP = self._l3_attribute_map_bk
|
l3.RESOURCE_ATTRIBUTE_MAP = self._l3_attribute_map_bk
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
super(ExtGwModeTestCase, self).tearDown()
|
super(ExtGwModeIntTestCase, self).tearDown()
|
||||||
|
|
||||||
def _set_router_external_gateway(self, router_id, network_id,
|
def _set_router_external_gateway(self, router_id, network_id,
|
||||||
snat_enabled=None,
|
snat_enabled=None,
|
||||||
@ -413,3 +425,24 @@ class ExtGwModeTestCase(test_db_plugin.NeutronDbPluginV2TestCase,
|
|||||||
def test_router_update_ext_gwinfo_with_invalid_snat_setting(self):
|
def test_router_update_ext_gwinfo_with_invalid_snat_setting(self):
|
||||||
self._test_router_update_ext_gwinfo(
|
self._test_router_update_ext_gwinfo(
|
||||||
'xxx', None, expected_http_code=exc.HTTPBadRequest.code)
|
'xxx', None, expected_http_code=exc.HTTPBadRequest.code)
|
||||||
|
|
||||||
|
|
||||||
|
class ExtGwModeSepTestCase(ExtGwModeIntTestCase):
|
||||||
|
|
||||||
|
def setUp(self, plugin=None):
|
||||||
|
# Store l3 resource attribute map as it will be updated
|
||||||
|
self._l3_attribute_map_bk = {}
|
||||||
|
for item in l3.RESOURCE_ATTRIBUTE_MAP:
|
||||||
|
self._l3_attribute_map_bk[item] = (
|
||||||
|
l3.RESOURCE_ATTRIBUTE_MAP[item].copy())
|
||||||
|
plugin = plugin or (
|
||||||
|
'neutron.tests.unit.test_l3_plugin.TestNoL3NatPlugin')
|
||||||
|
# the L3 service plugin
|
||||||
|
l3_plugin = ('neutron.tests.unit.test_extension_ext_gw_mode.'
|
||||||
|
'TestDbSepPlugin')
|
||||||
|
svc_plugins = {'l3_plugin_name': l3_plugin}
|
||||||
|
# for these tests we need to enable overlapping ips
|
||||||
|
cfg.CONF.set_default('allow_overlapping_ips', True)
|
||||||
|
super(ExtGwModeSepTestCase, self).setUp(plugin=plugin,
|
||||||
|
svc_plugins=svc_plugins)
|
||||||
|
self.addCleanup(self.restore_l3_attribute_map)
|
||||||
|
166
neutron/tests/unit/test_extension_ext_net.py
Normal file
166
neutron/tests/unit/test_extension_ext_net.py
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright (c) 2013 OpenStack Foundation.
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import contextlib
|
||||||
|
import itertools
|
||||||
|
|
||||||
|
import testtools
|
||||||
|
from webob import exc
|
||||||
|
|
||||||
|
from neutron.common.test_lib import test_config
|
||||||
|
from neutron import context
|
||||||
|
from neutron.db import models_v2
|
||||||
|
from neutron.extensions import external_net as external_net
|
||||||
|
from neutron.manager import NeutronManager
|
||||||
|
from neutron.openstack.common import log as logging
|
||||||
|
from neutron.openstack.common import uuidutils
|
||||||
|
from neutron.tests.unit import test_api_v2
|
||||||
|
from neutron.tests.unit import test_db_plugin
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
_uuid = uuidutils.generate_uuid
|
||||||
|
_get_path = test_api_v2._get_path
|
||||||
|
|
||||||
|
|
||||||
|
class ExtNetTestExtensionManager(object):
|
||||||
|
|
||||||
|
def get_resources(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_actions(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_request_extensions(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class ExtNetDBTestCase(test_db_plugin.NeutronDbPluginV2TestCase):
|
||||||
|
|
||||||
|
def _create_network(self, fmt, name, admin_state_up, **kwargs):
|
||||||
|
"""Override the routine for allowing the router:external attribute."""
|
||||||
|
# attributes containing a colon should be passed with
|
||||||
|
# a double underscore
|
||||||
|
new_args = dict(itertools.izip(map(lambda x: x.replace('__', ':'),
|
||||||
|
kwargs),
|
||||||
|
kwargs.values()))
|
||||||
|
arg_list = new_args.pop('arg_list', ()) + (external_net.EXTERNAL,)
|
||||||
|
return super(ExtNetDBTestCase, self)._create_network(
|
||||||
|
fmt, name, admin_state_up, arg_list=arg_list, **new_args)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
test_config['plugin_name_v2'] = (
|
||||||
|
'neutron.tests.unit.test_l3_plugin.TestNoL3NatPlugin')
|
||||||
|
ext_mgr = ExtNetTestExtensionManager()
|
||||||
|
test_config['extension_manager'] = ext_mgr
|
||||||
|
super(ExtNetDBTestCase, self).setUp()
|
||||||
|
|
||||||
|
def _set_net_external(self, net_id):
|
||||||
|
self._update('networks', net_id,
|
||||||
|
{'network': {external_net.EXTERNAL: True}})
|
||||||
|
|
||||||
|
def test_list_nets_external(self):
|
||||||
|
with self.network() as n1:
|
||||||
|
self._set_net_external(n1['network']['id'])
|
||||||
|
with self.network():
|
||||||
|
body = self._list('networks')
|
||||||
|
self.assertEqual(len(body['networks']), 2)
|
||||||
|
|
||||||
|
body = self._list('networks',
|
||||||
|
query_params="%s=True" %
|
||||||
|
external_net.EXTERNAL)
|
||||||
|
self.assertEqual(len(body['networks']), 1)
|
||||||
|
|
||||||
|
body = self._list('networks',
|
||||||
|
query_params="%s=False" %
|
||||||
|
external_net.EXTERNAL)
|
||||||
|
self.assertEqual(len(body['networks']), 1)
|
||||||
|
|
||||||
|
def test_list_nets_external_pagination(self):
|
||||||
|
if self._skip_native_pagination:
|
||||||
|
self.skipTest("Skip test for not implemented pagination feature")
|
||||||
|
with contextlib.nested(self.network(name='net1'),
|
||||||
|
self.network(name='net3')) as (n1, n3):
|
||||||
|
self._set_net_external(n1['network']['id'])
|
||||||
|
self._set_net_external(n3['network']['id'])
|
||||||
|
with self.network(name='net2') as n2:
|
||||||
|
self._test_list_with_pagination(
|
||||||
|
'network', (n1, n3), ('name', 'asc'), 1, 3,
|
||||||
|
query_params='router:external=True')
|
||||||
|
self._test_list_with_pagination(
|
||||||
|
'network', (n2, ), ('name', 'asc'), 1, 2,
|
||||||
|
query_params='router:external=False')
|
||||||
|
|
||||||
|
def test_get_network_succeeds_without_filter(self):
|
||||||
|
plugin = NeutronManager.get_plugin()
|
||||||
|
ctx = context.Context(None, None, is_admin=True)
|
||||||
|
result = plugin.get_networks(ctx, filters=None)
|
||||||
|
self.assertEqual(result, [])
|
||||||
|
|
||||||
|
def test_network_filter_hook_admin_context(self):
|
||||||
|
plugin = NeutronManager.get_plugin()
|
||||||
|
ctx = context.Context(None, None, is_admin=True)
|
||||||
|
model = models_v2.Network
|
||||||
|
conditions = plugin._network_filter_hook(ctx, model, [])
|
||||||
|
self.assertEqual(conditions, [])
|
||||||
|
|
||||||
|
def test_network_filter_hook_nonadmin_context(self):
|
||||||
|
plugin = NeutronManager.get_plugin()
|
||||||
|
ctx = context.Context('edinson', 'cavani')
|
||||||
|
model = models_v2.Network
|
||||||
|
txt = "externalnetworks.network_id IS NOT NULL"
|
||||||
|
conditions = plugin._network_filter_hook(ctx, model, [])
|
||||||
|
self.assertEqual(conditions.__str__(), txt)
|
||||||
|
# Try to concatenate conditions
|
||||||
|
conditions = plugin._network_filter_hook(ctx, model, conditions)
|
||||||
|
self.assertEqual(conditions.__str__(), "%s OR %s" % (txt, txt))
|
||||||
|
|
||||||
|
def test_create_port_external_network_non_admin_fails(self):
|
||||||
|
with self.network(router__external=True) as ext_net:
|
||||||
|
with self.subnet(network=ext_net) as ext_subnet:
|
||||||
|
with testtools.ExpectedException(
|
||||||
|
exc.HTTPClientError) as ctx_manager:
|
||||||
|
with self.port(subnet=ext_subnet,
|
||||||
|
set_context='True',
|
||||||
|
tenant_id='noadmin'):
|
||||||
|
pass
|
||||||
|
self.assertEqual(ctx_manager.exception.code, 403)
|
||||||
|
|
||||||
|
def test_create_port_external_network_admin_suceeds(self):
|
||||||
|
with self.network(router__external=True) as ext_net:
|
||||||
|
with self.subnet(network=ext_net) as ext_subnet:
|
||||||
|
with self.port(subnet=ext_subnet) as port:
|
||||||
|
self.assertEqual(port['port']['network_id'],
|
||||||
|
ext_net['network']['id'])
|
||||||
|
|
||||||
|
def test_create_external_network_non_admin_fails(self):
|
||||||
|
with testtools.ExpectedException(exc.HTTPClientError) as ctx_manager:
|
||||||
|
with self.network(router__external=True,
|
||||||
|
set_context='True',
|
||||||
|
tenant_id='noadmin'):
|
||||||
|
pass
|
||||||
|
self.assertEqual(ctx_manager.exception.code, 403)
|
||||||
|
|
||||||
|
def test_create_external_network_admin_suceeds(self):
|
||||||
|
with self.network(router__external=True) as ext_net:
|
||||||
|
self.assertEqual(ext_net['network'][external_net.EXTERNAL],
|
||||||
|
True)
|
||||||
|
|
||||||
|
|
||||||
|
class ExtNetDBTestCaseXML(ExtNetDBTestCase):
|
||||||
|
fmt = 'xml'
|
@ -51,32 +51,20 @@ class ExtraRouteTestExtensionManager(object):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
# This plugin class is just for testing
|
# This plugin class is for tests with plugin that integrates L3.
|
||||||
class TestExtraRoutePlugin(test_l3.TestL3NatPlugin,
|
class TestExtraRouteIntPlugin(test_l3.TestL3NatIntPlugin,
|
||||||
extraroute_db.ExtraRoute_db_mixin):
|
extraroute_db.ExtraRoute_db_mixin):
|
||||||
|
supported_extension_aliases = ["external-net", "router", "extraroute"]
|
||||||
|
|
||||||
|
|
||||||
|
# A fake l3 service plugin class with extra route capability for
|
||||||
|
# plugins that delegate away L3 routing functionality
|
||||||
|
class TestExtraRouteL3NatServicePlugin(test_l3.TestL3NatServicePlugin,
|
||||||
|
extraroute_db.ExtraRoute_db_mixin):
|
||||||
supported_extension_aliases = ["router", "extraroute"]
|
supported_extension_aliases = ["router", "extraroute"]
|
||||||
|
|
||||||
|
|
||||||
class ExtraRouteDBTestCase(test_l3.L3NatDBTestCase):
|
class ExtraRouteDBTestCaseBase(object):
|
||||||
|
|
||||||
def setUp(self, plugin=None):
|
|
||||||
if not plugin:
|
|
||||||
plugin = ('neutron.tests.unit.test_extension_extraroute.'
|
|
||||||
'TestExtraRoutePlugin')
|
|
||||||
test_config['plugin_name_v2'] = plugin
|
|
||||||
# for these tests we need to enable overlapping ips
|
|
||||||
cfg.CONF.set_default('allow_overlapping_ips', True)
|
|
||||||
cfg.CONF.set_default('max_routes', 3)
|
|
||||||
ext_mgr = ExtraRouteTestExtensionManager()
|
|
||||||
test_config['extension_manager'] = ext_mgr
|
|
||||||
#L3NatDBTestCase will overwrite plugin_name_v2,
|
|
||||||
#so we don't need to setUp on the class here
|
|
||||||
super(test_l3.L3NatTestCaseBase, self).setUp()
|
|
||||||
|
|
||||||
# Set to None to reload the drivers
|
|
||||||
notifier_api._drivers = None
|
|
||||||
cfg.CONF.set_override("notification_driver", [test_notifier.__name__])
|
|
||||||
|
|
||||||
def _routes_update_prepare(self, router_id, subnet_id,
|
def _routes_update_prepare(self, router_id, subnet_id,
|
||||||
port_id, routes, skip_add=False):
|
port_id, routes, skip_add=False):
|
||||||
if not skip_add:
|
if not skip_add:
|
||||||
@ -442,5 +430,57 @@ class ExtraRouteDBTestCase(test_l3.L3NatDBTestCase):
|
|||||||
('name', 'asc'), 2, 2)
|
('name', 'asc'), 2, 2)
|
||||||
|
|
||||||
|
|
||||||
class ExtraRouteDBTestCaseXML(ExtraRouteDBTestCase):
|
class ExtraRouteDBIntTestCase(test_l3.L3NatDBIntTestCase,
|
||||||
|
ExtraRouteDBTestCaseBase):
|
||||||
|
|
||||||
|
def setUp(self, plugin=None):
|
||||||
|
if not plugin:
|
||||||
|
plugin = ('neutron.tests.unit.test_extension_extraroute.'
|
||||||
|
'TestExtraRouteIntPlugin')
|
||||||
|
test_config['plugin_name_v2'] = plugin
|
||||||
|
# for these tests we need to enable overlapping ips
|
||||||
|
cfg.CONF.set_default('allow_overlapping_ips', True)
|
||||||
|
cfg.CONF.set_default('max_routes', 3)
|
||||||
|
ext_mgr = ExtraRouteTestExtensionManager()
|
||||||
|
test_config['extension_manager'] = ext_mgr
|
||||||
|
# L3NatDBIntTestCase will overwrite plugin_name_v2,
|
||||||
|
# so we don't need to setUp on the class here
|
||||||
|
super(test_l3.L3BaseForIntTests, self).setUp()
|
||||||
|
|
||||||
|
# Set to None to reload the drivers
|
||||||
|
notifier_api._drivers = None
|
||||||
|
cfg.CONF.set_override("notification_driver", [test_notifier.__name__])
|
||||||
|
|
||||||
|
|
||||||
|
class ExtraRouteDBIntTestCaseXML(ExtraRouteDBIntTestCase):
|
||||||
|
fmt = 'xml'
|
||||||
|
|
||||||
|
|
||||||
|
class ExtraRouteDBSepTestCase(test_l3.L3NatDBSepTestCase,
|
||||||
|
ExtraRouteDBTestCaseBase):
|
||||||
|
def setUp(self):
|
||||||
|
# the plugin without L3 support
|
||||||
|
test_config['plugin_name_v2'] = (
|
||||||
|
'neutron.tests.unit.test_l3_plugin.TestNoL3NatPlugin')
|
||||||
|
# the L3 service plugin
|
||||||
|
l3_plugin = ('neutron.tests.unit.test_extension_extraroute.'
|
||||||
|
'TestExtraRouteL3NatServicePlugin')
|
||||||
|
service_plugins = {'l3_plugin_name': l3_plugin}
|
||||||
|
|
||||||
|
# for these tests we need to enable overlapping ips
|
||||||
|
cfg.CONF.set_default('allow_overlapping_ips', True)
|
||||||
|
cfg.CONF.set_default('max_routes', 3)
|
||||||
|
ext_mgr = ExtraRouteTestExtensionManager()
|
||||||
|
test_config['extension_manager'] = ext_mgr
|
||||||
|
# L3NatDBSepTestCase will overwrite plugin_name_v2,
|
||||||
|
# so we don't need to setUp on the class here
|
||||||
|
super(test_l3.L3BaseForSepTests, self).setUp(
|
||||||
|
service_plugins=service_plugins)
|
||||||
|
|
||||||
|
# Set to None to reload the drivers
|
||||||
|
notifier_api._drivers = None
|
||||||
|
cfg.CONF.set_override("notification_driver", [test_notifier.__name__])
|
||||||
|
|
||||||
|
|
||||||
|
class ExtraRouteDBSepTestCaseXML(ExtraRouteDBSepTestCase):
|
||||||
fmt = 'xml'
|
fmt = 'xml'
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import copy
|
import copy
|
||||||
import itertools
|
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
@ -34,15 +33,19 @@ from neutron.common import constants as l3_constants
|
|||||||
from neutron.common import exceptions as q_exc
|
from neutron.common import exceptions as q_exc
|
||||||
from neutron.common.test_lib import test_config
|
from neutron.common.test_lib import test_config
|
||||||
from neutron import context
|
from neutron import context
|
||||||
|
from neutron.db import api as qdbapi
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
|
from neutron.db import external_net_db
|
||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
from neutron.db import models_v2
|
from neutron.db import model_base
|
||||||
|
from neutron.extensions import external_net
|
||||||
from neutron.extensions import l3
|
from neutron.extensions import l3
|
||||||
from neutron.manager import NeutronManager
|
from neutron.manager import NeutronManager
|
||||||
from neutron.openstack.common import log as logging
|
from neutron.openstack.common import log as logging
|
||||||
from neutron.openstack.common.notifier import api as notifier_api
|
from neutron.openstack.common.notifier import api as notifier_api
|
||||||
from neutron.openstack.common.notifier import test_notifier
|
from neutron.openstack.common.notifier import test_notifier
|
||||||
from neutron.openstack.common import uuidutils
|
from neutron.openstack.common import uuidutils
|
||||||
|
from neutron.plugins.common import constants as service_constants
|
||||||
from neutron.tests.unit import test_api_v2
|
from neutron.tests.unit import test_api_v2
|
||||||
from neutron.tests.unit import test_db_plugin
|
from neutron.tests.unit import test_db_plugin
|
||||||
from neutron.tests.unit import test_extensions
|
from neutron.tests.unit import test_extensions
|
||||||
@ -105,9 +108,8 @@ class L3NatExtensionTestCase(testlib_api.WebTestCase):
|
|||||||
instances = self.plugin.return_value
|
instances = self.plugin.return_value
|
||||||
instances._RouterPluginBase__native_pagination_support = True
|
instances._RouterPluginBase__native_pagination_support = True
|
||||||
instances._RouterPluginBase__native_sorting_support = True
|
instances._RouterPluginBase__native_sorting_support = True
|
||||||
# Instantiate mock plugin and enable the 'router' extension
|
# Enable the 'router' extension
|
||||||
NeutronManager.get_plugin().supported_extension_aliases = (
|
instances.supported_extension_aliases = ["router"]
|
||||||
["router"])
|
|
||||||
ext_mgr = L3TestExtensionManager()
|
ext_mgr = L3TestExtensionManager()
|
||||||
self.ext_mdw = test_extensions.setup_extensions_middleware(ext_mgr)
|
self.ext_mdw = test_extensions.setup_extensions_middleware(ext_mgr)
|
||||||
self.api = webtest.TestApp(self.ext_mdw)
|
self.api = webtest.TestApp(self.ext_mdw)
|
||||||
@ -253,20 +255,18 @@ class L3NatExtensionTestCaseXML(L3NatExtensionTestCase):
|
|||||||
fmt = 'xml'
|
fmt = 'xml'
|
||||||
|
|
||||||
|
|
||||||
# This plugin class is just for testing
|
# This base plugin class is for tests.
|
||||||
class TestL3NatPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
class TestL3NatBasePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
l3_db.L3_NAT_db_mixin):
|
external_net_db.External_net_db_mixin):
|
||||||
|
|
||||||
__native_pagination_support = True
|
__native_pagination_support = True
|
||||||
__native_sorting_support = True
|
__native_sorting_support = True
|
||||||
|
|
||||||
supported_extension_aliases = ["router"]
|
|
||||||
|
|
||||||
def create_network(self, context, network):
|
def create_network(self, context, network):
|
||||||
session = context.session
|
session = context.session
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
net = super(TestL3NatPlugin, self).create_network(context,
|
net = super(TestL3NatBasePlugin, self).create_network(context,
|
||||||
network)
|
network)
|
||||||
self._process_l3_create(context, net, network['network'])
|
self._process_l3_create(context, net, network['network'])
|
||||||
return net
|
return net
|
||||||
|
|
||||||
@ -274,31 +274,56 @@ class TestL3NatPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
|
|
||||||
session = context.session
|
session = context.session
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
net = super(TestL3NatPlugin, self).update_network(context, id,
|
net = super(TestL3NatBasePlugin, self).update_network(context, id,
|
||||||
network)
|
network)
|
||||||
self._process_l3_update(context, net, network['network'])
|
self._process_l3_update(context, net, network['network'])
|
||||||
return net
|
return net
|
||||||
|
|
||||||
def delete_port(self, context, id, l3_port_check=True):
|
def delete_port(self, context, id, l3_port_check=True):
|
||||||
if l3_port_check:
|
plugin = NeutronManager.get_service_plugins().get(
|
||||||
self.prevent_l3_port_deletion(context, id)
|
service_constants.L3_ROUTER_NAT)
|
||||||
self.disassociate_floatingips(context, id)
|
if plugin:
|
||||||
return super(TestL3NatPlugin, self).delete_port(context, id)
|
if l3_port_check:
|
||||||
|
plugin.prevent_l3_port_deletion(context, id)
|
||||||
|
plugin.disassociate_floatingips(context, id)
|
||||||
|
return super(TestL3NatBasePlugin, self).delete_port(context, id)
|
||||||
|
|
||||||
|
|
||||||
|
# This plugin class is for tests with plugin that integrates L3.
|
||||||
|
class TestL3NatIntPlugin(TestL3NatBasePlugin,
|
||||||
|
l3_db.L3_NAT_db_mixin):
|
||||||
|
|
||||||
|
supported_extension_aliases = ["external-net", "router"]
|
||||||
|
|
||||||
|
|
||||||
|
# This plugin class is for tests with plugin not supporting L3.
|
||||||
|
class TestNoL3NatPlugin(TestL3NatBasePlugin):
|
||||||
|
|
||||||
|
__native_pagination_support = True
|
||||||
|
__native_sorting_support = True
|
||||||
|
|
||||||
|
supported_extension_aliases = ["external-net"]
|
||||||
|
|
||||||
|
|
||||||
|
# A L3 routing service plugin class for tests with plugins that
|
||||||
|
# delegate away L3 routing functionality
|
||||||
|
class TestL3NatServicePlugin(db_base_plugin_v2.CommonDbMixin,
|
||||||
|
l3_db.L3_NAT_db_mixin):
|
||||||
|
|
||||||
|
supported_extension_aliases = ["router"]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
qdbapi.register_models(base=model_base.BASEV2)
|
||||||
|
|
||||||
|
def get_plugin_type(self):
|
||||||
|
return service_constants.L3_ROUTER_NAT
|
||||||
|
|
||||||
|
def get_plugin_description(self):
|
||||||
|
return "L3 Routing Service Plugin for testing"
|
||||||
|
|
||||||
|
|
||||||
class L3NatTestCaseMixin(object):
|
class L3NatTestCaseMixin(object):
|
||||||
|
|
||||||
def _create_network(self, fmt, name, admin_state_up, **kwargs):
|
|
||||||
"""Override the routine for allowing the router:external attribute."""
|
|
||||||
# attributes containing a colon should be passed with
|
|
||||||
# a double underscore
|
|
||||||
new_args = dict(itertools.izip(map(lambda x: x.replace('__', ':'),
|
|
||||||
kwargs),
|
|
||||||
kwargs.values()))
|
|
||||||
arg_list = new_args.pop('arg_list', ()) + (l3.EXTERNAL,)
|
|
||||||
return super(L3NatTestCaseMixin, self)._create_network(
|
|
||||||
fmt, name, admin_state_up, arg_list=arg_list, **new_args)
|
|
||||||
|
|
||||||
def _create_router(self, fmt, tenant_id, name=None,
|
def _create_router(self, fmt, tenant_id, name=None,
|
||||||
admin_state_up=None, set_context=False,
|
admin_state_up=None, set_context=False,
|
||||||
arg_list=None, **kwargs):
|
arg_list=None, **kwargs):
|
||||||
@ -380,7 +405,7 @@ class L3NatTestCaseMixin(object):
|
|||||||
|
|
||||||
def _set_net_external(self, net_id):
|
def _set_net_external(self, net_id):
|
||||||
self._update('networks', net_id,
|
self._update('networks', net_id,
|
||||||
{'network': {l3.EXTERNAL: True}})
|
{'network': {external_net.EXTERNAL: True}})
|
||||||
|
|
||||||
def _create_floatingip(self, fmt, network_id, port_id=None,
|
def _create_floatingip(self, fmt, network_id, port_id=None,
|
||||||
fixed_ip=None, set_context=False):
|
fixed_ip=None, set_context=False):
|
||||||
@ -480,30 +505,7 @@ class L3NatTestCaseMixin(object):
|
|||||||
public_sub['subnet']['network_id'])
|
public_sub['subnet']['network_id'])
|
||||||
|
|
||||||
|
|
||||||
class L3NatTestCaseBase(L3NatTestCaseMixin,
|
class L3NatTestCaseBase(L3NatTestCaseMixin):
|
||||||
test_db_plugin.NeutronDbPluginV2TestCase):
|
|
||||||
|
|
||||||
def setUp(self, plugin=None, ext_mgr=None,
|
|
||||||
service_plugins=None):
|
|
||||||
test_config['plugin_name_v2'] = (
|
|
||||||
'neutron.tests.unit.test_l3_plugin.TestL3NatPlugin')
|
|
||||||
# for these tests we need to enable overlapping ips
|
|
||||||
cfg.CONF.set_default('allow_overlapping_ips', True)
|
|
||||||
ext_mgr = ext_mgr or L3TestExtensionManager()
|
|
||||||
super(L3NatTestCaseBase, self).setUp(
|
|
||||||
plugin=plugin, ext_mgr=ext_mgr,
|
|
||||||
service_plugins=service_plugins)
|
|
||||||
|
|
||||||
# Set to None to reload the drivers
|
|
||||||
notifier_api._drivers = None
|
|
||||||
cfg.CONF.set_override("notification_driver", [test_notifier.__name__])
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
test_notifier.NOTIFICATIONS = []
|
|
||||||
super(L3NatTestCaseBase, self).tearDown()
|
|
||||||
|
|
||||||
|
|
||||||
class L3NatDBTestCase(L3NatTestCaseBase):
|
|
||||||
|
|
||||||
def test_router_create(self):
|
def test_router_create(self):
|
||||||
name = 'router1'
|
name = 'router1'
|
||||||
@ -1119,7 +1121,7 @@ class L3NatDBTestCase(L3NatTestCaseBase):
|
|||||||
r['router']['id'],
|
r['router']['id'],
|
||||||
s1['subnet']['network_id'])
|
s1['subnet']['network_id'])
|
||||||
self._update('networks', s1['subnet']['network_id'],
|
self._update('networks', s1['subnet']['network_id'],
|
||||||
{'network': {'router:external': False}},
|
{'network': {external_net.EXTERNAL: False}},
|
||||||
expected_code=exc.HTTPConflict.code)
|
expected_code=exc.HTTPConflict.code)
|
||||||
self._remove_external_gateway_from_router(
|
self._remove_external_gateway_from_router(
|
||||||
r['router']['id'],
|
r['router']['id'],
|
||||||
@ -1135,7 +1137,7 @@ class L3NatDBTestCase(L3NatTestCaseBase):
|
|||||||
r['router']['id'],
|
r['router']['id'],
|
||||||
s1['subnet']['network_id'])
|
s1['subnet']['network_id'])
|
||||||
self._update('networks', testnet['network']['id'],
|
self._update('networks', testnet['network']['id'],
|
||||||
{'network': {'router:external': False}})
|
{'network': {external_net.EXTERNAL: False}})
|
||||||
self._remove_external_gateway_from_router(
|
self._remove_external_gateway_from_router(
|
||||||
r['router']['id'],
|
r['router']['id'],
|
||||||
s1['subnet']['network_id'])
|
s1['subnet']['network_id'])
|
||||||
@ -1486,91 +1488,6 @@ class L3NatDBTestCase(L3NatTestCaseBase):
|
|||||||
break
|
break
|
||||||
self.assertTrue(found)
|
self.assertTrue(found)
|
||||||
|
|
||||||
def test_list_nets_external(self):
|
|
||||||
with self.network() as n1:
|
|
||||||
self._set_net_external(n1['network']['id'])
|
|
||||||
with self.network():
|
|
||||||
body = self._list('networks')
|
|
||||||
self.assertEqual(len(body['networks']), 2)
|
|
||||||
|
|
||||||
body = self._list('networks',
|
|
||||||
query_params="%s=True" % l3.EXTERNAL)
|
|
||||||
self.assertEqual(len(body['networks']), 1)
|
|
||||||
|
|
||||||
body = self._list('networks',
|
|
||||||
query_params="%s=False" % l3.EXTERNAL)
|
|
||||||
self.assertEqual(len(body['networks']), 1)
|
|
||||||
|
|
||||||
def test_list_nets_external_pagination(self):
|
|
||||||
if self._skip_native_pagination:
|
|
||||||
self.skipTest("Skip test for not implemented pagination feature")
|
|
||||||
with contextlib.nested(self.network(name='net1'),
|
|
||||||
self.network(name='net3')) as (n1, n3):
|
|
||||||
self._set_net_external(n1['network']['id'])
|
|
||||||
self._set_net_external(n3['network']['id'])
|
|
||||||
with self.network(name='net2') as n2:
|
|
||||||
self._test_list_with_pagination(
|
|
||||||
'network', (n1, n3), ('name', 'asc'), 1, 3,
|
|
||||||
query_params='router:external=True')
|
|
||||||
self._test_list_with_pagination(
|
|
||||||
'network', (n2, ), ('name', 'asc'), 1, 2,
|
|
||||||
query_params='router:external=False')
|
|
||||||
|
|
||||||
def test_get_network_succeeds_without_filter(self):
|
|
||||||
plugin = NeutronManager.get_plugin()
|
|
||||||
ctx = context.Context(None, None, is_admin=True)
|
|
||||||
result = plugin.get_networks(ctx, filters=None)
|
|
||||||
self.assertEqual(result, [])
|
|
||||||
|
|
||||||
def test_network_filter_hook_admin_context(self):
|
|
||||||
plugin = NeutronManager.get_plugin()
|
|
||||||
ctx = context.Context(None, None, is_admin=True)
|
|
||||||
model = models_v2.Network
|
|
||||||
conditions = plugin._network_filter_hook(ctx, model, [])
|
|
||||||
self.assertEqual(conditions, [])
|
|
||||||
|
|
||||||
def test_network_filter_hook_nonadmin_context(self):
|
|
||||||
plugin = NeutronManager.get_plugin()
|
|
||||||
ctx = context.Context('edinson', 'cavani')
|
|
||||||
model = models_v2.Network
|
|
||||||
txt = "externalnetworks.network_id IS NOT NULL"
|
|
||||||
conditions = plugin._network_filter_hook(ctx, model, [])
|
|
||||||
self.assertEqual(conditions.__str__(), txt)
|
|
||||||
# Try to concatenate confitions
|
|
||||||
conditions = plugin._network_filter_hook(ctx, model, conditions)
|
|
||||||
self.assertEqual(conditions.__str__(), "%s OR %s" % (txt, txt))
|
|
||||||
|
|
||||||
def test_create_port_external_network_non_admin_fails(self):
|
|
||||||
with self.network(router__external=True) as ext_net:
|
|
||||||
with self.subnet(network=ext_net) as ext_subnet:
|
|
||||||
with testlib_api.ExpectedException(
|
|
||||||
exc.HTTPClientError) as ctx_manager:
|
|
||||||
with self.port(subnet=ext_subnet,
|
|
||||||
set_context='True',
|
|
||||||
tenant_id='noadmin'):
|
|
||||||
pass
|
|
||||||
self.assertEqual(ctx_manager.exception.code, 403)
|
|
||||||
|
|
||||||
def test_create_port_external_network_admin_suceeds(self):
|
|
||||||
with self.network(router__external=True) as ext_net:
|
|
||||||
with self.subnet(network=ext_net) as ext_subnet:
|
|
||||||
with self.port(subnet=ext_subnet) as port:
|
|
||||||
self.assertEqual(port['port']['network_id'],
|
|
||||||
ext_net['network']['id'])
|
|
||||||
|
|
||||||
def test_create_external_network_non_admin_fails(self):
|
|
||||||
with testlib_api.ExpectedException(exc.HTTPClientError) as ctx_manager:
|
|
||||||
with self.network(router__external=True,
|
|
||||||
set_context='True',
|
|
||||||
tenant_id='noadmin'):
|
|
||||||
pass
|
|
||||||
self.assertEqual(ctx_manager.exception.code, 403)
|
|
||||||
|
|
||||||
def test_create_external_network_admin_suceeds(self):
|
|
||||||
with self.network(router__external=True) as ext_net:
|
|
||||||
self.assertEqual(ext_net['network'][l3.EXTERNAL],
|
|
||||||
True)
|
|
||||||
|
|
||||||
def test_router_delete_subnet_inuse_returns_409(self):
|
def test_router_delete_subnet_inuse_returns_409(self):
|
||||||
with self.router() as r:
|
with self.router() as r:
|
||||||
with self.subnet() as s:
|
with self.subnet() as s:
|
||||||
@ -1588,12 +1505,9 @@ class L3NatDBTestCase(L3NatTestCaseBase):
|
|||||||
None)
|
None)
|
||||||
|
|
||||||
|
|
||||||
class L3AgentDbTestCase(L3NatTestCaseBase):
|
class L3AgentDbTestCaseBase(L3NatTestCaseMixin):
|
||||||
"""Unit tests for methods called by the L3 agent."""
|
|
||||||
|
|
||||||
def setUp(self):
|
"""Unit tests for methods called by the L3 agent."""
|
||||||
self.plugin = TestL3NatPlugin()
|
|
||||||
super(L3AgentDbTestCase, self).setUp()
|
|
||||||
|
|
||||||
def test_l3_agent_routers_query_interfaces(self):
|
def test_l3_agent_routers_query_interfaces(self):
|
||||||
with self.router() as r:
|
with self.router() as r:
|
||||||
@ -1633,7 +1547,7 @@ class L3AgentDbTestCase(L3NatTestCaseBase):
|
|||||||
{'ip_address': '9.0.1.5',
|
{'ip_address': '9.0.1.5',
|
||||||
'subnet_id': subnet['subnet']['id']}]}}
|
'subnet_id': subnet['subnet']['id']}]}}
|
||||||
ctx = context.get_admin_context()
|
ctx = context.get_admin_context()
|
||||||
self.plugin.update_port(ctx, p['port']['id'], port)
|
self.core_plugin.update_port(ctx, p['port']['id'], port)
|
||||||
routers = self.plugin.get_sync_data(ctx, None)
|
routers = self.plugin.get_sync_data(ctx, None)
|
||||||
self.assertEqual(1, len(routers))
|
self.assertEqual(1, len(routers))
|
||||||
interfaces = routers[0].get(l3_constants.INTERFACE_KEY, [])
|
interfaces = routers[0].get(l3_constants.INTERFACE_KEY, [])
|
||||||
@ -1677,7 +1591,8 @@ class L3AgentDbTestCase(L3NatTestCaseBase):
|
|||||||
def _test_notify_op_agent(self, target_func, *args):
|
def _test_notify_op_agent(self, target_func, *args):
|
||||||
l3_rpc_agent_api_str = (
|
l3_rpc_agent_api_str = (
|
||||||
'neutron.api.rpc.agentnotifiers.l3_rpc_agent_api.L3AgentNotifyAPI')
|
'neutron.api.rpc.agentnotifiers.l3_rpc_agent_api.L3AgentNotifyAPI')
|
||||||
plugin = NeutronManager.get_plugin()
|
plugin = NeutronManager.get_service_plugins()[
|
||||||
|
service_constants.L3_ROUTER_NAT]
|
||||||
oldNotify = plugin.l3_rpc_notifier
|
oldNotify = plugin.l3_rpc_notifier
|
||||||
try:
|
try:
|
||||||
with mock.patch(l3_rpc_agent_api_str) as notifyApi:
|
with mock.patch(l3_rpc_agent_api_str) as notifyApi:
|
||||||
@ -1736,5 +1651,95 @@ class L3AgentDbTestCase(L3NatTestCaseBase):
|
|||||||
self._test_notify_op_agent(self._test_floatingips_op_agent)
|
self._test_notify_op_agent(self._test_floatingips_op_agent)
|
||||||
|
|
||||||
|
|
||||||
class L3NatDBTestCaseXML(L3NatDBTestCase):
|
class L3BaseForIntTests(test_db_plugin.NeutronDbPluginV2TestCase):
|
||||||
|
|
||||||
|
def setUp(self, plugin=None, ext_mgr=None):
|
||||||
|
test_config['plugin_name_v2'] = (
|
||||||
|
'neutron.tests.unit.test_l3_plugin.TestL3NatIntPlugin')
|
||||||
|
# for these tests we need to enable overlapping ips
|
||||||
|
cfg.CONF.set_default('allow_overlapping_ips', True)
|
||||||
|
ext_mgr = ext_mgr or L3TestExtensionManager()
|
||||||
|
test_config['extension_manager'] = ext_mgr
|
||||||
|
super(L3BaseForIntTests, self).setUp(plugin=plugin, ext_mgr=ext_mgr)
|
||||||
|
|
||||||
|
# Set to None to reload the drivers
|
||||||
|
notifier_api._drivers = None
|
||||||
|
cfg.CONF.set_override("notification_driver", [test_notifier.__name__])
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
test_notifier.NOTIFICATIONS = []
|
||||||
|
del test_config['extension_manager']
|
||||||
|
super(L3BaseForIntTests, self).tearDown()
|
||||||
|
|
||||||
|
|
||||||
|
class L3BaseForSepTests(test_db_plugin.NeutronDbPluginV2TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
# the plugin without L3 support
|
||||||
|
test_config['plugin_name_v2'] = (
|
||||||
|
'neutron.tests.unit.test_l3_plugin.TestNoL3NatPlugin')
|
||||||
|
# the L3 service plugin
|
||||||
|
l3_plugin = ('neutron.tests.unit.test_l3_plugin.'
|
||||||
|
'TestL3NatServicePlugin')
|
||||||
|
service_plugins = {'l3_plugin_name': l3_plugin}
|
||||||
|
|
||||||
|
# for these tests we need to enable overlapping ips
|
||||||
|
cfg.CONF.set_default('allow_overlapping_ips', True)
|
||||||
|
ext_mgr = L3TestExtensionManager()
|
||||||
|
test_config['extension_manager'] = ext_mgr
|
||||||
|
super(L3BaseForSepTests, self).setUp(service_plugins=service_plugins)
|
||||||
|
|
||||||
|
# Set to None to reload the drivers
|
||||||
|
notifier_api._drivers = None
|
||||||
|
cfg.CONF.set_override("notification_driver", [test_notifier.__name__])
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
test_notifier.NOTIFICATIONS = []
|
||||||
|
del test_config['extension_manager']
|
||||||
|
super(L3BaseForSepTests, self).tearDown()
|
||||||
|
|
||||||
|
|
||||||
|
class L3AgentDbIntTestCase(L3BaseForIntTests, L3AgentDbTestCaseBase):
|
||||||
|
|
||||||
|
"""Unit tests for methods called by the L3 agent for
|
||||||
|
the case where core plugin implements L3 routing.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.core_plugin = TestL3NatIntPlugin()
|
||||||
|
# core plugin is also plugin providing L3 routing
|
||||||
|
self.plugin = self.core_plugin
|
||||||
|
super(L3AgentDbIntTestCase, self).setUp()
|
||||||
|
|
||||||
|
|
||||||
|
class L3AgentDbSepTestCase(L3BaseForSepTests, L3AgentDbTestCaseBase):
|
||||||
|
|
||||||
|
"""Unit tests for methods called by the L3 agent for the
|
||||||
|
case where separate service plugin implements L3 routing.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.core_plugin = TestNoL3NatPlugin()
|
||||||
|
# core plugin is also plugin providing L3 routing
|
||||||
|
self.plugin = TestL3NatServicePlugin()
|
||||||
|
super(L3AgentDbSepTestCase, self).setUp()
|
||||||
|
|
||||||
|
|
||||||
|
class L3NatDBIntTestCase(L3BaseForIntTests, L3NatTestCaseBase):
|
||||||
|
|
||||||
|
"""Unit tests for core plugin with L3 routing integrated."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class L3NatDBSepTestCase(L3BaseForSepTests, L3NatTestCaseBase):
|
||||||
|
|
||||||
|
"""Unit tests for a separate L3 routing service plugin."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class L3NatDBIntTestCaseXML(L3NatDBIntTestCase):
|
||||||
|
fmt = 'xml'
|
||||||
|
|
||||||
|
|
||||||
|
class L3NatDBSepTestCaseXML(L3NatDBSepTestCase):
|
||||||
fmt = 'xml'
|
fmt = 'xml'
|
||||||
|
@ -52,8 +52,8 @@ class RouterServiceInsertionTestPlugin(
|
|||||||
db_base_plugin_v2.NeutronDbPluginV2):
|
db_base_plugin_v2.NeutronDbPluginV2):
|
||||||
|
|
||||||
supported_extension_aliases = [
|
supported_extension_aliases = [
|
||||||
"router", "router-service-type", "routed-service-insertion",
|
"router", "router-service-type",
|
||||||
"service-type", "lbaas"
|
"routed-service-insertion", "service-type", "lbaas"
|
||||||
]
|
]
|
||||||
|
|
||||||
def create_router(self, context, router):
|
def create_router(self, context, router):
|
||||||
|
@ -421,9 +421,12 @@ class XMLDictSerializer(DictSerializer):
|
|||||||
node.set(constants.ATOM_XMLNS, constants.ATOM_NAMESPACE)
|
node.set(constants.ATOM_XMLNS, constants.ATOM_NAMESPACE)
|
||||||
node.set(constants.XSI_NIL_ATTR, constants.XSI_NAMESPACE)
|
node.set(constants.XSI_NIL_ATTR, constants.XSI_NAMESPACE)
|
||||||
ext_ns = self.metadata.get(constants.EXT_NS, {})
|
ext_ns = self.metadata.get(constants.EXT_NS, {})
|
||||||
|
ext_ns_bc = self.metadata.get(constants.EXT_NS_COMP, {})
|
||||||
for prefix in used_prefixes:
|
for prefix in used_prefixes:
|
||||||
if prefix in ext_ns:
|
if prefix in ext_ns:
|
||||||
node.set('xmlns:' + prefix, ext_ns[prefix])
|
node.set('xmlns:' + prefix, ext_ns[prefix])
|
||||||
|
if prefix in ext_ns_bc:
|
||||||
|
node.set('xmlns:' + prefix, ext_ns_bc[prefix])
|
||||||
|
|
||||||
def _to_xml_node(self, parent, metadata, nodename, data, used_prefixes):
|
def _to_xml_node(self, parent, metadata, nodename, data, used_prefixes):
|
||||||
"""Recursive method to convert data members to XML nodes."""
|
"""Recursive method to convert data members to XML nodes."""
|
||||||
@ -607,6 +610,10 @@ class XMLDeserializer(TextDeserializer):
|
|||||||
for prefix, _ns in ext_ns.items():
|
for prefix, _ns in ext_ns.items():
|
||||||
if ns == _ns:
|
if ns == _ns:
|
||||||
return prefix + ":" + bare_tag
|
return prefix + ":" + bare_tag
|
||||||
|
ext_ns_bc = self.metadata.get(constants.EXT_NS_COMP, {})
|
||||||
|
for prefix, _ns in ext_ns_bc.items():
|
||||||
|
if ns == _ns:
|
||||||
|
return prefix + ":" + bare_tag
|
||||||
else:
|
else:
|
||||||
return tag
|
return tag
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user