]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Implement IPAM Driver loader
authorPavel Bondar <pbondar@infoblox.com>
Thu, 15 Jan 2015 12:00:02 +0000 (15:00 +0300)
committerPavel Bondar <pbondar@infoblox.com>
Mon, 1 Jun 2015 17:05:19 +0000 (20:05 +0300)
IPAM Driver is loaded based on value of 'ipam_driver'.
Added new variable 'ipam_driver' in config.

DocImpact
Partially-Implements: blueprint neutron-ipam

Change-Id: Ia52ad70ef4f0b02cf82cfefcf50b9f1e30b05b79

etc/neutron.conf [changed mode: 0644->0755]
neutron/common/config.py
neutron/ipam/driver.py
neutron/manager.py
neutron/tests/unit/ipam/fake_driver.py [new file with mode: 0755]
neutron/tests/unit/test_ipam.py [changed mode: 0644->0755]
setup.cfg [changed mode: 0644->0755]

old mode 100644 (file)
new mode 100755 (executable)
index ee42954..5b58519
 # core_plugin =
 # Example: core_plugin = ml2
 
+# (StrOpt) Neutron IPAM (IP address management) driver to be loaded from the
+# neutron.ipam_drivers namespace. See setup.cfg for the entry point names.
+# If ipam_driver is not set (default behavior), no ipam driver is used.
+# Example: ipam_driver =
+# In order to use the reference implementation of neutron ipam driver, use
+# 'internal'.
+# Example: ipam_driver = internal
+
 # (ListOpt) List of service plugin entrypoints to be loaded from the
 # neutron.service_plugins namespace. See setup.cfg for the entrypoint names of
 # the plugins included in the neutron source distribution. For compatibility
index 2837b4ca69565705436578e099c0c9e3a2b41d65..93f57159f3e29a1d0b1dbf9947818c4659a06697 100644 (file)
@@ -131,6 +131,8 @@ core_opts = [
                 help=_('If True, effort is made to advertise MTU settings '
                        'to VMs via network methods (DHCP and RA MTU options) '
                        'when the network\'s preferred MTU is known.')),
+    cfg.StrOpt('ipam_driver', default=None,
+               help=_('IPAM driver to use.')),
     cfg.BoolOpt('vlan_transparent', default=False,
                 help=_('If True, then allow plugins that support it to '
                        'create VLAN transparent networks.')),
index ed40b5eee8d64cc2399276df6768b74d1eaa2590..0e54e8856da1741c55637f9720bdaf663714b622 100644 (file)
 
 import abc
 
+from oslo_config import cfg
+from oslo_log import log
 import six
 
-from oslo_log import log
+from neutron import manager
 
 LOG = log.getLogger(__name__)
 
@@ -43,7 +45,12 @@ class Pool(object):
         :type subnet_pool: dict
         :returns: An instance of Driver for the given subnet pool
         """
-        raise NotImplementedError
+        ipam_driver_name = cfg.CONF.ipam_driver
+        mgr = manager.NeutronManager
+        LOG.debug("Loading ipam driver: %s", ipam_driver_name)
+        driver_class = mgr.load_class_for_provider('neutron.ipam_drivers',
+                                                   ipam_driver_name)
+        return driver_class(subnet_pool, context)
 
     @abc.abstractmethod
     def allocate_subnet(self, request):
index 503d79448e7a557c1d3ad3d4fb2b7582f06e1214..19e50047ea35004a06586411b9707bd0e6b1d990 100644 (file)
@@ -127,7 +127,11 @@ class NeutronManager(object):
         self.service_plugins = {constants.CORE: self.plugin}
         self._load_service_plugins()
 
-    def _get_plugin_instance(self, namespace, plugin_provider):
+    @staticmethod
+    def load_class_for_provider(namespace, plugin_provider):
+        if not plugin_provider:
+            LOG.exception(_LE("Error, plugin is not set"))
+            raise ImportError(_("Plugin not found."))
         try:
             # Try to resolve plugin by name
             mgr = driver.DriverManager(namespace, plugin_provider)
@@ -140,6 +144,10 @@ class NeutronManager(object):
                 LOG.exception(_LE("Error loading plugin by name, %s"), e1)
                 LOG.exception(_LE("Error loading plugin by class, %s"), e2)
                 raise ImportError(_("Plugin not found."))
+        return plugin_class
+
+    def _get_plugin_instance(self, namespace, plugin_provider):
+        plugin_class = self.load_class_for_provider(namespace, plugin_provider)
         return plugin_class()
 
     def _load_services_from_core_plugin(self):
diff --git a/neutron/tests/unit/ipam/fake_driver.py b/neutron/tests/unit/ipam/fake_driver.py
new file mode 100755 (executable)
index 0000000..3236a4c
--- /dev/null
@@ -0,0 +1,35 @@
+# Copyright (c) 2015 Infoblox Inc.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from neutron.ipam import driver
+
+
+class FakeDriver(driver.Pool):
+    """Fake IPAM driver for tests only
+
+    Just implement IPAM Driver interface without any functionality inside
+    """
+
+    def allocate_subnet(self, subnet):
+        return driver.Subnet()
+
+    def get_subnet(self, cidr):
+        return driver.Subnet()
+
+    def update_subnet(self, request):
+        return driver.Subnet()
+
+    def remove_subnet(self, cidr):
+        pass
old mode 100644 (file)
new mode 100755 (executable)
index aeec959..bb8759f
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import types
+
+import mock
 import netaddr
+from oslo_config import cfg
 
 from neutron.common import constants
 from neutron.common import ipv6_utils
+from neutron import context
 from neutron import ipam
+from neutron.ipam import driver
 from neutron.ipam import exceptions as ipam_exc
+from neutron import manager
 from neutron.openstack.common import uuidutils
 from neutron.tests import base
+from neutron.tests.unit.ipam import fake_driver
+
+FAKE_IPAM_CLASS = 'neutron.tests.unit.ipam.fake_driver.FakeDriver'
 
 
 class IpamSubnetRequestTestCase(base.BaseTestCase):
@@ -224,3 +234,54 @@ class TestAddressRequest(base.BaseTestCase):
                           mac='meh',
                           alien='et',
                           prefix='meh')
+
+
+class TestIpamDriverLoader(base.BaseTestCase):
+
+    def setUp(self):
+        super(TestIpamDriverLoader, self).setUp()
+        self.ctx = context.get_admin_context()
+
+    def _verify_fake_ipam_driver_is_loaded(self, driver_name):
+        mgr = manager.NeutronManager
+        ipam_driver = mgr.load_class_for_provider('neutron.ipam_drivers',
+                                                  driver_name)
+
+        self.assertEqual(
+            fake_driver.FakeDriver, ipam_driver,
+            "loaded ipam driver should be FakeDriver")
+
+    def _verify_import_error_is_generated(self, driver_name):
+        mgr = manager.NeutronManager
+        self.assertRaises(ImportError, mgr.load_class_for_provider,
+                          'neutron.ipam_drivers',
+                          driver_name)
+
+    def test_ipam_driver_is_loaded_by_class(self):
+        self._verify_fake_ipam_driver_is_loaded(FAKE_IPAM_CLASS)
+
+    def test_ipam_driver_is_loaded_by_name(self):
+        self._verify_fake_ipam_driver_is_loaded('fake')
+
+    def test_ipam_driver_raises_import_error(self):
+        self._verify_import_error_is_generated(
+            'neutron.tests.unit.ipam.SomeNonExistentClass')
+
+    def test_ipam_driver_raises_import_error_for_none(self):
+        self._verify_import_error_is_generated(None)
+
+    def _load_ipam_driver(self, driver_name, subnet_pool_id):
+        cfg.CONF.set_override("ipam_driver", driver_name)
+        return driver.Pool.get_instance(subnet_pool_id, self.ctx)
+
+    def test_ipam_driver_is_loaded_from_ipam_driver_config_value(self):
+        ipam_driver = self._load_ipam_driver('fake', None)
+        self.assertIsInstance(
+            ipam_driver, (fake_driver.FakeDriver, types.ClassType),
+            "loaded ipam driver should be of type FakeDriver")
+
+    @mock.patch(FAKE_IPAM_CLASS)
+    def test_ipam_driver_is_loaded_with_subnet_pool_id(self, ipam_mock):
+        subnet_pool_id = 'SomePoolID'
+        self._load_ipam_driver('fake', subnet_pool_id)
+        ipam_mock.assert_called_once_with(subnet_pool_id, self.ctx)
old mode 100644 (file)
new mode 100755 (executable)
index 3934f54..593760c
--- a/setup.cfg
+++ b/setup.cfg
@@ -198,6 +198,9 @@ neutron.ml2.extension_drivers =
     cisco_n1kv_ext = neutron.plugins.ml2.drivers.cisco.n1kv.n1kv_ext_driver:CiscoN1kvExtensionDriver
 neutron.openstack.common.cache.backends =
     memory = neutron.openstack.common.cache._backends.memory:MemoryBackend
+neutron.ipam_drivers =
+    fake = neutron.tests.unit.ipam.fake_driver:FakeDriver
+    internal = neutron.ipam.drivers.neutrondb_ipam.driver:NeutronDbPool
 # These are for backwards compat with Icehouse notification_driver configuration values
 oslo.messaging.notify.drivers =
     neutron.openstack.common.notifier.log_notifier = oslo_messaging.notify._impl_log:LogDriver