Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import traceback
import time

import ipaddress

class NeutronNetworkService(object):
"""
Expand Down Expand Up @@ -155,57 +155,74 @@ def _get_unused_cidr(self, client, cp_resvd_cidrs, logger):
:return str:
"""

# Algorithm below is a very simplistic one where we choose one of the three prefixes and then use
# /24 networks starting with that prefix. This algorithm will break if all three 10.X, 192.168.X and 172.X
# networks are used in a given On Prem Network.

# We basically start with a 10.0. network to find a subnet that does not overlap with
# either the reserved_cidrs or currently allocated CIDRs
# currently supports /24 subnets
logger.debug("reserved CIDRs: {0}".format(cp_resvd_cidrs))

candidate_prefixes = {'10': '10.0', '192.168': '192.168', '172': '172.0'}
cp_resvd_cidrs = cp_resvd_cidrs.split(",")
possible_prefixes = filter(lambda x: any(map(lambda y: not y.strip().startswith(x), cp_resvd_cidrs)),
candidate_prefixes.keys())
logger.debug("Possible Prefixes that can be used: {0}".format(possible_prefixes))
if not possible_prefixes:
return None

prefix = possible_prefixes[0]
subnet_prefix = candidate_prefixes[prefix]

# Get all subnets that start with 'our prefix'
subnets = client.list_subnets(fields=['cidr', 'id'])['subnets']
subnet_cidrs = map(lambda x: x.get('cidr'), subnets)

allocated_subnets = []
for subnet in subnets:
if subnet['cidr'].startswith(prefix):
allocated_subnets.append(subnet['cidr'])

allocated_subnets.sort()
logger.debug("Allocated Subnets: {0}".format(",".join(allocated_subnets)))

if not allocated_subnets:
subnet_num = 0
else:
last_subnet = allocated_subnets[-1]
subnet_num = int(last_subnet.split("/")[0].split(".")[2])
subnet_num += 1
if subnet_num == 255:
subnet_num = 0
cidr = ".".join([subnet_prefix, str(subnet_num), "0/24"])
while cidr in subnet_cidrs:
subnet_num += 1
cidr = ".".join([subnet_prefix, str(subnet_num), "0/24"])
else:
cidr = ".".join([subnet_prefix,str(subnet_num), "0/24"])
blacklist_cidrs = map(lambda x: x.strip(), cp_resvd_cidrs.split(","))

current_subnets = client.list_subnets(fields=['cidr', 'id'])['subnets']
current_subnets_cidrs = map(lambda x: unicode(x.get('cidr')), current_subnets)

# Total CIDRs we don't care about are - reserved + currently allocated

blacklist_cidrs += current_subnets_cidrs
blacklist_cidrs = map(lambda x: unicode(x), blacklist_cidrs)
blacklist_subnets = map(lambda x: ipaddress.IPv4Network(x), blacklist_cidrs)

# start with a 10 subnet
found_subnet = None
first_octet = 10
for i in range(256):
second_octet = i
for j in range(256):
third_octet = j
subnet_str = '{0}.{1}.{2}.0/24'.format(first_octet, second_octet, third_octet)
u_subnet_str = unicode(subnet_str)
u_subnet = ipaddress.IPv4Network(u_subnet_str)
# print u_subnet, blacklist_subnets
if not any(map(lambda x: u_subnet.overlaps(x), blacklist_subnets)):
found_subnet = u_subnet
break
if found_subnet:
break

if not found_subnet:
first_octet = 172
for i in range(16, 32):
second_octet = i
for j in range(256):
third_octet = j
subnet_str = '{0}.{1}.{2}.0/24'.format(first_octet, second_octet, third_octet)
u_subnet_str = unicode(subnet_str)
u_subnet = ipaddress.IPv4Network(u_subnet_str)
if not any(map(lambda x: u_subnet.overlaps(x), blacklist_subnets)):
found_subnet = u_subnet
break
if found_subnet:
break

logger.debug("Found {0} CIDR".format(cidr))
if not found_subnet:
first_octet = 192
second_octet = 168
for j in range(256):
third_octet = j
subnet_str = '{0}.{1}.{2}.0/24'.format(first_octet, second_octet, third_octet)
u_subnet_str = unicode(subnet_str)
u_subnet = ipaddress.IPv4Network(u_subnet_str)
if not any(map(lambda x: u_subnet.overlaps(x), blacklist_subnets)):
found_subnet = u_subnet
break

if subnet_num == 255:
if not found_subnet:
return None

cidr = str(found_subnet)

return cidr


def create_floating_ip(self, openstack_session, floating_ip_subnet_id, logger):
"""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,56 @@ def test_get_network_with_segmentation_id_no_network(self):
logger=self.mock_logger)
self.assertEqual(result, None)

def test_valid_cidr_returned(self):

mock_client = Mock()
test_neutron_network_service.neutron_client.Client = Mock(return_value=mock_client)
mock_client.create_subnet = Mock(return_value={'subnet': 'subnet success'})

mock_return_subnets = {'subnets': [{'cidr': '10.0.0.0/24', 'id': 'test-id-1'},
{'cidr': '10.0.1.0/24', 'id': 'test-id-2'}]}

test_reserved_subnets = '172.0.0.0/8, 192.168.0.0/24'
mock_client.list_subnets = Mock(return_value=mock_return_subnets)
result = self.network_service._get_unused_cidr(client=mock_client,
cp_resvd_cidrs=test_reserved_subnets,
logger=self.mock_logger)
self.assertEqual(result, '10.0.2.0/24')

def none_cidr_returned(self):
mock_client = Mock()
test_neutron_network_service.neutron_client.Client = Mock(return_value=mock_client)
mock_client.create_subnet = Mock(return_value={'subnet': 'subnet success'})

mock_return_subnets = {'subnets': [{'cidr': '10.0.0.0/24', 'id': 'test-id-1'},
{'cidr': '10.0.1.0/24', 'id': 'test-id-2'}]}

test_reserved_subnets = '10.0.0.0/8, 172.16.0.0/12 , 192.168.0.0/24'
mock_client.list_subnets = Mock(return_value=mock_return_subnets)
result = self.network_service._get_unused_cidr(client=mock_client,
cp_resvd_cidrs=test_reserved_subnets,
logger=self.mock_logger)
self.assertEqual(result, None)

def test_create_and_attach_subnet_to_net_success(self):

test_net_id = 'test-net-id'
mock_client = Mock()
test_neutron_network_service.neutron_client.Client = Mock(return_value=mock_client)
mock_client.create_subnet = Mock(return_value={'subnet':'subnet success'})

self.network_service._get_unused_cidr = Mock(return_value = '10.0.0.0/24')
mock_return_subnets = {'subnets':[{'cidr': '192.168.1.0/24', 'id':'test-id-1'},
{'cidr': '192.168.1.0/24', 'id': 'test-id-2'}]}

test_reserved_subnets = '10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/24'
mock_client.list_subnets = Mock(return_value=mock_return_subnets)

cp_resource_model = Mock()
cp_resource_model.reserved_networks = test_reserved_subnets
# self.network_service._get_unused_cidr = Mock(return_value = '10.0.0.0/24')

result = self.network_service.create_and_attach_subnet_to_net(openstack_session=self.openstack_session,
cp_resource_model=Mock(),
cp_resource_model=cp_resource_model,
net_id=test_net_id,
logger=self.mock_logger)
self.assertEqual(result, 'subnet success')
Expand Down