Merge pull request #540 from roaet/allow_allocation_pool_shrinking
Allowing subnet allocation pool shrinking
This commit is contained in:
		@@ -41,8 +41,12 @@ STRATEGY = network_strategy.STRATEGY
 | 
			
		||||
quark_subnet_opts = [
 | 
			
		||||
    cfg.BoolOpt('allow_allocation_pool_update',
 | 
			
		||||
                default=False,
 | 
			
		||||
                help=_('Controls whether or not to allow allocation_pool'
 | 
			
		||||
                       'updates'))
 | 
			
		||||
                help=_('Controls whether or not to allow allocation_pool '
 | 
			
		||||
                       'updates')),
 | 
			
		||||
    cfg.BoolOpt('allow_allocation_pool_growth',
 | 
			
		||||
                default=False,
 | 
			
		||||
                help=_('Controls whether or not to allow allocation_pool '
 | 
			
		||||
                       'growing. Otherwise shrinking is only allowed'))
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
CONF.register_opts(quark_subnet_opts, "QUARK")
 | 
			
		||||
@@ -226,6 +230,21 @@ def create_subnet(context, subnet):
 | 
			
		||||
    return subnet_dict
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _pool_is_growing(original_pool, new_pool):
 | 
			
		||||
    # create IPSet for original pool
 | 
			
		||||
    ori_set = netaddr.IPSet()
 | 
			
		||||
    for rng in original_pool._alloc_pools:
 | 
			
		||||
        ori_set.add(netaddr.IPRange(rng['start'], rng['end']))
 | 
			
		||||
 | 
			
		||||
    # create IPSet for net pool
 | 
			
		||||
    new_set = netaddr.IPSet()
 | 
			
		||||
    for rng in new_pool._alloc_pools:
 | 
			
		||||
        new_set.add(netaddr.IPRange(rng['start'], rng['end']))
 | 
			
		||||
 | 
			
		||||
    # we are growing the original set is not a superset of the new set
 | 
			
		||||
    return not ori_set.issuperset(new_set)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def update_subnet(context, id, subnet):
 | 
			
		||||
    """Update values of a subnet.
 | 
			
		||||
 | 
			
		||||
@@ -267,6 +286,16 @@ def update_subnet(context, id, subnet):
 | 
			
		||||
        else:
 | 
			
		||||
            alloc_pools = allocation_pool.AllocationPools(subnet_db["cidr"],
 | 
			
		||||
                                                          allocation_pools)
 | 
			
		||||
            original_pools = subnet_db.allocation_pools
 | 
			
		||||
            ori_pools = allocation_pool.AllocationPools(subnet_db["cidr"],
 | 
			
		||||
                                                        original_pools)
 | 
			
		||||
            # Check if the pools are growing or shrinking
 | 
			
		||||
            is_growing = _pool_is_growing(ori_pools, alloc_pools)
 | 
			
		||||
            if not CONF.QUARK.allow_allocation_pool_growth and is_growing:
 | 
			
		||||
                raise n_exc.BadRequest(
 | 
			
		||||
                    resource="subnets",
 | 
			
		||||
                    msg="Allocation pools may not be updated to be larger "
 | 
			
		||||
                        "do to configuration settings")
 | 
			
		||||
 | 
			
		||||
        quota.QUOTAS.limit_check(
 | 
			
		||||
            context,
 | 
			
		||||
 
 | 
			
		||||
@@ -200,6 +200,19 @@ class QuarkCreateSubnets(BaseFunctionalTest):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QuarkUpdateSubnets(BaseFunctionalTest):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        super(QuarkUpdateSubnets, self).setUp()
 | 
			
		||||
        self.og = CONF.QUARK.allow_allocation_pool_update
 | 
			
		||||
        self.og1 = CONF.QUARK.allow_allocation_pool_growth
 | 
			
		||||
        CONF.set_override('allow_allocation_pool_update', True, 'QUARK')
 | 
			
		||||
        CONF.set_override('allow_allocation_pool_growth', True, 'QUARK')
 | 
			
		||||
 | 
			
		||||
    def tearDown(self):
 | 
			
		||||
        super(QuarkUpdateSubnets, self).tearDown()
 | 
			
		||||
        CONF.set_override('allow_allocation_pool_update', self.og, 'QUARK')
 | 
			
		||||
        CONF.set_override('allow_allocation_pool_growth', self.og1, 'QUARK')
 | 
			
		||||
 | 
			
		||||
    @contextlib.contextmanager
 | 
			
		||||
    def _stubs(self, network, subnet):
 | 
			
		||||
        self.ipam = quark.ipam.QuarkIpamANY()
 | 
			
		||||
@@ -210,8 +223,6 @@ class QuarkUpdateSubnets(BaseFunctionalTest):
 | 
			
		||||
            yield net, sub1
 | 
			
		||||
 | 
			
		||||
    def test_update_allocation_pools(self):
 | 
			
		||||
        og = CONF.QUARK.allow_allocation_pool_update
 | 
			
		||||
        CONF.set_override('allow_allocation_pool_update', True, 'QUARK')
 | 
			
		||||
        cidr = "192.168.1.0/24"
 | 
			
		||||
        ip_network = netaddr.IPNetwork(cidr)
 | 
			
		||||
        network = dict(name="public", tenant_id="fake", network_plugin="BASE")
 | 
			
		||||
@@ -250,4 +261,115 @@ class QuarkUpdateSubnets(BaseFunctionalTest):
 | 
			
		||||
                    for ip in netaddr.IPRange(extent['start'], extent['end']):
 | 
			
		||||
                        self.assertFalse(ip in ip_set)
 | 
			
		||||
                prev_pool = pool
 | 
			
		||||
        CONF.set_override('allow_allocation_pool_update', og, 'QUARK')
 | 
			
		||||
 | 
			
		||||
    def test_allow_allocation_pool_growth(self):
 | 
			
		||||
        CONF.set_override('allow_allocation_pool_growth', True, 'QUARK')
 | 
			
		||||
        cidr = "192.168.1.0/24"
 | 
			
		||||
        ip_network = netaddr.IPNetwork(cidr)
 | 
			
		||||
        network = dict(name="public", tenant_id="fake", network_plugin="BASE")
 | 
			
		||||
        network = {"network": network}
 | 
			
		||||
        pool = [dict(start='192.168.1.15', end='192.168.1.30')]
 | 
			
		||||
        subnet = dict(id=1, ip_version=4, next_auto_assign_ip=2,
 | 
			
		||||
                      cidr=cidr, first_ip=ip_network.first,
 | 
			
		||||
                      last_ip=ip_network.last, ip_policy=None,
 | 
			
		||||
                      allocation_pools=pool, tenant_id="fake")
 | 
			
		||||
        subnet = {"subnet": subnet}
 | 
			
		||||
        with self._stubs(network, subnet) as (net, sub1):
 | 
			
		||||
            subnet = subnet_api.get_subnet(self.context, 1)
 | 
			
		||||
            start_pools = subnet['allocation_pools']
 | 
			
		||||
            new_pool = [dict(start='192.168.1.10', end='192.168.1.50')]
 | 
			
		||||
 | 
			
		||||
            subnet_update = {"subnet": dict(allocation_pools=new_pool)}
 | 
			
		||||
            subnet = subnet_api.update_subnet(self.context, 1,
 | 
			
		||||
                                              subnet_update)
 | 
			
		||||
            self.assertNotEqual(start_pools, subnet['allocation_pools'])
 | 
			
		||||
            self.assertEqual(new_pool, subnet['allocation_pools'])
 | 
			
		||||
            policies = policy_api.get_ip_policies(self.context)
 | 
			
		||||
            self.assertEqual(1, len(policies))
 | 
			
		||||
            policy = policies[0]
 | 
			
		||||
            ip_set = netaddr.IPSet()
 | 
			
		||||
            for ip in policy['exclude']:
 | 
			
		||||
                ip_set.add(netaddr.IPNetwork(ip))
 | 
			
		||||
            for extent in new_pool:
 | 
			
		||||
                for ip in netaddr.IPRange(extent['start'], extent['end']):
 | 
			
		||||
                    self.assertFalse(ip in ip_set)
 | 
			
		||||
 | 
			
		||||
            start_ip_set = netaddr.IPSet()
 | 
			
		||||
            for rng in start_pools:
 | 
			
		||||
                start_ip_set.add(netaddr.IPRange(rng['start'], rng['end']))
 | 
			
		||||
 | 
			
		||||
            new_ip_set = netaddr.IPSet()
 | 
			
		||||
            for rng in subnet['allocation_pools']:
 | 
			
		||||
                new_ip_set.add(netaddr.IPRange(rng['start'], rng['end']))
 | 
			
		||||
 | 
			
		||||
            self.assertTrue(start_ip_set | new_ip_set != start_ip_set)
 | 
			
		||||
 | 
			
		||||
    def test_do_not_allow_allocation_pool_growth(self):
 | 
			
		||||
        CONF.set_override('allow_allocation_pool_growth', False, 'QUARK')
 | 
			
		||||
        cidr = "192.168.1.0/24"
 | 
			
		||||
        ip_network = netaddr.IPNetwork(cidr)
 | 
			
		||||
        network = dict(name="public", tenant_id="fake", network_plugin="BASE")
 | 
			
		||||
        network = {"network": network}
 | 
			
		||||
        pool = [dict(start='192.168.1.15', end='192.168.1.30')]
 | 
			
		||||
        subnet = dict(id=1, ip_version=4, next_auto_assign_ip=2,
 | 
			
		||||
                      cidr=cidr, first_ip=ip_network.first,
 | 
			
		||||
                      last_ip=ip_network.last, ip_policy=None,
 | 
			
		||||
                      allocation_pools=pool, tenant_id="fake")
 | 
			
		||||
        subnet = {"subnet": subnet}
 | 
			
		||||
        with self._stubs(network, subnet) as (net, sub1):
 | 
			
		||||
            subnet = subnet_api.get_subnet(self.context, 1)
 | 
			
		||||
            start_pools = subnet['allocation_pools']
 | 
			
		||||
            new_pool = [dict(start='192.168.1.10', end='192.168.1.50')]
 | 
			
		||||
 | 
			
		||||
            start_ip_set = netaddr.IPSet()
 | 
			
		||||
            for rng in start_pools:
 | 
			
		||||
                start_ip_set.add(netaddr.IPRange(rng['start'], rng['end']))
 | 
			
		||||
 | 
			
		||||
            new_ip_set = netaddr.IPSet()
 | 
			
		||||
            for rng in new_pool:
 | 
			
		||||
                new_ip_set.add(netaddr.IPRange(rng['start'], rng['end']))
 | 
			
		||||
 | 
			
		||||
            self.assertTrue(start_ip_set | new_ip_set != start_ip_set)
 | 
			
		||||
 | 
			
		||||
            subnet_update = {"subnet": dict(allocation_pools=new_pool)}
 | 
			
		||||
            with self.assertRaises(n_exc.BadRequest):
 | 
			
		||||
                subnet = subnet_api.update_subnet(self.context, 1,
 | 
			
		||||
                                                  subnet_update)
 | 
			
		||||
 | 
			
		||||
    def _test_allow_allocation_pool_identity(self, conf_flag):
 | 
			
		||||
        CONF.set_override('allow_allocation_pool_growth', conf_flag, 'QUARK')
 | 
			
		||||
        cidr = "192.168.1.0/24"
 | 
			
		||||
        ip_network = netaddr.IPNetwork(cidr)
 | 
			
		||||
        network = dict(name="public", tenant_id="fake", network_plugin="BASE")
 | 
			
		||||
        network = {"network": network}
 | 
			
		||||
        pool = [dict(start='192.168.1.15', end='192.168.1.30')]
 | 
			
		||||
        subnet = dict(id=1, ip_version=4, next_auto_assign_ip=2,
 | 
			
		||||
                      cidr=cidr, first_ip=ip_network.first,
 | 
			
		||||
                      last_ip=ip_network.last, ip_policy=None,
 | 
			
		||||
                      allocation_pools=pool, tenant_id="fake")
 | 
			
		||||
        subnet = {"subnet": subnet}
 | 
			
		||||
        with self._stubs(network, subnet) as (net, sub1):
 | 
			
		||||
            subnet = subnet_api.get_subnet(self.context, 1)
 | 
			
		||||
            start_pools = subnet['allocation_pools']
 | 
			
		||||
            new_pool = [dict(start='192.168.1.15', end='192.168.1.30')]
 | 
			
		||||
 | 
			
		||||
            start_ip_set = netaddr.IPSet()
 | 
			
		||||
            for rng in start_pools:
 | 
			
		||||
                start_ip_set.add(netaddr.IPRange(rng['start'], rng['end']))
 | 
			
		||||
 | 
			
		||||
            new_ip_set = netaddr.IPSet()
 | 
			
		||||
            for rng in new_pool:
 | 
			
		||||
                new_ip_set.add(netaddr.IPRange(rng['start'], rng['end']))
 | 
			
		||||
 | 
			
		||||
            self.assertTrue(start_ip_set == new_ip_set)
 | 
			
		||||
 | 
			
		||||
            subnet_update = {"subnet": dict(allocation_pools=new_pool)}
 | 
			
		||||
            subnet = subnet_api.update_subnet(self.context, 1, subnet_update)
 | 
			
		||||
            self.assertEqual(start_pools, subnet['allocation_pools'])
 | 
			
		||||
            self.assertEqual(new_pool, subnet['allocation_pools'])
 | 
			
		||||
 | 
			
		||||
    def test_allow_allocation_pool_identity_when_growth_false(self):
 | 
			
		||||
        self._test_allow_allocation_pool_identity(False)
 | 
			
		||||
 | 
			
		||||
    def test_allow_allocation_pool_identity_when_growth_true(self):
 | 
			
		||||
        self._test_allow_allocation_pool_identity(True)
 | 
			
		||||
 
 | 
			
		||||
@@ -1087,12 +1087,17 @@ class TestQuarkUpdateSubnet(test_quark_plugin.TestQuarkPlugin):
 | 
			
		||||
    def test_update_subnet_allocation_pools_invalid_outside(self):
 | 
			
		||||
        og = cfg.CONF.QUARK.allow_allocation_pool_update
 | 
			
		||||
        cfg.CONF.set_override('allow_allocation_pool_update', True, 'QUARK')
 | 
			
		||||
        og1 = cfg.CONF.QUARK.allow_allocation_pool_growth
 | 
			
		||||
        cfg.CONF.set_override('allow_allocation_pool_growth', True, 'QUARK')
 | 
			
		||||
        pools = [dict(start="172.16.1.10", end="172.16.1.20")]
 | 
			
		||||
        s = dict(subnet=dict(allocation_pools=pools))
 | 
			
		||||
        with self._stubs() as (dns_create, route_update, route_create):
 | 
			
		||||
            with self.assertRaises(n_exc_ext.OutOfBoundsAllocationPool):
 | 
			
		||||
                self.plugin.update_subnet(self.context, 1, s)
 | 
			
		||||
        cfg.CONF.set_override('allow_allocation_pool_update', og, 'QUARK')
 | 
			
		||||
        try:
 | 
			
		||||
            with self._stubs() as (dns_create, route_update, route_create):
 | 
			
		||||
                with self.assertRaises(n_exc_ext.OutOfBoundsAllocationPool):
 | 
			
		||||
                    self.plugin.update_subnet(self.context, 1, s)
 | 
			
		||||
        finally:
 | 
			
		||||
            cfg.CONF.set_override('allow_allocation_pool_update', og, 'QUARK')
 | 
			
		||||
            cfg.CONF.set_override('allow_allocation_pool_growth', og1, 'QUARK')
 | 
			
		||||
 | 
			
		||||
    def test_update_subnet_allocation_pools_zero(self):
 | 
			
		||||
        with self._stubs() as (dns_create, route_update, route_create):
 | 
			
		||||
@@ -1162,11 +1167,14 @@ class TestQuarkUpdateSubnet(test_quark_plugin.TestQuarkPlugin):
 | 
			
		||||
        cfg.CONF.set_override('allow_allocation_pool_update', og, 'QUARK')
 | 
			
		||||
 | 
			
		||||
    def test_update_subnet_allocation_pools_invalid(self):
 | 
			
		||||
        og = cfg.CONF.QUARK.allow_allocation_pool_update
 | 
			
		||||
        cfg.CONF.set_override('allow_allocation_pool_update', False, 'QUARK')
 | 
			
		||||
        pools = [dict(start="172.16.0.1", end="172.16.0.250")]
 | 
			
		||||
        s = dict(subnet=dict(allocation_pools=pools))
 | 
			
		||||
        with self._stubs() as (dns_create, route_update, route_create):
 | 
			
		||||
            with self.assertRaises(n_exc.BadRequest):
 | 
			
		||||
                self.plugin.update_subnet(self.context, 1, s)
 | 
			
		||||
        cfg.CONF.set_override('allow_allocation_pool_update', og, 'QUARK')
 | 
			
		||||
 | 
			
		||||
    def test_update_subnet_conflicting_gateway(self):
 | 
			
		||||
        og = cfg.CONF.QUARK.allow_allocation_pool_update
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user