Merge pull request #1 from TimStallard/tds

better bgpmap internal route handling, other minor changes
This commit is contained in:
Simon Marsh 2019-01-30 18:41:38 +00:00 committed by GitHub
commit fca8545fcf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 91 additions and 35 deletions

103
lg.py
View File

@ -123,7 +123,7 @@ def whois_command(query):
def bird_command(host, proto, query):
"""Alias to bird_proxy for bird service"""
if app.config.get("UNIFIED_DAEMON", False):
return bird_proxy(host, "ipv4", "bird", query)
return bird_proxy(host, app.config.get("PROTO_DEFAULT", "ipv4"), "bird", query)
else:
return bird_proxy(host, proto, "bird", query)
@ -145,6 +145,8 @@ def bird_proxy(host, proto, service, query):
path = service
proxyHost = app.config["PROXY"].get(host, "")
if isinstance(proxyHost, int):
proxyHost = "%s:%s" % (host, proxyHost)
if not proxyHost:
return False, 'Host "%s" invalid' % host
@ -185,14 +187,12 @@ def inject_commands():
return dict(commands=commands, commands_dict=commands_dict)
@app.context_processor
def inject_all_host():
return dict(all_hosts="+".join(app.config["PROXY"].keys()))
@app.route("/")
def hello():
return redirect("/summary/%s/ipv4" % "+".join(app.config["PROXY"].keys()))
if app.config.get("UNIFIED_DAEMON", False):
return redirect("/summary/all")
else:
return redirect("/summary/all/%s" % app.config.get("PROTO_DEFAULT", "ipv4"))
def error_page(text):
@ -230,18 +230,20 @@ def whois():
return jsonify(output=output, title=query)
SUMMARY_UNWANTED_PROTOS = ["Kernel", "Static", "Device"]
SUMMARY_UNWANTED_PROTOS = ["Kernel", "Static", "Device", "BFD", "Direct"]
@app.route("/summary/<hosts>")
@app.route("/summary/<hosts>/<proto>")
def summary(hosts, proto="ipv4"):
set_session("summary", hosts, proto, "")
command = "show protocols"
summary = {}
errors = []
for host in hosts.split("+"):
hosts = hosts.split("+")
if hosts == ["all"]:
hosts = app.config["PROXY"].keys()
for host in hosts:
ret, res = bird_command(host, proto, command)
res = res.split("\n")
@ -284,8 +286,9 @@ def summary(hosts, proto="ipv4"):
return render_template('summary.html', summary=summary, command=command, errors=errors)
@app.route("/detail/<hosts>")
@app.route("/detail/<hosts>/<proto>")
def detail(hosts, proto):
def detail(hosts, proto="ipv4"):
name = get_query()
if not name:
@ -296,7 +299,10 @@ def detail(hosts, proto):
detail = {}
errors = []
for host in hosts.split("+"):
hosts = hosts.split("+")
if hosts == ["all"]:
hosts = app.config["PROXY"].keys()
for host in hosts:
ret, res = bird_command(host, proto, command)
res = res.split("\n")
@ -308,13 +314,14 @@ def detail(hosts, proto):
errors.append("%s: bird command failed with error, %s" % (host, "\n".join(res)))
continue
detail[host] = {"status": res[1], "description": add_links(res[2:])}
detail[host] = {"status": res[1], "description": add_links(res[2:]).decode("utf-8")}
return render_template('detail.html', detail=detail, command=command, errors=errors)
@app.route("/traceroute/<hosts>")
@app.route("/traceroute/<hosts>/<proto>")
def traceroute(hosts, proto):
def traceroute(hosts, proto="ipv4"):
q = get_query()
if not q:
@ -325,9 +332,16 @@ def traceroute(hosts, proto):
if app.config.get("UNIFIED_DAEMON", False):
if not ip_is_valid(q):
try:
q = resolve_any(q)
if app.config.get("UNIFIED_TRACEROUTE_IPV6", True):
q = resolve_any(q)
else:
q = resolve(q, "A")
except:
return error_page("%s is unresolvable" % q)
if ipv6_is_valid(q):
proto = "ipv6"
else:
proto = "ipv4"
else:
if proto == "ipv6" and not ipv6_is_valid(q):
try:
@ -342,7 +356,10 @@ def traceroute(hosts, proto):
errors = []
infos = {}
for host in hosts.split("+"):
hosts = hosts.split("+")
if hosts == ["all"]:
hosts = app.config["PROXY"].keys()
for host in hosts:
status, resultat = bird_proxy(host, proto, "traceroute", q)
if status is False:
errors.append("%s" % resultat)
@ -353,43 +370,51 @@ def traceroute(hosts, proto):
return render_template('traceroute.html', infos=infos, errors=errors)
@app.route("/adv/<hosts>")
@app.route("/adv/<hosts>/<proto>")
def show_route_filter(hosts, proto):
def show_route_filter(hosts, proto="ipv4"):
return show_route("adv", hosts, proto)
@app.route("/adv_bgpmap/<hosts>")
@app.route("/adv_bgpmap/<hosts>/<proto>")
def show_route_filter_bgpmap(hosts, proto):
def show_route_filter_bgpmap(hosts, proto="ipv4"):
return show_route("adv_bgpmap", hosts, proto)
@app.route("/where/<hosts>")
@app.route("/where/<hosts>/<proto>")
def show_route_where(hosts, proto):
def show_route_where(hosts, proto="ipv4"):
return show_route("where", hosts, proto)
@app.route("/where_detail/<hosts>")
@app.route("/where_detail/<hosts>/<proto>")
def show_route_where_detail(hosts, proto):
def show_route_where_detail(hosts, proto="ipv4"):
return show_route("where_detail", hosts, proto)
@app.route("/where_bgpmap/<hosts>")
@app.route("/where_bgpmap/<hosts>/<proto>")
def show_route_where_bgpmap(hosts, proto):
def show_route_where_bgpmap(hosts, proto="ipv4"):
return show_route("where_bgpmap", hosts, proto)
@app.route("/prefix/<hosts>")
@app.route("/prefix/<hosts>/<proto>")
def show_route_for(hosts, proto):
def show_route_for(hosts, proto="ipv4"):
return show_route("prefix", hosts, proto)
@app.route("/prefix_detail/<hosts>")
@app.route("/prefix_detail/<hosts>/<proto>")
def show_route_for_detail(hosts, proto):
def show_route_for_detail(hosts, proto="ipv4"):
return show_route("prefix_detail", hosts, proto)
@app.route("/prefix_bgpmap/<hosts>")
@app.route("/prefix_bgpmap/<hosts>/<proto>")
def show_route_for_bgpmap(hosts, proto):
def show_route_for_bgpmap(hosts, proto="ipv4"):
return show_route("prefix_bgpmap", hosts, proto)
@ -519,7 +544,9 @@ def show_bgpmap():
hop_label = ""
add_node(_as, fillcolor=(first and "#F5A9A9" or "white"))
add_node(_as, fillcolor=("white"))
if first:
nodes[_as].set_fillcolor("#F5A9A9")
if hop_label:
edge = add_edge(nodes[previous_as], nodes[_as], label=hop_label, fontsize="7")
else:
@ -587,7 +614,8 @@ def build_as_tree_from_raw_bird_ouput(host, proto, text):
for rt_host, rt_ips in app.config["ROUTER_IP"].iteritems():
# Special case for internal routing
if peer_ip in rt_ips:
path = [rt_host]
paths.append([peer_protocol_name, rt_host])
path = None
break
else:
# ugly hack for good printing
@ -603,8 +631,14 @@ def build_as_tree_from_raw_bird_ouput(host, proto, text):
if expr3.group(1).strip():
net_dest = expr3.group(1).strip()
expr4 = re.search(r'^dev', line)
#handle on-link routes
if expr4:
paths.append([peer_protocol_name, net_dest])
path = None
if line.startswith("BGP.as_path:"):
if line.startswith("BGP.as_path:") and path:
path.extend(line.replace("BGP.as_path:", "").strip().split(" "))
if path:
@ -677,7 +711,11 @@ def show_route(request_type, hosts, proto):
detail = {}
errors = []
for host in hosts.split("+"):
hosts = hosts.split("+")
if hosts == ["all"]:
hosts = app.config["PROXY"].keys()
allhosts = hosts[:]
for host in allhosts:
ret, res = bird_command(host, proto, command)
res = res.split("\n")
@ -691,6 +729,15 @@ def show_route(request_type, hosts, proto):
if bgpmap:
detail[host] = build_as_tree_from_raw_bird_ouput(host, proto, res)
#for internal routes via hosts not selected
#add them to the list, but only show preferred route
if host not in hosts:
detail[host] = detail[host][:1]
for path in detail[host]:
if len(path) == 2:
if (path[1] not in allhosts) and (path[1] in app.config["PROXY"]):
allhosts.append(path[1])
else:
detail[host] = add_links(res)

View File

@ -5,7 +5,10 @@ function change_url(loc){
}
function reload(){
loc = "/" + request_type + "/" + hosts + "/" + proto;
loc = "/" + request_type + "/" + hosts;
if(proto){
loc += "/" + proto;
}
if (request_type != "summary" ){
if( request_args != undefined && request_args != ""){
loc = loc + "?q=" + encodeURIComponent(request_args);
@ -23,7 +26,9 @@ function update_view(){
$(".navbar li").removeClass('active');
$("a#"+proto+".proto").addClass('active');
if(proto){
$("a#"+proto+".proto").addClass('active');
}
$(".hosts a[id='"+hosts+"']").addClass('active');
$(".request_type a#"+request_type).parent().addClass('active');

View File

@ -18,7 +18,7 @@
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<a class="navbar-brand" href="/">{{config.DOMAIN|capitalize}}</a>
<ul class="nav nav-pills">
<li class="nav-item hosts mr-1"><a class="nav-link" id="{{all_hosts}}" href="#">all</a></li>
<li class="nav-item hosts mr-1"><a class="nav-link" id="all" href="#">all</a></li>
{% for host in config.PROXY %}
<li class="nav-item hosts mr-1"><a class="nav-link" id="{{host}}" href="#">{{host}}</a></li>
@ -76,7 +76,7 @@
<div class="list-group history">
{% for hosts, proto, request_type, request_args in session.history %}
<a class="list-group-item list-group-item-action {% if loop.first %}active{% endif %}"
href="/{{ [request_type, hosts, proto]|join("/") }}{% if request_args %}?q={{request_args}}{% endif %}">
href="/{{ [request_type, hosts]|join("/") }}{% if not config.UNIFIED_DAEMON %}/{{proto}}{% endif %}{% if request_args %}?q={{request_args}}{% endif %}">
{{hosts}}{% if not config.UNIFIED_DAEMON %}/{{proto}}{% endif %}: {{ commands_dict[request_type]|replace("...", request_args) }}
</a>
@ -119,7 +119,11 @@
request_type = "{{session.request_type}}";
request_args = "{{session.request_args}}";
hosts = "{{session.hosts}}";
{% if config.UNIFIED_DAEMON %}
proto = ""
{% else %}
proto = "{{session.proto}}";
{% endif %}
history_query = {{session.history|tojson|safe}};
</script>
<script type="text/javascript" src="{{url_for('static', filename='js/lg.js') }}"></script>

View File

@ -3,7 +3,7 @@
{% for host in detail %}
<h3>
{{host}}: {{command}}
<small><a class="pull-right" href="/{{session.request_type|replace("_detail","")}}_bgpmap/{{session.hosts}}/{{session.proto}}?q={{session.request_args}}">View the BGP map</a></small>
<small><a class="pull-right" href="/{{session.request_type|replace("_detail","")}}_bgpmap/{{session.hosts}}{% if not config.UNIFIED_DAEMON %}/{{session.proto}}{% endif %}?q={{session.request_args}}">View the BGP map</a></small>
</h3>
{% if session.request_args != expression|replace("/32","")|replace("/128","") %}
<i>DNS: <a href="/whois/{{session.request_args}}" class="whois">{{session.request_args}}</a> => <a href="/whois/{{ expression|replace("/32","")|replace("/128","") }}" class="whois">{{expression|replace("/32","")|replace("/128","")}}</a></i><br />

View File

@ -9,7 +9,7 @@
<tbody>
{% for row in summary[host] %}
<tr class="{{ loop.cycle('odd', 'even') }}">
<td><a href="/detail/{{host}}/{{session.proto}}?q={{row.name}}">{{row.name}}</a></td>
<td><a href="/detail/{{host}}{% if not config.UNIFIED_DAEMON %}/{{session.proto}}{% endif %}?q={{row.name}}">{{row.name}}</a></td>
<td>{{row.proto}}</td>
<td><span class="badge badge-{% if row.state == "up" %}success{% elif row.state == "down" %}default{% elif row.state == "start" and row.info == "Passive" %}info{% else %}danger{% endif %}">{{row.state}}</span></td>
<td>{{row.since}}</td>

View File

@ -1,7 +1,7 @@
{% extends "layout.html" %}
{% block body %}
{% for host in infos %}
<h3 id="traceroute_cmd_{{host}}">{{host}}/{{session.proto}}: traceroute {{session.request_args}}</h3><br />
<h3 id="traceroute_cmd_{{host}}">{{host}}{% if not config.UNIFIED_DAEMON %}/{{session.proto}}{% endif %}: traceroute {{session.request_args}}</h3><br />
{% if infos[host]|trim %}
<pre>{{infos[host]|trim|safe}}</pre>
{% endif %}