]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Add stevedore aliases for interface_driver configuration
authorMartin Hickey <martin.hickey@ie.ibm.com>
Wed, 14 Oct 2015 21:32:49 +0000 (22:32 +0100)
committerMartin Hickey <martin.hickey@ie.ibm.com>
Mon, 19 Oct 2015 21:10:53 +0000 (22:10 +0100)
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

etc/dhcp_agent.ini
etc/l3_agent.ini
neutron/agent/common/utils.py
neutron/common/utils.py
neutron/manager.py
neutron/tests/unit/agent/common/test_utils.py
neutron/tests/unit/test_manager.py
setup.cfg

index 6996ed24fb473f4e98222f955e489e4c79970d9f..40c6c47e50264c6f015ae4b04df61cd3d69a94cb 100644 (file)
@@ -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.
index b3ac40c338269096c1b244b606d08f98d7b12049..a0c9de71e6c59ddfd16cf45408ac851e1f802960 100644 (file)
@@ -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
index a6255709b2467cf0fa0021facba6fb83c9f40ea7..f45ab600b93f52f6a773049e5b48e7c12c4c4381 100644 (file)
@@ -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)
index 1fe6ab1ce5ca9fdbaa135ccf627c6acde94ce44b..47c25e6e614a4f3bf83775db8a2d20ed8e9f7900 100644 (file)
@@ -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
index 51c9bf5cf48b0ad10f2cb3681e9c3212671f1914..e5ec3cb4960cc132b66c01d732effeb9a0471c93 100644 (file)
 #    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)
index a4cf66802043948df9eb284235ddd027b1d503f5..772b4e354cf69bb77eaa509077bc91762f7fa1b1 100644 (file)
@@ -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)
index 2020804fd4f20d81e7c326f0ff1d159aea433654..97c236d6f50c22d2f429b3973d62517c6be5fb5c 100644 (file)
@@ -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')
index 7cf270aae31c78a7b449a4698397ff1b2dd8bbf9..dd3f3b6c29a82e39ecb43800375615abb7a35ab4 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -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