Skip to content
Snippets Groups Projects

Feature/reporting 307 msr vpn proxy endpoint

Merged Sam Roberts requested to merge feature/REPORTING-307-msr-vpn-proxy-endpoint into develop
All threads resolved!
Files
2
@@ -64,12 +64,19 @@ These endpoints are intended for use by MSR.
@@ -64,12 +64,19 @@ These endpoints are intended for use by MSR.
.. autofunction:: inventory_provider.routes.msr.mdvpn
.. autofunction:: inventory_provider.routes.msr.mdvpn
 
/msr/services
/msr/services
--------------------------------------------
--------------------------------------------
.. autofunction:: inventory_provider.routes.msr.get_system_correlation_services
.. autofunction:: inventory_provider.routes.msr.get_system_correlation_services
 
/msr/vpn-proxy
 
--------------------------------------------
 
 
.. autofunction:: inventory_provider.routes.msr.vpn-proxy
 
 
helpers
helpers
-------------------------------------
-------------------------------------
@@ -321,6 +328,34 @@ MDVPN_LIST_SCHEMA = {
@@ -321,6 +328,34 @@ MDVPN_LIST_SCHEMA = {
'items': {'$ref': '#/definitions/mdvpn_group'}
'items': {'$ref': '#/definitions/mdvpn_group'}
}
}
 
VPN_PROXY_LIST_SCHEMA = {
 
'$schema': 'http://json-schema.org/draft-07/schema#',
 
'definitions': {
 
'vpn_proxy_peering': {
 
'type': 'object',
 
'properties': {
 
'pop': {'type': 'string'},
 
'nren': {'type': 'string'},
 
'group': {'type': 'string'},
 
'v4': {'type': 'string'}
 
},
 
'additionalProperties': False
 
}
 
},
 
'type': 'array',
 
'items': {'$ref': '#/definitions/vpn_proxy_peering'}
 
}
 
 
DOMAIN_TO_POP_MAPPING = {
 
"mad.es": "Madrid",
 
"bra.sk": "Bratislava",
 
"vie.at": "Vienna",
 
"gen.ch": "Geneva",
 
"fra.de": "Frankfurt",
 
"pra.cz": "Prague",
 
"ams.nl": "Amsterdam"
 
}
 
@routes.after_request
@routes.after_request
def after_request(resp):
def after_request(resp):
@@ -1010,22 +1045,19 @@ def mdvpn():
@@ -1010,22 +1045,19 @@ def mdvpn():
yield formatted_peering
yield formatted_peering
def _vpnrr_peerings(asn, vpnrr_index):
def _vpnrr_peerings(asn, vpnrr_index):
if asn in vpnrr_index:
# rearrange into index using ipv4 as key
vrr_peering_group = vpnrr_index[asn]
# this will collect related entries under the same ipv4
# rearrange into index using ipv4 as key
ip_index = _make_group_index(vpnrr_index.get(asn, []), 'address')
# this will collect related entries under the same ipv4
for ip, ip_details in ip_index.items():
ip_index = _make_group_index(vrr_peering_group, 'address')
hostnames = [item['hostname'] for item in ip_details]
for ip in ip_index:
description = ip_details[0]['description']
ip_details = ip_index[ip] # a list of all info for given ipv4
hostnames = [item['hostname'] for item in ip_details]
description = ip_details[0]['description']
formatted_peering = {
formatted_peering = {
"description": _get_consistent_description(description),
"description": _get_consistent_description(description),
"v4": ip,
"v4": ip,
"hostname": hostnames
"hostname": hostnames
}
}
yield formatted_peering
yield formatted_peering
def _peerings_for_nren(asn, bgplu_index, vpnrr_index):
def _peerings_for_nren(asn, bgplu_index, vpnrr_index):
return {
return {
@@ -1053,3 +1085,91 @@ def mdvpn():
@@ -1053,3 +1085,91 @@ def mdvpn():
for pair in nren_asn_map]
for pair in nren_asn_map]
response = json.dumps(nren_details)
response = json.dumps(nren_details)
return Response(response, mimetype='application/json')
return Response(response, mimetype='application/json')
 
 
 
@routes.route('/vpn-proxy', methods=['GET', 'POST'])
 
@common.require_accepts_json
 
def vpn_proxy():
 
"""
 
Handler for `/vpn-proxy`
 
 
This method returns a list of all L3VPN related VPN proxy peerings.
 
 
The response will be formatted according to the following schema:
 
 
.. asjson::
 
inventory_provider.routes.msr.VPN_PROXY_LIST_SCHEMA
 
 
:return:
 
"""
 
 
def _is_relevant(item):
 
"""
 
Determine if a given peering in the VPN-PROXY logical system is
 
relevant to this endpoint (whether it's related to L3VPN)
 
:param item: peering dict
 
:return: True if the peering is L3VPN relevant, False otherwise
 
"""
 
desc = item.get("description")
 
if desc is None:
 
return False
 
return "L3VPN" in desc
 
 
def _look_up_city_from_hostname(hostname):
 
"""
 
Get the city name for a peering from a partial hostname match.
 
This uses a hardcoded lookup table.
 
:param hostname: hostname for the peering
 
:return: city name if found, "Unknown" otherwise
 
"""
 
for snippet in DOMAIN_TO_POP_MAPPING:
 
if snippet in hostname:
 
return DOMAIN_TO_POP_MAPPING[snippet]
 
return "Unknown"
 
 
def _extract_nren_from_description(desc, group):
 
"""
 
Retrieve the relevant NREN from the peering description and group.
 
This approach is, by its nature, very fragile to any changes to
 
descriptions, and should be revisited when that happens.
 
 
:param desc: description of a VPN-Proxy peering
 
:param group: group of the same VPN-Proxy peering
 
:return: name of the NREN
 
"""
 
if group == "PRACE":
 
# common trait: the NREN is the first word in the description
 
return desc.split(' ')[0]
 
else:
 
# only other group is XiFi, and only CESNet is relevant
 
return 'CESNet'
 
 
def _format_peerings(vpnproxy):
 
"""
 
Generator that iterates through a list of peering dicts, yielding
 
appropriately reformatted peerings if they are relevant to L3VPN.
 
:param vpnproxy: list of peering dicts taken from current redis
 
:return: generator of reformated peerings
 
"""
 
for peering in vpnproxy:
 
if _is_relevant(peering):
 
desc = peering["description"]
 
group = peering["group"]
 
hostname = peering["hostname"]
 
formatted_peering = {
 
"pop": _look_up_city_from_hostname(hostname),
 
"nren": _extract_nren_from_description(desc, group),
 
"group": group,
 
"v4": peering.get("address")
 
}
 
yield formatted_peering
 
 
r = common.get_current_redis()
 
cache_key = 'classifier-cache:msr:vpn-proxy'
 
response = _ignore_cache_or_retrieve(request, cache_key, r)
 
if not response:
 
vpnproxy = json.loads(
 
r.get('juniper-peerings:logical-system:VPN-PROXY').decode('utf-8'))
 
peerings = list(_format_peerings(vpnproxy))
 
response = json.dumps(peerings)
 
return Response(response, mimetype='application/json')
Loading