diff --git a/inventory_provider/routes/mic.py b/inventory_provider/routes/mic.py index be6e70ae3513745d90caceacfb4efcf9576af87b..e4b7499db63ed96d0883fb566ed847f60b4f267b 100644 --- a/inventory_provider/routes/mic.py +++ b/inventory_provider/routes/mic.py @@ -38,6 +38,13 @@ SITES_LIST_SCHEMA = { } } +NODES_LIST_SCHEMA = { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "array", + "items": {"type": "string"}, + "additionalProperties": False +} + @routes.route('/sites') def get_sites(): @@ -60,3 +67,16 @@ def get_sites(): r.set(cache_key, result.encode('utf-8')) return Response(result, mimetype='application/json') + + +@routes.route('/nodes/<site>') +def get_nodes(site): + cache_key = f'classifier-cache:mic:nodes:{site}' + r = common.get_current_redis() + result = _ignore_cache_or_retrieve(request, cache_key, r) + if not result: + result = r.get(f'ims:pop_nodes:{site}') + if result: + r.set(cache_key, result) + result = result.decode('utf-8') + return Response(result, mimetype='application/json') diff --git a/inventory_provider/tasks/worker.py b/inventory_provider/tasks/worker.py index 33d396f5e1fca6505c917c21a6fd44ccf0cb4139..53b9454365bf37b18fb726fc635aeea4fb716f01 100644 --- a/inventory_provider/tasks/worker.py +++ b/inventory_provider/tasks/worker.py @@ -996,6 +996,10 @@ def transform_ims_data(data): interface_services = defaultdict(list) # using a dict to ensure no duplicates node_pair_services = defaultdict(dict) + pop_nodes = defaultdict(list) + + for value in locations.values(): + pop_nodes[value['pop']['name']].append(value['equipment-name']) for key, value in port_id_details.items(): for details in value: @@ -1063,7 +1067,8 @@ def transform_ims_data(data): 'interface_services': interface_services, 'services_by_type': services_by_type, 'node_pair_services': node_pair_services, - 'sid_services': sid_services + 'sid_services': sid_services, + 'pop_nodes': pop_nodes } @@ -1075,6 +1080,7 @@ def persist_ims_data(data, use_current=False): services_by_type = data['services_by_type'] node_pair_services = data['node_pair_services'] sid_services = data['sid_services'] + pop_nodes = data['pop_nodes'] def _get_pops(): # de-dupe the sites (by abbreviation) @@ -1099,7 +1105,8 @@ def persist_ims_data(data, use_current=False): 'ims:interface_services:*', 'ims:access_services:*', 'ims:gws_indirect:*', - 'ims:node_pair_services:*' + 'ims:node_pair_services:*', + 'ims:pop_nodes:*' ]: rp = r.pipeline() for k in r.scan_iter(key_pattern, count=1000): @@ -1134,6 +1141,12 @@ def persist_ims_data(data, use_current=False): f'ims:node_pair_services:{k}', json.dumps(list(v.values()))) rp.execute() + rp = r.pipeline() + for k, v in pop_nodes.items(): + rp.set( + f'ims:pop_nodes:{k}', + json.dumps(sorted(v))) + rp.execute() rp = r.pipeline() diff --git a/test/data/router-info.json b/test/data/router-info.json index 9c7f8fae60f683657157596af5f7d128e7f0aaad..f1d75202a5ed84d46f7354bcb8672f298f2d1a9f 100644 Binary files a/test/data/router-info.json and b/test/data/router-info.json differ diff --git a/test/test_mic_routes.py b/test/test_mic_routes.py index 063044682fbeaaf525b2670a0c6f9fd5da60ca8d..1f527444e61c6f7d536337679fd3cdfa259be232 100644 --- a/test/test_mic_routes.py +++ b/test/test_mic_routes.py @@ -2,7 +2,7 @@ import json import jsonschema -from inventory_provider.routes.mic import SITES_LIST_SCHEMA +from inventory_provider.routes.mic import SITES_LIST_SCHEMA, NODES_LIST_SCHEMA DEFAULT_REQUEST_HEADERS = { "Content-type": "application/json", @@ -20,5 +20,11 @@ def test_get_sites(client, mocked_redis): jsonschema.validate(response_data, SITES_LIST_SCHEMA) -# def test_get_sites_data(mocked_redis): -# +def test_get_nodes(client, mocked_redis): + rv = client.get( + '/mic/nodes/AMSTERDAM', + headers=DEFAULT_REQUEST_HEADERS) + assert rv.status_code == 200 + assert rv.is_json + response_data = json.loads(rv.data.decode('utf-8')) + jsonschema.validate(response_data, NODES_LIST_SCHEMA) diff --git a/test/test_worker.py b/test/test_worker.py index f98bc1b2b0a61933071edaf686f3aa365af87ab7..6693e97117a3d867e1b8b96b93205df764f80316 100644 --- a/test/test_worker.py +++ b/test/test_worker.py @@ -119,18 +119,21 @@ def test_extract_ims_data(mocker): def test_transform_ims_data(): locations = { "eq_a": { + "equipment-name": "eq_a", "pop": { "name": "pop_loc_a", "abbreviation": "pla", } }, "eq_b": { + "equipment-name": "eq_b", "pop": { "name": "pop_loc_b", "abbreviation": "plb", } }, "UNKNOWN_LOC": { + "equipment-name": "UNKNOWN_LOC", "pop": { "name": "UNKNOWN", "abbreviation": "UNKNOWN", @@ -326,6 +329,14 @@ def test_transform_ims_data(): "geant_nodes": ["eq_b"] } res = transform_ims_data(data) + pop_nodes_res = { + "pop_loc_a": ["eq_a"], + "pop_loc_b": ["eq_b"], + "UNKNOWN": ["UNKNOWN_LOC"] + } + assert sorted(res["pop_nodes"].keys()) == sorted(pop_nodes_res.keys()) + for k, v in pop_nodes_res.items(): + assert v == res["pop_nodes"][k] ifs = res["interface_services"] assert list(ifs.keys()) == [ "eq_a:if_a", "eq_b:if_b", "eq_a:if_c", "eq_b:if_c"] @@ -392,9 +403,19 @@ def test_persist_ims_data(mocker, data_config, mocked_redis): return_value=r) data = { + "pop_nodes": { + "LOC A": ["eq_a"], + "LOC B": ["eq_b"] + }, "locations": { - "loc_a": {'pop': {'name': "LOC A", 'abbreviation': 'aaa'}}, - "loc_b": {'pop': {'name': "LOC B", 'abbreviation': 'bbb'}}, + "eq_a": { + 'equipment-name': 'eq_a', + 'pop': {'name': "LOC A", 'abbreviation': 'aaa'} + }, + "eq_b": { + 'equipment-name': 'eq_b', + 'pop': {'name': "LOC B", 'abbreviation': 'bbb'} + }, }, "lg_routers": [ {"equipment name": "lg_eq1"}, {"equipment name": "lg_eq2"} @@ -442,8 +463,11 @@ def test_persist_ims_data(mocker, data_config, mocked_redis): r.delete(k) persist_ims_data(data) + assert [k.decode("utf-8") for k in r.keys("ims:pop_nodes:*")] == \ + ["ims:pop_nodes:LOC A", "ims:pop_nodes:LOC B"] + assert [k.decode("utf-8") for k in r.keys("ims:location:*")] == \ - ["ims:location:loc_a", "ims:location:loc_b"] + ["ims:location:eq_a", "ims:location:eq_b"] assert [k.decode("utf-8") for k in r.keys("ims:lg:*")] == \ ["ims:lg:lg_eq1", "ims:lg:lg_eq2"]