]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Add request factory for pluggable IPAM
authorPavel Bondar <pbondar@infoblox.com>
Wed, 17 Jun 2015 12:48:09 +0000 (15:48 +0300)
committerPavel Bondar <pbondar@infoblox.com>
Fri, 19 Jun 2015 12:31:58 +0000 (15:31 +0300)
Pluggable IPAM implementation requires separation between requesting
address/subnet and it's actual allocation, which can happen on
third-party IPAM servers. Request factory stands for simplifying
building right request from input.

Added AddressRequestFactory and SubnetRequestFactory.

AddressRequestFactory creates instance of AnyAddressRequest or
SpecificAddressRequest depending on presence of ip address in input.
SubnetRequestFactory creates instance of AnySubnetRequest or
SpecificSubnetRequest depending on input.

get_subnet_request_factory and get_address_request_factory can be
redefined on driver level to use custom request factories.

Partially-Implements: blueprint neutron-ipam

Change-Id: Iedc0cfa326d60810099148f0ef8a1edac9e8aa12

neutron/ipam/__init__.py
neutron/ipam/driver.py
neutron/tests/unit/test_ipam.py

index 4a8e6d1c3c281b49ac4bce3e6c2a631c330ed5f6..c756946bacbfa793a221127ba2d1ff1478ce7fee 100644 (file)
@@ -241,3 +241,30 @@ class AutomaticAddressRequest(SpecificAddressRequest):
 
 class RouterGatewayAddressRequest(AddressRequest):
     """Used to request allocating the special router gateway address."""
+
+
+class BaseRequestFactory(object):
+    """Factory class to create right request based on input"""
+    any_request = None
+    specific_request = None
+    address_index = 0
+
+    @classmethod
+    def get_request(cls, *args, **kwargs):
+        args_list = [a for a in args]
+        address = args_list.pop(cls.address_index)
+        if not address:
+            return cls.any_request(*args_list, **kwargs)
+        else:
+            return cls.specific_request(*args, **kwargs)
+
+
+class AddressRequestFactory(BaseRequestFactory):
+    any_request = AnyAddressRequest
+    specific_request = SpecificAddressRequest
+
+
+class SubnetRequestFactory(BaseRequestFactory):
+    any_request = AnySubnetRequest
+    specific_request = SpecificSubnetRequest
+    address_index = 2
index 0e54e8856da1741c55637f9720bdaf663714b622..30e28cc25a94de815a585703f6afddbf27815a61 100644 (file)
@@ -16,6 +16,7 @@ from oslo_config import cfg
 from oslo_log import log
 import six
 
+from neutron import ipam
 from neutron import manager
 
 LOG = log.getLogger(__name__)
@@ -95,6 +96,20 @@ class Pool(object):
         :raises: IPAMAllocationNotFound
         """
 
+    def get_subnet_request_factory(self):
+        """Returns default SubnetRequestFactory
+
+        Can be overridden on driver level to return custom factory
+        """
+        return ipam.SubnetRequestFactory
+
+    def get_address_request_factory(self):
+        """Returns default AddressRequestFactory
+
+        Can be overridden on driver level to return custom factory
+        """
+        return ipam.AddressRequestFactory
+
 
 @six.add_metaclass(abc.ABCMeta)
 class Subnet(object):
index bb8759f63d0bb192b80d09c44f5a24d0c125048c..ffaa100cf5279e4cd6e88133b61604958847ca6d 100755 (executable)
@@ -285,3 +285,82 @@ class TestIpamDriverLoader(base.BaseTestCase):
         subnet_pool_id = 'SomePoolID'
         self._load_ipam_driver('fake', subnet_pool_id)
         ipam_mock.assert_called_once_with(subnet_pool_id, self.ctx)
+
+
+class TestAddressRequestFactory(base.BaseTestCase):
+
+    def test_specific_address_request_is_loaded(self):
+        for address in ('10.12.0.15', 'fffe::1'):
+            self.assertIsInstance(
+                ipam.AddressRequestFactory.get_request(address),
+                ipam.SpecificAddressRequest)
+
+    def test_any_address_request_is_loaded(self):
+        for addr in [None, '']:
+            self.assertIsInstance(
+                ipam.AddressRequestFactory.get_request(addr),
+                ipam.AnyAddressRequest)
+
+
+class TestSubnetRequestFactory(IpamSubnetRequestTestCase):
+
+    def test_specific_subnet_request_is_loaded(self):
+        addresses = [
+            '10.12.0.15/24',
+            '10.12.0.0/24',
+            'fffe::1/64',
+            'fffe::/64']
+        for address in addresses:
+            self.assertIsInstance(
+                ipam.SubnetRequestFactory.get_request(self.tenant_id,
+                                                      self.subnet_id,
+                                                      address),
+                ipam.SpecificSubnetRequest)
+
+    def test_any_address_request_is_loaded_for_ipv4(self):
+        self.assertIsInstance(
+            ipam.SubnetRequestFactory.get_request(self.tenant_id,
+                                                  self.subnet_id,
+                                                  None,
+                                                  constants.IPv4,
+                                                  8),
+            ipam.AnySubnetRequest)
+
+    def test_any_address_request_is_loaded_for_ipv6(self):
+        self.assertIsInstance(
+            ipam.SubnetRequestFactory.get_request(self.tenant_id,
+                                                  self.subnet_id,
+                                                  None,
+                                                  constants.IPv6,
+                                                  64),
+            ipam.AnySubnetRequest)
+
+    def test_args_are_passed_to_specific_request(self):
+        request = ipam.SubnetRequestFactory.get_request(
+            self.tenant_id,
+            self.subnet_id,
+            '192.168.1.0/24')
+        self.assertIsInstance(request,
+                              ipam.SpecificSubnetRequest)
+        self.assertEqual(self.tenant_id, request.tenant_id)
+        self.assertEqual(self.subnet_id, request.subnet_id)
+        self.assertEqual(None, request.gateway_ip)
+        self.assertEqual(None, request.allocation_pools)
+
+
+class TestGetRequestFactory(base.BaseTestCase):
+
+    def setUp(self):
+        super(TestGetRequestFactory, self).setUp()
+        cfg.CONF.set_override('ipam_driver', 'fake')
+        self.driver = driver.Pool.get_instance(None, None)
+
+    def test_get_subnet_request_factory(self):
+        self.assertEqual(
+            self.driver.get_subnet_request_factory(),
+            ipam.SubnetRequestFactory)
+
+    def test_get_address_request_factory(self):
+        self.assertEqual(
+            self.driver.get_address_request_factory(),
+            ipam.AddressRequestFactory)