Added check on plugin.supported_extension_aliases
Added check to neutron.api.extensions.PluginAwareExtensionManager which raises an exception when an alias in the plugin's `supported_extension_aliases` list is not found in the set of loaded extension aliases. If an alias is missing, it means the extension for that alias has not been loaded, has not been found, and the file is missing from paths listed in `oslo.config.CONF.api_extensions_path`. This guards against a common class of bugs in plugins, such as typographical errors in the `supported_extension_aliases` property. Plugin changes: * bigswitch.plugin: Moves api_extensions_path override to plugin's __init__ method, similar to other plugins. * cisco.n1kv.n1kv_neutron_plugin: Removes "policy_profile_binding" and "network_profile_binding" as they don't exist in Neutron currently. Removed override of api_extensions_path as it is loaded through cisco.network_plugin. * cisco.network_plugin: Renames "Cisco Credential" to "credential". Adds api_extension_path override to plugin's __init__ method. * metaplugin.meta_neutron_plugin: Avoids alias of empty string when cfg.CONF.META.supported_extension_aliases is an empty string. * midonet.plugin: Fixes regression of98e16a06
from715b16ac
. * nec.nec_plugin: Extended override of api_extensions_path to append nec extensions path to existing configured path. * nicira.NeutronPlugin: Extended override of api_extensions_path to append NXP_EXT_PATH to existing configured path. Fixes: bug 1225080 Change-Id: Idcaade221d83c611fcbd87b503b2c8377d106962
This commit is contained in:
parent
bc18247313
commit
f4c8a18314
@ -18,6 +18,7 @@
|
||||
|
||||
from abc import ABCMeta
|
||||
import imp
|
||||
import itertools
|
||||
import os
|
||||
|
||||
from oslo.config import cfg
|
||||
@ -578,6 +579,7 @@ class PluginAwareExtensionManager(ExtensionManager):
|
||||
def __init__(self, path, plugins):
|
||||
self.plugins = plugins
|
||||
super(PluginAwareExtensionManager, self).__init__(path)
|
||||
self.check_if_plugin_extensions_loaded()
|
||||
|
||||
def _check_extension(self, extension):
|
||||
"""Check if an extension is supported by any plugin."""
|
||||
@ -616,6 +618,16 @@ class PluginAwareExtensionManager(ExtensionManager):
|
||||
NeutronManager.get_service_plugins())
|
||||
return cls._instance
|
||||
|
||||
def check_if_plugin_extensions_loaded(self):
|
||||
"""Check if an extension supported by a plugin has been loaded."""
|
||||
plugin_extensions = set(itertools.chain.from_iterable([
|
||||
getattr(plugin, "supported_extension_aliases", [])
|
||||
for plugin in self.plugins.values()]))
|
||||
missing_aliases = plugin_extensions - set(self.extensions)
|
||||
if missing_aliases:
|
||||
raise exceptions.ExtensionsNotFound(
|
||||
extensions=list(missing_aliases))
|
||||
|
||||
|
||||
class RequestExtension(object):
|
||||
"""Extend requests and responses of core Neutron OpenStack API controllers.
|
||||
@ -662,3 +674,9 @@ def get_extensions_path():
|
||||
paths = ':'.join([cfg.CONF.api_extensions_path, paths])
|
||||
|
||||
return paths
|
||||
|
||||
|
||||
def append_api_extensions_path(paths):
|
||||
paths = [cfg.CONF.api_extensions_path] + paths
|
||||
cfg.CONF.set_override('api_extensions_path',
|
||||
':'.join([p for p in paths if p]))
|
||||
|
@ -261,6 +261,10 @@ class InvalidExtensionEnv(BadRequest):
|
||||
message = _("Invalid extension environment: %(reason)s")
|
||||
|
||||
|
||||
class ExtensionsNotFound(NotFound):
|
||||
message = _("Extensions not found: %(extensions)s")
|
||||
|
||||
|
||||
class InvalidContentType(NeutronException):
|
||||
message = _("Invalid content type %(content_type)s")
|
||||
|
||||
|
@ -48,11 +48,11 @@ import base64
|
||||
import copy
|
||||
import httplib
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from neutron.api import extensions as neutron_extensions
|
||||
from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
|
||||
from neutron.common import constants as const
|
||||
from neutron.common import exceptions
|
||||
@ -77,17 +77,12 @@ from neutron.openstack.common import importutils
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.openstack.common import rpc
|
||||
from neutron.plugins.bigswitch.db import porttracker_db
|
||||
from neutron.plugins.bigswitch import extensions
|
||||
from neutron.plugins.bigswitch import routerrule_db
|
||||
from neutron.plugins.bigswitch.version import version_string_with_vcs
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
# Include the BigSwitch Extensions path in the api_extensions
|
||||
EXTENSIONS_PATH = os.path.join(os.path.dirname(__file__), 'extensions')
|
||||
if not cfg.CONF.api_extensions_path:
|
||||
cfg.CONF.set_override('api_extensions_path',
|
||||
EXTENSIONS_PATH)
|
||||
|
||||
restproxy_opts = [
|
||||
cfg.StrOpt('servers', default='localhost:8800',
|
||||
help=_("A comma separated list of BigSwitch or Floodlight "
|
||||
@ -450,6 +445,9 @@ class NeutronRestProxyV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
# init DB, proxy's persistent store defaults to in-memory sql-lite DB
|
||||
db.configure_db()
|
||||
|
||||
# Include the BigSwitch Extensions path in the api_extensions
|
||||
neutron_extensions.append_api_extensions_path(extensions.__path__)
|
||||
|
||||
# 'servers' is the list of network controller REST end-points
|
||||
# (used in order specified till one suceeds, and it is sticky
|
||||
# till next failure). Use 'server_auth' to encode api-key
|
||||
|
@ -21,8 +21,6 @@
|
||||
|
||||
import eventlet
|
||||
|
||||
from oslo.config import cfg as q_conf
|
||||
|
||||
from neutron.agent import securitygroups_rpc as sg_rpc
|
||||
from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
|
||||
from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
|
||||
@ -148,8 +146,6 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
# bulk operations.
|
||||
__native_bulk_support = False
|
||||
supported_extension_aliases = ["provider", "agent",
|
||||
"policy_profile_binding",
|
||||
"network_profile_binding",
|
||||
"n1kv_profile", "network_profile",
|
||||
"policy_profile", "external-net", "router",
|
||||
"credential"]
|
||||
@ -164,11 +160,6 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
n1kv_db_v2.initialize()
|
||||
c_cred.Store.initialize()
|
||||
self._initialize_network_ranges()
|
||||
# If no api_extensions_path is provided set the following
|
||||
if not q_conf.CONF.api_extensions_path:
|
||||
q_conf.CONF.set_override(
|
||||
'api_extensions_path',
|
||||
'extensions:neutron/plugins/cisco/extensions')
|
||||
self._setup_vsm()
|
||||
self._setup_rpc()
|
||||
|
||||
|
@ -22,6 +22,7 @@ import logging
|
||||
from sqlalchemy import orm
|
||||
import webob.exc as wexc
|
||||
|
||||
from neutron.api import extensions as neutron_extensions
|
||||
from neutron.api.v2 import base
|
||||
from neutron.common import exceptions as exc
|
||||
from neutron.db import db_base_plugin_v2
|
||||
@ -31,13 +32,14 @@ from neutron.plugins.cisco.common import cisco_constants as const
|
||||
from neutron.plugins.cisco.common import cisco_exceptions as cexc
|
||||
from neutron.plugins.cisco.common import config
|
||||
from neutron.plugins.cisco.db import network_db_v2 as cdb
|
||||
from neutron.plugins.cisco import extensions
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PluginV2(db_base_plugin_v2.NeutronDbPluginV2):
|
||||
"""Meta-Plugin with v2 API support for multiple sub-plugins."""
|
||||
supported_extension_aliases = ["Cisco Credential", "Cisco qos"]
|
||||
supported_extension_aliases = ["credential", "Cisco qos"]
|
||||
_methods_to_delegate = ['create_network',
|
||||
'delete_network', 'update_network', 'get_network',
|
||||
'get_networks',
|
||||
@ -81,6 +83,8 @@ class PluginV2(db_base_plugin_v2.NeutronDbPluginV2):
|
||||
self.supported_extension_aliases.extend(
|
||||
self._model.supported_extension_aliases)
|
||||
|
||||
neutron_extensions.append_api_extensions_path(extensions.__path__)
|
||||
|
||||
# Extend the fault map
|
||||
self._extend_fault_map()
|
||||
|
||||
|
@ -51,11 +51,12 @@ class MetaPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
|
||||
def __init__(self, configfile=None):
|
||||
LOG.debug(_("Start initializing metaplugin"))
|
||||
self.supported_extension_aliases = \
|
||||
cfg.CONF.META.supported_extension_aliases.split(',')
|
||||
self.supported_extension_aliases += ['flavor', 'external-net',
|
||||
self.supported_extension_aliases = ['flavor', 'external-net',
|
||||
'router', 'ext-gw-mode',
|
||||
'extraroute']
|
||||
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):
|
||||
|
@ -204,7 +204,7 @@ class MidonetPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
securitygroups_db.SecurityGroupDbMixin):
|
||||
|
||||
supported_extension_aliases = ['external-net', 'router', 'security-group',
|
||||
'agent' 'dhcp_agent_scheduler', 'binding']
|
||||
'agent', 'dhcp_agent_scheduler', 'binding']
|
||||
__native_bulk_support = False
|
||||
|
||||
def __init__(self):
|
||||
|
@ -122,7 +122,6 @@ PACKET_FILTER_ATTR_MAP = {COLLECTION: PACKET_FILTER_ATTR_PARAMS}
|
||||
|
||||
|
||||
class Packetfilter(extensions.ExtensionDescriptor):
|
||||
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
return ALIAS
|
||||
@ -157,10 +156,6 @@ class Packetfilter(extensions.ExtensionDescriptor):
|
||||
COLLECTION, resource, attr_map=PACKET_FILTER_ATTR_PARAMS)
|
||||
return [pf_ext]
|
||||
|
||||
def update_attributes_map(self, attributes):
|
||||
super(Packetfilter, self).update_attributes_map(
|
||||
attributes, extension_attrs_map=PACKET_FILTER_ATTR_MAP)
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
if version == "2.0":
|
||||
return PACKET_FILTER_ATTR_MAP
|
||||
|
@ -14,7 +14,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.api.v2 import attributes
|
||||
from neutron.openstack.common import log as logging
|
||||
|
||||
@ -33,7 +32,7 @@ ROUTER_PROVIDER_ATTRIBUTE = {
|
||||
}
|
||||
|
||||
|
||||
class Router_provider(extensions.ExtensionDescriptor):
|
||||
class Router_provider(object):
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
return "Router Provider"
|
||||
|
@ -17,6 +17,7 @@
|
||||
# @author: Akihiro MOTOKI
|
||||
|
||||
from neutron.agent import securitygroups_rpc as sg_rpc
|
||||
from neutron.api import extensions as neutron_extensions
|
||||
from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
|
||||
from neutron.api.v2 import attributes as attrs
|
||||
from neutron.common import constants as const
|
||||
@ -46,6 +47,7 @@ from neutron.plugins.nec.common import config
|
||||
from neutron.plugins.nec.common import exceptions as nexc
|
||||
from neutron.plugins.nec.db import api as ndb
|
||||
from neutron.plugins.nec.db import router as rdb
|
||||
from neutron.plugins.nec import extensions
|
||||
from neutron.plugins.nec import nec_router
|
||||
from neutron.plugins.nec import ofc_manager
|
||||
from neutron.plugins.nec import packet_filter
|
||||
@ -104,11 +106,8 @@ class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
self.ofc = ofc_manager.OFCManager()
|
||||
self.base_binding_dict = self._get_base_binding_dict()
|
||||
portbindings_base.register_port_dict_function()
|
||||
# Set the plugin default extension path
|
||||
# if no api_extensions_path is specified.
|
||||
if not config.CONF.api_extensions_path:
|
||||
config.CONF.set_override('api_extensions_path',
|
||||
'neutron/plugins/nec/extensions')
|
||||
|
||||
neutron_extensions.append_api_extensions_path(extensions.__path__)
|
||||
|
||||
self.setup_rpc()
|
||||
self.l3_rpc_notifier = nec_router.L3AgentNotifyAPI()
|
||||
|
@ -27,6 +27,7 @@ from oslo.config import cfg
|
||||
from sqlalchemy.orm import exc as sa_exc
|
||||
import webob.exc
|
||||
|
||||
from neutron.api import extensions as neutron_extensions
|
||||
from neutron.api.v2 import attributes as attr
|
||||
from neutron.api.v2 import base
|
||||
from neutron.common import constants
|
||||
@ -181,9 +182,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
'default': self._nvp_delete_port}
|
||||
}
|
||||
|
||||
# If no api_extensions_path is provided set the following
|
||||
if not cfg.CONF.api_extensions_path:
|
||||
cfg.CONF.set_override('api_extensions_path', NVP_EXT_PATH)
|
||||
neutron_extensions.append_api_extensions_path([NVP_EXT_PATH])
|
||||
self.nvp_opts = cfg.CONF.NVP
|
||||
self.nvp_sync_opts = cfg.CONF.NVP_SYNC
|
||||
self.cluster = create_nvp_cluster(cfg.CONF,
|
||||
|
@ -18,9 +18,9 @@
|
||||
# @author: Abhishek Raut, Cisco Systems Inc.
|
||||
|
||||
from mock import patch
|
||||
import os
|
||||
from oslo.config import cfg
|
||||
|
||||
from neutron.api import extensions as neutron_extensions
|
||||
from neutron.api.v2 import attributes
|
||||
from neutron.common.test_lib import test_config
|
||||
from neutron import context
|
||||
@ -204,8 +204,7 @@ class N1kvPluginTestCase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
n1kv_neutron_plugin.N1kvNeutronPluginV2._setup_vsm = _fake_setup_vsm
|
||||
|
||||
test_config['plugin_name_v2'] = self._plugin_name
|
||||
cfg.CONF.set_override('api_extensions_path',
|
||||
os.path.dirname(extensions.__file__))
|
||||
neutron_extensions.append_api_extensions_path(extensions.__path__)
|
||||
self.addCleanup(cfg.CONF.reset)
|
||||
ext_mgr = NetworkProfileTestExtensionManager()
|
||||
test_config['extension_manager'] = ext_mgr
|
||||
|
@ -32,6 +32,7 @@ from neutron.db import db_base_plugin_v2
|
||||
from neutron import manager
|
||||
from neutron.plugins.nicira.dbexts import nicira_networkgw_db
|
||||
from neutron.plugins.nicira.extensions import nvp_networkgw as networkgw
|
||||
from neutron.plugins.nicira.NeutronPlugin import NVP_EXT_PATH
|
||||
from neutron import quota
|
||||
from neutron.tests import base
|
||||
from neutron.tests.unit import test_api_v2
|
||||
@ -630,6 +631,10 @@ class TestNetworkGatewayPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
|
||||
supported_extension_aliases = ["network-gateway"]
|
||||
|
||||
def __init__(self, **args):
|
||||
super(TestNetworkGatewayPlugin, self).__init__(**args)
|
||||
extensions.append_api_extensions_path([NVP_EXT_PATH])
|
||||
|
||||
def delete_port(self, context, id, nw_gw_port_check=True):
|
||||
if nw_gw_port_check:
|
||||
port = self._get_port(context, id)
|
||||
|
@ -17,12 +17,14 @@
|
||||
|
||||
import os
|
||||
|
||||
import mock
|
||||
import routes
|
||||
import webob
|
||||
import webtest
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.common import config
|
||||
from neutron.common import exceptions
|
||||
from neutron.db import db_base_plugin_v2
|
||||
from neutron.openstack.common import jsonutils
|
||||
from neutron.openstack.common import log as logging
|
||||
@ -447,6 +449,8 @@ class PluginAwareExtensionManagerTest(base.BaseTestCase):
|
||||
def test_unsupported_extensions_are_not_loaded(self):
|
||||
stub_plugin = ext_stubs.StubPlugin(supported_extensions=["e1", "e3"])
|
||||
plugin_info = {constants.CORE: stub_plugin}
|
||||
with mock.patch("neutron.api.extensions.PluginAwareExtensionManager."
|
||||
"check_if_plugin_extensions_loaded"):
|
||||
ext_mgr = extensions.PluginAwareExtensionManager('', plugin_info)
|
||||
|
||||
ext_mgr.add_extension(ext_stubs.StubExtension("e1"))
|
||||
@ -478,9 +482,11 @@ class PluginAwareExtensionManagerTest(base.BaseTestCase):
|
||||
supported_extension_aliases = ["supported_extension"]
|
||||
|
||||
plugin_info = {constants.CORE: PluginWithoutExpectedIface()}
|
||||
with mock.patch("neutron.api.extensions.PluginAwareExtensionManager."
|
||||
"check_if_plugin_extensions_loaded"):
|
||||
ext_mgr = extensions.PluginAwareExtensionManager('', plugin_info)
|
||||
ext_mgr.add_extension(
|
||||
ext_stubs.ExtensionExpectingPluginInterface("supported_extension"))
|
||||
ext_mgr.add_extension(ext_stubs.ExtensionExpectingPluginInterface(
|
||||
"supported_extension"))
|
||||
|
||||
self.assertNotIn("e1", ext_mgr.extensions)
|
||||
|
||||
@ -494,9 +500,11 @@ class PluginAwareExtensionManagerTest(base.BaseTestCase):
|
||||
pass
|
||||
|
||||
plugin_info = {constants.CORE: PluginWithExpectedInterface()}
|
||||
with mock.patch("neutron.api.extensions.PluginAwareExtensionManager."
|
||||
"check_if_plugin_extensions_loaded"):
|
||||
ext_mgr = extensions.PluginAwareExtensionManager('', plugin_info)
|
||||
ext_mgr.add_extension(
|
||||
ext_stubs.ExtensionExpectingPluginInterface("supported_extension"))
|
||||
ext_mgr.add_extension(ext_stubs.ExtensionExpectingPluginInterface(
|
||||
"supported_extension"))
|
||||
|
||||
self.assertIn("supported_extension", ext_mgr.extensions)
|
||||
|
||||
@ -509,6 +517,9 @@ class PluginAwareExtensionManagerTest(base.BaseTestCase):
|
||||
pass
|
||||
stub_plugin = ext_stubs.StubPlugin(supported_extensions=["e1"])
|
||||
plugin_info = {constants.CORE: stub_plugin}
|
||||
|
||||
with mock.patch("neutron.api.extensions.PluginAwareExtensionManager."
|
||||
"check_if_plugin_extensions_loaded"):
|
||||
ext_mgr = extensions.PluginAwareExtensionManager('', plugin_info)
|
||||
ext_mgr.add_extension(ExtensionForQuamtumPluginInterface("e1"))
|
||||
|
||||
@ -525,6 +536,8 @@ class PluginAwareExtensionManagerTest(base.BaseTestCase):
|
||||
|
||||
stub_plugin = ext_stubs.StubPlugin(supported_extensions=["e1"])
|
||||
plugin_info = {constants.CORE: stub_plugin}
|
||||
with mock.patch("neutron.api.extensions.PluginAwareExtensionManager."
|
||||
"check_if_plugin_extensions_loaded"):
|
||||
ext_mgr = extensions.PluginAwareExtensionManager('', plugin_info)
|
||||
ext_mgr.add_extension(ExtensionWithNoNeedForPluginInterface("e1"))
|
||||
|
||||
@ -537,11 +550,21 @@ class PluginAwareExtensionManagerTest(base.BaseTestCase):
|
||||
|
||||
stub_plugin = ext_stubs.StubPlugin(supported_extensions=["e1"])
|
||||
plugin_info = {constants.DUMMY: stub_plugin}
|
||||
with mock.patch("neutron.api.extensions.PluginAwareExtensionManager."
|
||||
"check_if_plugin_extensions_loaded"):
|
||||
ext_mgr = extensions.PluginAwareExtensionManager('', plugin_info)
|
||||
ext_mgr.add_extension(NonCorePluginExtenstion("e1"))
|
||||
|
||||
self.assertIn("e1", ext_mgr.extensions)
|
||||
|
||||
def test_unloaded_supported_extensions_raises_exception(self):
|
||||
stub_plugin = ext_stubs.StubPlugin(
|
||||
supported_extensions=["unloaded_extension"])
|
||||
plugin_info = {constants.CORE: stub_plugin}
|
||||
self.assertRaises(exceptions.ExtensionsNotFound,
|
||||
extensions.PluginAwareExtensionManager,
|
||||
'', plugin_info)
|
||||
|
||||
|
||||
class ExtensionControllerTest(testlib_api.WebTestCase):
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user