diff --git a/inventory_provider/routes/classifier.py b/inventory_provider/routes/classifier.py index 5a0cf4d53c5063504966df0b799c6eb7430042fc..8f88fcf5ae7a47882124379dbf38b6b8ddd96d5b 100644 --- a/inventory_provider/routes/classifier.py +++ b/inventory_provider/routes/classifier.py @@ -1,13 +1,38 @@ import ipaddress import json -from flask import Blueprint, Response +from flask import Blueprint, Response, jsonify from inventory_provider.routes import common 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>", methods=['GET', 'POST']) @common.require_accepts_json @@ -46,30 +71,50 @@ def get_trap_metadata(source_equipment, interface): 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 (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: """ + 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__ keyword = description.split(' ')[0] # regex needed??? (e.g. tabs???) r = common.get_redis() for k in r.keys('ix_public_peer:*'): - peer = r.get(k.decode('utf-8')).decode('utf-8') - peer = json.loads(peer) - assert peer['description'] is not None # sanity: as above... - if not peer['description'].startswith(keyword): + other = r.get(k.decode('utf-8')).decode('utf-8') + other = json.loads(other) + + 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 - peer_address = ipaddress.ip_address(peer['name']) + peer_address = ipaddress.ip_address(other['name']) if protocol == type(peer_address).__name__: - yield peer['name'] + result['group'].append(other['name']) + return result def find_interfaces(address): """ @@ -88,12 +133,19 @@ def find_interfaces(address): 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: """ + + 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() for interface in find_interfaces(address): @@ -124,31 +176,20 @@ def peer_info(address): if result: result = result.decode('utf-8') 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 = {} info = r.get('ix_public_peer:%s' % address) if info: info = info.decode('utf-8') - result['ix-public-peer-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)) + result['ix-public-peer-info'] = ix_peering_info(json.loads(info)) info = r.get('vpn_rr_peer:%s' % address) if info: info = info.decode('utf-8') 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: result['interfaces'] = interfaces diff --git a/test/test_classifier_routes.py b/test/test_classifier_routes.py index 2382d76fc01e3c9f95ccbe9fad460a4665dbe1a4..89e85cd4c4be9f3a3cd3c3d2734301b5a8d419eb 100644 --- a/test/test_classifier_routes.py +++ b/test/test_classifier_routes.py @@ -85,10 +85,20 @@ def test_peer_info( "required": ["name", "description", "as"], "additionalProperties": False }, - "ix-public-peer-group": { + "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"} + }, + "required": ["peer", "group", "router"], + "additionalProperties": False + }, "interface-info": { "type": "object", "properties": { @@ -119,9 +129,7 @@ def test_peer_info( "type": "object", "properties": { - "ix-public-peer-info": {"$ref": "#/definitions/ix-public-peer"}, - "ix-public-peer-group": { - "$ref": "#/definitions/ix-public-peer-group"}, + "ix-public-peer-info": {"$ref": "#/definitions/ix-public-peer-info"}, "vpn-rr-peer-info": {"$ref": "#/definitions/vpn-rr-peer"}, "interfaces": { "type": "array",