Skip to content

Commit

Permalink
Fixes: Support single-active BGPaaS object attached to multiple VMIs
Browse files Browse the repository at this point in the history
Changes to schema and API server to accomodate configuring
ports for BGPaaS.

Change-Id: I2a6b6ca4e47c714f5b6b846b417648a6c8846219
Partial-Bug: 1649707
  • Loading branch information
Ranjeet R committed Aug 18, 2017
1 parent bd18d81 commit 19c29e2
Show file tree
Hide file tree
Showing 6 changed files with 318 additions and 64 deletions.
66 changes: 66 additions & 0 deletions src/config/api-server/vnc_cfg_types.py
Expand Up @@ -155,6 +155,36 @@ def dbe_read(cls, db_conn, res_type, obj_uuid, obj_fields=None):
# end class Resource

class GlobalSystemConfigServer(Resource, GlobalSystemConfig):
@classmethod
def _check_valid_port_range(cls, port_start, port_end):
if port_start > port_end:
return (False, (400, 'Invalid Port range specified'))
return True, ''

@classmethod
def _check_bgpaas_ports(cls, obj_dict, db_conn):
bgpaas_ports = obj_dict.get('bgpaas_parameters')
if not bgpaas_ports:
return (True, '')

ok, msg = cls._check_valid_port_range(bgpaas_ports['port_start'],
bgpaas_ports['port_end'])
if not ok:
return ok, msg

ok, global_sys_cfg = cls.dbe_read(db_conn, 'global_system_config',
obj_dict.get('uuid'))
if not ok:
return (ok, global_sys_cfg)
cur_bgpaas_ports = global_sys_cfg.get('bgpaas_parameters') or\
{'port_start': 50000, 'port_end': 50512}
if (bgpaas_ports['port_start'] > cur_bgpaas_ports['port_start'] or
bgpaas_ports['port_end'] < cur_bgpaas_ports['port_end']):
return (False, (400, 'BGP Port range cannot be shrunk'))

return (True, '')
# end _check_bgpaas_ports

@classmethod
def _check_asn(cls, obj_dict, db_conn):
global_asn = obj_dict.get('autonomous_system')
Expand Down Expand Up @@ -200,6 +230,13 @@ def _check_udc(cls, obj_dict, udcs):

@classmethod
def pre_dbe_create(cls, tenant_name, obj_dict, db_conn):
bgpaas_ports = obj_dict.get('bgpaas_parameters')
if bgpaas_ports:
ok, msg = cls._check_valid_port_range(bgpaas_ports['port_start'],
bgpaas_ports['port_end'])
if not ok:
return ok, msg

ok, result = cls._check_udc(obj_dict, [])
if not ok:
return ok, result
Expand All @@ -220,6 +257,11 @@ def pre_dbe_update(cls, id, fq_name, obj_dict, db_conn, **kwargs):
ok, result = cls._check_asn(obj_dict, db_conn)
if not ok:
return ok, result

ok, result = cls._check_bgpaas_ports(obj_dict, db_conn)
if not ok:
return ok, result

return True, ''
# end pre_dbe_update

Expand Down Expand Up @@ -3334,6 +3376,30 @@ def pre_dbe_create(cls, tenant_name, obj_dict, db_conn):
# end class FloatingIpPoolServer


class BgpAsAServiceServer(Resource, BgpAsAService):
@classmethod
def pre_dbe_create(cls, tenant_name, obj_dict, db_conn):
if (not obj_dict.get('bgpaas_shared') == True or
obj_dict.get('bgpaas_ip_address') != None):
return True, ''
return (False, (400, 'BGPaaS IP Address needs to be ' +
'configured if BGPaaS is shared'))
# end pre_dbe_create

@classmethod
def pre_dbe_update(cls, id, fq_name, obj_dict, db_conn, **kwargs):
if 'bgpaas_shared' in obj_dict:
ok, result = cls.dbe_read(db_conn, 'bgp_as_a_service', id)

if not ok:
return ok, result
if result.get('bgpaas_shared') != obj_dict['bgpaas_shared']:
return (False, (400, 'BGPaaS sharing cannot be modified'))
return True, ""
# end pre_dbe_update
# end BgpAsAServiceServer


class PhysicalRouterServer(Resource, PhysicalRouter):
@classmethod
def post_dbe_read(cls, obj_dict, db_conn):
Expand Down
124 changes: 90 additions & 34 deletions src/config/common/zkclient.py
Expand Up @@ -22,30 +22,17 @@

class IndexAllocator(object):

def __init__(self, zookeeper_client, path, size=0, start_idx=0,
reverse=False,alloc_list=None, max_alloc=0):
def __init__(self, zookeeper_client, path, size=0, start_idx=0,
reverse=False, alloc_list=None, max_alloc=0):
self._size = size
self._start_idx = start_idx
if alloc_list is None:
self._alloc_list = [{'start':start_idx, 'end':start_idx+size}]
self._alloc_list = [{'start': start_idx, 'end': start_idx+size}]
else:
sorted_alloc_list = sorted(alloc_list, key=lambda k: k['start'])
self._alloc_list = sorted_alloc_list

alloc_count = len(self._alloc_list)
total_size = 0
size = 0

#check for overlap in alloc_list --TODO
for alloc_idx in range (0, alloc_count -1):
idx_start_addr = self._alloc_list[alloc_idx]['start']
idx_end_addr = self._alloc_list[alloc_idx]['end']
next_start_addr = self._alloc_list[alloc_idx+1]['start']
if next_start_addr <= idx_end_addr:
raise Exception(
'Allocation Lists Overlapping: %s' %(alloc_list))
size += idx_end_addr - idx_start_addr + 1
size += self._alloc_list[alloc_count-1]['end'] - self._alloc_list[alloc_count-1]['start'] + 1
size = self._get_range_size(self._alloc_list)

if max_alloc == 0:
self._max_alloc = size
Expand All @@ -59,56 +46,125 @@ def __init__(self, zookeeper_client, path, size=0, start_idx=0,
for idx in self._zookeeper_client.get_children(path):
idx_int = self._get_bit_from_zk_index(int(idx))
if idx_int >= 0:
self._set_in_use(idx_int)
self._set_in_use(self._in_use, idx_int)
# end for idx
# end __init__

def _get_zk_index_from_bit(self, idx):
# Given a set of ranges (alloc_list), return
# the cumulative count of the ranges.
def _get_range_size(self, alloc_list):
alloc_count = len(alloc_list)
size = 0

# check for overlap in alloc_list --TODO
for alloc_idx in range(0, alloc_count - 1):
idx_start_addr = alloc_list[alloc_idx]['start']
idx_end_addr = alloc_list[alloc_idx]['end']
next_start_addr = alloc_list[alloc_idx+1]['start']
if next_start_addr <= idx_end_addr:
raise Exception(
'Allocation Lists Overlapping: %s' % (alloc_list))
size += idx_end_addr - idx_start_addr + 1
size += (alloc_list[alloc_count-1]['end'] -
alloc_list[alloc_count-1]['start'] + 1)

return size

def _has_ranges_shrunk(self, old_list, new_list):
if len(old_list) != len(new_list):
return True

for i, new_pool in enumerate(new_list):
old_pool = old_list[i]
if (new_pool['start'] > old_pool['start'] or
new_pool['end'] < old_pool['end']):
return True

return False

# Reallocates the indexes to a new set of indexes provided by
# the user.
# Limitation -
# 1. No. of alloc pools needs to be constant
# For example, [10-20] cannot become [10-20],[25-30]
# 2. Every alloc pool can only expand but not shrink
# For ex, [10-20] can become [9-20] or [10-22] or [9-22]
# but not [15-17]
#
def reallocate(self, new_alloc_list):
sorted_alloc_list = sorted(new_alloc_list,
key=lambda k: k['start'])

if not self._has_ranges_shrunk(self._alloc_list, sorted_alloc_list):
raise Exception('Indexes allocated cannot be shrunk: %s' %
(self._alloc_list))

size = self._get_range_size(sorted_alloc_list)
self._max_alloc = size

new_in_use = bitarray(0)
for idx, bitval in enumerate(self._in_use):
if not bitval:
continue
zk_idx = self._get_zk_index_from_bit(idx)
idx_int = self._get_bit_from_zk_index(zk_idx, sorted_alloc_list)

if idx_int >= 0:
self._set_in_use(new_in_use, idx_int)

self._in_use = new_in_use
# end for idx

def _get_zk_index_from_bit(self, idx, alloc_list=None):
if not alloc_list:
alloc_list = self._alloc_list
size = idx
if self._reverse:
for alloc in reversed(self._alloc_list):
for alloc in reversed(alloc_list):
size -= alloc['end'] - alloc['start'] + 1
if size < 0:
return alloc['start']-size - 1
return alloc['start'] - size - 1
else:
for alloc in self._alloc_list:
for alloc in alloc_list:
size -= alloc['end'] - alloc['start'] + 1
if size < 0:
return alloc['end']+size + 1
return alloc['end']+size + 1

raise ResourceExhaustionError(
'Cannot get zk index from bit %s' %(idx))
'Cannot get zk index from bit %s' % (idx))
# end _get_zk_index

def _get_bit_from_zk_index(self, idx):
def _get_bit_from_zk_index(self, idx, alloc_list=None):
if not alloc_list:
alloc_list = self._alloc_list
size = 0
if self._reverse:
for alloc in reversed(self._alloc_list):
for alloc in reversed(alloc_list):
if alloc['start'] <= idx <= alloc['end']:
return alloc['end'] - idx + size
size += alloc['end'] - alloc['start'] + 1
pass
else:
for alloc in self._alloc_list:
for alloc in alloc_list:
if alloc['start'] <= idx <= alloc['end']:
return idx - alloc['start'] + size
size += alloc['end'] - alloc['start'] + 1
return -1
# end _get_bit_from_zk_index

def _set_in_use(self, bitnum):
def _set_in_use(self, array, bitnum):
# if the index is higher than _max_alloc, do not use the bitarray, in
# order to reduce the size of the bitarray. Otherwise, set the bit
# corresponding to idx to 1 and extend the _in_use bitarray if needed
if bitnum > self._max_alloc:
return
if bitnum >= self._in_use.length():
temp = bitarray(bitnum - self._in_use.length())
if bitnum >= array.length():
temp = bitarray(bitnum - array.length())
temp.setall(0)
temp.append('1')
self._in_use.extend(temp)
array.extend(temp)
else:
self._in_use[bitnum] = 1
array[bitnum] = 1
# end _set_in_use

def _reset_in_use(self, bitnum):
Expand All @@ -127,7 +183,7 @@ def set_in_use(self, idx):
bit_idx = self._get_bit_from_zk_index(idx)
if bit_idx < 0:
return
self._set_in_use(bit_idx)
self._set_in_use(self._in_use, bit_idx)
# end set_in_use

def reset_in_use(self, idx):
Expand Down Expand Up @@ -199,7 +255,7 @@ def read(self, idx):
if id_val is not None:
bit_idx = self._get_bit_from_zk_index(idx)
if bit_idx >= 0:
self._set_in_use(bit_idx)
self._set_in_use(self._in_use, bit_idx)
return id_val
# end read

Expand Down

0 comments on commit 19c29e2

Please sign in to comment.