diff --git a/app.py b/app.py new file mode 100644 index 0000000..4cb4587 --- /dev/null +++ b/app.py @@ -0,0 +1,597 @@ +import json +import subprocess +from jinja2 import Template +from flask import Flask, render_template_string, jsonify, url_for + +app = Flask(__name__) + +def run_bgp_curl_command(): + curl_command = [ + "curl", "-k", "--location", "--request", "POST", "https://ip:port/show", + "--form", "data={\"op\": \"show\", \"path\": [\"bgp\", \"summ\"]}", + "--form", "key=key" + ] + response = subprocess.check_output(curl_command, text=True) + return json.loads(response) + +def run_arp_curl_command(): + curl_command = [ + "curl", "-k", "--location", "--request", "POST", "https://ip:port/show", + "--form", "data={\"op\": \"show\", \"path\": [\"arp\"]}", + "--form", "key=key" + ] + response = subprocess.check_output(curl_command, text=True) + return json.loads(response) + +def run_interfaces_curl_command(): + curl_command = [ + "curl", "-k", "--location", "--request", "POST", "https://ip:port/show", + "--form", "data={\"op\": \"show\", \"path\": [\"interfaces\"]}", + "--form", "key=key" + ] + response = subprocess.check_output(curl_command, text=True) + return json.loads(response) + +def parse_bgp_data(data): + ipv4_section = "" + ipv6_section = "" + ipv4_info = {} + ipv6_info = {} + + if "data" in data: + raw_data = data["data"] + + if "IPv4 Unicast Summary" in raw_data: + ipv4_raw = raw_data.split("IPv4 Unicast Summary (VRF default):")[1] + ipv4_section = ipv4_raw.split("IPv6 Unicast Summary (VRF default):")[0].strip() + ipv4_info = extract_bgp_info(ipv4_raw) + + if "IPv6 Unicast Summary" in raw_data: + ipv6_raw = raw_data.split("IPv6 Unicast Summary (VRF default):")[1].strip() + ipv6_section = ipv6_raw + ipv6_info = extract_bgp_info(ipv6_raw) + + def process_peers(peer_data): + peers = [] + for line in peer_data.split("\n"): + if line.strip().startswith("Neighbor"): + continue + if line.strip(): + peer_info = line.split() + if len(peer_info) >= 12: + peers.append({ + "neighbor": peer_info[0], + "version": peer_info[1], + "as_number": peer_info[2], + "msg_received": peer_info[3], + "msg_sent": peer_info[4], + "table_version": peer_info[5], + "in_queue": peer_info[6], + "out_queue": peer_info[7], + "up_down": peer_info[8], + "state_pfx_rcd": peer_info[9], + "prefix_sent": peer_info[10], + "description": " ".join(peer_info[11:]) + }) + return peers + + ipv4_peers = process_peers(ipv4_section) + ipv6_peers = process_peers(ipv6_section) + + return ipv4_info, ipv4_peers, ipv6_info, ipv6_peers + +def extract_bgp_info(raw_data): + lines = raw_data.split("\n") + info = {} + for line in lines: + if "BGP router identifier" in line: + parts = line.split(",") + info["router_id"] = parts[0].split("identifier")[1].strip() + info["local_as"] = parts[1].split("number")[1].strip().split(" ")[0] + if "vrf-id" in parts[-1]: + info["vrf_id"] = parts[-1].split("vrf-id")[1].strip() + if "BGP table version" in line: + info["table_version"] = line.split("version")[1].strip() + if "RIB entries" in line: + parts = line.split(",") + info["rib_entries"] = parts[0].split("entries")[1].strip() + info["rib_memory"] = parts[1].split("using")[1].strip() + if "Peers" in line: + parts = line.split(",") + info["peers"] = parts[0].split("Peers")[1].strip() + info["peers_memory"] = parts[1].split("using")[1].strip() + return info + +def parse_arp_data(data): + arp_table = [] + + if "data" in data: + raw_data = data["data"] + + for line in raw_data.split("\n"): + if line.strip() and not line.startswith("Address") and "---" not in line: + arp_info = line.split() + if len(arp_info) >= 4: + arp_table.append({ + "address": arp_info[0], + "interface": arp_info[1], + "link_layer_address": arp_info[2], + "state": arp_info[3] + }) + + return arp_table + +def parse_interface_data(data): + interface_table = [] + + if "data" in data: + raw_data = data["data"] + + for line in raw_data.split("\n"): + if line.startswith("Interface") and "IP Address" in line: + continue + + if line.startswith("Codes:"): + continue + + if line.strip().startswith('-'): + continue + + if line.strip(): + interface_info = line.split() + if len(interface_info) >= 6: + interface_table.append({ + "interface": interface_info[0], + "ip_address": interface_info[1] if interface_info[1] != '-' else 'N/A', + "mac_address": interface_info[2], + "vrf": interface_info[3], + "mtu": interface_info[4], + "status": interface_info[5], + "description": " ".join(interface_info[6:]) + }) + + return interface_table + +def generate_bgp_html_table(ipv4_info, ipv4_peers, ipv6_info, ipv6_peers): + html_template = """ + + + + + + BGP Table + + + + + + +
+

Core1.Doet.pixelHosting.nl

+

BGP Table

+
+ + + +
+ +
+

IPv4 Unicast Summary

+

BGP Router ID: {{ ipv4_info.router_id }}, Local AS Number: {{ ipv4_info.local_as }} VRF ID: {{ ipv4_info.vrf_id }}

+

BGP Table Version: {{ ipv4_info.table_version }}

+

RIB Entries: {{ ipv4_info.rib_entries }}, using {{ ipv4_info.rib_memory }}

+

Peers: {{ ipv4_info.peers }}, using {{ ipv4_info.peers_memory }}

+ + + + + + + + + + + + + + + + + + + + {% for peer in ipv4_peers %} + + + + + + + + + + + + + + + {% endfor %} + +
NeighborVersion (V)AS NumberMessages ReceivedMessages SentTable VersionInbound Queue (InQ)Outbound Queue (OutQ)Up/DownState/PfxRcdPrefix Sent (PfxSnt)Description
{{ peer.neighbor }}{{ peer.version }}{{ peer.as_number }}{{ peer.msg_received }}{{ peer.msg_sent }}{{ peer.table_version }}{{ peer.in_queue }}{{ peer.out_queue }}{{ peer.up_down }}{{ peer.state_pfx_rcd }}{{ peer.prefix_sent }}{{ peer.description }}
+

JSON version

+
+ +
+

IPv6 Unicast Summary

+

BGP Router ID: {{ ipv6_info.router_id }}, Local AS Number: {{ ipv6_info.local_as }} VRF ID: {{ ipv6_info.vrf_id }}

+

BGP Table Version: {{ ipv6_info.table_version }}

+

RIB Entries: {{ ipv6_info.rib_entries }}, using {{ ipv6_info.rib_memory }}

+

Peers: {{ ipv6_info.peers }}, using {{ ipv6_info.peers_memory }}

+ + + + + + + + + + + + + + + + + + + + {% for peer in ipv6_peers %} + + + + + + + + + + + + + + + {% endfor %} + +
NeighborVersion (V)AS NumberMessages ReceivedMessages SentTable VersionInbound Queue (InQ)Outbound Queue (OutQ)Up/DownState/PfxRcdPrefix Sent (PfxSnt)Description
{{ peer.neighbor }}{{ peer.version }}{{ peer.as_number }}{{ peer.msg_received }}{{ peer.msg_sent }}{{ peer.table_version }}{{ peer.in_queue }}{{ peer.out_queue }}{{ peer.up_down }}{{ peer.state_pfx_rcd }}{{ peer.prefix_sent }}{{ peer.description }}
+

JSON version

+
+ +
+ + + + + + + + """ + + template = Template(html_template) + html_output = template.render(ipv4_info=ipv4_info, ipv4_peers=ipv4_peers, ipv6_info=ipv6_info, ipv6_peers=ipv6_peers) + + return html_output + +def generate_arp_html_table(arp_table): + html_template = """ + + + + + + ARP Table + + + + + + +
+

Core1.Doet.pixelHosting.nl

+

ARP Table

+
+ + + +
+ +
+ + + + + + + + + + + + {% for entry in arp_table %} + + + + + + + {% endfor %} + +
AddressInterfaceLink Layer AddressState
{{ entry.address }}{{ entry.interface }}{{ entry.link_layer_address }}{{ entry.state }}
+

JSON version

+
+ +
+ + + + + + + + """ + template = Template(html_template) + html_output = template.render(arp_table=arp_table) + + return html_output + +def generate_interfaces_html_table(interface_table): + html_template = """ + + + + + + Interface Table + + + + + + +
+

Core1.Doet.pixelHosting.nl

+

Interface Table

+
+ + + +
+ +
+ +

Codes: S - State, L - Link, u - Up, D - Down, A - Admin Down

+ + + + + + + + + + + + + + {% for entry in interface_table %} + + + + + + + + + + {% endfor %} + +
InterfaceIP AddressMAC AddressVRFMTUStatusDescription
{{ entry.interface }}{{ entry.ip_address }}{{ entry.mac_address }}{{ entry.vrf }}{{ entry.mtu }}{{ entry.status }}{{ entry.description }}
+

JSON version

+
+ +
+ + + + + + + + """ + + template = Template(html_template) + html_output = template.render(interface_table=interface_table) + + return html_output + +def generate_bgp_json(ipv4_info, ipv4_peers, ipv6_info, ipv6_peers): + return { + "ipv4_info": ipv4_info, + "ipv4_peers": ipv4_peers, + "ipv6_info": ipv6_info, + "ipv6_peers": ipv6_peers + } + +def generate_arp_json(arp_table): + return {"arp_table": arp_table} + +@app.route("/bgp") +def bgp(): + bgp_data = run_bgp_curl_command() + ipv4_info, ipv4_peers, ipv6_info, ipv6_peers = parse_bgp_data(bgp_data) + bgp_html = generate_bgp_html_table(ipv4_info, ipv4_peers, ipv6_info, ipv6_peers) + return render_template_string(bgp_html) + +@app.route("/bgp/json") +def bgp_json(): + bgp_data = run_bgp_curl_command() + ipv4_info, ipv4_peers, ipv6_info, ipv6_peers = parse_bgp_data(bgp_data) + return jsonify(generate_bgp_json(ipv4_info, ipv4_peers, ipv6_info, ipv6_peers)) + +@app.route("/arp") +def arp(): + arp_data = run_arp_curl_command() + arp_table = parse_arp_data(arp_data) + arp_html = generate_arp_html_table(arp_table) + return render_template_string(arp_html) + +@app.route("/arp/json") +def arp_json(): + arp_data = run_arp_curl_command() + arp_table = parse_arp_data(arp_data) + return jsonify(generate_arp_json(arp_table)) + +@app.route('/interfaces') +def interface_table_page(): + data = run_interfaces_curl_command() + interface_table = parse_interface_data(data) + interfaces_html = generate_interfaces_html_table(interface_table) # Correct variable name + return render_template_string(interfaces_html) # Render the correct variable + +@app.route('/interfaces/json') +def interface_table_summary_json(): + data = run_interfaces_curl_command() + interface_table = parse_interface_data(data) + return jsonify({"interface_table": interface_table}) + +if __name__ == "__main__": + app.run(debug=True, host="0.0.0.0", port=5000) \ No newline at end of file