Skip to content
Snippets Groups Projects
Commit 1f0dd444 authored by Erik Reid's avatar Erik Reid
Browse files

refactored to reduce cyclomatic complexity

parent 226a3077
No related branches found
No related tags found
No related merge requests found
......@@ -882,6 +882,127 @@ def get_peering_services():
return Response(response, mimetype="application/json")
@functools.cache
def _load_all_interfaces():
"""
loads all ip interfaces in the network and returns as a dict
of dicts:
hostname -> interface name -> interface info
:return: dict of dicts
"""
# dict of dicts:
# peering_info[hostname][interface_name] = dict of ifc details
result = defaultdict(dict)
host_if_extraction_re = re.compile(r'^netconf-interfaces:(.+?):')
for doc in common.load_json_docs(
config_params=current_app.config['INVENTORY_PROVIDER_CONFIG'],
key_pattern='netconf-interfaces:*',
num_threads=20):
matches = host_if_extraction_re.match(doc['key'])
if matches:
hostname = matches[1]
interface_name = doc['value']['name']
result[hostname][interface_name] = doc['value']
return result
@functools.cache
def _load_redundant_access_peers():
"""
load all peers that should be considered
redundant for access services
that is, all peers for services like NREN-APx
:return: dict of [peer address] -> [remote asn]
"""
r = common.get_current_redis()
result = {}
# cf. REPORTING-312: limited to eGEANT group,
# but this can be expanded here in future
redundant_access_groups = ['eGEANT']
for g in redundant_access_groups:
doc = r.get(f'juniper-peerings:group:{g}')
for peer in json.loads(doc.decode('utf-8')):
result[peer['address']] = peer['remote-asn']
return result
def _ip_endpoint_extractor(endpoint_details: dict):
"""
special-purpose method used only by _endpoint_extractor
operates on a dictionary formatted as in worker.transform_ims_data
(cf sid_services)
WARNING: assumes hostname is a router in _load_all_interfaces,
asserts if not
:param endpoint_details: dict formatted as in worker.transform_ims_data
:return: dict formatted
as SYSTEM_CORRELATION_SERVICES_LIST_SCHEMA.ip-endpoint
"""
hostname = ims_equipment_to_hostname(endpoint_details['equipment'])
interface = endpoint_details['port'].lower()
ip_endpoint = {
'hostname': hostname,
'interface': interface,
}
all_interfaces = _load_all_interfaces()
# sanity: should have already been checked
assert hostname in all_interfaces
host_info = all_interfaces[hostname]
interface_info = host_info.get(interface, {})
addresses = {}
ipv4 = interface_info.get('ipv4')
ipv6 = interface_info.get('ipv6')
if ipv4:
addresses['v4'] = ipv4[0]
if ipv6:
addresses['v6'] = ipv6[0]
if addresses:
ip_endpoint['addresses'] = addresses
return ip_endpoint
def _endpoint_extractor(endpoint_details: Dict):
"""
special-purpose method used only by get_system_correlation_services
operates on a dictionary formatted as in worker.transform_ims_data
(cf sid_services)
WARNING: assumes hostname is a router in _load_all_interfaces,
asserts if not
:param endpoint_details: dict formatted as in worker.transform_ims_data
:return: dict formatted as one element of the array
SYSTEM_CORRELATION_SERVICES_LIST_SCHEMA.endpoints
"""
if not endpoint_details['geant_equipment']:
return
potential_hostname = ims_equipment_to_hostname(
endpoint_details['equipment'])
all_routers = _load_all_interfaces().keys()
if potential_hostname in all_routers:
return _ip_endpoint_extractor(endpoint_details)
else:
return {
'equipment': endpoint_details['equipment'],
'port': endpoint_details['port']
}
@routes.route('/services', methods=['GET', 'POST'])
@common.require_accepts_json
def get_system_correlation_services():
......@@ -901,87 +1022,27 @@ def get_system_correlation_services():
:return:
"""
def _get_redundancy_asn(endpoints):
# endpoints should be a list formatted as
# SYSTEM_CORRELATION_SERVICES_LIST_SCHEMA.endpoints
redundant_peerings = _load_redundant_access_peers()
for ep in endpoints:
addresses = ep.get('addresses', {})
for ifc_address in addresses.values():
for p, asn in redundant_peerings.items():
peer = ipaddress.ip_address(p)
ifc = ipaddress.ip_interface(ifc_address)
if peer in ifc.network:
return asn
return None
cache_key = 'classifier-cache:msr:services'
r = common.get_current_redis()
response = _ignore_cache_or_retrieve(request, cache_key, r)
if not response:
# dict of dicts:
# peering_info[hostname][interface_name] = dict of ifc details
peering_info = defaultdict(dict)
host_if_extraction_re = re.compile(r'^netconf-interfaces:(.+?):')
for doc in common.load_json_docs(
config_params=current_app.config['INVENTORY_PROVIDER_CONFIG'],
key_pattern='netconf-interfaces:*',
num_threads=20):
matches = host_if_extraction_re.match(doc['key'])
if matches:
peering_info[matches[1]][doc['value']['name']] = doc['value']
def _load_redundant_peers():
# REPORTING-312: limited to eGEANT group,
# but this can be expanded here in future
redundant_access_groups = ['eGEANT']
for g in redundant_access_groups:
doc = r.get(f'juniper-peerings:group:{g}')
for peer in json.loads(doc.decode('utf-8')):
yield peer['address'], peer['remote-asn']
# dict of peers & asn's: [peer address] -> asn
redundant_access_group_peers = dict(_load_redundant_peers())
def _ip_endpoint_extractor(endpoint_details: Dict):
hostname = ims_equipment_to_hostname(endpoint_details['equipment'])
interface = endpoint_details['port'].lower()
ip_endpoint = {
'hostname': hostname,
'interface': interface,
}
host_info = peering_info[hostname]
interface_info = host_info.get(interface, {})
addresses = {}
ipv4 = interface_info.get('ipv4')
ipv6 = interface_info.get('ipv6')
if ipv4:
addresses['v4'] = ipv4[0]
if ipv6:
addresses['v6'] = ipv6[0]
if addresses:
ip_endpoint['addresses'] = addresses
return ip_endpoint
def _optical_endpoint_extractor(endpoint_details: Dict):
return {
'equipment': endpoint_details['equipment'],
'port': endpoint_details['port']
}
def _endpoint_extractor(endpoint_details: Dict):
if not endpoint_details['geant_equipment']:
return
potential_hostname = ims_equipment_to_hostname(
endpoint_details['equipment'])
if potential_hostname in peering_info.keys():
return _ip_endpoint_extractor(endpoint_details)
else:
return _optical_endpoint_extractor(endpoint_details)
def _get_redundancy_asn(service):
for ep in service['endpoints']:
addresses = ep.get('addresses', {})
for ifc_address in addresses.values():
for p, asn in redundant_access_group_peers.items():
peer = ipaddress.ip_address(p)
ifc = ipaddress.ip_interface(ifc_address)
if peer in ifc.network:
return asn
return None
sid_services = json.loads(r.get('ims:sid_services').decode('utf-8'))
response = []
......@@ -1003,7 +1064,7 @@ def get_system_correlation_services():
service_info['endpoints'].append(endpoint)
if service_info.get('endpoints'):
asn = _get_redundancy_asn(service_info)
asn = _get_redundancy_asn(service_info['endpoints'])
if asn:
service_info['redundant_asn'] = asn
response.append(service_info)
......@@ -1013,7 +1074,7 @@ def get_system_correlation_services():
if response:
response = json.dumps(response, indent=2)
r.set(cache_key, response.encode('utf-8'))
# r.set(cache_key, response.encode('utf-8'))
if not response:
return Response(
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment