From b595997b96dd5fe8aec3ffc05a7f6dcde1bdccce Mon Sep 17 00:00:00 2001 From: Federico Ressi Date: Fri, 21 Jun 2019 13:45:29 +0200 Subject: [PATCH] Generate random subnet CIDRs Change-Id: I3955ef6505450d673f8f5ce40f474f9336d200ef --- tobiko/openstack/neutron/_cidr.py | 44 ++++++++++++++++++- .../tests/functional/openstack/test_stacks.py | 2 - 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/tobiko/openstack/neutron/_cidr.py b/tobiko/openstack/neutron/_cidr.py index 211681e90..234907a74 100644 --- a/tobiko/openstack/neutron/_cidr.py +++ b/tobiko/openstack/neutron/_cidr.py @@ -13,10 +13,13 @@ # under the License. from __future__ import absolute_import +import random + import netaddr +from netaddr.strategy import ipv4 +from netaddr.strategy import ipv6 import tobiko - from tobiko.openstack.neutron import _client @@ -59,7 +62,7 @@ class CIDRGeneratorFixture(tobiko.SharedFixture): self.client = _client.neutron_client(self.client) def setup_cidr_generator(self): - self.cidr_generator = self.cidr.subnet(self.prefixlen) + self.cidr_generator = random_subnets(self.cidr, self.prefixlen) def new_cidr(self): used_cidrs = set(_client.list_subnet_cidrs(client=self.client)) @@ -94,3 +97,40 @@ class IPv6CIDRGeneratorFixture(CIDRGeneratorFixture): class NoSuchCIDRLeft(tobiko.TobikoException): message = ("No such subnet CIDR left " "(CIDR={cidr!s}, prefixlen={prefixlen!s})") + + +def random_subnets(cidr, prefixlen): + """ + A generator that divides up this IPNetwork's subnet into smaller + subnets based on a specified CIDR prefix. + + :param prefixlen: a CIDR prefix indicating size of subnets to be + returned. + + :return: an iterator containing random IPNetwork subnet objects. + """ + + version = cidr.version + module = {4: ipv4, 6: ipv6}[version] + width = module.width + if not 0 <= cidr.prefixlen <= width: + message = "CIDR prefix /{!r} invalid for IPv{!s}!".format( + prefixlen, cidr.version) + raise ValueError(message) + + if not cidr.prefixlen <= prefixlen: + # Don't return anything. + raise StopIteration + + # Calculate number of subnets to be returned. + max_subnets = 2 ** (width - cidr.prefixlen) // 2 ** (width - prefixlen) + + base_subnet = module.int_to_str(cidr.first) + i = 0 + rand = random.Random(cidr) + while True: + subnet = netaddr.IPNetwork('%s/%d' % (base_subnet, prefixlen), version) + subnet.value += (subnet.size * rand.randrange(0, max_subnets)) + subnet.prefixlen = prefixlen + i += 1 + yield subnet diff --git a/tobiko/tests/functional/openstack/test_stacks.py b/tobiko/tests/functional/openstack/test_stacks.py index a388b4aab..cc57297a0 100644 --- a/tobiko/tests/functional/openstack/test_stacks.py +++ b/tobiko/tests/functional/openstack/test_stacks.py @@ -42,7 +42,6 @@ class NetworkTestCase(testtools.TestCase): self.assertEqual(self.stack.network_details['mtu'], self.stack.outputs.mtu) - @testtools.skip('Subnet CIDR allocation is broken') def test_ipv4_subnet_cidr(self): if not self.stack.has_ipv4: tobiko.skip('Stack {!s} has no ipv4 subnet', self.stack.stack_name) @@ -52,7 +51,6 @@ class NetworkTestCase(testtools.TestCase): self.assertEqual(neutron.show_subnet(self.stack.ipv4_subnet_id), subnet) - @testtools.skip('Subnet CIDR allocation is broken') def test_ipv6_subnet_cidr(self): if not self.stack.has_ipv6: tobiko.skip('Stack {!s} has no ipv6 subnet', self.stack.stack_name)