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

Finished feature more-ix-peer-info.

parents a567caef 509ce5e7
No related branches found
No related tags found
No related merge requests found
...@@ -379,7 +379,7 @@ Any non-empty responses are JSON formatted messages. ...@@ -379,7 +379,7 @@ Any non-empty responses are JSON formatted messages.
The response will be formatted according to the following syntax: The response will be formatted according to the following syntax:
```json ```json
{ {
"$schema": "http://json-schema.org/draft-07/schema#", "$schema": "http://json-schema.org/draft-07/schema#",
"type": "object", "type": "object",
...@@ -428,10 +428,20 @@ Any non-empty responses are JSON formatted messages. ...@@ -428,10 +428,20 @@ Any non-empty responses are JSON formatted messages.
"required": ["name", "description", "as"], "required": ["name", "description", "as"],
"additionalProperties": False "additionalProperties": False
}, },
"ix-public-peer-group": { "ix-public-peer-list": {
"type": "array", "type": "array",
"items": {"$ref": "#/definitions/ip-address"} "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"}
},
"required": ["peer", "group", "router"],
"additionalProperties": False
},
"interface-info": { "interface-info": {
"type": "object", "type": "object",
"properties": { "properties": {
...@@ -462,9 +472,7 @@ Any non-empty responses are JSON formatted messages. ...@@ -462,9 +472,7 @@ Any non-empty responses are JSON formatted messages.
"type": "object", "type": "object",
"properties": { "properties": {
"ix-public-peer-info": {"$ref": "#/definitions/ix-public-peer"}, "ix-public-peer-info": {"$ref": "#/definitions/ix-public-peer-info"},
"ix-public-peer-group": {
"$ref": "#/definitions/ix-public-peer-group"},
"vpn-rr-peer-info": {"$ref": "#/definitions/vpn-rr-peer"}, "vpn-rr-peer-info": {"$ref": "#/definitions/vpn-rr-peer"},
"interfaces": { "interfaces": {
"type": "array", "type": "array",
......
...@@ -24,6 +24,6 @@ ...@@ -24,6 +24,6 @@
classifier metadata api classifier metadata api
read snmp community string from netconf read snmp community string from netconf
derive active router list from junosspace derive active router list from junosspace
cache ix public & vpn rr peers read most live info from netconf
precompute cached list of ix public & vpn rr peers
use external logging config file use external logging config file
added utilities for the test environment
...@@ -8,6 +8,31 @@ from inventory_provider.routes import common ...@@ -8,6 +8,31 @@ from inventory_provider.routes import common
routes = Blueprint("inventory-data-classifier-support-routes", __name__) routes = Blueprint("inventory-data-classifier-support-routes", __name__)
class ClassifierRequestError(Exception):
status_code = 500
def __init__(self):
super().__init__()
self.message = "Unclassified Internal Error"
class ClassifierProcessingError(ClassifierRequestError):
status_code = 422
def __init__(self, message, status_code=None):
super().__init__()
self.message = str(message)
if status_code is not None:
self.status_code = status_code
@routes.errorhandler(ClassifierRequestError)
def handle_request_error(error):
return Response(
response=error.message,
status=error.status_code)
@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
...@@ -46,29 +71,50 @@ def get_trap_metadata(source_equipment, interface): ...@@ -46,29 +71,50 @@ def get_trap_metadata(source_equipment, interface):
return Response(result, mimetype="application/json") return Response(result, mimetype="application/json")
def ix_peering_group(address, description): def ix_peering_info(peer_info):
""" """
TODO: this is probably the least efficient way of doing this TODO: this is probably the least efficient way of doing this
(if it's a problem, pre-compute these lists) (if it's a problem, pre-compute these lists)
:param ix_public_peer_info: ix public peer info loaded for address :param peer_info: an element from ix_public_peer:address
:return: :return:
""" """
result = {
'peer': peer_info,
'group': [],
'router': []
}
try:
address = ipaddress.ip_address(peer_info['name'])
except ValueError:
raise ClassifierProcessingError(
'unable to parse %r as an ip address' % address)
description = peer_info['description']
assert description is not None # sanity
protocol = type(address).__name__ protocol = type(address).__name__
keyword = description.split(' ')[0] # regex needed??? (e.g. tabs???) keyword = description.split(' ')[0] # regex needed??? (e.g. tabs???)
r = common.get_redis() r = common.get_redis()
for k in r.keys('ix_public_peer:*'): for k in r.keys('ix_public_peer:*'):
peer = r.get(k.decode('utf-8')).decode('utf-8') other = r.get(k.decode('utf-8')).decode('utf-8')
peer = json.loads(peer) other = json.loads(other)
assert peer['description'] is not None # sanity: as above...
if not peer['description'].startswith(keyword): if other['router'] == peer_info['router']:
result['router'].append(other['name'])
assert other['description'] is not None # sanity: as above...
if not other['description'].startswith(keyword):
continue continue
peer_address = ipaddress.ip_address(peer['name']) peer_address = ipaddress.ip_address(other['name'])
if protocol == type(peer_address).__name__: if protocol == type(peer_address).__name__:
yield peer['name'] result['group'].append(other['name'])
return result
def find_interfaces(address): def find_interfaces(address):
...@@ -88,12 +134,19 @@ def find_interfaces(address): ...@@ -88,12 +134,19 @@ def find_interfaces(address):
yield info yield info
def find_interfaces_and_services(address): def find_interfaces_and_services(address_str):
""" """
:param address: an ipaddress object :param address_str: an ipaddress object
:return: :return:
""" """
try:
address = ipaddress.ip_address(address_str)
except ValueError:
raise ClassifierProcessingError(
'unable to parse %r as an ip address' % address_str)
r = common.get_redis() r = common.get_redis()
for interface in find_interfaces(address): for interface in find_interfaces(address):
...@@ -124,31 +177,20 @@ def peer_info(address): ...@@ -124,31 +177,20 @@ def peer_info(address):
if result: if result:
result = result.decode('utf-8') result = result.decode('utf-8')
else: else:
try:
address_obj = ipaddress.ip_address(address)
except ValueError:
return Response(
response='unable to parse %r as an ip address' % address,
status=422,
mimetype="text/html")
result = {} result = {}
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'] = json.loads(info) result['ix-public-peer-info'] = ix_peering_info(json.loads(info))
description = result['ix-public-peer-info']['description']
assert description is not None # sanity
result['ix-public-peer-group'] = list(
ix_peering_group(address_obj, description))
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) result['vpn-rr-peer-info'] = json.loads(info)
interfaces = list(find_interfaces_and_services(address_obj)) interfaces = list(find_interfaces_and_services(address))
if interfaces: if interfaces:
result['interfaces'] = interfaces result['interfaces'] = interfaces
......
...@@ -23,8 +23,7 @@ def test_trap_metadata(client_with_mocked_data): ...@@ -23,8 +23,7 @@ def test_trap_metadata(client_with_mocked_data):
VPN_RR_PEER_INFO_KEYS = {'vpn-rr-peer-info'} VPN_RR_PEER_INFO_KEYS = {'vpn-rr-peer-info'}
IX_PUBLIC_PEER_INFO_KEYS = { IX_PUBLIC_PEER_INFO_KEYS = {'ix-public-peer-info', 'interfaces'}
'ix-public-peer-info', 'ix-public-peer-group', 'interfaces'}
@pytest.mark.parametrize('peer_address,expected_response_keys', [ @pytest.mark.parametrize('peer_address,expected_response_keys', [
...@@ -85,10 +84,20 @@ def test_peer_info( ...@@ -85,10 +84,20 @@ def test_peer_info(
"required": ["name", "description", "as"], "required": ["name", "description", "as"],
"additionalProperties": False "additionalProperties": False
}, },
"ix-public-peer-group": { "ix-public-peer-list": {
"type": "array", "type": "array",
"items": {"$ref": "#/definitions/ip-address"} "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"}
},
"required": ["peer", "group", "router"],
"additionalProperties": False
},
"interface-info": { "interface-info": {
"type": "object", "type": "object",
"properties": { "properties": {
...@@ -119,9 +128,8 @@ def test_peer_info( ...@@ -119,9 +128,8 @@ def test_peer_info(
"type": "object", "type": "object",
"properties": { "properties": {
"ix-public-peer-info": {"$ref": "#/definitions/ix-public-peer"}, "ix-public-peer-info": {
"ix-public-peer-group": { "$ref": "#/definitions/ix-public-peer-info"},
"$ref": "#/definitions/ix-public-peer-group"},
"vpn-rr-peer-info": {"$ref": "#/definitions/vpn-rr-peer"}, "vpn-rr-peer-info": {"$ref": "#/definitions/vpn-rr-peer"},
"interfaces": { "interfaces": {
"type": "array", "type": "array",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment