Developing lightweight computation at the DSG edge

Commit 42c0f84d authored by p4u's avatar p4u
Browse files

New features for bmx6 luci interface

parent 3134c4a4
......@@ -24,10 +24,9 @@ local bmx6json = require("luci.model.bmx6json")
module("luci.controller.bmx6", package.seeall)
function index()
local place = {}
local ucim = require "luci.model.uci"
local uci = ucim.cursor()
local place = {}
-- checking if ignore is on
if uci:get("luci-bmx6","luci","ignore") == "1" then
return nil
......@@ -46,18 +45,22 @@ function index()
---------------------------
-- Starting with the pages
---------------------------
--- neighbours/descriptions (default)
entry(place,call("action_neighbours_j"),place[#place])
table.insert(place,"neighbours_nojs")
entry(place, call("action_neighbours"), nil)
table.remove(place)
--- status (this is default one)
entry(place,call("action_status"),place[#place])
--- neighbours
table.insert(place,"Neighbours")
entry(place,call("action_neighbours"),"Neighbours")
table.insert(place,"Status")
entry(place,call("action_status"),"Status")
table.remove(place)
--- links
table.insert(place,"Links")
entry(place,call("action_links"),"Links")
entry(place,call("action_links"),"Links").leaf = true
table.remove(place)
--- chat
......@@ -65,6 +68,16 @@ function index()
entry(place,call("action_chat"),"Chat")
table.remove(place)
--- Graph
table.insert(place,"Graph")
entry(place, template("bmx6/graph"), "Graph")
table.remove(place)
--- Topology (hidden)
table.insert(place,"topology")
entry(place, call("action_topology"), nil)
table.remove(place)
--- configuration (CBI)
table.insert(place,"Configuration")
entry(place, cbi("bmx6/main"), "Configuration").dependent=false
......@@ -144,17 +157,26 @@ function action_neighbours()
luci.template.render("bmx6/neighbours", {originators=originators})
end
function action_links()
local links = bmx6json.get("links")
function action_neighbours_j()
local http = require "luci.http"
local link_non_js = "/cgi-bin/luci" .. http.getenv("PATH_INFO") .. 'neighbours_nojs'
luci.template.render("bmx6/neighbours_j", {link_non_js=link_non_js})
end
function action_links(host)
local links = bmx6json.get("links", host)
local devlinks = {}
local _,l
if links ~= nil then
links = links.links
for _,l in ipairs(links) do
devlinks[l.viaDev] = {}
end
for _,l in ipairs(links) do
l.globalId = luci.util.split(l.globalId,'.')[1]
table.insert(devlinks[l.viaDev],l)
end
end
......@@ -162,6 +184,46 @@ function action_links()
luci.template.render("bmx6/links", {links=devlinks})
end
function action_topology()
local originators = bmx6json.get("originators/all")
local o,i,l,i2
local first = true
luci.http.prepare_content("application/json")
luci.http.write('[ ')
for i,o in ipairs(originators) do
local links = bmx6json.get("links",o.primaryIp)
if links then
if first then
first = false
else
luci.http.write(', ')
end
luci.http.write('{ "globalId": "%s", "links": [' %o.globalId:match("^[^%.]+"))
local first2 = true
for i2,l in ipairs(links.links) do
if first2 then
first2 = false
else
luci.http.write(', ')
end
luci.http.write('{ "globalId": "%s", "rxRate": %s, "txRate": %s }'
%{ l.globalId:match("^[^%.]+"), l.rxRate, l.txRate })
end
luci.http.write(']}')
end
end
luci.http.write(' ]')
end
function action_chat()
local sms_dir = "/var/run/bmx6/sms"
local rcvd_dir = sms_dir .. "/rcvdSms"
......
<script type="text/javascript">//<![CDATA[
XHR.poll(5, '/cgi-bin/bmx6-info', { '$neighbours': '' },
function(x, st)
{
var originators = st.neighbours[0].originators;
var descriptions = st.neighbours[1].descriptions;
var tb = document.getElementById('descriptions_table');
if ( originators.length != descriptions.length )
{
var tr = tb.insertRow(-1);
tr.className = 'cbi-section-table-row';
var td = tr.insertCell(-1);
td.colSpan = 7;
td.innerHTML = '<em><br /><%:Some problem with JSON: lenght of originators and descriptions different. %></em>';
return 1;
}
if ( originators && descriptions && tb)
{
/* clear all rows */
while( tb.rows.length > 1 )
tb.deleteRow(1);
for( var i = 0; i < descriptions.length; i++ )
{
var tr = tb.insertRow(-1);
tr.className = 'cbi-section-table-row cbi-rowstyle-' + ((i % 2) + 1);
tr.insertCell(-1).innerHTML = descriptions[i].DESC_ADV.globalId.replace(/\.[^\.]+$/,"");
var extensions = descriptions[i].DESC_ADV.extensions;
//Looking for the extensions
var hna6 = [];
for( var e = 0; e < extensions.length; e++)
{
if( extensions[e].HNA6_EXTENSION )
{
hna6 = extensions[e].HNA6_EXTENSION;
break;
}
}
//Adding first HNA with prefix=128 as main address
var ipstxt = '';
var address;
var prefix;
for( var e = 0; e < hna6.length; e++ )
{
address = hna6[e].address;
prefix = hna6[e].prefixlen;
if ( prefix == '128' )
{
ipstxt += address;
break;
}
}
tr.insertCell(-1).innerHTML = ipstxt;
tr.insertCell(-1).innerHTML = originators[i].viaDev;
tr.insertCell(-1).innerHTML = originators[i].metric;
tr.insertCell(-1).innerHTML = originators[i].lastDesc;
tr.insertCell(-1).innerHTML = originators[i].lastRef;
tr.insertCell(-1).innerHTML = originators[i].blocked;
}
if( tb.rows.length == 1 )
{
var tr = tb.insertRow(-1);
tr.className = 'cbi-section-table-row';
var td = tr.insertCell(-1);
td.colSpan = 7;
td.innerHTML = '<em><br /><%:There are no nodes available.%></em>';
}
}
}
);
//]]></script>
<div class="cbi-map">
<fieldset class="cbi-section">
<legend><%:Mesh nodes%></legend>
<table class="cbi-section-table" id="descriptions_table">
<tr class="cbi-section-table-titles">
<th class="cbi-section-table-cell"><%:Hostname%></th>
<th class="cbi-section-table-cell"><%:Primary IP%></th>
<th class="cbi-section-table-cell"><%:Via Device%></th>
<th class="cbi-section-table-cell"><%:Metric%></th>
<th class="cbi-section-table-cell"><%:Last Desc%></th>
<th class="cbi-section-table-cell"><%:Last Ref%></th>
<th class="cbi-section-table-cell"><%:Blocked%></th>
</tr>
<tr class="cbi-section-table-row">
<td colspan="7"><em><br /><%:Collecting data...%></em></td>
</tr>
</table>
</fieldset>
</div>
<%#
LuCI - Lua Configuration Interface
Copyright 2012 Jo-Philipp Wich <xm@subsignal.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
-%>
<%
luci.http.prepare_content("text/html")
local location = { unpack(luci.dispatcher.context.path) }
location[#location] = "topology"
%>
<%+header%>
<script type="text/javascript" src="<%=resource%>/bmx6/js/raphael-min.js"></script>
<script type="text/javascript" src="<%=resource%>/bmx6/js/dracula_graffle.js"></script>
<script type="text/javascript" src="<%=resource%>/bmx6/js/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="<%=resource%>/bmx6/js/dracula_graph.js"></script>
<script type="text/javascript">//<![CDATA[
var redraw;
XHR.get('<%=luci.dispatcher.build_url(unpack(location))%>', null,
function(x, data)
{
var g = new Graph();
var seen = { };
for (var i = 0; i < (data.length); i++)
{
// node->node
if (data[i].globalId)
{
for (var j = 0; j < (data[i].links.length); j++)
{
var key = (data[i].globalId < data[i].links[j].globalId)
? data[i].globalId + '|' + data[i].links[j].globalId
: data[i].links[j].globalId + '|' + data[i].globalId;
if (!seen[key])
{
g.addEdge(data[i].globalId, data[i].links[j].globalId,
{ label: data[i].links[j].rxRate + '/' + data[i].links[j].txRate,
directed: false, stroke: '#aaaaaa', fill: '#ffffff',
'label-style': { 'font-size': 10 }});
seen[key] = true;
}
}
}
//g.addEdge(data[i].router, data[i].neighbor,
// { label: data[i].label, directed: true, stroke: '#aaaaaa' });
// node->leaf
//else if (data[i].router && data[i].gateway)
// g.addEdge(data[i].router, data[i].gateway,
// { label: 'leaf', stroke: '#cccccc' });
}
var canvas = document.getElementById('canvas');
var layouter = new Graph.Layout.Spring(g);
layouter.layout();
var renderer = new Graph.Renderer.Raphael(canvas.id, g, canvas.offsetWidth, canvas.offsetHeight);
renderer.draw();
redraw = function() {
layouter.layout();
renderer.draw();
}
}
);
//]]></script>
<button id="redraw" onclick="redraw();">redraw</button>
<div id="canvas" style="min-width:800px; min-height:800px"></div>
<%+footer%>
......@@ -2,7 +2,7 @@
<meta http-equiv="refresh" content="10" />
<h2><a id="content" name="content"><%:Links%></a></h2>
<br />
<div id="links" style="position:relative;padding-left:3px">
<div id="links" style="position:relative;padding-left:2px">
<% for j,d in pairs(links) do %>
......@@ -16,17 +16,20 @@
<div style="display:table">
<% for i,l in ipairs(d) do %>
<div id="link" style="background-color:#dadbe9;left:50px;width:500px;margin:10px;float:left;position:relative">
<div id="link" style="background-color:#dadbe9;left:50px;width:300px;margin:10px;float:left;position:relative">
<table>
<tr><th colspan="2">
<span style="color:grey;font-weight:700;text-align:left;">
<%=l.globalId%>
<br />
</span>
</th></tr>
<tr>
<td><img src="/luci-static/resources/bmx6/link.png"/></td>
<td>
<div id="gid" style="text-align:center;margin:5px;">
<a href="http://<%=l.llocalIp%>" target="_blank"><%=l.globalId%></a>
</div>
<ul>
<li>IP: <%=l.llocalIp%></li>
<li>Device: <strong><%=l.viaDev%></strong></li>
<li>Local IP: <a href="[<%=l.llocalIp%>]"><%=l.llocalIp%></a></li>
<li>Device: <%=l.viaDev%></li>
<li>Rate (rx/tx):
<% if l.rxRate+l.txRate < 120 then %>
<span style="color:red;">
......
<%+header%>
<script type="text/javascript">//<![CDATA[
var displayExtraInfo = function ( id ) {
document.getElementById('extra-info').innerHTML = document.getElementById(id).innerHTML;
}
XHR.poll(5, '/cgi-bin/bmx6-info', { '$neighbours': '' },
function(x, st)
{
var originators = st.neighbours[0].originators;
var descriptions = st.neighbours[1].descriptions;
var tb = document.getElementById('descriptions_table');
if ( originators.length != descriptions.length )
{
var tr = tb.insertRow(-1);
tr.className = 'cbi-section-table-row';
var td = tr.insertCell(-1);
td.colSpan = 7;
td.innerHTML = '<em><br /><%:Some problem with JSON: lenght of originators and descriptions different. %></em>';
td.innerHTML += '<em><%: Please perform a manually cache flush from a terminal: bmx6 -c --flushAll %></em>'
return 1;
}
if ( originators && descriptions && tb)
{
/* clear all rows */
while( tb.rows.length > 1 )
tb.deleteRow(1);
for( var i = 0; i < descriptions.length; i++ )
{
var tr = tb.insertRow(-1);
var nodename = descriptions[i].DESC_ADV.globalId.replace(/\.[^\.]+$/,"");
tr.className = 'cbi-section-table-row cbi-rowstyle-' + ((i % 2) + 1);
tr.insertCell(-1).innerHTML = '<a onclick="displayExtraInfo(\'ip-'+i+'\')"><img src=\"/luci-static/resources/cbi/help.gif\" /></a>';
tr.insertCell(-1).innerHTML = nodename;
var extensions = descriptions[i].DESC_ADV.extensions;
//Looking for the extensions
var hna6 = [];
var tun4in6 = [];
var tun6 = [];
for( var e = 0; e < extensions.length; e++)
{
if( extensions[e].HNA6_EXTENSION )
{
hna6 = extensions[e].HNA6_EXTENSION;
}
if ( extensions[e].TUN4IN6_NET_EXTENSION )
{
tun4in6 = extensions[e].TUN4IN6_NET_EXTENSION;
}
}
var gateways = '<ul>';
for ( var t = 0; t < tun4in6.length; t++)
{
gateways += "<li>"+tun4in6[t].network+'/'+tun4in6[t].networklen + ' | ';
gateways += tun4in6[t].bandwidth+'</li>';
}
gateways += '</ul>';
//Adding HNAs with prefix=128 as main address
var ipstxt = '';
var address;
var first = 1;
var ipstxt_hidden = '<ul>';
var hna6list = '<ul>';
for( var e = 0; e < hna6.length; e++ )
{
address = hna6[e].address;
prefix = hna6[e].prefixlen;
if ( prefix == '128' )
{
if (first)
{
ipstxt += address;
ipstxt_hidden += '<li><a href="http://['+address+']" >'+address+"</a></li>";
first = 0;
}
else {
ipstxt_hidden += '<li><a href="http://['+address+']" >'+address+"</a></li>";
}
}
else {
hna6list += '<li>'+address+'/'+prefix+'</li>';
}
}
hna6list += '</ul>';
ipstxt_hidden += '</ul>';
tr.insertCell(-1).innerHTML = ipstxt;
tr.insertCell(-1).innerHTML = originators[i].viaDev;
tr.insertCell(-1).innerHTML = originators[i].metric;
tr.insertCell(-1).innerHTML = originators[i].lastDesc;
tr.insertCell(-1).innerHTML = originators[i].lastRef;
tr.insertCell(-1).innerHTML = originators[i].blocked;
//tr.onclick = displayExtraInfo("ip-"+i);
extrainfo = '<div id="ip-'+ i +'" class="hideme">';
extrainfo += "<div class='inforow'><br /><br /><h4>"+nodename+'</h4></div>\n';
extrainfo += "<div class='inforow'><h5>Available IPs</h5>\n<p>" + ipstxt_hidden + "</p></div>\n";
extrainfo += "<div class='inforow'><h5>Gateways announced</h5>\n<p>" + gateways + "</p></div>\n";
extrainfo += "<div class='inforow'><h5>Networks announced</h5>\n<p>" + hna6list + "</p></div>\n";
extrainfo += "\n</div>";
tr.insertCell(-1).innerHTML = extrainfo;
}
if( tb.rows.length == 1 )
{
var tr = tb.insertRow(-1);
tr.className = 'cbi-section-table-row';
var td = tr.insertCell(-1);
td.colSpan = 7;
td.innerHTML = '<em><br /><%:There are no nodes available.%></em>';
}
}
}
);
//]]></script>
<style>
div.hideme{
display: none;
}
div.info{
background: #FFF;
border: solid 1px;
height: 80px;
display: block;
overflow: auto;
}
div.inforow{
text-align:left;
display:inline-block;
width:20%;
margin:5px;
vertical-align:top;
}
#extra-info ul { list-style: none outside none; margin-left: 0em; }
</style>
<div class="cbi-map">
<h2>Originators</h2>
<div class="cbi-map-descr"></div>
<div id="extra-info" class="info">
<br />
Click to the icon <img src="/luci-static/resources/cbi/help.gif" /> to see individual node information
</div>
<fieldset class="cbi-section">
<legend><%:Mesh nodes%></legend>
<table class="cbi-section-table" id="descriptions_table">
<tr class="cbi-section-table-titles">
<th class="cbi-section-table-cell"></th>
<th class="cbi-section-table-cell"><%:Hostname%></th>
<th class="cbi-section-table-cell"><%:Primary IP%></th>
<th class="cbi-section-table-cell"><%:Via Device%></th>
<th class="cbi-section-table-cell"><%:Metric%></th>
<th class="cbi-section-table-cell"><%:Last Desc%></th>
<th class="cbi-section-table-cell"><%:Last Ref%></th>
<th class="cbi-section-table-cell"><%:Blocked%></th>
</tr>
<tr class="cbi-section-table-row">
<td colspan="8"><em><br /><%:Collecting data...%></em></td>
</tr>
</table>
</fieldset>
</div>
<a href="<%=link_non_js%>">Go to non JavaScript view</a>
<%+footer%>
......@@ -29,8 +29,8 @@ BMX6_DIR="$(uci get bmx6.general.runtimeDir 2>/dev/null)" || BMX6_DIR="/var/run/
if [ "$1" == "-s" ]; then
QUERY="$2"
else
QUERY="$QUERY_STRING"
echo "Content-type: text/plain"
QUERY="${QUERY_STRING%%=*}"
echo "Content-type: application/json"
echo ""
fi
......@@ -41,29 +41,66 @@ check_path() {
[ $(echo "$path" | grep -c "^$BMX6_DIR") -ne 1 ] && exit 1
}