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

Finished feature NGM-20-remove-map-services.

parents 604b6bd5 5926e4d5
No related branches found
No related tags found
No related merge requests found
...@@ -19,70 +19,18 @@ static inventory information relevant to maps. ...@@ -19,70 +19,18 @@ static inventory information relevant to maps.
.. autofunction:: inventory_provider.routes.map.equipment .. 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 json
import logging import logging
import re
from flask import Blueprint, Response, request, jsonify from flask import Blueprint, jsonify
import jsonschema import jsonschema
from inventory_provider.routes import common from inventory_provider.routes import common
from inventory_provider.routes import msr
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
routes = Blueprint('map-support-routes', __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 = { EQUIPMENT_LIST_SCHEMA = {
'$schema': 'https://json-schema.org/draft/2020-12/schema', '$schema': 'https://json-schema.org/draft/2020-12/schema',
...@@ -127,127 +75,6 @@ POP_LIST_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']) @routes.route("/equipment", methods=['GET'])
@common.require_accepts_json @common.require_accepts_json
def equipment(service_type=None): def equipment(service_type=None):
......
import json import json
import jsonschema import jsonschema
import pytest
from inventory_provider.routes import map 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): def test_get_equipment(client):
rv = client.get( rv = client.get(
'/map/equipment', '/map/equipment',
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment