Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Removed reduntant code from virtual-machine-interface for AE allocation
Browse files Browse the repository at this point in the history
closes-jira-bug: CEM-15158

1. AE-ID allocation log is now moved from virtual-machine-interface
   resource class to virtual-port-group resource class
2. PEP-8 fixes
3. New UTs to cover ae-id alloc/dealloc for backward compatability

Change-Id: I16902fee2dd5d54b83da9f7a310c5b44bfb91be8
snmurali committed Jul 15, 2020
1 parent cdf323b commit 9e7aed6
Showing 3 changed files with 535 additions and 399 deletions.
Original file line number Diff line number Diff line change
@@ -17,7 +17,6 @@
from vnc_api.gen.resource_common import VirtualPortGroup
from vnc_api.gen.resource_xsd import MacAddressesType
from vnc_api.gen.resource_xsd import PolicyBasedForwardingRuleType
from vnc_api.gen.resource_xsd import VpgInterfaceParametersType

from vnc_cfg_api_server.context import get_context
from vnc_cfg_api_server.resources._resource_base import ResourceMixin
@@ -830,78 +829,6 @@ def pre_dbe_update(cls, id, fq_name, obj_dict, db_conn,

return True, ret_dict

@classmethod
def _notify_ae_id_modified(cls, obj_dict=None, notify=False):

if (obj_dict.get('deallocated_ae_id') and
len(obj_dict.get('deallocated_ae_id'))):
dealloc_dict_list = obj_dict.get('deallocated_ae_id')
for dealloc_dict in dealloc_dict_list:
ae_id = dealloc_dict.get('ae_id')
vpg_name = dealloc_dict.get('vpg_name')
prouter_name = dealloc_dict.get('prouter_name')
cls.vnc_zk_client.free_ae_id(
prouter_name, ae_id,
vpg_name, notify=notify)

if (obj_dict.get('allocated_ae_id') and
len(obj_dict.get('allocated_ae_id'))):
alloc_dict_list = obj_dict.get('allocated_ae_id')
for alloc_dict in alloc_dict_list:
ae_id = alloc_dict.get('ae_id')
vpg_name = alloc_dict.get('vpg_name')
prouter_name = alloc_dict.get('prouter_name')
cls.vnc_zk_client.alloc_ae_id(prouter_name, vpg_name, ae_id,
notify=True)

# Allocate ae_id:
# 1. Get the ae_id from the old PI ref which is already assoc with PR
# 2. If not, then check if it got already generated on this api call
# from the other PI that belongs to the same PR.
# 3. Else allocate the new ae_id. Id allocation is per PR 0-127 and key
# is the vpg name.
@classmethod
def _check_and_alloc_ae_id(cls, links, prouter_name,
vpg_name, old_pi_to_pr_dict):
if not len(links) > 1:
return None, None

for pr in old_pi_to_pr_dict.values():
if (pr.get('prouter_name') == prouter_name and
pr.get('ae_id') is not None):
attr_obj = VpgInterfaceParametersType(pr.get('ae_id'))
return attr_obj, pr.get('ae_id')

ae_num = cls.vnc_zk_client.alloc_ae_id(prouter_name, vpg_name)
attr_obj = VpgInterfaceParametersType(ae_num)

return attr_obj, ae_num

# Free ae_id:
# 1. If the PI ref is getting deleted and there in no other PI left
# that belongs to the same PR.
# 2. Or if there is only one physical link to VPG.
@classmethod
def _check_and_free_ae_id(cls, links, prouter_dict,
vpg_name, pi_to_pr_dict):
prouter_list = []
dealloc_dict = {}
for pr in pi_to_pr_dict.values():
prouter_list.append(pr)

prouter_name = prouter_dict.get('prouter_name')
if prouter_name not in prouter_list or len(links) < 2:
cls.vnc_zk_client.free_ae_id(prouter_name,
prouter_dict.get('ae_id'),
vpg_name)
dealloc_dict['ae_id'] = prouter_dict.get('ae_id')
dealloc_dict['prouter_name'] = prouter_dict.get('prouter_name')
dealloc_dict['vpg_name'] = vpg_name
prouter_dict['ae_id'] = None
return dealloc_dict

return

@classmethod
def _check_annotations(
cls, api_server, obj_uuid,
@@ -1574,7 +1501,6 @@ def _manage_vpg_association(cls, vmi_id, api_server, db_conn, phy_links,
phy_interface_uuids = []
old_phy_interface_uuids = []
new_pi_to_pr_dict = {}
old_pi_to_pr_dict = {}
for link in phy_links:
if link.get('fabric'):
if fabric_name is not None and fabric_name != link['fabric']:
@@ -1593,23 +1519,6 @@ def _manage_vpg_association(cls, vmi_id, api_server, db_conn, phy_links,
phy_interface_uuids.append(pi_uuid)
new_pi_to_pr_dict[pi_uuid] = prouter_name

# check if new physical interfaces belongs to some other vpg
for uuid in set(phy_interface_uuids):
ok, phy_interface_dict = db_conn.dbe_read(
obj_type='physical-interface',
obj_id=uuid,
obj_fields=['name', 'virtual_port_group_back_refs'])
if not ok:
return (ok, 400, phy_interface_dict)

vpg_refs = phy_interface_dict.get('virtual_port_group_back_refs')
if vpg_refs and vpg_refs[0]['to'][-1] != vpg_name:
msg = 'Physical interface %s already belong to the vpg %s' %\
(phy_interface_dict.get(
'name', phy_interface_dict['fq_name']),
vpg_refs[0]['to'][-1])
return (False, (400, msg))

if vpg_name: # read the vpg object
vpg_fq_name = ['default-global-system-config', fabric_name,
vpg_name]
@@ -1717,59 +1626,38 @@ def vlanid_sanitizer(vlanid):
return ok, result

old_phy_interface_refs = vpg_dict.get('physical_interface_refs')
for ref in old_phy_interface_refs or []:
old_pi_to_pr_dict[ref['uuid']] = {
'prouter_name': ref['to'][1],
'ae_id': ref['attr'].get('ae_num') if ref['attr'] else None}
old_phy_interface_uuids.append(ref['uuid'])

old_phy_interface_uuids = [ref['uuid'] for ref in
old_phy_interface_refs or []]
ret_dict = {}
ret_dict['deallocated_ae_id'] = []
ret_dict['allocated_ae_id'] = []

# delete old physical interfaces to the vpg
for uuid in set(old_phy_interface_uuids) - set(phy_interface_uuids):
prouter_dict = old_pi_to_pr_dict.get(uuid)
dealloc_dict = cls._check_and_free_ae_id(
phy_links, prouter_dict,
vpg_name, new_pi_to_pr_dict)
ret_dict['deallocated_ae_id'].append(dealloc_dict)

api_server.internal_request_ref_update(
'virtual-port-group',
vpg_uuid,
'DELETE',
'physical-interface',
uuid)
delete_pi_uuids = (set(old_phy_interface_uuids) -
set(phy_interface_uuids))
for uuid in delete_pi_uuids:
try:
api_server.internal_request_ref_update(
'virtual-port-group',
vpg_uuid,
'DELETE',
'physical-interface',
uuid)
except Exception as exc:
return False, (exc.status_code, exc.content)

# add new physical interfaces to the vpg
pr_to_ae_id = {}
for uuid in phy_interface_uuids:
prouter_name = new_pi_to_pr_dict.get(uuid)
if pr_to_ae_id.get(prouter_name) is None:
attr_obj, ae_id = cls._check_and_alloc_ae_id(
phy_links, prouter_name,
vpg_name, old_pi_to_pr_dict)
pr_to_ae_id[prouter_name] = ae_id

if len(phy_links) > 1 and ae_id is not None:
alloc_dict = {}
alloc_dict['ae_id'] = ae_id
alloc_dict['prouter_name'] = prouter_name
alloc_dict['vpg_name'] = vpg_name
ret_dict['allocated_ae_id'].append(alloc_dict)
else:
attr_obj = VpgInterfaceParametersType(
ae_num=pr_to_ae_id.get(prouter_name))

api_server.internal_request_ref_update(
'virtual-port-group',
vpg_uuid,
'ADD',
'physical-interface',
uuid,
attr=attr_obj.__dict__ if attr_obj else None,
relax_ref_for_delete=True)
create_pi_uuids = (set(phy_interface_uuids) -
set(old_phy_interface_uuids))
for uuid in create_pi_uuids:
try:
api_server.internal_request_ref_update(
'virtual-port-group',
vpg_uuid,
'ADD',
'physical-interface',
uuid,
relax_ref_for_delete=True)
except Exception as exc:
return False, (exc.status_code, exc.content)

# update intent-map with vn_id
# read intent map object
@@ -1839,29 +1727,6 @@ def pre_dbe_delete(cls, id, obj_dict, db_conn):
delete_dict = {'virtual_machine_refs': []}
cls._check_vrouter_link(obj_dict, kvp_dict, delete_dict, db_conn)

# Clean ae ids associated with VPG->PIs
for vpg_back_ref in obj_dict.get('virtual_port_group_back_refs',
[]):
fqname = vpg_back_ref['to']
vpg_uuid = db_conn.fq_name_to_uuid('virtual_port_group', fqname)
ok, vpg_dict = db_conn.dbe_read(
obj_type='virtual-port-group',
obj_id=vpg_uuid,
obj_fields=['physical_interface_refs'])
if not ok:
return ok, vpg_dict

notify_dict = {}
notify_dict['deallocated_ae_id'] = []
for pi_ref in vpg_dict.get('physical_interface_refs') or []:
if pi_ref['attr'] and pi_ref['attr'].get('ae_num') is not None:
dealloc_dict = {}
dealloc_dict['ae_id'] = pi_ref['attr'].get('ae_num')
dealloc_dict['prouter_name'] = pi_ref['to'][1]
dealloc_dict['vpg_name'] = fqname[2]
notify_dict['deallocated_ae_id'].append(dealloc_dict)
obj_dict.update(notify_dict)

return True, "", None

@classmethod
@@ -1948,27 +1813,4 @@ def post_dbe_delete(cls, id, obj_dict, db_conn):
api_server.internal_request_delete('virtual_port_group',
vpg_uuid)

# Clean ae ids associated with VPG->PIs
cls._notify_ae_id_modified(obj_dict)

return True, ""

@classmethod
def dbe_create_notification(cls, db_conn, obj_id, obj_dict):
cls._notify_ae_id_modified(obj_dict)

return True, ''

@classmethod
def dbe_update_notification(cls, obj_id, extra_dict=None):

if extra_dict is not None:
cls._notify_ae_id_modified(extra_dict, notify=True)

return True, ''

@classmethod
def dbe_delete_notification(cls, obj_id, obj_dict):
cls._notify_ae_id_modified(obj_dict, notify=True)

return True, ''
Original file line number Diff line number Diff line change
@@ -28,6 +28,9 @@ def _notify_ae_id_modified(cls, obj_dict=None, notify=False):
cls.vnc_zk_client.free_ae_id(
prouter_name, ae_id,
vpg_name, notify=notify)
msg = "NOTIFY: Deallocated AE-ID (%s) at VPG(%s)/PR(%s)" % (
ae_id, vpg_name, prouter_name)
cls.db_conn.config_log(msg, level=SandeshLevel.SYS_DEBUG)
if (obj_dict.get('allocated_ae_id') and
len(obj_dict.get('allocated_ae_id'))):
alloc_dict_list = obj_dict.get('allocated_ae_id')
@@ -37,15 +40,18 @@ def _notify_ae_id_modified(cls, obj_dict=None, notify=False):
prouter_name = alloc_dict.get('prouter_name')
cls.vnc_zk_client.alloc_ae_id(prouter_name, vpg_name, ae_id,
notify=True)
msg = "NOTIFY: Allocated AE-ID (%s) at VPG(%s)/PR(%s)" % (
ae_id, vpg_name, prouter_name)
cls.db_conn.config_log(msg, level=SandeshLevel.SYS_DEBUG)

@classmethod
def _alloc_ae_id(cls, prouter_name, vpg_name):
try:
pi_ae = cls.vnc_zk_client.alloc_ae_id(prouter_name, vpg_name)
except ResourceExhaustionError as exc:
except ResourceExhaustionError:
err_msg = ('ResourceExhaustionError: when allocating AE-ID for '
'virtual-port-group (%s) at physical-router (%s)' % (
vpg_name, prouter_name))
vpg_name, prouter_name))
return False, (400, err_msg)
attr_obj = VpgInterfaceParametersType(pi_ae)
attr_dict = attr_obj.__dict__
@@ -54,11 +60,17 @@ def _alloc_ae_id(cls, prouter_name, vpg_name):
'prouter_name': prouter_name,
'vpg_name': vpg_name,
}
msg = "Allocated AE-ID (%s) at VPG(%s)/PR(%s)" % (
pi_ae, vpg_name, prouter_name)
cls.db_conn.config_log(msg, level=SandeshLevel.SYS_DEBUG)
return True, (attr_dict, alloc_dict)

@classmethod
def _dealloc_ae_id(cls, prouter_name, ae_id, vpg_name):
cls.vnc_zk_client.free_ae_id(prouter_name, ae_id, vpg_name)
msg = "De-allocated AE-ID (%s) at VPG(%s)/PR(%s)" % (
ae_id, vpg_name, prouter_name)
cls.db_conn.config_log(msg, level=SandeshLevel.SYS_DEBUG)
dealloc_dict = {
'ae_id': ae_id,
'prouter_name': prouter_name,
@@ -70,13 +82,10 @@ def _dealloc_ae_id(cls, prouter_name, ae_id, vpg_name):
def _process_alloc_ae_id(cls, db_obj_dict, vpg_name, obj_dict=None):
attr_dict = None
alloc_dealloc_dict = {'allocated_ae_id': [], 'deallocated_ae_id': []}
alloc_list = []
dealloc_list = []
curr_pr_dict = {}
curr_pi_dict = {}
db_pi_dict = {}
db_pr_dict = {}
extra_deallocate_dict = {}
vpg_uuid = db_obj_dict['uuid']
if not obj_dict:
obj_dict = {}
@@ -92,20 +101,30 @@ def _process_alloc_ae_id(cls, db_obj_dict, vpg_name, obj_dict=None):
if not (ref['to'][1] in db_pr_dict and db_pr_dict[ref['to'][1]]):
db_pr_dict[ref['to'][1]] = ref['attr']

create_pi_uuids = list(set(curr_pi_dict.keys()) - set(db_pi_dict.keys()))
delete_pi_uuids = list(set(db_pi_dict.keys()) - set(curr_pi_dict.keys()))
create_pi_uuids = list(set(curr_pi_dict.keys()) -
set(db_pi_dict.keys()))
delete_pi_uuids = list(set(db_pi_dict.keys()) -
set(curr_pi_dict.keys()))

# no PIs in db_obj_dict
if len(create_pi_uuids) < 2 and len(db_pi_dict.keys()) == 0:
msg = "Skip AE-ID allocation as Creating PI len(%s) < 2" % (
create_pi_uuids)
cls.db_conn.config_log(msg, level=SandeshLevel.SYS_DEBUG)
return True, (attr_dict, alloc_dealloc_dict)

# nothing to delete or add
if len(create_pi_uuids) == len(delete_pi_uuids) == 0:
msg = "Skip AE-ID allocation as no PI to Create / Delete"
cls.db_conn.config_log(msg, level=SandeshLevel.SYS_DEBUG)
return True, (attr_dict, alloc_dealloc_dict)

# nothing to delete, because rest of PIs shares same PR
if (len(create_pi_uuids) == 0 and len(delete_pi_uuids) == 1 and
len(db_pr_dict.keys()) == 1 and len(db_pi_dict.keys()) > 2):
msg = "Skip AE-ID allocation as rest PI(%s) shares same PR(%s)" % (
db_pi_dict.keys(), db_pr_dict.keys())
cls.db_conn.config_log(msg, level=SandeshLevel.SYS_DEBUG)
return True, (attr_dict, alloc_dealloc_dict)

# allocate case
@@ -120,31 +139,34 @@ def _process_alloc_ae_id(cls, db_obj_dict, vpg_name, obj_dict=None):
return ok, result
attr_dict, _alloc_dict = result
alloc_dealloc_dict['allocated_ae_id'].append(_alloc_dict)
msg = "Allocating AE-ID(%s) for PI(%s) at VPG(%s)/PR(%s)" % (
msg = "Allocated AE-ID(%s) for PI(%s) at VPG(%s)/PR(%s)" % (
attr_dict, pi_uuid, vpg_name, pi_pr)
cls.db_conn.config_log(msg, level=SandeshLevel.SYS_INFO)
cls.db_conn.config_log(msg, level=SandeshLevel.SYS_DEBUG)
else:
attr_dict = pi_ae

# re-allocate existing single PI if any
if (len(db_pi_dict.keys()) == 1 and len(create_pi_uuids) == 1):
db_pi_uuid = db_pi_dict.keys()[0]
if (db_pi_dict.values()[0] != curr_pi_dict.get(create_pi_uuids[0])):
db_pi_uuid = list(db_pi_dict.keys())[0]
if (list(db_pi_dict.values())[0] !=
curr_pi_dict.get(create_pi_uuids[0])):
# allocate a new ae-id as it belongs to different PR
db_pr = db_pi_dict.values()[0]
db_pr = list(db_pi_dict.values())[0]
ok, result = cls._alloc_ae_id(db_pr, vpg_name)
if not ok:
return ok, result
attr_dict_leftover_pi, _alloc_dict = result
alloc_dealloc_dict['allocated_ae_id'].append(_alloc_dict)
msg = "Allocating AE-ID(%s) for PI(%s) at VPG(%s)/PR(%s)" % (
attr_dict_leftover_pi, db_pi_uuid, vpg_name, db_pr)
cls.db_conn.config_log(msg, level=SandeshLevel.SYS_INFO)
msg = ("Allocated AE-ID(%s) for PI(%s) at "
"VPG(%s)/PR(%s)" % (
attr_dict_leftover_pi, db_pi_uuid,
vpg_name, db_pr))
cls.db_conn.config_log(msg, level=SandeshLevel.SYS_DEBUG)
else:
attr_dict_leftover_pi = attr_dict
msg = "Re-using AE-ID(%s) for PI(%s) at VPG(%s)/PR(%s)" % (
attr_dict_leftover_pi, db_pi_uuid, vpg_name, pi_pr)
cls.db_conn.config_log(msg, level=SandeshLevel.SYS_INFO)
cls.db_conn.config_log(msg, level=SandeshLevel.SYS_DEBUG)
(ok, result) = cls.db_conn.ref_update(
'virtual_port_group',
vpg_uuid,
@@ -157,14 +179,14 @@ def _process_alloc_ae_id(cls, db_obj_dict, vpg_name, obj_dict=None):
relax_ref_for_delete=True)
msg = "Updated AE-ID(%s) in PI(%s) ref to VPG(%s)" % (
attr_dict_leftover_pi, db_pi_uuid, vpg_name)
cls.db_conn.config_log(msg, level=SandeshLevel.SYS_INFO)
cls.db_conn.config_log(msg, level=SandeshLevel.SYS_DEBUG)

# deallocate case
_in_dealloc_list = []
for pi_uuid in delete_pi_uuids:
pi_pr = db_pi_dict.get(pi_uuid)
pi_ae = db_pr_dict.get(pi_pr)
db_pi_prs = db_pi_dict.values().count(pi_pr)
db_pi_prs = list(db_pi_dict.values()).count(pi_pr)
# PR/VPG is already considered for deallocation, so no need
# to dealloc again
if '%s:%s' % (pi_pr, vpg_name) in _in_dealloc_list:
@@ -179,15 +201,15 @@ def _process_alloc_ae_id(cls, db_obj_dict, vpg_name, obj_dict=None):
_in_dealloc_list.append('%s:%s' % (pi_pr, vpg_name))
msg = "Deallocated AE-ID(%s) for PI(%s) at VPG(%s)/PR(%s)" % (
ae_id, pi_uuid, vpg_name, pi_pr)
cls.db_conn.config_log(msg, level=SandeshLevel.SYS_INFO)
cls.db_conn.config_log(msg, level=SandeshLevel.SYS_DEBUG)

# de-allocate leftover single PI, if any
# in delete case, whatever comes in curr_pi_dict are the
# leftovers because for delete refs, ref to be deleted
# will not be coming in payload
if (len(curr_pi_dict.keys()) == 1 and
len(db_pi_dict.keys()) == len(delete_pi_uuids) + 1):
pi_uuid = curr_pi_dict.keys()[0]
len(db_pi_dict.keys()) == len(delete_pi_uuids) + 1):
pi_uuid = list(curr_pi_dict.keys())[0]
pi_pr = curr_pi_dict.get(pi_uuid)
pi_ae = curr_pr_dict.get(pi_pr)
if '%s:%s' % (pi_pr, vpg_name) not in _in_dealloc_list:
@@ -199,9 +221,9 @@ def _process_alloc_ae_id(cls, db_obj_dict, vpg_name, obj_dict=None):
# record deallocated pr/vpg
_in_dealloc_list.append('%s:%s' % (pi_pr, vpg_name))
msg = ("Deallocated AE-ID(%s) from leftover PI(%s) at "
"VPG(%s)/PR(%s)" % (
ae_id, pi_uuid, vpg_name, pi_pr))
cls.db_conn.config_log(msg, level=SandeshLevel.SYS_INFO)
"VPG(%s)/PR(%s)" % (
ae_id, pi_uuid, vpg_name, pi_pr))
cls.db_conn.config_log(msg, level=SandeshLevel.SYS_DEBUG)
pi_ae = db_pr_dict.get(pi_pr)
(ok, result) = cls.db_conn.ref_update(
'virtual_port_group',
@@ -211,7 +233,6 @@ def _process_alloc_ae_id(cls, db_obj_dict, vpg_name, obj_dict=None):
{'attr': None},
'ADD',
db_obj_dict.get('id_perms'),
attr_to_publish=None,
relax_ref_for_delete=True)

return True, (attr_dict, alloc_dealloc_dict)
@@ -275,9 +296,9 @@ def update_physical_intf_type(cls, obj_dict=None,
msg = ""
for pi, vpgs in pis_attached_to_vpg.items():
for vpg in vpgs:
msg += (
'PI (%s) VPG-UUID (%s) VPG-FQNAME (%s); ' % (
pi, vpg['uuid'], ":".join(vpg['to'])))
msg += (
'PI (%s) VPG-UUID (%s) VPG-FQNAME (%s); ' % (
pi, vpg['uuid'], ":".join(vpg['to'])))
return (
False,
(400, "physical interfaces already added at other VPGs can not"
@@ -372,11 +393,13 @@ def pre_dbe_update(cls, id, fq_name, obj_dict, db_conn, **kwargs):
ok, res = cls.update_physical_intf_type(obj_dict, db_obj_dict)
if not ok:
return ok, res
ok, res = cls._process_alloc_ae_id(db_obj_dict, fq_name[-1], obj_dict)
# Allocate/Deallocate AE-IDs for the attached PIs
ok, res = cls._process_alloc_ae_id(
db_obj_dict, fq_name[-1], obj_dict)
if not ok:
return ok, res
if res[0] and kwargs.get('ref_args'):
kwargs['ref_args']['data']['attr'] = res[0]
if res[0] and kwargs.get('ref_update'):
kwargs['ref_update']['data']['attr'] = res[0]
ret_val = res[1]

return True, ret_val

Large diffs are not rendered by default.

0 comments on commit 9e7aed6

Please sign in to comment.