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

Finished feature add-related-interface-services-to-metadata.

parents 82aaa8c2 04211843
No related branches found
No related tags found
No related merge requests found
import ipaddress import ipaddress
import json import json
import re
from flask import Blueprint, Response from flask import Blueprint, Response
...@@ -33,6 +34,22 @@ def handle_request_error(error): ...@@ -33,6 +34,22 @@ def handle_request_error(error):
status=error.status_code) status=error.status_code)
def base_interface_name(interface):
m = re.match(r'(.*?)(\.\d+)?$', interface)
assert m # sanity: anything should match
return m.group(1)
def related_interfaces(hostname, interface):
r = common.get_redis()
prefix = 'netconf-interfaces:%s:' % hostname
for k in r.keys(prefix + base_interface_name(interface) + '*'):
k = k.decode('utf-8')
assert k.startswith(prefix) # sanity
assert len(k) > len(prefix) # sanity (contains at least an interface)
yield k[len(prefix):]
@routes.route("/trap-metadata/<source_equipment>/<path:interface>", @routes.route("/trap-metadata/<source_equipment>/<path:interface>",
methods=['GET', 'POST']) methods=['GET', 'POST'])
@common.require_accepts_json @common.require_accepts_json
...@@ -57,6 +74,18 @@ def get_trap_metadata(source_equipment, interface): ...@@ -57,6 +74,18 @@ def get_trap_metadata(source_equipment, interface):
if ifc_info: if ifc_info:
result['interface'] = json.loads(ifc_info.decode('utf-8')) result['interface'] = json.loads(ifc_info.decode('utf-8'))
def _related_services():
for related in related_interfaces(source_equipment, interface):
rs = r.get('opsdb:interface_services:%s:%s'
% (source_equipment, related))
if rs:
for s in json.loads(rs.decode('utf-8')):
yield s
related_services = list(_related_services())
if related_services:
result['related-services'] = related_services
if not result: if not result:
return Response( return Response(
response="no available info for {} {}".format( response="no available info for {} {}".format(
......
...@@ -7,19 +7,123 @@ DEFAULT_REQUEST_HEADERS = { ...@@ -7,19 +7,123 @@ DEFAULT_REQUEST_HEADERS = {
"Accept": ["application/json"] "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+$'
},
"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"}
},
"ipv6": {
"type": "array",
"items": {"$ref": "#/definitions/ipv6-interface-address"}
}
},
"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"]
},
"circuit_type": {
"type": "string",
"enum": ["path", "service", "l2circuit"]
},
"service_type": {"type": "string"},
"project": {"type": "string"},
"equipment": {"type": "string"},
"other_end_equipment": {"type": "string"},
"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: 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
}
},
"type": "object",
"properties": {
"services": {
"type": "array",
"items": {"$ref": "#/definitions/service-info"}
},
"interface": {"$ref": "#/definitions/interface-info"},
"related-services": {
"type": "array",
"items": {"$ref": "#/definitions/service-info"}
}
},
"required": ["interface"],
"additionalProperties": False
}
def test_trap_metadata(client_with_mocked_data): def test_trap_metadata(client_with_mocked_data):
response_schema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object"
}
rv = client_with_mocked_data.get( rv = client_with_mocked_data.get(
'/classifier/trap-metadata/mx1.ams.nl.geant.net/ae15.1500', '/classifier/trap-metadata/mx1.ams.nl.geant.net/ae15.1500',
headers=DEFAULT_REQUEST_HEADERS) headers=DEFAULT_REQUEST_HEADERS)
assert rv.status_code == 200 assert rv.status_code == 200
assert rv.is_json assert rv.is_json
response_data = json.loads(rv.data.decode('utf-8')) response_data = json.loads(rv.data.decode('utf-8'))
jsonschema.validate(response_data, response_schema) jsonschema.validate(response_data, JUNIPER_LINK_METADATA)
VPN_RR_PEER_INFO_KEYS = {'vpn-rr-peer-info'} VPN_RR_PEER_INFO_KEYS = {'vpn-rr-peer-info'}
......
import pytest
from inventory_provider.routes import classifier
@pytest.mark.parametrize('interface_name,base_name', [
('ae0', 'ae0'),
('ae0.0', 'ae0'),
('ae1.0', 'ae1'),
('ae10.2603', 'ae10'),
('et-3/1/2', 'et-3/1/2'),
('et-3/1/2.100', 'et-3/1/2'),
('xe-2/1/0', 'xe-2/1/0'),
('xe-2/1/0.933', 'xe-2/1/0'),
# degenerate cases ... check expected regex behavior
('xe-2/1/0.933.933', 'xe-2/1/0.933'),
(' sss.333.aaa ', ' sss.333.aaa '),
(' sss.333.aaa .999', ' sss.333.aaa ')
]
)
def test_base_interface_name(interface_name, base_name):
assert classifier.base_interface_name(interface_name) == base_name
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment