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

Finished feature DBOARD3-232-add-location-data-to-responses.

parents b7de8b6c 86e9f5cf
No related branches found
No related tags found
No related merge requests found
......@@ -13,6 +13,65 @@ routes = Blueprint("inventory-data-classifier-support-routes", __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):
status_code = 500
......@@ -86,7 +145,11 @@ def get_juniper_link_info(source_equipment, interface):
if result:
result = result.decode('utf-8')
else:
result = {}
result = {
'locations': []
}
top_level_services = []
services = r.get(
......@@ -95,6 +158,8 @@ def get_juniper_link_info(source_equipment, interface):
result['services'] = json.loads(services.decode('utf=8'))
for s in result['services']:
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(
'netconf-interfaces:%s:%s' % (source_equipment, interface))
......@@ -132,6 +197,10 @@ def get_juniper_link_info(source_equipment, interface):
if 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)
# cache this data for the next call
r.set(cache_key, result.encode('utf-8'))
......@@ -243,33 +312,45 @@ def peer_info(address):
address = obj.exploded
except ValueError:
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()
cache_key = 'classifier-cache:peer:%s' % address
cache_key = f'classifier-cache:peer:{address}'
result = r.get(cache_key)
if result:
result = result.decode('utf-8')
else:
result = {}
result = {
'locations': []
}
info = r.get('ix_public_peer:%s' % address)
if info:
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)
if info:
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))
if 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)
# cache this data for the next call
r.set(cache_key, result.encode('utf-8'))
......@@ -293,7 +374,9 @@ def get_trap_metadata(source_equipment, interface, circuit_id):
if result:
result = result.decode('utf-8')
else:
result = {}
result = {
'locations': []
}
top_level_services = []
services = r.get(
......@@ -306,6 +389,8 @@ def get_trap_metadata(source_equipment, interface, circuit_id):
top_level_services.extend(tls)
if 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())
if gl:
......@@ -337,9 +422,6 @@ def get_coriant_info(equipment_name, entity_string):
equipment_name, entity_string)
result = r.get(cache_key)
# this is just for development to save deleting the cache every time
# result = False
if result:
result = result.decode('utf-8')
else:
......@@ -356,7 +438,8 @@ def get_coriant_info(equipment_name, entity_string):
result = {
'equipment name': equipment_name,
'card id': m.group(1),
'port number': m.group(2)
'port number': m.group(2),
'locations': []
}
config = current_app.config['INVENTORY_PROVIDER_CONFIG']
......@@ -367,6 +450,16 @@ def get_coriant_info(equipment_name, entity_string):
if 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)
if top_level_services:
......
......@@ -143,6 +143,7 @@ def flask_config_filename():
@pytest.fixture
def mocked_redis(mocker):
MockedRedis.db = None # force data to be reloaded
mocker.patch(
'inventory_provider.tasks.common.redis.StrictRedis',
MockedRedis)
......
......@@ -2,13 +2,10 @@
just checks that the worker methods call the right functions
and some data ends up in the right place ... otherwise not very detailed
"""
import contextlib
import os
from inventory_provider.tasks import worker
from inventory_provider.tasks import common
from inventory_provider.tasks.common import _get_redis
......@@ -22,19 +19,11 @@ def backend_db():
}).db
@contextlib.contextmanager
def _mocked_connection(x):
yield x
def test_update_locations(mocker, mocked_worker_module, mocked_redis):
mocker.patch(
'inventory_provider.db.opsdb.lookup_pop_info',
lambda c, h: [{'C': c, 'H': h}])
mocker.patch(
'inventory_provider.db.db.connection',
_mocked_connection)
def _cached_locations():
db = backend_db()
......
......@@ -8,109 +8,139 @@ DEFAULT_REQUEST_HEADERS = {
"Accept": ["application/json"]
}
JUNIPER_LINK_METADATA = {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"definitions": {
"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+$'
LOCATIONS_DEFINITIONS = {
"location-endpoint": {
"type": "object",
"properties": {
"equipment": {"type": "string"},
"name": {"type": "string"},
"abbreviation": {"type": "string"}
},
"ipv6-interface-address": {
"type": "string",
"pattern": r'^[a-f\d:]+/\d+$'
"required": ["equipment", "name", "abbreviation"],
"additionalProperties": False
},
"location": {
"type": "object",
"properties": {
"a": {"$ref": "#/definitions/location-endpoint"},
"b": {"$ref": "#/definitions/location-endpoint"}
},
"interface-info": {
"type": "object",
"properties": {
"name": {"type": "string"},
"description": {"type": "string"},
"ipv4": {
"type": "array",
"items": {"$ref": "#/definitions/ipv4-interface-address"}
},
"ipv6": {
"type": "array",
"items": {"$ref": "#/definitions/ipv6-interface-address"}
},
"required": ["a"],
"additionalProperties": False
},
"locations-list": {
"type": "array",
"items": {"$ref": "#/definitions/location"}
}
}
# TODO: check what's changed: added to make tests pass
'bundle': {"type": "array"}
JUNIPER_LINK_METADATA_DEFINITIONS = {
"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"],
"additionalProperties": False
"ipv6": {
"type": "array",
"items": {"$ref": "#/definitions/ipv6-interface-address"}
},
# TODO: check what's changed: added to make tests pass
'bundle': {"type": "array"}
},
"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"},
"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"}
"required": ["name", "description", "ipv4", "ipv6"],
"additionalProperties": False
},
"service-info": {
"type": "object",
"properties": {
"id": {"type": "integer"},
"name": {"type": "string"},
"status": {
"type": "string",
"enum": ["operational", "installed", "planned", "ordered"]
},
# 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
}
"circuit_type": {
"type": "string",
"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
# (... 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",
......@@ -123,7 +153,8 @@ JUNIPER_LINK_METADATA = {
"related-services": {
"type": "array",
"items": {"$ref": "#/definitions/service-info"}
}
},
"locations": {"$ref": "#/definitions/locations-list"}
},
# "required": ["interface"],
"additionalProperties": False
......@@ -156,12 +187,18 @@ def test_juniper_link_info_not_found(client):
'ipv4': [],
'ipv6': [],
'bundle': []
}
},
'locations': [{
'a': {
'equipment': 'mx1.ams.nl.geant.net',
'name': 'Amsterdam',
'abbreviation': 'ams'}
}]
}
VPN_RR_PEER_INFO_KEYS = {'vpn-rr-peer-info'}
IX_PUBLIC_PEER_INFO_KEYS = {'ix-public-peer-info', 'interfaces'}
VPN_RR_PEER_INFO_KEYS = {'vpn-rr-peer-info', 'locations'}
IX_PUBLIC_PEER_INFO_KEYS = {'ix-public-peer-info', 'interfaces', 'locations'}
@pytest.mark.parametrize('peer_address,expected_response_keys', [
......@@ -173,95 +210,98 @@ IX_PUBLIC_PEER_INFO_KEYS = {'ix-public-peer-info', 'interfaces'}
)
def test_peer_info(
client, peer_address, expected_response_keys):
response_schema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"definitions": {
"ip-address": {
"type": "string",
"oneOf": [
{"pattern": r'^(\d+\.){3}\d+$'},
{"pattern": r'^([a-f\d]{4}:){7}[a-f\d]{4}$'}
]
},
"interface-address": {
"type": "string",
"oneOf": [
{"pattern": r'^(\d+\.){3}\d+/\d+$'},
{"pattern": r'^[a-f\d:]+/\d+$'}
]
},
"vpn-rr-peer": {
"type": "object",
"properties": {
"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"}
response_schema_definitions = {
"ip-address": {
"type": "string",
"oneOf": [
{"pattern": r'^(\d+\.){3}\d+$'},
{"pattern": r'^([a-f\d]{4}:){7}[a-f\d]{4}$'}
]
},
"interface-address": {
"type": "string",
"oneOf": [
{"pattern": r'^(\d+\.){3}\d+/\d+$'},
{"pattern": r'^[a-f\d:]+/\d+$'}
]
},
"vpn-rr-peer": {
"type": "object",
"properties": {
"name": {"$ref": "#/definitions/ip-address"},
"description": {"type": "string"},
"peer-as": {"type": "integer"},
"router": {"type": "string"}
},
"ix-public-peer-info": {
"type": "object",
"properties": {
"peer": {"$ref": "#/definitions/ix-public-peer"},
"group": {"$ref": "#/definitions/ix-public-peer-list"},
"router": {"$ref": "#/definitions/ix-public-peer-list"}
},
"required": ["peer", "group", "router"],
"additionalProperties": False
"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
}
},
"interface-info": {
"type": "object",
"properties": {
"name": {"$ref": "#/definitions/ip-address"},
"interface address": {
"$ref": "#/definitions/interface-address"},
"interface name": {"type": "string"},
"router": {"type": "string"}
},
"required": [
"name", "interface address", "interface name", "router"],
"additionalProperties": False
"required": ["name", "description", "as"],
"additionalProperties": False
},
"ix-public-peer-list": {
"type": "array",
"items": {"$ref": "#/definitions/ip-address"}
},
"ix-public-peer-info": {
"type": "object",
"properties": {
"peer": {"$ref": "#/definitions/ix-public-peer"},
"group": {"$ref": "#/definitions/ix-public-peer-list"},
"router": {"$ref": "#/definitions/ix-public-peer-list"}
},
"service-info": {
"type": "object"
"required": ["peer", "group", "router"],
"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": {
"type": "object",
"properties": {
"interface": {"$ref": "#/definitions/interface-info"},
"services": {
"type": "array",
"items": {"$ref": "#/definitions/service-info"}
}
"required": [
"name", "interface address", "interface name", "router"],
"additionalProperties": False
},
"service-info": {
"type": "object"
},
"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",
......@@ -272,7 +312,8 @@ def test_peer_info(
"interfaces": {
"type": "array",
"items": {"$ref": "#/definitions/interface-lookup-info"}
}
},
"locations": {"$ref": "#/definitions/locations-list"}
},
"additionalProperties": False
}
......@@ -301,7 +342,7 @@ def test_peer_not_found(client):
headers=DEFAULT_REQUEST_HEADERS)
assert rv.status_code == 200
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', [
......@@ -325,7 +366,27 @@ def test_coriant_info(
'inventory_provider.db.db.connection', mocked_connection)
mocker.patch(
'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(
'/classifier/coriant-info/{equipment}/{entity}'.format(
......@@ -346,8 +407,18 @@ def test_coriant_info(
'C': CONNECTION,
'E': equipment,
'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
......
......@@ -6,74 +6,103 @@ DEFAULT_REQUEST_HEADERS = {
"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 = {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"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_DEFINITIONS, **LOCATIONS_DEFINITIONS
},
"type": "object",
......@@ -89,6 +118,7 @@ INFINERA_LINK_METADATA = {
"geant-lambda": {
"$ref": "#/definitions/geant-lambda"
},
"locations": {"$ref": "#/definitions/locations-list"}
},
"additionalProperties": False
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment