Add stevedore aliases for interface_driver configuration
Changed the interface_driver configure for agents from class imports to stevedor aliases. The loading method needed to be updated to load as a DriverManager. Backward compatability for configuration as class import. DocImpact Change-Id: Ic349691989484286cd7c60eaf3ad1454c5852d1f Closes-Bug: #1504536
This commit is contained in:
parent
d57c546f1f
commit
c5db6050e5
@ -13,7 +13,7 @@
|
||||
|
||||
# Example of interface_driver option for OVS based plugins(OVS, Ryu, NEC, NVP,
|
||||
# BigSwitch/Floodlight)
|
||||
# interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver
|
||||
# interface_driver = openvswitch
|
||||
|
||||
# Name of Open vSwitch bridge to use
|
||||
# ovs_integration_bridge = br-int
|
||||
@ -24,7 +24,7 @@
|
||||
# ovs_use_veth = False
|
||||
|
||||
# Example of interface_driver option for LinuxBridge
|
||||
# interface_driver = neutron.agent.linux.interface.BridgeInterfaceDriver
|
||||
# interface_driver = linuxbridge
|
||||
|
||||
# The agent can use other DHCP drivers. Dnsmasq is the simplest and requires
|
||||
# no additional setup of the DHCP server.
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
# Example of interface_driver option for OVS based plugins (OVS, Ryu, NEC)
|
||||
# that supports L3 agent
|
||||
# interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver
|
||||
# interface_driver = openvswitch
|
||||
|
||||
# Use veth for an OVS interface or not.
|
||||
# Support kernels with limited namespace support
|
||||
@ -16,7 +16,7 @@
|
||||
# ovs_use_veth = False
|
||||
|
||||
# Example of interface_driver option for LinuxBridge
|
||||
# interface_driver = neutron.agent.linux.interface.BridgeInterfaceDriver
|
||||
# interface_driver = linuxbridge
|
||||
|
||||
# Allow overlapping IP (Must have kernel build with CONFIG_NET_NS=y and
|
||||
# iproute2 package that supports namespaces). This option is deprecated and
|
||||
|
@ -17,9 +17,9 @@ import os
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import importutils
|
||||
|
||||
from neutron.agent.common import config
|
||||
from neutron.common import utils as neutron_utils
|
||||
from neutron.i18n import _LE
|
||||
|
||||
|
||||
@ -32,19 +32,24 @@ else:
|
||||
LOG = logging.getLogger(__name__)
|
||||
config.register_root_helper(cfg.CONF)
|
||||
|
||||
INTERFACE_NAMESPACE = 'neutron.interface_drivers'
|
||||
|
||||
|
||||
execute = utils.execute
|
||||
|
||||
|
||||
def load_interface_driver(conf):
|
||||
if not conf.interface_driver:
|
||||
LOG.error(_LE('An interface driver must be specified'))
|
||||
raise SystemExit(1)
|
||||
"""Load interface driver for agents like DHCP or L3 agent.
|
||||
|
||||
:param conf: driver configuration object
|
||||
:raises SystemExit of 1 if driver cannot be loaded
|
||||
"""
|
||||
|
||||
try:
|
||||
return importutils.import_object(conf.interface_driver, conf)
|
||||
except ImportError as e:
|
||||
LOG.error(_LE("Error importing interface driver "
|
||||
"'%(driver)s': %(inner)s"),
|
||||
{'driver': conf.interface_driver,
|
||||
'inner': e})
|
||||
loaded_class = neutron_utils.load_class_by_alias_or_classname(
|
||||
INTERFACE_NAMESPACE, conf.interface_driver)
|
||||
return loaded_class(conf)
|
||||
except ImportError:
|
||||
LOG.error(_LE("Error loading interface driver '%s'"),
|
||||
conf.interface_driver)
|
||||
raise SystemExit(1)
|
||||
|
@ -30,6 +30,7 @@ import os
|
||||
import random
|
||||
import signal
|
||||
import socket
|
||||
import sys
|
||||
import tempfile
|
||||
import uuid
|
||||
|
||||
@ -38,9 +39,12 @@ from oslo_concurrency import lockutils
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
from oslo_utils import importutils
|
||||
import six
|
||||
from stevedore import driver
|
||||
|
||||
from neutron.common import constants as n_const
|
||||
from neutron.i18n import _LE
|
||||
|
||||
TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -487,3 +491,32 @@ def replace_file(file_name, data):
|
||||
tmp_file.write(data)
|
||||
os.chmod(tmp_file.name, 0o644)
|
||||
os.rename(tmp_file.name, file_name)
|
||||
|
||||
|
||||
def load_class_by_alias_or_classname(namespace, name):
|
||||
"""Load class using stevedore alias or the class name
|
||||
:param namespace: namespace where the alias is defined
|
||||
:param name: alias or class name of the class to be loaded
|
||||
:returns class if calls can be loaded
|
||||
:raises ImportError if class cannot be loaded
|
||||
"""
|
||||
|
||||
if not name:
|
||||
LOG.error(_LE("Alias or class name is not set"))
|
||||
raise ImportError(_("Class not found."))
|
||||
try:
|
||||
# Try to resolve class by alias
|
||||
mgr = driver.DriverManager(namespace, name)
|
||||
class_to_load = mgr.driver
|
||||
except RuntimeError:
|
||||
e1_info = sys.exc_info()
|
||||
# Fallback to class name
|
||||
try:
|
||||
class_to_load = importutils.import_class(name)
|
||||
except (ImportError, ValueError):
|
||||
LOG.error(_LE("Error loading class by alias"),
|
||||
exc_info=e1_info)
|
||||
LOG.error(_LE("Error loading class by class name"),
|
||||
exc_info=True)
|
||||
raise ImportError(_("Class not found."))
|
||||
return class_to_load
|
||||
|
@ -13,23 +13,19 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import sys
|
||||
import weakref
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
import oslo_messaging
|
||||
from oslo_service import periodic_task
|
||||
from oslo_utils import importutils
|
||||
import six
|
||||
|
||||
from neutron.common import utils
|
||||
from neutron.db import flavors_db
|
||||
from neutron.i18n import _LE, _LI
|
||||
from neutron.i18n import _LI
|
||||
from neutron.plugins.common import constants
|
||||
|
||||
from stevedore import driver
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -136,25 +132,18 @@ class NeutronManager(object):
|
||||
|
||||
@staticmethod
|
||||
def load_class_for_provider(namespace, plugin_provider):
|
||||
if not plugin_provider:
|
||||
LOG.error(_LE("Error, plugin is not set"))
|
||||
raise ImportError(_("Plugin not found."))
|
||||
"""Loads plugin using alias or class name
|
||||
:param namespace: namespace where alias is defined
|
||||
:param plugin_provider: plugin alias or class name
|
||||
:returns plugin that is loaded
|
||||
:raises ImportError if fails to load plugin
|
||||
"""
|
||||
|
||||
try:
|
||||
# Try to resolve plugin by name
|
||||
mgr = driver.DriverManager(namespace, plugin_provider)
|
||||
plugin_class = mgr.driver
|
||||
except RuntimeError:
|
||||
e1_info = sys.exc_info()
|
||||
# fallback to class name
|
||||
try:
|
||||
plugin_class = importutils.import_class(plugin_provider)
|
||||
except ImportError:
|
||||
LOG.error(_LE("Error loading plugin by name"),
|
||||
exc_info=e1_info)
|
||||
LOG.error(_LE("Error loading plugin by class"),
|
||||
exc_info=True)
|
||||
raise ImportError(_("Plugin not found."))
|
||||
return plugin_class
|
||||
return utils.load_class_by_alias_or_classname(namespace,
|
||||
plugin_provider)
|
||||
except ImportError:
|
||||
raise ImportError(_("Plugin '%s' not found.") % plugin_provider)
|
||||
|
||||
def _get_plugin_instance(self, namespace, plugin_provider):
|
||||
plugin_class = self.load_class_for_provider(namespace, plugin_provider)
|
||||
|
@ -42,7 +42,7 @@ class TestLoadInterfaceDriver(base.BaseTestCase):
|
||||
def test_load_interface_driver_does_not_consume_irrelevant_errors(self):
|
||||
self.conf.set_override('interface_driver',
|
||||
'neutron.agent.linux.interface.NullDriver')
|
||||
with mock.patch('oslo_utils.importutils.import_object',
|
||||
with mock.patch('oslo_utils.importutils.import_class',
|
||||
side_effect=RuntimeError()):
|
||||
with testlib_api.ExpectedException(RuntimeError):
|
||||
utils.load_interface_driver(self.conf)
|
||||
@ -52,3 +52,38 @@ class TestLoadInterfaceDriver(base.BaseTestCase):
|
||||
'neutron.agent.linux.interface.NullDriver')
|
||||
self.assertIsInstance(utils.load_interface_driver(self.conf),
|
||||
interface.NullDriver)
|
||||
|
||||
def test_load_null_interface_driver_success(self):
|
||||
self.conf.set_override('interface_driver',
|
||||
'null')
|
||||
self.assertIsInstance(utils.load_interface_driver(self.conf),
|
||||
interface.NullDriver)
|
||||
|
||||
def test_load_ivs_interface_driver_success(self):
|
||||
self.conf.set_override('interface_driver',
|
||||
'ivs')
|
||||
self.assertIsInstance(utils.load_interface_driver(self.conf),
|
||||
interface.IVSInterfaceDriver)
|
||||
|
||||
def test_load_linuxbridge_interface_driver_success(self):
|
||||
self.conf.set_override('interface_driver',
|
||||
'linuxbridge')
|
||||
self.assertIsInstance(utils.load_interface_driver(self.conf),
|
||||
interface.BridgeInterfaceDriver)
|
||||
|
||||
def test_load_midonet_interface_driver_success(self):
|
||||
self.conf.set_override('interface_driver',
|
||||
'midonet')
|
||||
self.assertIsInstance(utils.load_interface_driver(self.conf),
|
||||
interface.MidonetInterfaceDriver)
|
||||
|
||||
def test_load_ovs_interface_driver_success(self):
|
||||
self.conf.set_override('interface_driver',
|
||||
'openvswitch')
|
||||
self.assertIsInstance(utils.load_interface_driver(self.conf),
|
||||
interface.OVSInterfaceDriver)
|
||||
|
||||
def test_load_interface_driver_as_alias_wrong_driver(self):
|
||||
self.conf.set_override('interface_driver', 'openvswitchXX')
|
||||
with testlib_api.ExpectedException(SystemExit):
|
||||
utils.load_interface_driver(self.conf)
|
||||
|
@ -21,6 +21,7 @@ from neutron import manager
|
||||
from neutron.plugins.common import constants
|
||||
from neutron.tests import base
|
||||
from neutron.tests.unit import dummy_plugin
|
||||
from neutron.tests.unit import testlib_api
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -139,3 +140,12 @@ class NeutronManagerTestCase(base.BaseTestCase):
|
||||
'dummy': 'dummy_agent_notifier'}
|
||||
core_plugin = manager.NeutronManager.get_plugin()
|
||||
self.assertEqual(expected, core_plugin.agent_notifiers)
|
||||
|
||||
def test_load_class_for_provider(self):
|
||||
manager.NeutronManager.load_class_for_provider(
|
||||
'neutron.core_plugins', 'ml2')
|
||||
|
||||
def test_load_class_for_provider_wrong_plugin(self):
|
||||
with testlib_api.ExpectedException(ImportError):
|
||||
manager.NeutronManager.load_class_for_provider(
|
||||
'neutron.core_plugins', 'ml2XXXXXX')
|
||||
|
@ -173,6 +173,12 @@ oslo.messaging.notify.drivers =
|
||||
neutron.openstack.common.notifier.test_notifier = oslo_messaging.notify._impl_test:TestDriver
|
||||
neutron.db.alembic_migrations =
|
||||
neutron = neutron.db.migration:alembic_migrations
|
||||
neutron.interface_drivers =
|
||||
ivs = neutron.agent.linux.interface:IVSInterfaceDriver
|
||||
linuxbridge = neutron.agent.linux.interface:BridgeInterfaceDriver
|
||||
midonet = neutron.agent.linux.interface:MidonetInterfaceDriver
|
||||
null = neutron.agent.linux.interface:NullDriver
|
||||
openvswitch = neutron.agent.linux.interface:OVSInterfaceDriver
|
||||
|
||||
[build_sphinx]
|
||||
all_files = 1
|
||||
|
Loading…
Reference in New Issue
Block a user