Skip to content
Snippets Groups Projects
Commit 223503d3 authored by Release Webservice's avatar Release Webservice
Browse files

Finished release 0.38.

parents af03cc29 da18e813
No related branches found
No related tags found
No related merge requests found
...@@ -54,4 +54,5 @@ ...@@ -54,4 +54,5 @@
DBOARD3-203: omit 'inactive' interfaces DBOARD3-203: omit 'inactive' interfaces
0.35: POL1-135: added customer(user) info to service category api response 0.35: POL1-135: added customer(user) info to service category api response
0.36: DBOARD3-218: added project name to circuit info 0.36: DBOARD3-218: added project name to circuit info
0.37: DBOARD3-220: make redis/sentinel socket timeouts configurable 0.37: DBOARD3-220: make redis/sentinel socket timeouts configurable
\ No newline at end of file 0.38: DBOARD3-234/DBOARD3-232: standardized location data in classifier responses
\ No newline at end of file
...@@ -13,6 +13,65 @@ routes = Blueprint("inventory-data-classifier-support-routes", __name__) ...@@ -13,6 +13,65 @@ routes = Blueprint("inventory-data-classifier-support-routes", __name__)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def _LOCATION(equipment, name, abbreviation):
return {
'equipment': equipment,
'name': name,
'abbreviation': abbreviation
}
def _remove_duplicates_from_list(l):
"""
removes duplicates from the input list
the list items must be encodable as json
:param l:
:return: a new list with unique elements
"""
tmp_dict = dict([(json.dumps(item, sort_keys=True), item) for item in l])
return list(tmp_dict.values())
def _location_from_router(router_name):
r = common.get_current_redis()
result = r.get(f'opsdb:location:{router_name}')
if not result:
logger.error(f'error looking up location for {router_name}')
return None
result = json.loads(result.decode('utf-8'))
if not result:
logger.error(f'sanity failure: empty list for location {router_name}')
return None
return {
'a': _LOCATION(
equipment=result[0]['equipment-name'],
name=result[0]['pop']['name'],
abbreviation=result[0]['pop']['abbreviation'])
}
def _location_from_service_dict(s):
location = {
'a': _LOCATION(
equipment=s['equipment'],
name=s['pop_name'],
abbreviation=s['pop_abbreviation'])
}
if all(s[n] for n in (
'other_end_equipment',
'other_end_pop_name',
'other_end_pop_abbreviation')):
location['b'] = _LOCATION(
equipment=s['other_end_equipment'],
name=s['other_end_pop_name'],
abbreviation=s['other_end_pop_abbreviation'])
return location
class ClassifierRequestError(Exception): class ClassifierRequestError(Exception):
status_code = 500 status_code = 500
...@@ -86,7 +145,11 @@ def get_juniper_link_info(source_equipment, interface): ...@@ -86,7 +145,11 @@ def get_juniper_link_info(source_equipment, interface):
if result: if result:
result = result.decode('utf-8') result = result.decode('utf-8')
else: else:
result = {}
result = {
'locations': []
}
top_level_services = [] top_level_services = []
services = r.get( services = r.get(
...@@ -95,6 +158,8 @@ def get_juniper_link_info(source_equipment, interface): ...@@ -95,6 +158,8 @@ def get_juniper_link_info(source_equipment, interface):
result['services'] = json.loads(services.decode('utf=8')) result['services'] = json.loads(services.decode('utf=8'))
for s in result['services']: for s in result['services']:
top_level_services.extend(get_top_level_services(s['id'], r)) top_level_services.extend(get_top_level_services(s['id'], r))
result['locations'] += [
_location_from_service_dict(s) for s in result['services']]
ifc_info = r.get( ifc_info = r.get(
'netconf-interfaces:%s:%s' % (source_equipment, interface)) 'netconf-interfaces:%s:%s' % (source_equipment, interface))
...@@ -132,6 +197,10 @@ def get_juniper_link_info(source_equipment, interface): ...@@ -132,6 +197,10 @@ def get_juniper_link_info(source_equipment, interface):
if top_level_services: if top_level_services:
result['related-services'] = top_level_services result['related-services'] = top_level_services
if not result['locations']:
result['locations'] = [_location_from_router(source_equipment)]
result['locations'] = _remove_duplicates_from_list(result['locations'])
result = json.dumps(result) result = json.dumps(result)
# cache this data for the next call # cache this data for the next call
r.set(cache_key, result.encode('utf-8')) r.set(cache_key, result.encode('utf-8'))
...@@ -243,33 +312,45 @@ def peer_info(address): ...@@ -243,33 +312,45 @@ def peer_info(address):
address = obj.exploded address = obj.exploded
except ValueError: except ValueError:
raise ClassifierProcessingError( raise ClassifierProcessingError(
'unable to parse %r as an ip address' % address) f'unable to parse {address} as an ip address')
r = common.get_current_redis() r = common.get_current_redis()
cache_key = 'classifier-cache:peer:%s' % address cache_key = f'classifier-cache:peer:{address}'
result = r.get(cache_key) result = r.get(cache_key)
if result: if result:
result = result.decode('utf-8') result = result.decode('utf-8')
else: else:
result = {} result = {
'locations': []
}
info = r.get('ix_public_peer:%s' % address) info = r.get('ix_public_peer:%s' % address)
if info: if info:
info = info.decode('utf-8') info = info.decode('utf-8')
result['ix-public-peer-info'] = ix_peering_info(json.loads(info)) info = json.loads(info)
result['ix-public-peer-info'] = ix_peering_info(info)
router_location = _location_from_router(info['router'])
result['locations'] += [router_location]
info = r.get('vpn_rr_peer:%s' % address) info = r.get('vpn_rr_peer:%s' % address)
if info: if info:
info = info.decode('utf-8') info = info.decode('utf-8')
result['vpn-rr-peer-info'] = json.loads(info) info = json.loads(info)
result['vpn-rr-peer-info'] = info
router_location = _location_from_router(info['router'])
result['locations'] += [router_location]
interfaces = list(find_interfaces_and_services(address)) interfaces = list(find_interfaces_and_services(address))
if interfaces: if interfaces:
result['interfaces'] = interfaces result['interfaces'] = interfaces
for i in interfaces:
result['locations'] += [
_location_from_service_dict(s) for s in i['services']]
result['locations'] = _remove_duplicates_from_list(result['locations'])
result = json.dumps(result) result = json.dumps(result)
# cache this data for the next call # cache this data for the next call
r.set(cache_key, result.encode('utf-8')) r.set(cache_key, result.encode('utf-8'))
...@@ -293,7 +374,9 @@ def get_trap_metadata(source_equipment, interface, circuit_id): ...@@ -293,7 +374,9 @@ def get_trap_metadata(source_equipment, interface, circuit_id):
if result: if result:
result = result.decode('utf-8') result = result.decode('utf-8')
else: else:
result = {} result = {
'locations': []
}
top_level_services = [] top_level_services = []
services = r.get( services = r.get(
...@@ -306,6 +389,8 @@ def get_trap_metadata(source_equipment, interface, circuit_id): ...@@ -306,6 +389,8 @@ def get_trap_metadata(source_equipment, interface, circuit_id):
top_level_services.extend(tls) top_level_services.extend(tls)
if top_level_services: if top_level_services:
result['related-services'] = top_level_services result['related-services'] = top_level_services
result['locations'] += [
_location_from_service_dict(s) for s in result['services']]
gl = r.get('opsdb:geant_lambdas:%s' % circuit_id.lower()) gl = r.get('opsdb:geant_lambdas:%s' % circuit_id.lower())
if gl: if gl:
...@@ -337,9 +422,6 @@ def get_coriant_info(equipment_name, entity_string): ...@@ -337,9 +422,6 @@ def get_coriant_info(equipment_name, entity_string):
equipment_name, entity_string) equipment_name, entity_string)
result = r.get(cache_key) result = r.get(cache_key)
# this is just for development to save deleting the cache every time
# result = False
if result: if result:
result = result.decode('utf-8') result = result.decode('utf-8')
else: else:
...@@ -356,7 +438,8 @@ def get_coriant_info(equipment_name, entity_string): ...@@ -356,7 +438,8 @@ def get_coriant_info(equipment_name, entity_string):
result = { result = {
'equipment name': equipment_name, 'equipment name': equipment_name,
'card id': m.group(1), 'card id': m.group(1),
'port number': m.group(2) 'port number': m.group(2),
'locations': []
} }
config = current_app.config['INVENTORY_PROVIDER_CONFIG'] config = current_app.config['INVENTORY_PROVIDER_CONFIG']
...@@ -367,6 +450,16 @@ def get_coriant_info(equipment_name, entity_string): ...@@ -367,6 +450,16 @@ def get_coriant_info(equipment_name, entity_string):
if path: if path:
result['path'] = path result['path'] = path
result['locations'] += [{
'a': _LOCATION(
equipment=path['a']['equipment name'],
name=path['a']['pop']['name'],
abbreviation=path['a']['pop']['abbreviation']),
'b': _LOCATION(
equipment=path['b']['equipment name'],
name=path['b']['pop']['name'],
abbreviation=path['b']['pop']['abbreviation']),
}]
top_level_services = get_top_level_services(path['id'], r) top_level_services = get_top_level_services(path['id'], r)
if top_level_services: if top_level_services:
......
...@@ -2,7 +2,7 @@ from setuptools import setup, find_packages ...@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
setup( setup(
name='inventory-provider', name='inventory-provider',
version="0.37", version="0.38",
author='GEANT', author='GEANT',
author_email='swd@geant.org', author_email='swd@geant.org',
description='Dashboard inventory provider', description='Dashboard inventory provider',
......
...@@ -143,6 +143,7 @@ def flask_config_filename(): ...@@ -143,6 +143,7 @@ def flask_config_filename():
@pytest.fixture @pytest.fixture
def mocked_redis(mocker): def mocked_redis(mocker):
MockedRedis.db = None # force data to be reloaded
mocker.patch( mocker.patch(
'inventory_provider.tasks.common.redis.StrictRedis', 'inventory_provider.tasks.common.redis.StrictRedis',
MockedRedis) MockedRedis)
......
...@@ -2,13 +2,10 @@ ...@@ -2,13 +2,10 @@
just checks that the worker methods call the right functions just checks that the worker methods call the right functions
and some data ends up in the right place ... otherwise not very detailed and some data ends up in the right place ... otherwise not very detailed
""" """
import contextlib
import os import os
from inventory_provider.tasks import worker from inventory_provider.tasks import worker
from inventory_provider.tasks import common from inventory_provider.tasks import common
from inventory_provider.tasks.common import _get_redis from inventory_provider.tasks.common import _get_redis
...@@ -22,19 +19,11 @@ def backend_db(): ...@@ -22,19 +19,11 @@ def backend_db():
}).db }).db
@contextlib.contextmanager
def _mocked_connection(x):
yield x
def test_update_locations(mocker, mocked_worker_module, mocked_redis): def test_update_locations(mocker, mocked_worker_module, mocked_redis):
mocker.patch( mocker.patch(
'inventory_provider.db.opsdb.lookup_pop_info', 'inventory_provider.db.opsdb.lookup_pop_info',
lambda c, h: [{'C': c, 'H': h}]) lambda c, h: [{'C': c, 'H': h}])
mocker.patch(
'inventory_provider.db.db.connection',
_mocked_connection)
def _cached_locations(): def _cached_locations():
db = backend_db() db = backend_db()
......
...@@ -8,109 +8,139 @@ DEFAULT_REQUEST_HEADERS = { ...@@ -8,109 +8,139 @@ DEFAULT_REQUEST_HEADERS = {
"Accept": ["application/json"] "Accept": ["application/json"]
} }
JUNIPER_LINK_METADATA = { LOCATIONS_DEFINITIONS = {
"$schema": "http://json-schema.org/draft-07/schema#", "location-endpoint": {
"type": "object", "type": "object",
"properties": {
"definitions": { "equipment": {"type": "string"},
"ip-address": { "name": {"type": "string"},
"type": "string", "abbreviation": {"type": "string"}
"oneOf": [
{"pattern": r'^(\d+\.){3}\d+$'},
{"pattern": r'^([a-f\d]{4}:){7}[a-f\d]{4}$'}
]
},
"ipv4-interface-address": {
"type": "string",
"pattern": r'^(\d+\.){3}\d+/\d+$'
}, },
"ipv6-interface-address": { "required": ["equipment", "name", "abbreviation"],
"type": "string", "additionalProperties": False
"pattern": r'^[a-f\d:]+/\d+$' },
"location": {
"type": "object",
"properties": {
"a": {"$ref": "#/definitions/location-endpoint"},
"b": {"$ref": "#/definitions/location-endpoint"}
}, },
"interface-info": { "required": ["a"],
"type": "object", "additionalProperties": False
"properties": { },
"name": {"type": "string"}, "locations-list": {
"description": {"type": "string"}, "type": "array",
"ipv4": { "items": {"$ref": "#/definitions/location"}
"type": "array", }
"items": {"$ref": "#/definitions/ipv4-interface-address"} }
},
"ipv6": {
"type": "array",
"items": {"$ref": "#/definitions/ipv6-interface-address"}
},
# TODO: check what's changed: added to make tests pass JUNIPER_LINK_METADATA_DEFINITIONS = {
'bundle': {"type": "array"} "ip-address": {
"type": "string",
"oneOf": [
{"pattern": r'^(\d+\.){3}\d+$'},
{"pattern": r'^([a-f\d]{4}:){7}[a-f\d]{4}$'}
]
},
"ipv4-interface-address": {
"type": "string",
"pattern": r'^(\d+\.){3}\d+/\d+$'
},
"ipv6-interface-address": {
"type": "string",
"pattern": r'^[a-f\d:]+/\d+$'
},
"interface-info": {
"type": "object",
"properties": {
"name": {"type": "string"},
"description": {"type": "string"},
"ipv4": {
"type": "array",
"items": {"$ref": "#/definitions/ipv4-interface-address"}
}, },
"required": ["name", "description", "ipv4", "ipv6"], "ipv6": {
"additionalProperties": False "type": "array",
"items": {"$ref": "#/definitions/ipv6-interface-address"}
},
# TODO: check what's changed: added to make tests pass
'bundle': {"type": "array"}
}, },
"service-info": { "required": ["name", "description", "ipv4", "ipv6"],
"type": "object", "additionalProperties": False
"properties": { },
"id": {"type": "integer"}, "service-info": {
"name": {"type": "string"}, "type": "object",
"status": { "properties": {
"type": "string", "id": {"type": "integer"},
"enum": ["operational", "installed", "planned", "ordered"] "name": {"type": "string"},
}, "status": {
"circuit_type": { "type": "string",
"type": "string", "enum": ["operational", "installed", "planned", "ordered"]
"enum": ["path", "service", "l2circuit"]
},
"service_type": {"type": "string"},
"project": {"type": "string"},
"equipment": {"type": "string"},
"pop": {"type": "string"},
"pop_abbreviation": {"type": "string"},
"other_end_pop": {"type": "string"},
"other_end_pop_abbreviation": {"type": "string"},
"other_end_equipment": {"type": "string"},
"port": {"type": "string"},
"other_end_port": {"type": "string"},
"logical_unit": {
"oneOf": [
{"type": "integer"},
{"type": "string", "maxLength": 0}
]
},
"other_end_logical_unit": {
"oneOf": [
{"type": "integer"},
{"type": "string", "maxLength": 0}
]
},
"manufacturer": {
"type": "string",
"enum": ["juniper", "coriant", "infinera",
"cisco", "hewlett packard",
"corsa", "graham smith uk ltd",
"unknown", ""]
},
"card_id": {"type": "string"},
"other_end_card_id": {"type": "string"},
"interface_name": {"type": "string"},
"other_end_interface_name": {"type": "string"},
# TODO: check what's changed: added to make tests pass
'other_end_pop_name': {"type": "string"},
'pop_name': {"type": "string"}
}, },
# TODO: modify service-info so that "" entries are just omitted "circuit_type": {
# (... rather than requiring 'oneOf') "type": "string",
# TODO: put 'other_end_*' params in a sub dictionary "enum": ["path", "service", "l2circuit"]
# "required": [ },
# "id", "name", "status", "service_type": {"type": "string"},
# "circuit_type", "service_type", "project": {"type": "string"},
# "project", "port", "manufacturer", "equipment": {"type": "string"},
# "equipment", "logical_unit", "card_id", "interface_name" "pop": {"type": "string"},
# ], "pop_abbreviation": {"type": "string"},
"additionalProperties": False
} "other_end_pop": {"type": "string"},
"other_end_pop_abbreviation": {"type": "string"},
"other_end_equipment": {"type": "string"},
"port": {"type": "string"},
"other_end_port": {"type": "string"},
"logical_unit": {
"oneOf": [
{"type": "integer"},
{"type": "string", "maxLength": 0}
]
},
"other_end_logical_unit": {
"oneOf": [
{"type": "integer"},
{"type": "string", "maxLength": 0}
]
},
"manufacturer": {
"type": "string",
"enum": ["juniper", "coriant", "infinera",
"cisco", "hewlett packard",
"corsa", "graham smith uk ltd",
"unknown", ""]
},
"card_id": {"type": "string"},
"other_end_card_id": {"type": "string"},
"interface_name": {"type": "string"},
"other_end_interface_name": {"type": "string"},
# TODO: check what's changed: added to make tests pass
'other_end_pop_name': {"type": "string"},
'pop_name': {"type": "string"}
},
# TODO: modify service-info so that "" entries are just omitted
# (... rather than requiring 'oneOf')
# TODO: put 'other_end_*' params in a sub dictionary
# "required": [
# "id", "name", "status",
# "circuit_type", "service_type",
# "project", "port", "manufacturer",
# "equipment", "logical_unit", "card_id", "interface_name"
# ],
"additionalProperties": False
}
}
JUNIPER_LINK_METADATA = {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"definitions": {
**JUNIPER_LINK_METADATA_DEFINITIONS, **LOCATIONS_DEFINITIONS
}, },
"type": "object", "type": "object",
...@@ -123,7 +153,8 @@ JUNIPER_LINK_METADATA = { ...@@ -123,7 +153,8 @@ JUNIPER_LINK_METADATA = {
"related-services": { "related-services": {
"type": "array", "type": "array",
"items": {"$ref": "#/definitions/service-info"} "items": {"$ref": "#/definitions/service-info"}
} },
"locations": {"$ref": "#/definitions/locations-list"}
}, },
# "required": ["interface"], # "required": ["interface"],
"additionalProperties": False "additionalProperties": False
...@@ -156,12 +187,18 @@ def test_juniper_link_info_not_found(client): ...@@ -156,12 +187,18 @@ def test_juniper_link_info_not_found(client):
'ipv4': [], 'ipv4': [],
'ipv6': [], 'ipv6': [],
'bundle': [] 'bundle': []
} },
'locations': [{
'a': {
'equipment': 'mx1.ams.nl.geant.net',
'name': 'Amsterdam',
'abbreviation': 'ams'}
}]
} }
VPN_RR_PEER_INFO_KEYS = {'vpn-rr-peer-info'} VPN_RR_PEER_INFO_KEYS = {'vpn-rr-peer-info', 'locations'}
IX_PUBLIC_PEER_INFO_KEYS = {'ix-public-peer-info', 'interfaces'} IX_PUBLIC_PEER_INFO_KEYS = {'ix-public-peer-info', 'interfaces', 'locations'}
@pytest.mark.parametrize('peer_address,expected_response_keys', [ @pytest.mark.parametrize('peer_address,expected_response_keys', [
...@@ -173,95 +210,98 @@ IX_PUBLIC_PEER_INFO_KEYS = {'ix-public-peer-info', 'interfaces'} ...@@ -173,95 +210,98 @@ IX_PUBLIC_PEER_INFO_KEYS = {'ix-public-peer-info', 'interfaces'}
) )
def test_peer_info( def test_peer_info(
client, peer_address, expected_response_keys): client, peer_address, expected_response_keys):
response_schema = { response_schema_definitions = {
"$schema": "http://json-schema.org/draft-07/schema#", "ip-address": {
"type": "object", "type": "string",
"oneOf": [
"definitions": { {"pattern": r'^(\d+\.){3}\d+$'},
"ip-address": { {"pattern": r'^([a-f\d]{4}:){7}[a-f\d]{4}$'}
"type": "string", ]
"oneOf": [ },
{"pattern": r'^(\d+\.){3}\d+$'}, "interface-address": {
{"pattern": r'^([a-f\d]{4}:){7}[a-f\d]{4}$'} "type": "string",
] "oneOf": [
}, {"pattern": r'^(\d+\.){3}\d+/\d+$'},
"interface-address": { {"pattern": r'^[a-f\d:]+/\d+$'}
"type": "string", ]
"oneOf": [ },
{"pattern": r'^(\d+\.){3}\d+/\d+$'}, "vpn-rr-peer": {
{"pattern": r'^[a-f\d:]+/\d+$'} "type": "object",
] "properties": {
}, "name": {"$ref": "#/definitions/ip-address"},
"vpn-rr-peer": { "description": {"type": "string"},
"type": "object", "peer-as": {"type": "integer"},
"properties": { "router": {"type": "string"}
"name": {"$ref": "#/definitions/ip-address"},
"description": {"type": "string"},
"peer-as": {"type": "integer"},
"router": {"type": "string"}
},
"required": ["name", "description"],
"additionalProperties": False
},
"ix-public-peer": {
"type": "object",
"properties": {
"name": {"$ref": "#/definitions/ip-address"},
"description": {"type": "string"},
"router": {"type": "string"},
"as": {
"type": "object",
"properties": {
"local": {"type": "integer"},
"peer": {"type": "integer"},
},
"required": ["local", "peer"],
"additionalProperties": False
}
},
"required": ["name", "description", "as"],
"additionalProperties": False
},
"ix-public-peer-list": {
"type": "array",
"items": {"$ref": "#/definitions/ip-address"}
}, },
"ix-public-peer-info": { "required": ["name", "description"],
"type": "object", "additionalProperties": False
"properties": { },
"peer": {"$ref": "#/definitions/ix-public-peer"}, "ix-public-peer": {
"group": {"$ref": "#/definitions/ix-public-peer-list"}, "type": "object",
"router": {"$ref": "#/definitions/ix-public-peer-list"} "properties": {
}, "name": {"$ref": "#/definitions/ip-address"},
"required": ["peer", "group", "router"], "description": {"type": "string"},
"additionalProperties": False "router": {"type": "string"},
"as": {
"type": "object",
"properties": {
"local": {"type": "integer"},
"peer": {"type": "integer"},
},
"required": ["local", "peer"],
"additionalProperties": False
}
}, },
"interface-info": { "required": ["name", "description", "as"],
"type": "object", "additionalProperties": False
"properties": { },
"name": {"$ref": "#/definitions/ip-address"}, "ix-public-peer-list": {
"interface address": { "type": "array",
"$ref": "#/definitions/interface-address"}, "items": {"$ref": "#/definitions/ip-address"}
"interface name": {"type": "string"}, },
"router": {"type": "string"} "ix-public-peer-info": {
}, "type": "object",
"required": [ "properties": {
"name", "interface address", "interface name", "router"], "peer": {"$ref": "#/definitions/ix-public-peer"},
"additionalProperties": False "group": {"$ref": "#/definitions/ix-public-peer-list"},
"router": {"$ref": "#/definitions/ix-public-peer-list"}
}, },
"service-info": { "required": ["peer", "group", "router"],
"type": "object" "additionalProperties": False
},
"interface-info": {
"type": "object",
"properties": {
"name": {"$ref": "#/definitions/ip-address"},
"interface address": {
"$ref": "#/definitions/interface-address"},
"interface name": {"type": "string"},
"router": {"type": "string"}
}, },
"interface-lookup-info": { "required": [
"type": "object", "name", "interface address", "interface name", "router"],
"properties": { "additionalProperties": False
"interface": {"$ref": "#/definitions/interface-info"}, },
"services": { "service-info": {
"type": "array", "type": "object"
"items": {"$ref": "#/definitions/service-info"} },
} "interface-lookup-info": {
"type": "object",
"properties": {
"interface": {"$ref": "#/definitions/interface-info"},
"services": {
"type": "array",
"items": {"$ref": "#/definitions/service-info"}
} }
} }
}
}
response_schema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"definitions": {
**response_schema_definitions, **LOCATIONS_DEFINITIONS
}, },
"type": "object", "type": "object",
...@@ -272,7 +312,8 @@ def test_peer_info( ...@@ -272,7 +312,8 @@ def test_peer_info(
"interfaces": { "interfaces": {
"type": "array", "type": "array",
"items": {"$ref": "#/definitions/interface-lookup-info"} "items": {"$ref": "#/definitions/interface-lookup-info"}
} },
"locations": {"$ref": "#/definitions/locations-list"}
}, },
"additionalProperties": False "additionalProperties": False
} }
...@@ -301,7 +342,7 @@ def test_peer_not_found(client): ...@@ -301,7 +342,7 @@ def test_peer_not_found(client):
headers=DEFAULT_REQUEST_HEADERS) headers=DEFAULT_REQUEST_HEADERS)
assert rv.status_code == 200 assert rv.status_code == 200
response_data = json.loads(rv.data.decode('utf-8')) response_data = json.loads(rv.data.decode('utf-8'))
assert response_data == {} assert response_data == {'locations': []}
@pytest.mark.parametrize('id_,equipment,entity_name,card_id,port_number', [ @pytest.mark.parametrize('id_,equipment,entity_name,card_id,port_number', [
...@@ -325,7 +366,27 @@ def test_coriant_info( ...@@ -325,7 +366,27 @@ def test_coriant_info(
'inventory_provider.db.db.connection', mocked_connection) 'inventory_provider.db.db.connection', mocked_connection)
mocker.patch( mocker.patch(
'inventory_provider.db.opsdb.lookup_coriant_path', 'inventory_provider.db.opsdb.lookup_coriant_path',
lambda a, b, c, d: {'id': '123', 'C': a, 'E': b, 'CID': c, 'P': d}) lambda a, b, c, d: {
'id': '123',
'C': a,
'E': b,
'CID': c,
'P': d,
'a': {
'equipment name': 'abc',
'pop': {
'name': 'zzz',
'abbreviation': '123'
}
},
'b': {
'equipment name': 'ddd',
'pop': {
'name': 'aaa',
'abbreviation': '999'
}
}
})
rv = client.get( rv = client.get(
'/classifier/coriant-info/{equipment}/{entity}'.format( '/classifier/coriant-info/{equipment}/{entity}'.format(
...@@ -346,8 +407,18 @@ def test_coriant_info( ...@@ -346,8 +407,18 @@ def test_coriant_info(
'C': CONNECTION, 'C': CONNECTION,
'E': equipment, 'E': equipment,
'CID': card_id, 'CID': card_id,
'P': port_number 'P': port_number,
} 'a': {
'equipment name': 'abc',
'pop': {'name': 'zzz', 'abbreviation': '123'}},
'b': {
'equipment name': 'ddd',
'pop': {'name': 'aaa', 'abbreviation': '999'}}
},
'locations': [{
'a': {'equipment': 'abc', 'name': 'zzz', 'abbreviation': '123'},
'b': {'equipment': 'ddd', 'name': 'aaa', 'abbreviation': '999'}
}]
} }
assert response_data == expected_response assert response_data == expected_response
......
...@@ -6,74 +6,103 @@ DEFAULT_REQUEST_HEADERS = { ...@@ -6,74 +6,103 @@ DEFAULT_REQUEST_HEADERS = {
"Accept": ["application/json"] "Accept": ["application/json"]
} }
LOCATIONS_DEFINITIONS = {
"location-endpoint": {
"type": "object",
"properties": {
"equipment": {"type": "string"},
"name": {"type": "string"},
"abbreviation": {"type": "string"}
},
"required": ["equipment", "name", "abbreviation"],
"additionalProperties": False
},
"location": {
"type": "object",
"properties": {
"a": {"$ref": "#/definitions/location-endpoint"},
"b": {"$ref": "#/definitions/location-endpoint"}
},
"required": ["a"],
"additionalProperties": False
},
"locations-list": {
"type": "array",
"items": {"$ref": "#/definitions/location"}
}
}
INFINERA_LINK_METADATA_DEFINITIONS = {
"service-info": {
"type": "object",
"properties": {
"id": {"type": "integer"},
"name": {"type": "string"},
"status": {
"type": "string",
"enum": ["operational", "installed", "planned", "ordered"]
},
"circuit_type": {
"type": "string",
"enum": ["path", "service", "l2circuit"]
},
"service_type": {"type": "string"},
"project": {"type": "string"},
"pop_name": {"type": "string"},
"pop_abbreviation": {"type": "string"},
"other_end_pop_name": {"type": "string"},
"other_end_pop_abbreviation": {"type": "string"},
"equipment": {"type": "string"},
"other_end_equipment": {"type": "string"},
"port": {"type": "string"},
"other_end_port": {"type": "string"},
"logical_unit": {
"oneOf": [
{"type": "integer"},
{"type": "string", "maxLength": 0}
]
},
"other_end_logical_unit": {
"oneOf": [
{"type": "integer"},
{"type": "string", "maxLength": 0}
]
},
"manufacturer": {
"type": "string",
"enum": ["juniper", "coriant", "infinera",
"cisco", "hewlett packard",
"corsa", "graham smith uk ltd",
"unknown", ""]
},
"card_id": {"type": "string"},
"other_end_card_id": {"type": "string"},
"interface_name": {"type": "string"},
"other_end_interface_name": {"type": "string"}
},
"additionalProperties": False
},
"geant-lambda": {
"type": "object",
"properties": {
"id": {"type": "integer"},
"name": {"type": "string"},
"project": {"type": "string"},
"status": {
"type": "string",
"enum": ["operational", "installed", "planned", "ordered"]
},
},
"additionalProperties": False
}
}
INFINERA_LINK_METADATA = { INFINERA_LINK_METADATA = {
"$schema": "http://json-schema.org/draft-07/schema#", "$schema": "http://json-schema.org/draft-07/schema#",
"type": "object", "type": "object",
"definitions": { "definitions": {
"service-info": { **INFINERA_LINK_METADATA_DEFINITIONS, **LOCATIONS_DEFINITIONS
"type": "object",
"properties": {
"id": {"type": "integer"},
"name": {"type": "string"},
"status": {
"type": "string",
"enum": ["operational", "installed", "planned", "ordered"]
},
"circuit_type": {
"type": "string",
"enum": ["path", "service", "l2circuit"]
},
"service_type": {"type": "string"},
"project": {"type": "string"},
"pop_name": {"type": "string"},
"pop_abbreviation": {"type": "string"},
"other_end_pop_name": {"type": "string"},
"other_end_pop_abbreviation": {"type": "string"},
"equipment": {"type": "string"},
"other_end_equipment": {"type": "string"},
"port": {"type": "string"},
"other_end_port": {"type": "string"},
"logical_unit": {
"oneOf": [
{"type": "integer"},
{"type": "string", "maxLength": 0}
]
},
"other_end_logical_unit": {
"oneOf": [
{"type": "integer"},
{"type": "string", "maxLength": 0}
]
},
"manufacturer": {
"type": "string",
"enum": ["juniper", "coriant", "infinera",
"cisco", "hewlett packard",
"corsa", "graham smith uk ltd",
"unknown", ""]
},
"card_id": {"type": "string"},
"other_end_card_id": {"type": "string"},
"interface_name": {"type": "string"},
"other_end_interface_name": {"type": "string"}
},
"additionalProperties": False
},
"geant-lambda": {
"type": "object",
"properties": {
"id": {"type": "integer"},
"name": {"type": "string"},
"project": {"type": "string"},
"status": {
"type": "string",
"enum": ["operational", "installed", "planned", "ordered"]
},
},
"additionalProperties": False
}
}, },
"type": "object", "type": "object",
...@@ -89,6 +118,7 @@ INFINERA_LINK_METADATA = { ...@@ -89,6 +118,7 @@ INFINERA_LINK_METADATA = {
"geant-lambda": { "geant-lambda": {
"$ref": "#/definitions/geant-lambda" "$ref": "#/definitions/geant-lambda"
}, },
"locations": {"$ref": "#/definitions/locations-list"}
}, },
"additionalProperties": False "additionalProperties": False
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment