Browse Source

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
tags/8.0.0.0b1
Martin Hickey 3 years ago
parent
commit
c5db6050e5

+ 2
- 2
etc/dhcp_agent.ini View File

@@ -13,7 +13,7 @@
13 13
 
14 14
 # Example of interface_driver option for OVS based plugins(OVS, Ryu, NEC, NVP,
15 15
 # BigSwitch/Floodlight)
16
-# interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver
16
+# interface_driver = openvswitch
17 17
 
18 18
 # Name of Open vSwitch bridge to use
19 19
 # ovs_integration_bridge = br-int
@@ -24,7 +24,7 @@
24 24
 # ovs_use_veth = False
25 25
 
26 26
 # Example of interface_driver option for LinuxBridge
27
-# interface_driver = neutron.agent.linux.interface.BridgeInterfaceDriver
27
+# interface_driver = linuxbridge
28 28
 
29 29
 # The agent can use other DHCP drivers.  Dnsmasq is the simplest and requires
30 30
 # no additional setup of the DHCP server.

+ 2
- 2
etc/l3_agent.ini View File

@@ -8,7 +8,7 @@
8 8
 
9 9
 # Example of interface_driver option for OVS based plugins (OVS, Ryu, NEC)
10 10
 # that supports L3 agent
11
-# interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver
11
+# interface_driver = openvswitch
12 12
 
13 13
 # Use veth for an OVS interface or not.
14 14
 # Support kernels with limited namespace support
@@ -16,7 +16,7 @@
16 16
 # ovs_use_veth = False
17 17
 
18 18
 # Example of interface_driver option for LinuxBridge
19
-# interface_driver = neutron.agent.linux.interface.BridgeInterfaceDriver
19
+# interface_driver = linuxbridge
20 20
 
21 21
 # Allow overlapping IP (Must have kernel build with CONFIG_NET_NS=y and
22 22
 # iproute2 package that supports namespaces). This option is deprecated and

+ 15
- 10
neutron/agent/common/utils.py View File

@@ -17,9 +17,9 @@ import os
17 17
 
18 18
 from oslo_config import cfg
19 19
 from oslo_log import log as logging
20
-from oslo_utils import importutils
21 20
 
22 21
 from neutron.agent.common import config
22
+from neutron.common import utils as neutron_utils
23 23
 from neutron.i18n import _LE
24 24
 
25 25
 
@@ -32,19 +32,24 @@ else:
32 32
 LOG = logging.getLogger(__name__)
33 33
 config.register_root_helper(cfg.CONF)
34 34
 
35
+INTERFACE_NAMESPACE = 'neutron.interface_drivers'
36
+
35 37
 
36 38
 execute = utils.execute
37 39
 
38 40
 
39 41
 def load_interface_driver(conf):
40
-    if not conf.interface_driver:
41
-        LOG.error(_LE('An interface driver must be specified'))
42
-        raise SystemExit(1)
42
+    """Load interface driver for agents like DHCP or L3 agent.
43
+
44
+    :param conf: driver configuration object
45
+    :raises SystemExit of 1 if driver cannot be loaded
46
+    """
47
+
43 48
     try:
44
-        return importutils.import_object(conf.interface_driver, conf)
45
-    except ImportError as e:
46
-        LOG.error(_LE("Error importing interface driver "
47
-                      "'%(driver)s': %(inner)s"),
48
-                  {'driver': conf.interface_driver,
49
-                   'inner': e})
49
+        loaded_class = neutron_utils.load_class_by_alias_or_classname(
50
+                INTERFACE_NAMESPACE, conf.interface_driver)
51
+        return loaded_class(conf)
52
+    except ImportError:
53
+        LOG.error(_LE("Error loading interface driver '%s'"),
54
+                  conf.interface_driver)
50 55
         raise SystemExit(1)

+ 33
- 0
neutron/common/utils.py View File

@@ -30,6 +30,7 @@ import os
30 30
 import random
31 31
 import signal
32 32
 import socket
33
+import sys
33 34
 import tempfile
34 35
 import uuid
35 36
 
@@ -38,9 +39,12 @@ from oslo_concurrency import lockutils
38 39
 from oslo_config import cfg
39 40
 from oslo_log import log as logging
40 41
 from oslo_utils import excutils
42
+from oslo_utils import importutils
41 43
 import six
44
+from stevedore import driver
42 45
 
43 46
 from neutron.common import constants as n_const
47
+from neutron.i18n import _LE
44 48
 
45 49
 TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
46 50
 LOG = logging.getLogger(__name__)
@@ -487,3 +491,32 @@ def replace_file(file_name, data):
487 491
         tmp_file.write(data)
488 492
     os.chmod(tmp_file.name, 0o644)
489 493
     os.rename(tmp_file.name, file_name)
494
+
495
+
496
+def load_class_by_alias_or_classname(namespace, name):
497
+    """Load class using stevedore alias or the class name
498
+    :param namespace: namespace where the alias is defined
499
+    :param name: alias or class name of the class to be loaded
500
+    :returns class if calls can be loaded
501
+    :raises ImportError if class cannot be loaded
502
+    """
503
+
504
+    if not name:
505
+        LOG.error(_LE("Alias or class name is not set"))
506
+        raise ImportError(_("Class not found."))
507
+    try:
508
+        # Try to resolve class by alias
509
+        mgr = driver.DriverManager(namespace, name)
510
+        class_to_load = mgr.driver
511
+    except RuntimeError:
512
+        e1_info = sys.exc_info()
513
+        # Fallback to class name
514
+        try:
515
+            class_to_load = importutils.import_class(name)
516
+        except (ImportError, ValueError):
517
+            LOG.error(_LE("Error loading class by alias"),
518
+                      exc_info=e1_info)
519
+            LOG.error(_LE("Error loading class by class name"),
520
+                      exc_info=True)
521
+            raise ImportError(_("Class not found."))
522
+    return class_to_load

+ 12
- 23
neutron/manager.py View File

@@ -13,23 +13,19 @@
13 13
 #    License for the specific language governing permissions and limitations
14 14
 #    under the License.
15 15
 
16
-import sys
17 16
 import weakref
18 17
 
19 18
 from oslo_config import cfg
20 19
 from oslo_log import log as logging
21 20
 import oslo_messaging
22 21
 from oslo_service import periodic_task
23
-from oslo_utils import importutils
24 22
 import six
25 23
 
26 24
 from neutron.common import utils
27 25
 from neutron.db import flavors_db
28
-from neutron.i18n import _LE, _LI
26
+from neutron.i18n import _LI
29 27
 from neutron.plugins.common import constants
30 28
 
31
-from stevedore import driver
32
-
33 29
 
34 30
 LOG = logging.getLogger(__name__)
35 31
 
@@ -136,25 +132,18 @@ class NeutronManager(object):
136 132
 
137 133
     @staticmethod
138 134
     def load_class_for_provider(namespace, plugin_provider):
139
-        if not plugin_provider:
140
-            LOG.error(_LE("Error, plugin is not set"))
141
-            raise ImportError(_("Plugin not found."))
135
+        """Loads plugin using alias or class name
136
+        :param namespace: namespace where alias is defined
137
+        :param plugin_provider: plugin alias or class name
138
+        :returns plugin that is loaded
139
+        :raises ImportError if fails to load plugin
140
+        """
141
+
142 142
         try:
143
-            # Try to resolve plugin by name
144
-            mgr = driver.DriverManager(namespace, plugin_provider)
145
-            plugin_class = mgr.driver
146
-        except RuntimeError:
147
-            e1_info = sys.exc_info()
148
-            # fallback to class name
149
-            try:
150
-                plugin_class = importutils.import_class(plugin_provider)
151
-            except ImportError:
152
-                LOG.error(_LE("Error loading plugin by name"),
153
-                          exc_info=e1_info)
154
-                LOG.error(_LE("Error loading plugin by class"),
155
-                          exc_info=True)
156
-                raise ImportError(_("Plugin not found."))
157
-        return plugin_class
143
+            return utils.load_class_by_alias_or_classname(namespace,
144
+                    plugin_provider)
145
+        except ImportError:
146
+            raise ImportError(_("Plugin '%s' not found.") % plugin_provider)
158 147
 
159 148
     def _get_plugin_instance(self, namespace, plugin_provider):
160 149
         plugin_class = self.load_class_for_provider(namespace, plugin_provider)

+ 36
- 1
neutron/tests/unit/agent/common/test_utils.py View File

@@ -42,7 +42,7 @@ class TestLoadInterfaceDriver(base.BaseTestCase):
42 42
     def test_load_interface_driver_does_not_consume_irrelevant_errors(self):
43 43
         self.conf.set_override('interface_driver',
44 44
                                'neutron.agent.linux.interface.NullDriver')
45
-        with mock.patch('oslo_utils.importutils.import_object',
45
+        with mock.patch('oslo_utils.importutils.import_class',
46 46
                         side_effect=RuntimeError()):
47 47
             with testlib_api.ExpectedException(RuntimeError):
48 48
                 utils.load_interface_driver(self.conf)
@@ -52,3 +52,38 @@ class TestLoadInterfaceDriver(base.BaseTestCase):
52 52
                                'neutron.agent.linux.interface.NullDriver')
53 53
         self.assertIsInstance(utils.load_interface_driver(self.conf),
54 54
                               interface.NullDriver)
55
+
56
+    def test_load_null_interface_driver_success(self):
57
+        self.conf.set_override('interface_driver',
58
+                               'null')
59
+        self.assertIsInstance(utils.load_interface_driver(self.conf),
60
+                              interface.NullDriver)
61
+
62
+    def test_load_ivs_interface_driver_success(self):
63
+        self.conf.set_override('interface_driver',
64
+                               'ivs')
65
+        self.assertIsInstance(utils.load_interface_driver(self.conf),
66
+                              interface.IVSInterfaceDriver)
67
+
68
+    def test_load_linuxbridge_interface_driver_success(self):
69
+        self.conf.set_override('interface_driver',
70
+                               'linuxbridge')
71
+        self.assertIsInstance(utils.load_interface_driver(self.conf),
72
+                              interface.BridgeInterfaceDriver)
73
+
74
+    def test_load_midonet_interface_driver_success(self):
75
+        self.conf.set_override('interface_driver',
76
+                               'midonet')
77
+        self.assertIsInstance(utils.load_interface_driver(self.conf),
78
+                              interface.MidonetInterfaceDriver)
79
+
80
+    def test_load_ovs_interface_driver_success(self):
81
+        self.conf.set_override('interface_driver',
82
+                               'openvswitch')
83
+        self.assertIsInstance(utils.load_interface_driver(self.conf),
84
+                              interface.OVSInterfaceDriver)
85
+
86
+    def test_load_interface_driver_as_alias_wrong_driver(self):
87
+        self.conf.set_override('interface_driver', 'openvswitchXX')
88
+        with testlib_api.ExpectedException(SystemExit):
89
+            utils.load_interface_driver(self.conf)

+ 10
- 0
neutron/tests/unit/test_manager.py View File

@@ -21,6 +21,7 @@ from neutron import manager
21 21
 from neutron.plugins.common import constants
22 22
 from neutron.tests import base
23 23
 from neutron.tests.unit import dummy_plugin
24
+from neutron.tests.unit import testlib_api
24 25
 
25 26
 
26 27
 LOG = logging.getLogger(__name__)
@@ -139,3 +140,12 @@ class NeutronManagerTestCase(base.BaseTestCase):
139 140
                     'dummy': 'dummy_agent_notifier'}
140 141
         core_plugin = manager.NeutronManager.get_plugin()
141 142
         self.assertEqual(expected, core_plugin.agent_notifiers)
143
+
144
+    def test_load_class_for_provider(self):
145
+        manager.NeutronManager.load_class_for_provider(
146
+            'neutron.core_plugins', 'ml2')
147
+
148
+    def test_load_class_for_provider_wrong_plugin(self):
149
+        with testlib_api.ExpectedException(ImportError):
150
+            manager.NeutronManager.load_class_for_provider(
151
+                    'neutron.core_plugins', 'ml2XXXXXX')

+ 6
- 0
setup.cfg View File

@@ -173,6 +173,12 @@ oslo.messaging.notify.drivers =
173 173
     neutron.openstack.common.notifier.test_notifier = oslo_messaging.notify._impl_test:TestDriver
174 174
 neutron.db.alembic_migrations =
175 175
     neutron = neutron.db.migration:alembic_migrations
176
+neutron.interface_drivers =
177
+    ivs = neutron.agent.linux.interface:IVSInterfaceDriver
178
+    linuxbridge = neutron.agent.linux.interface:BridgeInterfaceDriver
179
+    midonet = neutron.agent.linux.interface:MidonetInterfaceDriver
180
+    null = neutron.agent.linux.interface:NullDriver
181
+    openvswitch = neutron.agent.linux.interface:OVSInterfaceDriver
176 182
 
177 183
 [build_sphinx]
178 184
 all_files = 1

Loading…
Cancel
Save