Update modules/visual_route.py
This commit is contained in:
parent
28c196d431
commit
9dd1d08393
1 changed files with 26 additions and 20 deletions
|
|
@ -1,4 +1,3 @@
|
||||||
import requests
|
|
||||||
import re
|
import re
|
||||||
import json
|
import json
|
||||||
import socket
|
import socket
|
||||||
|
|
@ -13,10 +12,9 @@ TRANSIT_COMMUNITIES = set(filter(None, os.getenv('BGP_COMMUNITIES_TRANSIT', '').
|
||||||
IX_COMMUNITIES = set(filter(None, os.getenv('BGP_COMMUNITIES_IX', '').split(',')))
|
IX_COMMUNITIES = set(filter(None, os.getenv('BGP_COMMUNITIES_IX', '').split(',')))
|
||||||
CUSTOMER_COMMUNITIES = set(filter(None, os.getenv('BGP_COMMUNITIES_CUSTOMER', '').split(',')))
|
CUSTOMER_COMMUNITIES = set(filter(None, os.getenv('BGP_COMMUNITIES_CUSTOMER', '').split(',')))
|
||||||
|
|
||||||
API_URL = os.getenv('BGP_API_URL', 'http://127.0.0.1:5000/bgp-route/lookup')
|
|
||||||
AS_NAME_CACHE = {}
|
AS_NAME_CACHE = {}
|
||||||
AS_NAME_WRAP_WIDTH = 25
|
AS_NAME_WRAP_WIDTH = 25
|
||||||
ROUTER_NAME = os.getenv('BGP_VIS_ROUTER_NAME', 'My Router')
|
ROUTER_NAME_FALLBACK = os.getenv('BGP_VIS_ROUTER_NAME', 'My Router')
|
||||||
MAX_IP_CIDR_LENGTH = 45
|
MAX_IP_CIDR_LENGTH = 45
|
||||||
|
|
||||||
def _is_valid_ip_or_prefix(target: str) -> bool:
|
def _is_valid_ip_or_prefix(target: str) -> bool:
|
||||||
|
|
@ -73,18 +71,25 @@ def _bulk_get_as_names(asn_numbers: list[str]):
|
||||||
for asn in lookup_list:
|
for asn in lookup_list:
|
||||||
if asn not in AS_NAME_CACHE: AS_NAME_CACHE[asn] = ""
|
if asn not in AS_NAME_CACHE: AS_NAME_CACHE[asn] = ""
|
||||||
|
|
||||||
def _get_bgp_data(ip_address: str, ip_version: str) -> str | None:
|
def _get_bgp_data(ip_address: str, ip_version: str, location_config: dict, bgp_lookup_func) -> str | None:
|
||||||
payload = {"ip_version": ip_version, "bgprouteprefix": ip_address}
|
|
||||||
headers = {"Content-Type": "application/json"}
|
|
||||||
try:
|
try:
|
||||||
response = requests.post(API_URL, json=payload, headers=headers, timeout=10)
|
api_url = location_config.get("vyos_api_url")
|
||||||
response.raise_for_status()
|
api_key = location_config.get("vyos_api_key")
|
||||||
data = response.json()
|
vrf_name = location_config.get("bgp_vrf_name")
|
||||||
if data.get("success") and data.get("data"): return data["data"]
|
|
||||||
else: return None
|
response_data = bgp_lookup_func(api_url, api_key, vrf_name, ip_version, ip_address)
|
||||||
except requests.exceptions.RequestException: return None
|
|
||||||
|
if response_data.get("success") and "data" in response_data:
|
||||||
|
return response_data["data"]
|
||||||
|
else:
|
||||||
|
error_message = response_data.get('error', 'Unknown error')
|
||||||
|
print(f"BGP lookup via VyOS API failed for {ip_address}. Error: {error_message}")
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
print(f"An exception occurred during internal BGP lookup: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
def _parse_bgp_paths_to_graph(bgp_data: str) -> dict:
|
def _parse_bgp_paths_to_graph(bgp_data: str, router_name: str) -> dict:
|
||||||
prefix_match = re.search(r"BGP routing table entry for ([\w:./-]+)", bgp_data)
|
prefix_match = re.search(r"BGP routing table entry for ([\w:./-]+)", bgp_data)
|
||||||
prefix = prefix_match.group(1) if prefix_match else "Unknown Prefix"
|
prefix = prefix_match.group(1) if prefix_match else "Unknown Prefix"
|
||||||
lines = bgp_data.split('\n')
|
lines = bgp_data.split('\n')
|
||||||
|
|
@ -164,7 +169,7 @@ def _parse_bgp_paths_to_graph(bgp_data: str) -> dict:
|
||||||
if not ordered_paths:
|
if not ordered_paths:
|
||||||
return {"nodes": [], "edges": []}
|
return {"nodes": [], "edges": []}
|
||||||
|
|
||||||
nodes.append({"id": ROUTER_NAME, "label": f"<b>{ROUTER_NAME}</b>", "color": '#FADBD8', "x": 0, "y": 0, "fixed": True, "path_category": "global", "is_active": True})
|
nodes.append({"id": router_name, "label": f"<b>{router_name}</b>", "color": '#FADBD8', "x": 0, "y": 0, "fixed": True, "path_category": "global", "is_active": True})
|
||||||
nodes.append({"id": prefix, "label": f"<b>{prefix}</b>", "color": '#FADBD8', "x": (max_path_len + 1) * X_SEPARATION, "y": 0, "fixed": True, "path_category": "global", "is_active": True})
|
nodes.append({"id": prefix, "label": f"<b>{prefix}</b>", "color": '#FADBD8', "x": (max_path_len + 1) * X_SEPARATION, "y": 0, "fixed": True, "path_category": "global", "is_active": True})
|
||||||
|
|
||||||
y_pos_counter_up, y_pos_counter_down = 1, 1
|
y_pos_counter_up, y_pos_counter_down = 1, 1
|
||||||
|
|
@ -193,7 +198,7 @@ def _parse_bgp_paths_to_graph(bgp_data: str) -> dict:
|
||||||
if j == 0 and path_info['next_hop']: label += f"\n<i>Next Hop: {path_info['next_hop']}{style['path_type']}</i>"
|
if j == 0 and path_info['next_hop']: label += f"\n<i>Next Hop: {path_info['next_hop']}{style['path_type']}</i>"
|
||||||
nodes.append({"id": unique_node_id, "label": label, "color": style['node_color'], "x": (j + 1) * X_SEPARATION, "y": lane_y, "fixed": True, "path_category": path_info['category'], "is_active": is_active_path})
|
nodes.append({"id": unique_node_id, "label": label, "color": style['node_color'], "x": (j + 1) * X_SEPARATION, "y": lane_y, "fixed": True, "path_category": path_info['category'], "is_active": is_active_path})
|
||||||
|
|
||||||
full_chain = [ROUTER_NAME] + path_node_ids + [prefix]
|
full_chain = [router_name] + path_node_ids + [prefix]
|
||||||
smooth_config = {"enabled": True, "type": "cubicBezier", "forceDirection": "horizontal", "roundness": 0.85}
|
smooth_config = {"enabled": True, "type": "cubicBezier", "forceDirection": "horizontal", "roundness": 0.85}
|
||||||
for j in range(len(full_chain) - 1):
|
for j in range(len(full_chain) - 1):
|
||||||
edges.append({"from": full_chain[j], "to": full_chain[j+1], "color": style['edge_color'], "width": style['width'], "dashes": style['dashes'], "path_category": path_info['category'], "is_active": is_active_path, "smooth": smooth_config})
|
edges.append({"from": full_chain[j], "to": full_chain[j+1], "color": style['edge_color'], "width": style['width'], "dashes": style['dashes'], "path_category": path_info['category'], "is_active": is_active_path, "smooth": smooth_config})
|
||||||
|
|
@ -201,7 +206,7 @@ def _parse_bgp_paths_to_graph(bgp_data: str) -> dict:
|
||||||
return {"nodes": nodes, "edges": edges, "path_count": len(ordered_paths)}
|
return {"nodes": nodes, "edges": edges, "path_count": len(ordered_paths)}
|
||||||
|
|
||||||
|
|
||||||
def get_raw_bgp_route(ip_address_str: str) -> tuple[str | None, str | None]:
|
def get_raw_bgp_route(ip_address_str: str, location_config: dict, bgp_lookup_func) -> tuple[str | None, str | None]:
|
||||||
ip_address_str, error = _validate_ip_prefix_input(ip_address_str)
|
ip_address_str, error = _validate_ip_prefix_input(ip_address_str)
|
||||||
if error:
|
if error:
|
||||||
return None, error
|
return None, error
|
||||||
|
|
@ -210,14 +215,15 @@ def get_raw_bgp_route(ip_address_str: str) -> tuple[str | None, str | None]:
|
||||||
if not address_to_lookup:
|
if not address_to_lookup:
|
||||||
return None, f"Invalid input '{ip_address_str}'."
|
return None, f"Invalid input '{ip_address_str}'."
|
||||||
|
|
||||||
bgp_data = _get_bgp_data(address_to_lookup, ip_version)
|
bgp_data = _get_bgp_data(address_to_lookup, ip_version, location_config, bgp_lookup_func)
|
||||||
if not bgp_data:
|
if not bgp_data:
|
||||||
return None, f"Route information not found for: {address_to_lookup}"
|
return None, f"Route information not found for: {address_to_lookup}"
|
||||||
|
|
||||||
return bgp_data, None
|
return bgp_data, None
|
||||||
|
|
||||||
|
def generate_visual_route_graph(ip_address_str: str, location_config: dict, bgp_lookup_func) -> dict:
|
||||||
|
router_name = location_config.get('router_name', ROUTER_NAME_FALLBACK)
|
||||||
|
|
||||||
def generate_visual_route_graph(ip_address_str: str) -> dict:
|
|
||||||
ip_address_str, error = _validate_ip_prefix_input(ip_address_str)
|
ip_address_str, error = _validate_ip_prefix_input(ip_address_str)
|
||||||
if error:
|
if error:
|
||||||
return {"error": error}
|
return {"error": error}
|
||||||
|
|
@ -226,11 +232,11 @@ def generate_visual_route_graph(ip_address_str: str) -> dict:
|
||||||
if not address_to_lookup:
|
if not address_to_lookup:
|
||||||
return {"error": f"Invalid input '{ip_address_str}'."}
|
return {"error": f"Invalid input '{ip_address_str}'."}
|
||||||
|
|
||||||
bgp_data = _get_bgp_data(address_to_lookup, ip_version)
|
bgp_data = _get_bgp_data(address_to_lookup, ip_version, location_config, bgp_lookup_func)
|
||||||
if not bgp_data:
|
if not bgp_data:
|
||||||
return {"not_found": True, "target": address_to_lookup}
|
return {"not_found": True, "target": address_to_lookup}
|
||||||
|
|
||||||
graph_data = _parse_bgp_paths_to_graph(bgp_data)
|
graph_data = _parse_bgp_paths_to_graph(bgp_data, router_name)
|
||||||
|
|
||||||
if not graph_data.get("nodes"):
|
if not graph_data.get("nodes"):
|
||||||
return {"not_found": True, "target": address_to_lookup}
|
return {"not_found": True, "target": address_to_lookup}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue