Merge "Metaplugin decomposition"

This commit is contained in:
Jenkins 2015-03-05 04:49:15 +00:00 committed by Gerrit Code Review
commit 7cd356964c
9 changed files with 15 additions and 1217 deletions

View File

@ -401,7 +401,7 @@ The following chart captures the following aspects:
+-------------------------------+-----------------------+-----------+------------------+---------+--------------+
| networking-hyperv_ | | | | | |
+-------------------------------+-----------------------+-----------+------------------+---------+--------------+
| networking-metaplugin_ | | | | | |
| networking-metaplugin_ | core | no | no | [C] | Kilo |
+-------------------------------+-----------------------+-----------+------------------+---------+--------------+
| networking-midonet_ | core,lb | yes | yes | [C] | Kilo |
+-------------------------------+-----------------------+-----------+------------------+---------+--------------+
@ -440,6 +440,11 @@ Arista
.. _networking-metaplugin:
Metaplugin
----------
* Git: https://github.com/ntt-sic/networking-metaplugin
.. _networking-midonet:
MidoNet

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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)