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

Finished feature DBOARD3-552-neteng-pop-api.

parents d5b112ef 3afd62e0
No related branches found
No related tags found
No related merge requests found
...@@ -12,9 +12,20 @@ These endpoints are intended for use by neteng tools. ...@@ -12,9 +12,20 @@ These endpoints are intended for use by neteng tools.
.. autofunction:: inventory_provider.routes.neteng.get_location .. autofunction:: inventory_provider.routes.neteng.get_location
/neteng/pops
---------------------------------
.. autofunction:: inventory_provider.routes.neteng.get_pop_names
/neteng/pop/name
---------------------------------
.. autofunction:: inventory_provider.routes.neteng.get_pop_location
""" """
import json import json
import logging import logging
import re
import threading import threading
from flask import Blueprint, Response, jsonify from flask import Blueprint, Response, jsonify
...@@ -25,6 +36,12 @@ routes = Blueprint('neteng-query-routes', __name__) ...@@ -25,6 +36,12 @@ routes = Blueprint('neteng-query-routes', __name__)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
_subnet_lookup_semaphore = threading.Semaphore() _subnet_lookup_semaphore = threading.Semaphore()
STRING_LIST_SCHEMA = {
'$schema': 'http://json-schema.org/draft-07/schema#',
'type': 'array',
'items': {'type': 'string'}
}
@routes.after_request @routes.after_request
def after_request(resp): def after_request(resp):
...@@ -35,9 +52,9 @@ def after_request(resp): ...@@ -35,9 +52,9 @@ def after_request(resp):
@common.require_accepts_json @common.require_accepts_json
def get_location(equipment): def get_location(equipment):
""" """
Handler for `/neteng/location/equipment-name` Handler for `/neteng/location/<equipment-name>`
This method will pop location information for the IMS node This method will return pop location information for the IMS node
with name = `equipment-name`. with name = `equipment-name`.
404 is returned if the IMS node name is not known. 404 is returned if the IMS node name is not known.
...@@ -66,3 +83,66 @@ def get_location(equipment): ...@@ -66,3 +83,66 @@ def get_location(equipment):
mimetype='text/html') mimetype='text/html')
return jsonify(value[0]) return jsonify(value[0])
@routes.route('/pops', methods=['GET', 'POST'])
@common.require_accepts_json
def get_pop_names():
"""
Handler for `/neteng/pops`
This method will return a list of defined pop
names. Elements from this list can be used
with `/neteng/pop`.
.. asjson::
inventory_provider.routes.neteng.STRING_LIST_SCHEMA
:return: as above
"""
def _pops():
r = common.get_current_redis()
for k in r.scan_iter('ims:pop:*', count=1000):
k = k.decode('utf-8')
m = re.match('^ims:pop:(.+)$', k)
yield m.group(1)
return jsonify(sorted(list(_pops())))
@routes.route('/pop/<name>', methods=['GET', 'POST'])
@common.require_accepts_json
def get_pop_location(name):
"""
Handler for `/neteng/pop/<name>`
This method will return location information for the POP
with name = `name` in IMS.
404 is returned if the POP name is not known.
Otherwise the return value will be formatted as:
.. asjson::
inventory_provider.db.ims_data.POP_LOCATION_SCHEMA
:return: as above
"""
r = common.get_current_redis()
value = r.get(f'ims:pop:{name}')
if not value:
return Response(
response='no location information available for "{pop}"',
status=404,
mimetype='text/html')
value = json.loads(value.decode('utf-8'))
if not value:
return Response(
response='unexpected empty cached data for "{name}"',
status=500,
mimetype='text/html')
return jsonify(value)
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
...@@ -2,7 +2,9 @@ import json ...@@ -2,7 +2,9 @@ import json
import jsonschema import jsonschema
import pytest import pytest
from inventory_provider.db.ims_data import NODE_LOCATION_SCHEMA from inventory_provider.db.ims_data \
import NODE_LOCATION_SCHEMA, POP_LOCATION_SCHEMA
from inventory_provider.routes.neteng import STRING_LIST_SCHEMA
@pytest.mark.parametrize('equipment_name', [ @pytest.mark.parametrize('equipment_name', [
...@@ -25,3 +27,35 @@ def test_location_not_found(client, mocked_redis): ...@@ -25,3 +27,35 @@ def test_location_not_found(client, mocked_redis):
'/neteng/location/BOGUS.EQUIPMENT.NAME', '/neteng/location/BOGUS.EQUIPMENT.NAME',
headers={'Accept': ['application/json']}) headers={'Accept': ['application/json']})
assert rv.status_code == 404 assert rv.status_code == 404
def test_get_pops(client, mocked_redis):
rv = client.get(
'/neteng/pops',
headers={'Accept': ['application/json']})
assert rv.status_code == 200
jsonschema.validate(
json.loads(rv.data.decode('utf-8')),
STRING_LIST_SCHEMA)
@pytest.mark.parametrize('pop_name', [
'AMSTERDAM', 'VIENNA', 'LONDON', 'LONDON 2'
])
def test_pop_location(client, mocked_redis, pop_name):
rv = client.post(
f'/neteng/pop/{pop_name}',
headers={'Accept': ['application/json']})
assert rv.status_code == 200
jsonschema.validate(
json.loads(rv.data.decode('utf-8')),
POP_LOCATION_SCHEMA)
s = json.loads(rv.data.decode('utf-8'))
print(s)
def test_pop_not_found(client, mocked_redis):
rv = client.post(
'/neteng/pop/BOGUS.POP.NAME',
headers={'Accept': ['application/json']})
assert rv.status_code == 404
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment