diff --git a/inventory_provider/routes/map.py b/inventory_provider/routes/map.py index 9029e61a4b073fa0172b0d1cd7dab08bade649b1..ad4a3821ee987c4218be72c2e0ccea43289f5d03 100644 --- a/inventory_provider/routes/map.py +++ b/inventory_provider/routes/map.py @@ -19,70 +19,18 @@ static inventory information relevant to maps. .. autofunction:: inventory_provider.routes.map.equipment -/map/services/<service-type> ---------------------------------- - -.. autofunction:: inventory_provider.routes.map.services - - -/map/service-types ---------------------------------- - -.. autofunction:: inventory_provider.routes.map.service_types - """ import json import logging -import re -from flask import Blueprint, Response, request, jsonify +from flask import Blueprint, jsonify import jsonschema from inventory_provider.routes import common -from inventory_provider.routes import msr logger = logging.getLogger(__name__) routes = Blueprint('map-support-routes', __name__) - -SERVICE_LIST_SCHEMA = { - '$schema': 'https://json-schema.org/draft/2020-12/schema', - - 'definitions': { - 'service': { - 'type': 'object', - 'properties': { - 'sid': {'type': 'string'}, - 'name': {'type': 'string'}, - 'type': {'type': 'string'}, - 'pops': { - 'type': 'array', - 'items': {'type': 'string'} - }, - 'overlays': { - 'type': 'object', - 'properties': { - 'speed': {'type': 'number'}, - } - }, - }, - 'required': ['sid', 'name', 'type', 'pops', 'overlays'], - 'additionalProperties': False - }, - }, - - 'type': 'array', - 'items': {'$ref': '#/definitions/service'} -} - - -SERVICE_TYPE_LIST_SCHEMA = { - '$schema': 'https://json-schema.org/draft/2020-12/schema', - 'type': 'array', - 'items': {'type': 'string'} -} - - EQUIPMENT_LIST_SCHEMA = { '$schema': 'https://json-schema.org/draft/2020-12/schema', @@ -127,127 +75,6 @@ POP_LIST_SCHEMA = { } -def _load_all_services(): - - r = common.get_current_redis() - equipment_list = json.loads(r.get('ims:map:equipment').decode('utf-8')) - equipment_dict = {_x['name']: _x for _x in equipment_list} - - def _operational(s): - return s["status"].lower() == "operational" - - def _hostname_to_equipment(_hn): - m = re.match(r'^(.+)\.geant\.net$', _hn) - if not m: - logger.error(f'unexpected hostname pattern: {_hn}') - return '?' - return m.group(1).upper() - - def _endpoint_to_pop(_endpoint: dict[str, str]) -> str: - - if 'hostname' in _endpoint: - eq_name = _hostname_to_equipment(_endpoint['hostname']) - elif 'equipment' in _endpoint: - eq_name = _endpoint['equipment'] - else: - logger.error(f'no equipment or hostname in endpoint: {_endpoint}') - return '?' - - if eq_name not in equipment_dict: - # TODO: is this really possible if all data is read from IMS at the same time? - logger.error(f"unknown endpoint equipment: {eq_name}") - return '?' - - return equipment_dict[eq_name]['pop'] - - def _reformat_service(s): - _pops = map(_endpoint_to_pop, s["endpoints"]) - return { - "name": s["name"], - "pops": list(_pops), - "sid": s["sid"], - "type": s["service_type"], - "overlays": { - "speed": s["speed"], - } - } - - cache_key_all_services = "classifier-cache:map:services" - - all_map_service_info = common._ignore_cache_or_retrieve(request, cache_key_all_services, r) - if all_map_service_info: - all_map_service_info = json.loads(all_map_service_info) - else: - msr_services = filter(_operational, msr.load_all_msr_services()) - all_map_service_info = map(_reformat_service, msr_services) - all_map_service_info = list(all_map_service_info) - r.set(cache_key_all_services, json.dumps(all_map_service_info)) - - return all_map_service_info - - -@routes.route("/services", methods=['GET']) -@routes.route('/services/<service_type>', methods=['GET']) -@common.require_accepts_json -def services(service_type=None): - """ - Handler for `/map/services` and - `/map/services/<service_type>` - which returns information for either all services - or those of a specific service type. - - This endpoint is used by the mapping-provider to get - static information about all operationalservices. - - .. asjson:: - inventory_provider.routes.map.SERVICE_LIST_SCHEMA - - :param service_type: optional filter on service name - :return: list of services - """ - - result = _load_all_services() - - if service_type: - result = [s for s in result if s["type"] == service_type] - - if not result: - message = f'no {service_type} services found' \ - if service_type else 'no services found' - return Response( - response=message, - status=404, - mimetype='text/html') - - return jsonify(result) - - -@routes.route("/service-types", methods=['GET']) -@common.require_accepts_json -def service_types(): - """ - Handler for `/map/service-types` which returns - all known operationalservice types in the network - - This endpoint is used by the mapping-provider to get - static information about all operationalservices. - - .. asjson:: - inventory_provider.routes.map.SERVICE_LIST_SCHEMA - - :return: list of service types - """ - service_types = set([s["type"] for s in _load_all_services()]) - - if not service_types: - return Response( - response='no service types found', - status=404, - mimetype='text/html') - - return jsonify(list(service_types)) - - @routes.route("/equipment", methods=['GET']) @common.require_accepts_json def equipment(service_type=None): diff --git a/test/test_map_routes.py b/test/test_map_routes.py index 0e6b141dd3793fe865bfe0f3f2971d0a6fd67b6a..cfc8237d5a018a0f52d75af435e53b0c94848be9 100644 --- a/test/test_map_routes.py +++ b/test/test_map_routes.py @@ -1,51 +1,9 @@ import json import jsonschema -import pytest - from inventory_provider.routes import map -def test_get_all_services(client): - rv = client.get( - '/map/services', - headers={'Accept': ['application/json']}) - assert rv.status_code == 200 - assert rv.is_json - response_data = json.loads(rv.data.decode('utf-8')) - jsonschema.validate(response_data, map.SERVICE_LIST_SCHEMA) - assert response_data # test data is non-empty - - -@pytest.mark.parametrize( - 'service_type', [ - 'ETHERNET', - 'IP TRUNK', - 'GEANT IP', - 'IP PEERING - R&E']) -def test_get_services_by_type(client, service_type): - rv = client.get( - f'/map/services/{service_type}', - headers={'Accept': ['application/json']}) - assert rv.status_code == 200 - assert rv.is_json - response_data = json.loads(rv.data.decode('utf-8')) - jsonschema.validate(response_data, map.SERVICE_LIST_SCHEMA) - assert response_data # test data is non-empty - - -def test_get_service_types(client): - rv = client.get( - '/map/service-types', - headers={'Accept': ['application/json']}) - assert rv.status_code == 200 - assert rv.is_json - response_data = json.loads(rv.data.decode('utf-8')) - jsonschema.validate(response_data, map.SERVICE_TYPE_LIST_SCHEMA) - assert response_data # test data is non-empty - print(json.dumps(response_data, indent=2)) - - def test_get_equipment(client): rv = client.get( '/map/equipment',