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.
.. autofunction:: inventory_provider.routes.msr.mdvpn
/msr/services
--------------------------------------------
.. autofunction:: inventory_provider.routes.msr.get_system_correlation_services
/msr/vpn-proxy
--------------------------------------------
.. autofunction:: inventory_provider.routes.msr.vpn-proxy
helpers
-------------------------------------
@@ -321,6 +328,34 @@ MDVPN_LIST_SCHEMA = {
'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
def after_request(resp):
@@ -1010,22 +1045,19 @@ def mdvpn():
yield formatted_peering
def _vpnrr_peerings(asn, vpnrr_index):
if asn in vpnrr_index:
vrr_peering_group = vpnrr_index[asn]
# rearrange into index using ipv4 as key
# this will collect related entries under the same ipv4
ip_index = _make_group_index(vrr_peering_group, 'address')
for ip in ip_index:
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']
# rearrange into index using ipv4 as key
# this will collect related entries under the same ipv4
ip_index = _make_group_index(vpnrr_index.get(asn, []), 'address')
for ip, ip_details in ip_index.items():
hostnames = [item['hostname'] for item in ip_details]
description = ip_details[0]['description']
formatted_peering = {
"description": _get_consistent_description(description),
"v4": ip,
"hostname": hostnames
}
yield formatted_peering
formatted_peering = {
"description": _get_consistent_description(description),
"v4": ip,
"hostname": hostnames
}
yield formatted_peering
def _peerings_for_nren(asn, bgplu_index, vpnrr_index):
return {
@@ -1053,3 +1085,91 @@ def mdvpn():
for pair in nren_asn_map]
response = json.dumps(nren_details)
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