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