Skip to content
Snippets Groups Projects
Commit 2f3bc862 authored by Robert Latta's avatar Robert Latta
Browse files

added all juniper related classifications

parent 711cd409
No related branches found
No related tags found
No related merge requests found
import ipaddress import ipaddress
import json import json
import logging import logging
import re
from flask import Blueprint, Response, current_app from flask import Blueprint, Response, current_app
...@@ -11,34 +12,7 @@ routes = Blueprint("ims-inventory-data-classifier-support-routes", __name__) ...@@ -11,34 +12,7 @@ routes = Blueprint("ims-inventory-data-classifier-support-routes", __name__)
logger = logging.getLogger(__name__) logger = logging.getLogger(__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.after_request
def after_request(resp):
return common.after_request(resp)
def _LOCATION(equipment, name, abbreviation): def _LOCATION(equipment, name, abbreviation):
...@@ -100,6 +74,36 @@ def _location_from_service_dict(s): ...@@ -100,6 +74,36 @@ def _location_from_service_dict(s):
return location return location
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.after_request
def after_request(resp):
return common.after_request(resp)
def related_interfaces(hostname, interface): def related_interfaces(hostname, interface):
r = common.get_current_redis() r = common.get_current_redis()
prefix = 'netconf-interfaces:%s:' % hostname prefix = 'netconf-interfaces:%s:' % hostname
...@@ -130,18 +134,28 @@ def get_top_level_services(circuit_id, r): ...@@ -130,18 +134,28 @@ def get_top_level_services(circuit_id, r):
return tls return tls
def get_ims_equipment_name(equipment_name: str) -> str:
ims_equipment_name = equipment_name.upper()
if ims_equipment_name.startswith('MX'):
ims_equipment_name = ims_equipment_name.split('.GEANT.NET')[0]
return ims_equipment_name
def get_ims_interface(interface: str) -> str:
return interface.upper()
@routes.route("/juniper-link-info/<source_equipment>/<path:interface>", @routes.route("/juniper-link-info/<source_equipment>/<path:interface>",
methods=['GET', 'POST']) methods=['GET', 'POST'])
@common.require_accepts_json @common.require_accepts_json
def get_juniper_link_info(source_equipment: str, interface: str): def get_juniper_link_info(source_equipment: str, interface: str):
ims_source_equipment = source_equipment.upper() ims_source_equipment = get_ims_equipment_name(source_equipment)
ims_interface = interface.upper() ims_interface = get_ims_interface(interface)
if ims_source_equipment.startswith('MX'):
ims_source_equipment = ims_source_equipment.split('.GEANT.NET')[0]
r = common.get_current_redis() r = common.get_current_redis()
cache_key = f'ims-classifier-cache:juniper:{ims_source_equipment}:{ims_interface}' cache_key = \
f'ims-classifier-cache:juniper:{ims_source_equipment}:{ims_interface}'
# result = r.get(cache_key) # result = r.get(cache_key)
result = False result = False
...@@ -217,3 +231,154 @@ def get_juniper_link_info(source_equipment: str, interface: str): ...@@ -217,3 +231,154 @@ def get_juniper_link_info(source_equipment: str, interface: str):
r.set(cache_key, result.encode('utf-8')) r.set(cache_key, result.encode('utf-8'))
return Response(result, mimetype="application/json") return Response(result, mimetype="application/json")
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 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
keyword = description.split(' ')[0] # regex needed??? (e.g. tabs???)
for doc in common.load_json_docs(
config_params=current_app.config['INVENTORY_PROVIDER_CONFIG'],
key_pattern='ix_public_peer:*',
num_threads=10):
other = doc['value']
if other['router'] == peer_info['router']:
result['router'].append(other['name'])
assert other['description'] is not None # sanity: as above...
if other['description'].startswith(keyword):
result['group'].append(other['name'])
return result
def find_interfaces(address):
"""
TODO: this is probably the least efficient way of doing this
(if it's a problem, pre-compute these lists)
:param address: an ipaddress object
:return:
"""
r = common.get_current_redis()
for k in r.keys('subnets:*'):
k = k.decode('utf-8')
m = re.match(r'^subnets:(.*)$', k)
assert m, 'sanity failure: redis returned an invalid key name'
interface = ipaddress.ip_interface(m.group(1))
if address in interface.network:
info = r.get(k).decode('utf-8')
info = json.loads(info)
for ifc in info:
yield ifc
def find_interfaces_and_services(address_str):
"""
:param address_str: an ipaddress object
:return:
"""
try:
address = ipaddress.ip_address(address_str)
except ValueError:
raise ClassifierProcessingError(
f'unable to parse {address_str} as an ip address')
r = common.get_current_redis()
for interface in find_interfaces(address):
ims_equipment = get_ims_equipment_name(interface["router"])
ims_interface = get_ims_interface(interface["interface name"])
services = r.get(
f'ims:interface_services:{ims_equipment}:{ims_interface}')
if not services:
services = []
else:
services = json.loads(services.decode('utf=8'))
yield {
'interface': interface,
'services': services
}
@routes.route("/peer-info/<address>", methods=['GET', 'POST'])
@common.require_accepts_json
def peer_info(address):
# canonicalize the input address first ...
try:
obj = ipaddress.ip_address(address)
address = obj.exploded
except ValueError:
raise ClassifierProcessingError(
f'unable to parse {address} as an ip address')
r = common.get_current_redis()
cache_key = f'classifier-cache:peer:{address}'
# result = r.get(cache_key)
result = False
if result:
result = result.decode('utf-8')
else:
result = {
'locations': []
}
info = r.get(f'ix_public_peer:{address}')
if info:
info = info.decode('utf-8')
info = json.loads(info)
result['ix-public-peer-info'] = ix_peering_info(info)
result['locations'] += _locations_from_router(info['router'])
info = r.get('vpn_rr_peer:%s' % address)
if info:
info = info.decode('utf-8')
info = json.loads(info)
result['vpn-rr-peer-info'] = info
result['locations'] += _locations_from_router(info['router'])
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'))
return Response(result, mimetype="application/json")
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment