Metaplugin decomposition
The main code of Metaplugin is available here: https://github.com/ntt-sic/networking-metaplugin Change-Id: I9bf6609df4bbe5ed679fb42156f8dea4c87303c6 Partially-implements: blueprint core-vendor-decomposition Closes-bug: #1415304
This commit is contained in:
parent
0680e0b524
commit
6b991396f4
@ -401,7 +401,7 @@ The following chart captures the following aspects:
|
||||
+-------------------------------+-----------------------+-----------+------------------+---------+--------------+
|
||||
| networking-hyperv_ | | | | | |
|
||||
+-------------------------------+-----------------------+-----------+------------------+---------+--------------+
|
||||
| networking-metaplugin_ | | | | | |
|
||||
| networking-metaplugin_ | core | no | no | [C] | Kilo |
|
||||
+-------------------------------+-----------------------+-----------+------------------+---------+--------------+
|
||||
| networking-midonet_ | | | | | |
|
||||
+-------------------------------+-----------------------+-----------+------------------+---------+--------------+
|
||||
@ -440,6 +440,11 @@ Arista
|
||||
|
||||
.. _networking-metaplugin:
|
||||
|
||||
Metaplugin
|
||||
----------
|
||||
|
||||
* Git: https://github.com/ntt-sic/networking-metaplugin
|
||||
|
||||
.. _networking-midonet:
|
||||
|
||||
.. _networking-mlnx:
|
||||
|
@ -1,92 +1,6 @@
|
||||
# -- Background
|
||||
|
||||
This plugin supports multiple plugin at same time. This plugin is for L3 connectivility
|
||||
between networks which are realized by different plugins.This plugin adds new attributes 'flavor:network' and 'flavor:router".
|
||||
flavor:network corresponds to specific l2 plugin ( flavor-plugin mapping could be configurable by plugin_list config.
|
||||
flavor:router corresponds to specific l3 plugin ( flavor-plugin mapping could be configurable by l3_plugin_list config. Note that Metaplugin can provide l3 functionaliteis for l2 plugin which didn't support l3 extension yet.
|
||||
This plugin also support extensions. We can map extension to plugin by using extension_map config.
|
||||
|
||||
[database]
|
||||
# This line MUST be changed to actually run the plugin.
|
||||
# Example:
|
||||
# connection = mysql://root:nova@127.0.0.1:3306/ovs_neutron
|
||||
# Replace 127.0.0.1 above with the IP address of the database used by the
|
||||
# main neutron server. (Leave it as is if the database runs on this host.)
|
||||
connection = mysql://root:password@localhost/neutron_metaplugin?charset=utf8
|
||||
|
||||
# Database reconnection retry times - in event connectivity is lost
|
||||
# set to -1 implgies an infinite retry count
|
||||
# max_retries = 10
|
||||
# Database reconnection interval in seconds - in event connectivity is lost
|
||||
retry_interval = 2
|
||||
|
||||
[meta]
|
||||
## This is list of flavor:neutron_plugins
|
||||
# extension method is used in the order of this list
|
||||
plugin_list= 'openvswitch:neutron.plugins.openvswitch.ovs_neutron_plugin.OVSneutronPluginV2,linuxbridge:neutron.plugins.linuxbridge.lb_neutron_plugin.LinuxBridgePluginV2'
|
||||
# plugin for l3
|
||||
l3_plugin_list= 'openvswitch:neutron.plugins.openvswitch.ovs_neutron_plugin.OVSneutronPluginV2,linuxbridge:neutron.plugins.linuxbridge.lb_neutron_plugin.LinuxBridgePluginV2'
|
||||
|
||||
# Default value of flavor
|
||||
default_flavor = 'openvswitch'
|
||||
# Default value for l3
|
||||
default_l3_flavor = 'openvswitch'
|
||||
|
||||
# supported extensions
|
||||
supported_extension_aliases = 'providernet'
|
||||
# specific method map for each flavor to extensions
|
||||
extension_map = 'get_port_stats:nvp'
|
||||
|
||||
# -- BridgeDriver Configration
|
||||
# In order to use metaplugin, you should use MetaDriver. Following configation is needed.
|
||||
|
||||
[DEFAULT]
|
||||
# Meta Plugin
|
||||
# Mapping between flavor and driver
|
||||
meta_flavor_driver_mappings = openvswitch:neutron.agent.linux.interface.OVSInterfaceDriver, linuxbridge:neutron.agent.linux.interface.BridgeInterfaceDriver
|
||||
# interface driver for MetaPlugin
|
||||
interface_driver = neutron.agent.linux.interface.MetaInterfaceDriver
|
||||
|
||||
[proxy]
|
||||
auth_url = http://10.0.0.1:35357/v2.0
|
||||
auth_region = RegionOne
|
||||
admin_tenant_name = service
|
||||
admin_user = neutron
|
||||
admin_password = password
|
||||
|
||||
|
||||
# -- Agent
|
||||
Agents for Metaplugin are in neutron/plugins/metaplugin/agent
|
||||
linuxbridge_neutron_agent and ovs_neutron_agent is available.
|
||||
|
||||
# -- Extensions
|
||||
|
||||
- flavor
|
||||
MetaPlugin supports flavor and provider net extension.
|
||||
Metaplugin select plugin_list using flavor.
|
||||
One plugin may use multiple flavor value. If the plugin support flavor, it may provide
|
||||
multiple flavor of network.
|
||||
|
||||
- Attribute extension
|
||||
Each plugin can use attribute extension such as provider_net, if you specify that in supported_extension_aliases.
|
||||
|
||||
- providernet
|
||||
Vlan ID range of each plugin should be different, since Metaplugin dose not manage that.
|
||||
|
||||
#- limitations
|
||||
|
||||
Basically, All plugin should inherit NeutronDbPluginV2.
|
||||
Metaplugin assumes all plugin share same Database especially for IPAM part in NeutronV2 API.
|
||||
You can use another plugin if you use ProxyPluginV2, which proxies request to the another neutron server.
|
||||
|
||||
Example flavor configration for ProxyPluginV2
|
||||
|
||||
meta_flavor_driver_mappings = "openvswitch:neutron.agent.linux.interface.OVSInterfaceDriver,proxy:neutron.plugins.metaplugin.proxy_neutron_plugin.ProxyPluginV2"
|
||||
|
||||
- Limited L3 support
|
||||
In folsom version, l3 is an extension. There is no way to extend exntension attributes.
|
||||
so you can set flavor:router value but you can't get flavor:router value in API output.
|
||||
L3 agent dont's support flavor:router.
|
||||
|
||||
|
||||
# NOTE
|
||||
|
||||
The main source codes of Metaplugin is now in https://github.com/ntt-sic/networking-metaplugin.
|
||||
They were moved from Neutron tree to there according to core-vendor-decomposition.
|
||||
Defining config and DB are still here according to the decomposition policy.
|
||||
Codes of 'flavor' extension and interface driver used by *-agent remain in Neutron tree too.
|
||||
|
@ -1,50 +0,0 @@
|
||||
# Copyright 2012, Nachi Ueno, NTT MCL, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from sqlalchemy.orm import exc
|
||||
|
||||
from neutron.plugins.metaplugin import meta_models_v2
|
||||
|
||||
|
||||
def get_flavor_by_network(session, net_id):
|
||||
try:
|
||||
binding = (session.query(meta_models_v2.NetworkFlavor).
|
||||
filter_by(network_id=net_id).
|
||||
one())
|
||||
except exc.NoResultFound:
|
||||
return None
|
||||
return binding.flavor
|
||||
|
||||
|
||||
def add_network_flavor_binding(session, flavor, net_id):
|
||||
binding = meta_models_v2.NetworkFlavor(flavor=flavor, network_id=net_id)
|
||||
session.add(binding)
|
||||
return binding
|
||||
|
||||
|
||||
def get_flavor_by_router(session, router_id):
|
||||
try:
|
||||
binding = (session.query(meta_models_v2.RouterFlavor).
|
||||
filter_by(router_id=router_id).
|
||||
one())
|
||||
except exc.NoResultFound:
|
||||
return None
|
||||
return binding.flavor
|
||||
|
||||
|
||||
def add_router_flavor_binding(session, flavor, router_id):
|
||||
binding = meta_models_v2.RouterFlavor(flavor=flavor, router_id=router_id)
|
||||
session.add(binding)
|
||||
return binding
|
@ -13,402 +13,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import importutils
|
||||
|
||||
from neutron.common import exceptions as exc
|
||||
from neutron.common import topics
|
||||
from neutron import context as neutron_context
|
||||
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 l3_db
|
||||
from neutron.db import models_v2
|
||||
from neutron.extensions import flavor as ext_flavor
|
||||
from neutron.i18n import _LE
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.plugins.metaplugin.common import config # noqa
|
||||
from neutron.plugins.metaplugin import meta_db_v2
|
||||
from neutron.plugins.metaplugin import meta_models_v2
|
||||
from metaplugin.plugin import meta_neutron_plugin
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Hooks used to select records which belong a target plugin.
|
||||
def _meta_network_model_hook(context, original_model, query):
|
||||
return query.outerjoin(meta_models_v2.NetworkFlavor,
|
||||
meta_models_v2.NetworkFlavor.network_id ==
|
||||
models_v2.Network.id)
|
||||
|
||||
|
||||
def _meta_port_model_hook(context, original_model, query):
|
||||
return query.join(meta_models_v2.NetworkFlavor,
|
||||
meta_models_v2.NetworkFlavor.network_id ==
|
||||
models_v2.Port.network_id)
|
||||
|
||||
|
||||
def _meta_flavor_filter_hook(query, filters):
|
||||
if ext_flavor.FLAVOR_NETWORK in filters:
|
||||
return query.filter(meta_models_v2.NetworkFlavor.flavor ==
|
||||
filters[ext_flavor.FLAVOR_NETWORK][0])
|
||||
return query
|
||||
|
||||
|
||||
# Metaplugin Exceptions
|
||||
class FlavorNotFound(exc.NotFound):
|
||||
message = _("Flavor %(flavor)s could not be found")
|
||||
|
||||
|
||||
class FaildToAddFlavorBinding(exc.NeutronException):
|
||||
message = _("Failed to add flavor binding")
|
||||
|
||||
|
||||
class MetaPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
external_net_db.External_net_db_mixin,
|
||||
extraroute_db.ExtraRoute_db_mixin):
|
||||
|
||||
def __init__(self, configfile=None):
|
||||
super(MetaPluginV2, self).__init__()
|
||||
LOG.debug("Start initializing metaplugin")
|
||||
self.supported_extension_aliases = ['flavor', 'external-net']
|
||||
if cfg.CONF.META.supported_extension_aliases:
|
||||
cfg_aliases = cfg.CONF.META.supported_extension_aliases.split(',')
|
||||
self.supported_extension_aliases += cfg_aliases
|
||||
|
||||
# Ignore config option overapping
|
||||
def _is_opt_registered(opts, opt):
|
||||
if opt.dest in opts:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
cfg._is_opt_registered = _is_opt_registered
|
||||
|
||||
self.plugins = {}
|
||||
|
||||
plugin_list = [plugin_set.split(':')
|
||||
for plugin_set
|
||||
in cfg.CONF.META.plugin_list.split(',')]
|
||||
self.rpc_flavor = cfg.CONF.META.rpc_flavor
|
||||
topic_save = topics.PLUGIN
|
||||
topic_fake = topic_save + '-metaplugin'
|
||||
for flavor, plugin_provider in plugin_list:
|
||||
# Rename topic used by a plugin other than rpc_flavor during
|
||||
# loading the plugin instance if rpc_flavor is specified.
|
||||
# This enforces the plugin specified by rpc_flavor is only
|
||||
# consumer of 'q-plugin'. It is a bit tricky but there is no
|
||||
# bad effect.
|
||||
if self.rpc_flavor and self.rpc_flavor != flavor:
|
||||
topics.PLUGIN = topic_fake
|
||||
self.plugins[flavor] = self._load_plugin(plugin_provider)
|
||||
topics.PLUGIN = topic_save
|
||||
|
||||
self.l3_plugins = {}
|
||||
if cfg.CONF.META.l3_plugin_list:
|
||||
l3_plugin_list = [plugin_set.split(':')
|
||||
for plugin_set
|
||||
in cfg.CONF.META.l3_plugin_list.split(',')]
|
||||
for flavor, plugin_provider in l3_plugin_list:
|
||||
if flavor in self.plugins:
|
||||
self.l3_plugins[flavor] = self.plugins[flavor]
|
||||
else:
|
||||
# For l3 only plugin
|
||||
self.l3_plugins[flavor] = self._load_plugin(
|
||||
plugin_provider)
|
||||
|
||||
self.default_flavor = cfg.CONF.META.default_flavor
|
||||
if self.default_flavor not in self.plugins:
|
||||
raise exc.Invalid(_('default_flavor %s is not plugin list') %
|
||||
self.default_flavor)
|
||||
|
||||
if self.l3_plugins:
|
||||
self.default_l3_flavor = cfg.CONF.META.default_l3_flavor
|
||||
if self.default_l3_flavor not in self.l3_plugins:
|
||||
raise exc.Invalid(_('default_l3_flavor %s is not plugin list')
|
||||
% self.default_l3_flavor)
|
||||
self.supported_extension_aliases += ['router', 'ext-gw-mode',
|
||||
'extraroute']
|
||||
|
||||
if self.rpc_flavor and self.rpc_flavor not in self.plugins:
|
||||
raise exc.Invalid(_('rpc_flavor %s is not plugin list') %
|
||||
self.rpc_flavor)
|
||||
|
||||
self.extension_map = {}
|
||||
if not cfg.CONF.META.extension_map == '':
|
||||
extension_list = [method_set.split(':')
|
||||
for method_set
|
||||
in cfg.CONF.META.extension_map.split(',')]
|
||||
for method_name, flavor in extension_list:
|
||||
self.extension_map[method_name] = flavor
|
||||
|
||||
# Register hooks.
|
||||
# The hooks are applied for each target plugin instance when
|
||||
# calling the base class to get networks/ports so that only records
|
||||
# which belong to the plugin are selected.
|
||||
#NOTE: Doing registration here (within __init__()) is to avoid
|
||||
# registration when merely importing this file. This is only
|
||||
# for running whole unit tests.
|
||||
db_base_plugin_v2.NeutronDbPluginV2.register_model_query_hook(
|
||||
models_v2.Network,
|
||||
'metaplugin_net',
|
||||
_meta_network_model_hook,
|
||||
None,
|
||||
_meta_flavor_filter_hook)
|
||||
db_base_plugin_v2.NeutronDbPluginV2.register_model_query_hook(
|
||||
models_v2.Port,
|
||||
'metaplugin_port',
|
||||
_meta_port_model_hook,
|
||||
None,
|
||||
_meta_flavor_filter_hook)
|
||||
|
||||
def _load_plugin(self, plugin_provider):
|
||||
LOG.debug("Plugin location: %s", plugin_provider)
|
||||
plugin_klass = importutils.import_class(plugin_provider)
|
||||
return plugin_klass()
|
||||
|
||||
def _get_plugin(self, flavor):
|
||||
if flavor not in self.plugins:
|
||||
raise FlavorNotFound(flavor=flavor)
|
||||
return self.plugins[flavor]
|
||||
|
||||
def _get_l3_plugin(self, flavor):
|
||||
if flavor not in self.l3_plugins:
|
||||
raise FlavorNotFound(flavor=flavor)
|
||||
return self.l3_plugins[flavor]
|
||||
|
||||
def __getattr__(self, key):
|
||||
# At first, try to pickup extension command from extension_map
|
||||
|
||||
if key in self.extension_map:
|
||||
flavor = self.extension_map[key]
|
||||
plugin = self._get_plugin(flavor)
|
||||
if plugin and hasattr(plugin, key):
|
||||
return getattr(plugin, key)
|
||||
|
||||
# Second, try to match extension method in order of plugin list
|
||||
for flavor, plugin in self.plugins.items():
|
||||
if hasattr(plugin, key):
|
||||
return getattr(plugin, key)
|
||||
|
||||
# if no plugin support the method, then raise
|
||||
raise AttributeError()
|
||||
|
||||
def _extend_network_dict(self, context, network):
|
||||
flavor = self._get_flavor_by_network_id(context, network['id'])
|
||||
network[ext_flavor.FLAVOR_NETWORK] = flavor
|
||||
|
||||
def start_rpc_listeners(self):
|
||||
return self.plugins[self.rpc_flavor].start_rpc_listeners()
|
||||
|
||||
def rpc_workers_supported(self):
|
||||
#NOTE: If a plugin which supports multiple RPC workers is desired
|
||||
# to handle RPC, rpc_flavor must be specified.
|
||||
return (self.rpc_flavor and
|
||||
self.plugins[self.rpc_flavor].rpc_workers_supported())
|
||||
|
||||
def create_network(self, context, network):
|
||||
n = network['network']
|
||||
flavor = n.get(ext_flavor.FLAVOR_NETWORK)
|
||||
if str(flavor) not in self.plugins:
|
||||
flavor = self.default_flavor
|
||||
plugin = self._get_plugin(flavor)
|
||||
net = plugin.create_network(context, network)
|
||||
LOG.debug("Created network: %(net_id)s with flavor "
|
||||
"%(flavor)s", {'net_id': net['id'], 'flavor': flavor})
|
||||
try:
|
||||
meta_db_v2.add_network_flavor_binding(context.session,
|
||||
flavor, str(net['id']))
|
||||
except Exception:
|
||||
LOG.exception(_LE('Failed to add flavor bindings'))
|
||||
plugin.delete_network(context, net['id'])
|
||||
raise FaildToAddFlavorBinding()
|
||||
|
||||
LOG.debug("Created network: %s", net['id'])
|
||||
self._extend_network_dict(context, net)
|
||||
return net
|
||||
|
||||
def update_network(self, context, id, network):
|
||||
flavor = meta_db_v2.get_flavor_by_network(context.session, id)
|
||||
plugin = self._get_plugin(flavor)
|
||||
return plugin.update_network(context, id, network)
|
||||
|
||||
def delete_network(self, context, id):
|
||||
flavor = meta_db_v2.get_flavor_by_network(context.session, id)
|
||||
plugin = self._get_plugin(flavor)
|
||||
return plugin.delete_network(context, id)
|
||||
|
||||
def get_network(self, context, id, fields=None):
|
||||
flavor = meta_db_v2.get_flavor_by_network(context.session, id)
|
||||
plugin = self._get_plugin(flavor)
|
||||
net = plugin.get_network(context, id, fields)
|
||||
net['id'] = id
|
||||
if not fields or ext_flavor.FLAVOR_NETWORK in fields:
|
||||
self._extend_network_dict(context, net)
|
||||
if fields and 'id' not in fields:
|
||||
del net['id']
|
||||
return net
|
||||
|
||||
def get_networks(self, context, filters=None, fields=None):
|
||||
nets = []
|
||||
for flavor, plugin in self.plugins.items():
|
||||
if (filters and ext_flavor.FLAVOR_NETWORK in filters and
|
||||
flavor not in filters[ext_flavor.FLAVOR_NETWORK]):
|
||||
continue
|
||||
if filters:
|
||||
#NOTE: copy each time since a target plugin may modify
|
||||
# plugin_filters.
|
||||
plugin_filters = filters.copy()
|
||||
else:
|
||||
plugin_filters = {}
|
||||
plugin_filters[ext_flavor.FLAVOR_NETWORK] = [flavor]
|
||||
plugin_nets = plugin.get_networks(context, plugin_filters, fields)
|
||||
for net in plugin_nets:
|
||||
if not fields or ext_flavor.FLAVOR_NETWORK in fields:
|
||||
net[ext_flavor.FLAVOR_NETWORK] = flavor
|
||||
nets.append(net)
|
||||
return nets
|
||||
|
||||
def _get_flavor_by_network_id(self, context, network_id):
|
||||
return meta_db_v2.get_flavor_by_network(context.session, network_id)
|
||||
|
||||
def _get_flavor_by_router_id(self, context, router_id):
|
||||
return meta_db_v2.get_flavor_by_router(context.session, router_id)
|
||||
|
||||
def _get_plugin_by_network_id(self, context, network_id):
|
||||
flavor = self._get_flavor_by_network_id(context, network_id)
|
||||
return self._get_plugin(flavor)
|
||||
|
||||
def create_port(self, context, port):
|
||||
p = port['port']
|
||||
if 'network_id' not in p:
|
||||
raise exc.NotFound()
|
||||
plugin = self._get_plugin_by_network_id(context, p['network_id'])
|
||||
return plugin.create_port(context, port)
|
||||
|
||||
def update_port(self, context, id, port):
|
||||
port_in_db = self._get_port(context, id)
|
||||
plugin = self._get_plugin_by_network_id(context,
|
||||
port_in_db['network_id'])
|
||||
return plugin.update_port(context, id, port)
|
||||
|
||||
def delete_port(self, context, id, l3_port_check=True):
|
||||
port_in_db = self._get_port(context, id)
|
||||
plugin = self._get_plugin_by_network_id(context,
|
||||
port_in_db['network_id'])
|
||||
return plugin.delete_port(context, id, l3_port_check)
|
||||
|
||||
# This is necessary since there is a case that
|
||||
# NeutronManager.get_plugin()._make_port_dict is called.
|
||||
def _make_port_dict(self, port):
|
||||
context = neutron_context.get_admin_context()
|
||||
plugin = self._get_plugin_by_network_id(context,
|
||||
port['network_id'])
|
||||
return plugin._make_port_dict(port)
|
||||
|
||||
def get_port(self, context, id, fields=None):
|
||||
port_in_db = self._get_port(context, id)
|
||||
plugin = self._get_plugin_by_network_id(context,
|
||||
port_in_db['network_id'])
|
||||
return plugin.get_port(context, id, fields)
|
||||
|
||||
def get_ports(self, context, filters=None, fields=None):
|
||||
all_ports = []
|
||||
for flavor, plugin in self.plugins.items():
|
||||
if filters:
|
||||
#NOTE: copy each time since a target plugin may modify
|
||||
# plugin_filters.
|
||||
plugin_filters = filters.copy()
|
||||
else:
|
||||
plugin_filters = {}
|
||||
plugin_filters[ext_flavor.FLAVOR_NETWORK] = [flavor]
|
||||
ports = plugin.get_ports(context, plugin_filters, fields)
|
||||
all_ports += ports
|
||||
return all_ports
|
||||
|
||||
def create_subnet(self, context, subnet):
|
||||
s = subnet['subnet']
|
||||
if 'network_id' not in s:
|
||||
raise exc.NotFound()
|
||||
plugin = self._get_plugin_by_network_id(context,
|
||||
s['network_id'])
|
||||
return plugin.create_subnet(context, subnet)
|
||||
|
||||
def update_subnet(self, context, id, subnet):
|
||||
s = self.get_subnet(context, id)
|
||||
plugin = self._get_plugin_by_network_id(context,
|
||||
s['network_id'])
|
||||
return plugin.update_subnet(context, id, subnet)
|
||||
|
||||
def delete_subnet(self, context, id):
|
||||
s = self.get_subnet(context, id)
|
||||
plugin = self._get_plugin_by_network_id(context,
|
||||
s['network_id'])
|
||||
return plugin.delete_subnet(context, id)
|
||||
|
||||
def _extend_router_dict(self, context, router):
|
||||
flavor = self._get_flavor_by_router_id(context, router['id'])
|
||||
router[ext_flavor.FLAVOR_ROUTER] = flavor
|
||||
|
||||
def create_router(self, context, router):
|
||||
r = router['router']
|
||||
flavor = r.get(ext_flavor.FLAVOR_ROUTER)
|
||||
if str(flavor) not in self.l3_plugins:
|
||||
flavor = self.default_l3_flavor
|
||||
plugin = self._get_l3_plugin(flavor)
|
||||
r_in_db = plugin.create_router(context, router)
|
||||
LOG.debug("Created router: %(router_id)s with flavor "
|
||||
"%(flavor)s",
|
||||
{'router_id': r_in_db['id'], 'flavor': flavor})
|
||||
try:
|
||||
meta_db_v2.add_router_flavor_binding(context.session,
|
||||
flavor, str(r_in_db['id']))
|
||||
except Exception:
|
||||
LOG.exception(_LE('Failed to add flavor bindings'))
|
||||
plugin.delete_router(context, r_in_db['id'])
|
||||
raise FaildToAddFlavorBinding()
|
||||
|
||||
LOG.debug("Created router: %s", r_in_db['id'])
|
||||
self._extend_router_dict(context, r_in_db)
|
||||
return r_in_db
|
||||
|
||||
def update_router(self, context, id, router):
|
||||
flavor = meta_db_v2.get_flavor_by_router(context.session, id)
|
||||
plugin = self._get_l3_plugin(flavor)
|
||||
return plugin.update_router(context, id, router)
|
||||
|
||||
def delete_router(self, context, id):
|
||||
flavor = meta_db_v2.get_flavor_by_router(context.session, id)
|
||||
plugin = self._get_l3_plugin(flavor)
|
||||
return plugin.delete_router(context, id)
|
||||
|
||||
def get_router(self, context, id, fields=None):
|
||||
flavor = meta_db_v2.get_flavor_by_router(context.session, id)
|
||||
plugin = self._get_l3_plugin(flavor)
|
||||
router = plugin.get_router(context, id, fields)
|
||||
if not fields or ext_flavor.FLAVOR_ROUTER in fields:
|
||||
self._extend_router_dict(context, router)
|
||||
return router
|
||||
|
||||
def get_routers_with_flavor(self, context, filters=None,
|
||||
fields=None):
|
||||
collection = self._model_query(context, l3_db.Router)
|
||||
r_model = meta_models_v2.RouterFlavor
|
||||
collection = collection.join(r_model,
|
||||
l3_db.Router.id == r_model.router_id)
|
||||
if filters:
|
||||
for key, value in filters.iteritems():
|
||||
if key == ext_flavor.FLAVOR_ROUTER:
|
||||
column = meta_models_v2.RouterFlavor.flavor
|
||||
else:
|
||||
column = getattr(l3_db.Router, key, None)
|
||||
if column:
|
||||
collection = collection.filter(column.in_(value))
|
||||
return [self._make_router_dict(c, fields) for c in collection]
|
||||
|
||||
def get_routers(self, context, filters=None, fields=None):
|
||||
routers = self.get_routers_with_flavor(context, filters,
|
||||
None)
|
||||
return [self.get_router(context, router['id'],
|
||||
fields)
|
||||
for router in routers]
|
||||
MetaPluginV2 = meta_neutron_plugin.MetaPluginV2
|
||||
|
@ -13,123 +13,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
from neutron.db import db_base_plugin_v2
|
||||
from neutron.db import external_net_db
|
||||
from neutron.db import l3_db
|
||||
from neutron.i18n import _LE, _LW
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutronclient.common import exceptions
|
||||
from neutronclient.v2_0 import client
|
||||
from metaplugin.plugin import proxy_neutron_plugin
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ProxyPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
external_net_db.External_net_db_mixin,
|
||||
l3_db.L3_NAT_db_mixin):
|
||||
supported_extension_aliases = ["external-net", "router"]
|
||||
|
||||
def __init__(self, configfile=None):
|
||||
super(ProxyPluginV2, self).__init__()
|
||||
self.neutron = client.Client(
|
||||
username=cfg.CONF.PROXY.admin_user,
|
||||
password=cfg.CONF.PROXY.admin_password,
|
||||
tenant_name=cfg.CONF.PROXY.admin_tenant_name,
|
||||
auth_url=cfg.CONF.PROXY.auth_url,
|
||||
auth_strategy=cfg.CONF.PROXY.auth_strategy,
|
||||
region_name=cfg.CONF.PROXY.auth_region
|
||||
)
|
||||
|
||||
def _get_client(self):
|
||||
return self.neutron
|
||||
|
||||
def create_subnet(self, context, subnet):
|
||||
subnet_remote = self._get_client().create_subnet(subnet)
|
||||
subnet['subnet']['id'] = subnet_remote['id']
|
||||
tenant_id = self._get_tenant_id_for_create(context, subnet['subnet'])
|
||||
subnet['subnet']['tenant_id'] = tenant_id
|
||||
try:
|
||||
subnet_in_db = super(ProxyPluginV2, self).create_subnet(
|
||||
context, subnet)
|
||||
except Exception:
|
||||
self._get_client().delete_subnet(subnet_remote['id'])
|
||||
return subnet_in_db
|
||||
|
||||
def update_subnet(self, context, id, subnet):
|
||||
subnet_in_db = super(ProxyPluginV2, self).update_subnet(
|
||||
context, id, subnet)
|
||||
try:
|
||||
self._get_client().update_subnet(id, subnet)
|
||||
except Exception as e:
|
||||
LOG.error(_LE("Update subnet failed: %s"), e)
|
||||
return subnet_in_db
|
||||
|
||||
def delete_subnet(self, context, id):
|
||||
try:
|
||||
self._get_client().delete_subnet(id)
|
||||
except exceptions.NotFound:
|
||||
LOG.warn(_LW("Subnet in remote have already deleted"))
|
||||
return super(ProxyPluginV2, self).delete_subnet(context, id)
|
||||
|
||||
def create_network(self, context, network):
|
||||
network_remote = self._get_client().create_network(network)
|
||||
network['network']['id'] = network_remote['id']
|
||||
tenant_id = self._get_tenant_id_for_create(context, network['network'])
|
||||
network['network']['tenant_id'] = tenant_id
|
||||
try:
|
||||
network_in_db = super(ProxyPluginV2, self).create_network(
|
||||
context, network)
|
||||
except Exception:
|
||||
self._get_client().delete_network(network_remote['id'])
|
||||
return network_in_db
|
||||
|
||||
def update_network(self, context, id, network):
|
||||
network_in_db = super(ProxyPluginV2, self).update_network(
|
||||
context, id, network)
|
||||
try:
|
||||
self._get_client().update_network(id, network)
|
||||
except Exception as e:
|
||||
LOG.error(_LE("Update network failed: %s"), e)
|
||||
return network_in_db
|
||||
|
||||
def delete_network(self, context, id):
|
||||
try:
|
||||
self._get_client().delete_network(id)
|
||||
except exceptions.NetworkNotFoundClient:
|
||||
LOG.warn(_LW("Network in remote have already deleted"))
|
||||
return super(ProxyPluginV2, self).delete_network(context, id)
|
||||
|
||||
def create_port(self, context, port):
|
||||
port_remote = self._get_client().create_port(port)
|
||||
port['port']['id'] = port_remote['id']
|
||||
tenant_id = self._get_tenant_id_for_create(context, port['port'])
|
||||
port['port']['tenant_id'] = tenant_id
|
||||
try:
|
||||
port_in_db = super(ProxyPluginV2, self).create_port(
|
||||
context, port)
|
||||
except Exception:
|
||||
self._get_client().delete_port(port_remote['id'])
|
||||
return port_in_db
|
||||
|
||||
def update_port(self, context, id, port):
|
||||
port_in_db = super(ProxyPluginV2, self).update_port(
|
||||
context, id, port)
|
||||
try:
|
||||
self._get_client().update_port(id, port)
|
||||
except Exception as e:
|
||||
LOG.error(_LE("Update port failed: %s"), e)
|
||||
return port_in_db
|
||||
|
||||
def delete_port(self, context, id, l3_port_check=True):
|
||||
if l3_port_check:
|
||||
self.prevent_l3_port_deletion(context, id)
|
||||
self.disassociate_floatingips(context, id)
|
||||
|
||||
try:
|
||||
self._get_client().delete_port(id)
|
||||
except exceptions.PortNotFoundClient:
|
||||
LOG.warn(_LW("Port in remote have already deleted"))
|
||||
return super(ProxyPluginV2, self).delete_port(context, id)
|
||||
ProxyPluginV2 = proxy_neutron_plugin.ProxyPluginV2
|
||||
|
@ -1,77 +0,0 @@
|
||||
# Copyright 2012, Nachi Ueno, NTT MCL, Inc.
|
||||
#
|
||||
# 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.db import db_base_plugin_v2
|
||||
from neutron.db import external_net_db
|
||||
from neutron.db import l3_gwmode_db
|
||||
|
||||
|
||||
class Fake1(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
external_net_db.External_net_db_mixin,
|
||||
l3_gwmode_db.L3_NAT_db_mixin):
|
||||
supported_extension_aliases = ['external-net', 'router']
|
||||
|
||||
def fake_func(self):
|
||||
return 'fake1'
|
||||
|
||||
def create_network(self, context, network):
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
net = super(Fake1, self).create_network(context, network)
|
||||
self._process_l3_create(context, net, network['network'])
|
||||
return net
|
||||
|
||||
def update_network(self, context, id, network):
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
net = super(Fake1, self).update_network(context, id,
|
||||
network)
|
||||
self._process_l3_update(context, net, network['network'])
|
||||
return net
|
||||
|
||||
def delete_network(self, context, id):
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
self._process_l3_delete(context, id)
|
||||
return super(Fake1, self).delete_network(context, id)
|
||||
|
||||
def create_port(self, context, port):
|
||||
port = super(Fake1, self).create_port(context, port)
|
||||
return port
|
||||
|
||||
def create_subnet(self, context, subnet):
|
||||
subnet = super(Fake1, self).create_subnet(context, subnet)
|
||||
return subnet
|
||||
|
||||
def update_port(self, context, id, port):
|
||||
port = super(Fake1, self).update_port(context, id, port)
|
||||
return port
|
||||
|
||||
def delete_port(self, context, id, l3_port_check=True):
|
||||
if l3_port_check:
|
||||
self.prevent_l3_port_deletion(context, id)
|
||||
self.disassociate_floatingips(context, id)
|
||||
return super(Fake1, self).delete_port(context, id)
|
||||
|
||||
|
||||
class Fake2(Fake1):
|
||||
def fake_func(self):
|
||||
return 'fake2'
|
||||
|
||||
def fake_func2(self):
|
||||
return 'fake2'
|
||||
|
||||
def start_rpc_listeners(self):
|
||||
# return value is only used to confirm this method was called.
|
||||
return 'OK'
|
@ -1,78 +0,0 @@
|
||||
# Copyright (c) 2012 OpenStack Foundation.
|
||||
#
|
||||
# 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.tests.unit.metaplugin import test_metaplugin
|
||||
from neutron.tests.unit import test_db_plugin as test_plugin
|
||||
from neutron.tests.unit import test_l3_plugin
|
||||
|
||||
|
||||
class MetaPluginV2DBTestCase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
|
||||
_plugin_name = ('neutron.plugins.metaplugin.'
|
||||
'meta_neutron_plugin.MetaPluginV2')
|
||||
|
||||
def setUp(self, plugin=None, ext_mgr=None,
|
||||
service_plugins=None):
|
||||
# NOTE(salv-orlando): The plugin keyword argument is ignored,
|
||||
# as this class will always invoke super with self._plugin_name.
|
||||
# These keyword parameters ensure setUp methods always have the
|
||||
# same signature.
|
||||
test_metaplugin.setup_metaplugin_conf()
|
||||
ext_mgr = ext_mgr or test_l3_plugin.L3TestExtensionManager()
|
||||
self.addCleanup(test_metaplugin.unregister_meta_hooks)
|
||||
super(MetaPluginV2DBTestCase, self).setUp(
|
||||
plugin=self._plugin_name, ext_mgr=ext_mgr,
|
||||
service_plugins=service_plugins)
|
||||
|
||||
|
||||
class TestMetaBasicGet(test_plugin.TestBasicGet,
|
||||
MetaPluginV2DBTestCase):
|
||||
pass
|
||||
|
||||
|
||||
class TestMetaV2HTTPResponse(test_plugin.TestV2HTTPResponse,
|
||||
MetaPluginV2DBTestCase):
|
||||
pass
|
||||
|
||||
|
||||
class TestMetaPortsV2(test_plugin.TestPortsV2,
|
||||
MetaPluginV2DBTestCase):
|
||||
pass
|
||||
|
||||
|
||||
class TestMetaNetworksV2(test_plugin.TestNetworksV2,
|
||||
MetaPluginV2DBTestCase):
|
||||
pass
|
||||
|
||||
|
||||
class TestMetaSubnetsV2(test_plugin.TestSubnetsV2,
|
||||
MetaPluginV2DBTestCase):
|
||||
#TODO(nati) This test fails if we run all test, but It success just one
|
||||
def test_update_subnet_route(self):
|
||||
pass
|
||||
|
||||
def test_update_subnet_dns_to_None(self):
|
||||
pass
|
||||
|
||||
def test_update_subnet_route_to_None(self):
|
||||
pass
|
||||
|
||||
def test_update_subnet_dns(self):
|
||||
pass
|
||||
|
||||
|
||||
class TestMetaL3NatDBTestCase(test_l3_plugin.L3NatDBIntTestCase,
|
||||
MetaPluginV2DBTestCase):
|
||||
pass
|
@ -1,405 +0,0 @@
|
||||
# Copyright 2012, Nachi Ueno, NTT MCL, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
from oslo_config import cfg
|
||||
import testtools
|
||||
|
||||
from neutron.common import exceptions as exc
|
||||
from neutron.common import topics
|
||||
from neutron import context
|
||||
from neutron.db import db_base_plugin_v2
|
||||
from neutron.db import models_v2
|
||||
from neutron.extensions import flavor as ext_flavor
|
||||
from neutron.openstack.common import uuidutils
|
||||
from neutron.plugins.metaplugin import meta_neutron_plugin
|
||||
from neutron.tests.unit import testlib_api
|
||||
from neutron.tests.unit import testlib_plugin
|
||||
|
||||
CONF_FILE = ""
|
||||
META_PATH = "neutron.plugins.metaplugin"
|
||||
FAKE_PATH = "neutron.tests.unit.metaplugin"
|
||||
PROXY_PATH = "%s.proxy_neutron_plugin.ProxyPluginV2" % META_PATH
|
||||
PLUGIN_LIST = """
|
||||
fake1:%s.fake_plugin.Fake1,fake2:%s.fake_plugin.Fake2,proxy:%s
|
||||
""".strip() % (FAKE_PATH, FAKE_PATH, PROXY_PATH)
|
||||
L3_PLUGIN_LIST = """
|
||||
fake1:%s.fake_plugin.Fake1,fake2:%s.fake_plugin.Fake2
|
||||
""".strip() % (FAKE_PATH, FAKE_PATH)
|
||||
|
||||
|
||||
def setup_metaplugin_conf(has_l3=True):
|
||||
cfg.CONF.set_override('auth_url', 'http://localhost:35357/v2.0',
|
||||
'PROXY')
|
||||
cfg.CONF.set_override('auth_region', 'RegionOne', 'PROXY')
|
||||
cfg.CONF.set_override('admin_user', 'neutron', 'PROXY')
|
||||
cfg.CONF.set_override('admin_password', 'password', 'PROXY')
|
||||
cfg.CONF.set_override('admin_tenant_name', 'service', 'PROXY')
|
||||
cfg.CONF.set_override('plugin_list', PLUGIN_LIST, 'META')
|
||||
if has_l3:
|
||||
cfg.CONF.set_override('l3_plugin_list', L3_PLUGIN_LIST, 'META')
|
||||
else:
|
||||
cfg.CONF.set_override('l3_plugin_list', "", 'META')
|
||||
cfg.CONF.set_override('default_flavor', 'fake2', 'META')
|
||||
cfg.CONF.set_override('default_l3_flavor', 'fake1', 'META')
|
||||
cfg.CONF.set_override('base_mac', "12:34:56:78:90:ab")
|
||||
#TODO(nati) remove this after subnet quota change is merged
|
||||
cfg.CONF.set_override('max_dns_nameservers', 10)
|
||||
|
||||
|
||||
# Hooks registered by metaplugin must not exist for other plugins UT.
|
||||
# So hooks must be unregistered (overwrite to None in fact).
|
||||
def unregister_meta_hooks():
|
||||
db_base_plugin_v2.NeutronDbPluginV2.register_model_query_hook(
|
||||
models_v2.Network, 'metaplugin_net', None, None, None)
|
||||
db_base_plugin_v2.NeutronDbPluginV2.register_model_query_hook(
|
||||
models_v2.Port, 'metaplugin_port', None, None, None)
|
||||
|
||||
|
||||
class MetaNeutronPluginV2Test(testlib_api.SqlTestCase,
|
||||
testlib_plugin.PluginSetupHelper):
|
||||
"""Class conisting of MetaNeutronPluginV2 unit tests."""
|
||||
|
||||
has_l3 = True
|
||||
|
||||
def setUp(self):
|
||||
super(MetaNeutronPluginV2Test, self).setUp()
|
||||
self.fake_tenant_id = uuidutils.generate_uuid()
|
||||
self.context = context.get_admin_context()
|
||||
|
||||
self.addCleanup(unregister_meta_hooks)
|
||||
|
||||
setup_metaplugin_conf(self.has_l3)
|
||||
|
||||
self.client_cls_p = mock.patch('neutronclient.v2_0.client.Client')
|
||||
client_cls = self.client_cls_p.start()
|
||||
self.client_inst = mock.Mock()
|
||||
client_cls.return_value = self.client_inst
|
||||
self.client_inst.create_network.return_value = \
|
||||
{'id': 'fake_id'}
|
||||
self.client_inst.create_port.return_value = \
|
||||
{'id': 'fake_id'}
|
||||
self.client_inst.create_subnet.return_value = \
|
||||
{'id': 'fake_id'}
|
||||
self.client_inst.update_network.return_value = \
|
||||
{'id': 'fake_id'}
|
||||
self.client_inst.update_port.return_value = \
|
||||
{'id': 'fake_id'}
|
||||
self.client_inst.update_subnet.return_value = \
|
||||
{'id': 'fake_id'}
|
||||
self.client_inst.delete_network.return_value = True
|
||||
self.client_inst.delete_port.return_value = True
|
||||
self.client_inst.delete_subnet.return_value = True
|
||||
plugin = (meta_neutron_plugin.MetaPluginV2.__module__ + '.'
|
||||
+ meta_neutron_plugin.MetaPluginV2.__name__)
|
||||
self.setup_coreplugin(plugin)
|
||||
self.plugin = meta_neutron_plugin.MetaPluginV2(configfile=None)
|
||||
|
||||
def _fake_network(self, flavor):
|
||||
data = {'network': {'name': flavor,
|
||||
'admin_state_up': True,
|
||||
'shared': False,
|
||||
'router:external': [],
|
||||
'tenant_id': self.fake_tenant_id,
|
||||
ext_flavor.FLAVOR_NETWORK: flavor}}
|
||||
return data
|
||||
|
||||
def _fake_port(self, net_id):
|
||||
return {'port': {'name': net_id,
|
||||
'network_id': net_id,
|
||||
'admin_state_up': True,
|
||||
'device_id': 'bad_device_id',
|
||||
'device_owner': 'bad_device_owner',
|
||||
'admin_state_up': True,
|
||||
'host_routes': [],
|
||||
'fixed_ips': [],
|
||||
'mac_address': self.plugin._generate_mac(),
|
||||
'tenant_id': self.fake_tenant_id}}
|
||||
|
||||
def _fake_subnet(self, net_id):
|
||||
allocation_pools = [{'start': '10.0.0.2',
|
||||
'end': '10.0.0.254'}]
|
||||
return {'subnet': {'name': net_id,
|
||||
'network_id': net_id,
|
||||
'gateway_ip': '10.0.0.1',
|
||||
'dns_nameservers': ['10.0.0.2'],
|
||||
'host_routes': [],
|
||||
'cidr': '10.0.0.0/24',
|
||||
'allocation_pools': allocation_pools,
|
||||
'enable_dhcp': True,
|
||||
'ip_version': 4}}
|
||||
|
||||
def _fake_router(self, flavor):
|
||||
data = {'router': {'name': flavor, 'admin_state_up': True,
|
||||
'tenant_id': self.fake_tenant_id,
|
||||
ext_flavor.FLAVOR_ROUTER: flavor,
|
||||
'external_gateway_info': None}}
|
||||
return data
|
||||
|
||||
def test_create_delete_network(self):
|
||||
network1 = self._fake_network('fake1')
|
||||
ret1 = self.plugin.create_network(self.context, network1)
|
||||
self.assertEqual('fake1', ret1[ext_flavor.FLAVOR_NETWORK])
|
||||
|
||||
network2 = self._fake_network('fake2')
|
||||
ret2 = self.plugin.create_network(self.context, network2)
|
||||
self.assertEqual('fake2', ret2[ext_flavor.FLAVOR_NETWORK])
|
||||
|
||||
network3 = self._fake_network('proxy')
|
||||
ret3 = self.plugin.create_network(self.context, network3)
|
||||
self.assertEqual('proxy', ret3[ext_flavor.FLAVOR_NETWORK])
|
||||
|
||||
db_ret1 = self.plugin.get_network(self.context, ret1['id'])
|
||||
self.assertEqual('fake1', db_ret1['name'])
|
||||
|
||||
db_ret2 = self.plugin.get_network(self.context, ret2['id'])
|
||||
self.assertEqual('fake2', db_ret2['name'])
|
||||
|
||||
db_ret3 = self.plugin.get_network(self.context, ret3['id'])
|
||||
self.assertEqual('proxy', db_ret3['name'])
|
||||
|
||||
db_ret4 = self.plugin.get_networks(self.context)
|
||||
self.assertEqual(3, len(db_ret4))
|
||||
|
||||
db_ret5 = self.plugin.get_networks(
|
||||
self.context,
|
||||
{ext_flavor.FLAVOR_NETWORK: ['fake1']})
|
||||
self.assertEqual(1, len(db_ret5))
|
||||
self.assertEqual('fake1', db_ret5[0]['name'])
|
||||
self.plugin.delete_network(self.context, ret1['id'])
|
||||
self.plugin.delete_network(self.context, ret2['id'])
|
||||
self.plugin.delete_network(self.context, ret3['id'])
|
||||
|
||||
def test_create_delete_port(self):
|
||||
network1 = self._fake_network('fake1')
|
||||
network_ret1 = self.plugin.create_network(self.context, network1)
|
||||
network2 = self._fake_network('fake2')
|
||||
network_ret2 = self.plugin.create_network(self.context, network2)
|
||||
network3 = self._fake_network('proxy')
|
||||
network_ret3 = self.plugin.create_network(self.context, network3)
|
||||
|
||||
port1 = self._fake_port(network_ret1['id'])
|
||||
port2 = self._fake_port(network_ret2['id'])
|
||||
port3 = self._fake_port(network_ret3['id'])
|
||||
|
||||
port1_ret = self.plugin.create_port(self.context, port1)
|
||||
port2_ret = self.plugin.create_port(self.context, port2)
|
||||
port3_ret = self.plugin.create_port(self.context, port3)
|
||||
ports_all = self.plugin.get_ports(self.context)
|
||||
|
||||
self.assertEqual(network_ret1['id'], port1_ret['network_id'])
|
||||
self.assertEqual(network_ret2['id'], port2_ret['network_id'])
|
||||
self.assertEqual(network_ret3['id'], port3_ret['network_id'])
|
||||
self.assertEqual(3, len(ports_all))
|
||||
|
||||
port1_dict = self.plugin._make_port_dict(port1_ret)
|
||||
port2_dict = self.plugin._make_port_dict(port2_ret)
|
||||
port3_dict = self.plugin._make_port_dict(port3_ret)
|
||||
|
||||
self.assertEqual(port1_dict, port1_ret)
|
||||
self.assertEqual(port2_dict, port2_ret)
|
||||
self.assertEqual(port3_dict, port3_ret)
|
||||
|
||||
port1['port']['admin_state_up'] = False
|
||||
port2['port']['admin_state_up'] = False
|
||||
port3['port']['admin_state_up'] = False
|
||||
self.plugin.update_port(self.context, port1_ret['id'], port1)
|
||||
self.plugin.update_port(self.context, port2_ret['id'], port2)
|
||||
self.plugin.update_port(self.context, port3_ret['id'], port3)
|
||||
port_in_db1 = self.plugin.get_port(self.context, port1_ret['id'])
|
||||
port_in_db2 = self.plugin.get_port(self.context, port2_ret['id'])
|
||||
port_in_db3 = self.plugin.get_port(self.context, port3_ret['id'])
|
||||
self.assertEqual(False, port_in_db1['admin_state_up'])
|
||||
self.assertEqual(False, port_in_db2['admin_state_up'])
|
||||
self.assertEqual(False, port_in_db3['admin_state_up'])
|
||||
|
||||
self.plugin.delete_port(self.context, port1_ret['id'])
|
||||
self.plugin.delete_port(self.context, port2_ret['id'])
|
||||
self.plugin.delete_port(self.context, port3_ret['id'])
|
||||
|
||||
self.plugin.delete_network(self.context, network_ret1['id'])
|
||||
self.plugin.delete_network(self.context, network_ret2['id'])
|
||||
self.plugin.delete_network(self.context, network_ret3['id'])
|
||||
|
||||
def test_create_delete_subnet(self):
|
||||
# for this test we need to enable overlapping ips
|
||||
cfg.CONF.set_default('allow_overlapping_ips', True)
|
||||
network1 = self._fake_network('fake1')
|
||||
network_ret1 = self.plugin.create_network(self.context, network1)
|
||||
network2 = self._fake_network('fake2')
|
||||
network_ret2 = self.plugin.create_network(self.context, network2)
|
||||
network3 = self._fake_network('proxy')
|
||||
network_ret3 = self.plugin.create_network(self.context, network3)
|
||||
|
||||
subnet1 = self._fake_subnet(network_ret1['id'])
|
||||
subnet2 = self._fake_subnet(network_ret2['id'])
|
||||
subnet3 = self._fake_subnet(network_ret3['id'])
|
||||
|
||||
subnet1_ret = self.plugin.create_subnet(self.context, subnet1)
|
||||
subnet2_ret = self.plugin.create_subnet(self.context, subnet2)
|
||||
subnet3_ret = self.plugin.create_subnet(self.context, subnet3)
|
||||
self.assertEqual(network_ret1['id'], subnet1_ret['network_id'])
|
||||
self.assertEqual(network_ret2['id'], subnet2_ret['network_id'])
|
||||
self.assertEqual(network_ret3['id'], subnet3_ret['network_id'])
|
||||
|
||||
subnet_in_db1 = self.plugin.get_subnet(self.context, subnet1_ret['id'])
|
||||
subnet_in_db2 = self.plugin.get_subnet(self.context, subnet2_ret['id'])
|
||||
subnet_in_db3 = self.plugin.get_subnet(self.context, subnet3_ret['id'])
|
||||
|
||||
subnet1['subnet']['allocation_pools'].pop()
|
||||
subnet2['subnet']['allocation_pools'].pop()
|
||||
subnet3['subnet']['allocation_pools'].pop()
|
||||
|
||||
self.plugin.update_subnet(self.context,
|
||||
subnet1_ret['id'], subnet1)
|
||||
self.plugin.update_subnet(self.context,
|
||||
subnet2_ret['id'], subnet2)
|
||||
self.plugin.update_subnet(self.context,
|
||||
subnet3_ret['id'], subnet3)
|
||||
subnet_in_db1 = self.plugin.get_subnet(self.context, subnet1_ret['id'])
|
||||
subnet_in_db2 = self.plugin.get_subnet(self.context, subnet2_ret['id'])
|
||||
subnet_in_db3 = self.plugin.get_subnet(self.context, subnet3_ret['id'])
|
||||
|
||||
self.assertEqual(4, subnet_in_db1['ip_version'])
|
||||
self.assertEqual(4, subnet_in_db2['ip_version'])
|
||||
self.assertEqual(4, subnet_in_db3['ip_version'])
|
||||
|
||||
self.plugin.delete_subnet(self.context, subnet1_ret['id'])
|
||||
self.plugin.delete_subnet(self.context, subnet2_ret['id'])
|
||||
self.plugin.delete_subnet(self.context, subnet3_ret['id'])
|
||||
|
||||
self.plugin.delete_network(self.context, network_ret1['id'])
|
||||
self.plugin.delete_network(self.context, network_ret2['id'])
|
||||
self.plugin.delete_network(self.context, network_ret3['id'])
|
||||
|
||||
def test_create_delete_router(self):
|
||||
router1 = self._fake_router('fake1')
|
||||
router_ret1 = self.plugin.create_router(self.context, router1)
|
||||
router2 = self._fake_router('fake2')
|
||||
router_ret2 = self.plugin.create_router(self.context, router2)
|
||||
|
||||
self.assertEqual('fake1', router_ret1[ext_flavor.FLAVOR_ROUTER])
|
||||
self.assertEqual('fake2', router_ret2[ext_flavor.FLAVOR_ROUTER])
|
||||
|
||||
router_in_db1 = self.plugin.get_router(self.context, router_ret1['id'])
|
||||
router_in_db2 = self.plugin.get_router(self.context, router_ret2['id'])
|
||||
|
||||
self.assertEqual('fake1', router_in_db1[ext_flavor.FLAVOR_ROUTER])
|
||||
self.assertEqual('fake2', router_in_db2[ext_flavor.FLAVOR_ROUTER])
|
||||
|
||||
self.plugin.delete_router(self.context, router_ret1['id'])
|
||||
self.plugin.delete_router(self.context, router_ret2['id'])
|
||||
with testtools.ExpectedException(meta_neutron_plugin.FlavorNotFound):
|
||||
self.plugin.get_router(self.context, router_ret1['id'])
|
||||
|
||||
def test_extension_method(self):
|
||||
"""Test if plugin methods are accessible from self.plugin
|
||||
|
||||
This test compensates for the nondeterministic ordering of
|
||||
self.plugin's plugins dictionary. Fake Plugin 1 and Fake Plugin 2
|
||||
both have a function called fake_func and the order of
|
||||
self.plugin.plugins will determine which fake_func is called.
|
||||
"""
|
||||
fake1 = self.plugin.plugins.keys().index('fake1')
|
||||
fake2 = self.plugin.plugins.keys().index('fake2')
|
||||
fake1_before_fake2 = fake1 < fake2
|
||||
|
||||
fake_func_return = 'fake1' if fake1_before_fake2 else 'fake2'
|
||||
|
||||
self.assertEqual(fake_func_return, self.plugin.fake_func())
|
||||
self.assertEqual('fake2', self.plugin.fake_func2())
|
||||
|
||||
def test_extension_not_implemented_method(self):
|
||||
try:
|
||||
self.plugin.not_implemented()
|
||||
except AttributeError:
|
||||
return
|
||||
except Exception:
|
||||
self.fail("AttributeError Error is not raised")
|
||||
|
||||
self.fail("No Error is not raised")
|
||||
|
||||
def test_create_network_flavor_fail(self):
|
||||
with mock.patch('neutron.plugins.metaplugin.meta_db_v2.'
|
||||
'add_network_flavor_binding',
|
||||
side_effect=Exception):
|
||||
network = self._fake_network('fake1')
|
||||
self.assertRaises(meta_neutron_plugin.FaildToAddFlavorBinding,
|
||||
self.plugin.create_network,
|
||||
self.context,
|
||||
network)
|
||||
count = self.plugin.get_networks_count(self.context)
|
||||
self.assertEqual(count, 0)
|
||||
|
||||
def test_create_router_flavor_fail(self):
|
||||
with mock.patch('neutron.plugins.metaplugin.meta_db_v2.'
|
||||
'add_router_flavor_binding',
|
||||
side_effect=Exception):
|
||||
router = self._fake_router('fake1')
|
||||
self.assertRaises(meta_neutron_plugin.FaildToAddFlavorBinding,
|
||||
self.plugin.create_router,
|
||||
self.context,
|
||||
router)
|
||||
count = self.plugin.get_routers_count(self.context)
|
||||
self.assertEqual(count, 0)
|
||||
|
||||
|
||||
class MetaNeutronPluginV2TestWithoutL3(MetaNeutronPluginV2Test):
|
||||
"""Tests without l3_plugin_list configration."""
|
||||
|
||||
has_l3 = False
|
||||
|
||||
def test_supported_extension_aliases(self):
|
||||
self.assertEqual(self.plugin.supported_extension_aliases,
|
||||
['flavor', 'external-net'])
|
||||
|
||||
def test_create_delete_router(self):
|
||||
self.skipTest("Test case without router")
|
||||
|
||||
def test_create_router_flavor_fail(self):
|
||||
self.skipTest("Test case without router")
|
||||
|
||||
|
||||
class MetaNeutronPluginV2TestRpcFlavor(testlib_api.SqlTestCase):
|
||||
"""Tests for rpc_flavor."""
|
||||
|
||||
def setUp(self):
|
||||
super(MetaNeutronPluginV2TestRpcFlavor, self).setUp()
|
||||
self.addCleanup(unregister_meta_hooks)
|
||||
|
||||
def test_rpc_flavor(self):
|
||||
setup_metaplugin_conf()
|
||||
cfg.CONF.set_override('rpc_flavor', 'fake1', 'META')
|
||||
self.plugin = meta_neutron_plugin.MetaPluginV2()
|
||||
self.assertEqual(topics.PLUGIN, 'q-plugin')
|
||||
ret = self.plugin.rpc_workers_supported()
|
||||
self.assertFalse(ret)
|
||||
|
||||
def test_invalid_rpc_flavor(self):
|
||||
setup_metaplugin_conf()
|
||||
cfg.CONF.set_override('rpc_flavor', 'fake-fake', 'META')
|
||||
self.assertRaises(exc.Invalid,
|
||||
meta_neutron_plugin.MetaPluginV2)
|
||||
self.assertEqual(topics.PLUGIN, 'q-plugin')
|
||||
|
||||
def test_rpc_flavor_multiple_rpc_workers(self):
|
||||
setup_metaplugin_conf()
|
||||
cfg.CONF.set_override('rpc_flavor', 'fake2', 'META')
|
||||
self.plugin = meta_neutron_plugin.MetaPluginV2()
|
||||
self.assertEqual(topics.PLUGIN, 'q-plugin')
|
||||
ret = self.plugin.rpc_workers_supported()
|
||||
self.assertTrue(ret)
|
||||
ret = self.plugin.start_rpc_listeners()
|
||||
self.assertEqual('OK', ret)
|
Loading…
Reference in New Issue
Block a user