diff --git a/inventory_provider/routes/msr.py b/inventory_provider/routes/msr.py index c2f971bc87a322538234869bc55d76bc16aea27a..5e8670e317b0d8b4bee4922b106258d3b644ace8 100644 --- a/inventory_provider/routes/msr.py +++ b/inventory_provider/routes/msr.py @@ -362,6 +362,40 @@ DOMAIN_TO_POP_MAPPING = { "ams.nl": "Amsterdam" } +# very similar to PEERING_LIST_SCHEMA but +# with a field for NREN, which is required +ASN_PEER_LIST_SCHEMA = { + '$schema': 'http://json-schema.org/draft-07/schema#', + 'definitions': { + 'peering-instance': { + 'type': 'object', + 'properties': { + 'address': {'type': 'string'}, + 'description': {'type': 'string'}, + 'logical-system': {'type': 'string'}, + 'group': {'type': 'string'}, + 'hostname': {'type': 'string'}, + 'remote-asn': {'type': 'integer'}, + 'local-asn': {'type': 'integer'}, + 'instance': {'type': 'string'}, + 'nren': {'type': 'string'} + }, + # only vrr peerings have remote-asn + # only group peerings have local-asn or instance + # not all group peerings have 'description' + # and only vrr or vpn-proxy peerings are within a logical system + 'required': [ + 'address', + 'group', + 'hostname', + 'nren'], + 'additionalProperties': False + } + }, + 'type': 'array', + 'items': {'$ref': '#/definitions/peering-instance'} +} + @routes.after_request def after_request(resp): @@ -1203,14 +1237,14 @@ def asn_peers(asn): The response will be formatted according to the following schema: .. asjson:: - inventory_provider.routes.msr.PEERING_LIST_SCHEMA + inventory_provider.routes.msr.ASN_PEER_LIST_SCHEMA :param asn: specific ASN to get peers for :return: """ r = common.get_current_redis() - def _get_filtered_peers_for_asn(asn, group, instance): + def _get_filtered_peers_for_asn(asn, nren, group, instance): peers = json.loads(r.get(f'juniper-peerings:peer-asn:{asn}')) def _attribute_filter(peer, name, value): @@ -1223,12 +1257,12 @@ def asn_peers(asn): for peer in peers: if _attribute_filter(peer, "group", group) and \ _attribute_filter(peer, "instance", instance): + peer['nren'] = nren yield peer - def _get_filtered_peers(nren_asn_map, group, instance): - for pair in nren_asn_map: - asn = pair['asn'] - asn_peers = _get_filtered_peers_for_asn(asn, group, instance) + def _get_filtered_peers(asn_nren_map, group, instance): + for asn, nren in asn_nren_map.items(): + asn_peers = _get_filtered_peers_for_asn(asn, nren, group, instance) for peer in asn_peers: yield peer @@ -1241,10 +1275,26 @@ def asn_peers(asn): group = params.get('group', None) instance = params.get('instance', None) - if asn is not None: - peers = list(_get_filtered_peers_for_asn(asn, group, instance)) - else: + cache_key = f'classifier-cache:msr:asn-peers:{asn}:{group}:{instance}' + response = _ignore_cache_or_retrieve(request, cache_key, r) + + if not response: config = current_app.config['INVENTORY_PROVIDER_CONFIG'] - nren_asn_map = config['nren-asn-map'] - peers = list(_get_filtered_peers(nren_asn_map, group, instance)) - return jsonify(peers) + # set up quick lookup based on ASN + asn_nren_map = { + item['asn']: item['nren'] for item in config['nren-asn-map'] + } + + if asn is not None: + nren = asn_nren_map.get(asn, None) + peers = list( + _get_filtered_peers_for_asn(asn, nren, group, instance) + ) + else: + peers = list( + _get_filtered_peers(asn_nren_map, group, instance) + ) + response = json.dumps(peers) + r.set(cache_key, response.encode('utf-8')) + + return Response(response, mimetype='application/json') diff --git a/test/test_msr_routes.py b/test/test_msr_routes.py index b091cea3bd0effb6f5eca569f4c6219d7cfc3eb9..45668655024bc7064f2d00611be8af138c225d19 100644 --- a/test/test_msr_routes.py +++ b/test/test_msr_routes.py @@ -6,7 +6,7 @@ import pytest from inventory_provider.routes.msr import PEERING_LIST_SCHEMA, \ PEERING_GROUP_LIST_SCHEMA, PEERING_ADDRESS_SERVICES_LIST, \ SYSTEM_CORRELATION_SERVICES_LIST_SCHEMA, _get_services_for_address, \ - MDVPN_LIST_SCHEMA, VPN_PROXY_LIST_SCHEMA + MDVPN_LIST_SCHEMA, VPN_PROXY_LIST_SCHEMA, ASN_PEER_LIST_SCHEMA from inventory_provider.routes.poller import SERVICES_LIST_SCHEMA from inventory_provider.tasks.common import _get_redis @@ -366,7 +366,7 @@ def test_get_asn_peers_get(endpoint_variant, client, mocked_redis): assert rv.status_code == 200 assert rv.is_json response_data = json.loads(rv.data.decode('utf-8')) - jsonschema.validate(response_data, PEERING_LIST_SCHEMA) + jsonschema.validate(response_data, ASN_PEER_LIST_SCHEMA) assert response_data # test data is non-empty @@ -389,5 +389,5 @@ def test_get_asn_peers_post(endpoint_variant, post_body, client, mocked_redis): assert rv.status_code == 200 assert rv.is_json response_data = json.loads(rv.data.decode('utf-8')) - jsonschema.validate(response_data, PEERING_LIST_SCHEMA) + jsonschema.validate(response_data, ASN_PEER_LIST_SCHEMA) assert response_data # test data is non-empty