modules/admin-full: live status, validation for dhcp leases
This commit is contained in:
parent
e910619bbd
commit
cb3caa6e30
3 changed files with 147 additions and 37 deletions
|
@ -87,6 +87,9 @@ function index()
|
||||||
page.target = cbi("admin_network/dhcpleases")
|
page.target = cbi("admin_network/dhcpleases")
|
||||||
page.title = i18n("DHCP Leases")
|
page.title = i18n("DHCP Leases")
|
||||||
page.order = 30
|
page.order = 30
|
||||||
|
|
||||||
|
page = entry({"admin", "network", "dhcplease_status"}, call("lease_status"), nil)
|
||||||
|
page.leaf = true
|
||||||
end
|
end
|
||||||
|
|
||||||
page = node("admin", "network", "hosts")
|
page = node("admin", "network", "hosts")
|
||||||
|
@ -249,3 +252,43 @@ function wifi_status()
|
||||||
|
|
||||||
luci.http.status(404, "No such device")
|
luci.http.status(404, "No such device")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function lease_status()
|
||||||
|
local rv = { }
|
||||||
|
local leasefile = "/var/dhcp.leases"
|
||||||
|
|
||||||
|
local uci = require "luci.model.uci".cursor()
|
||||||
|
local nfs = require "nixio.fs"
|
||||||
|
|
||||||
|
uci:foreach("dhcp", "dnsmasq",
|
||||||
|
function(s)
|
||||||
|
if s.leasefile and nfs.access(s.leasefile) then
|
||||||
|
leasefile = s.leasefile
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local fd = io.open(leasefile, "r")
|
||||||
|
if fd then
|
||||||
|
while true do
|
||||||
|
local ln = fd:read("*l")
|
||||||
|
if not ln then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
local ts, mac, ip, name = ln:match("^(%d+) (%S+) (%S+) (%S+)")
|
||||||
|
if ts and mac and ip and name then
|
||||||
|
rv[#rv+1] = {
|
||||||
|
expires = os.difftime(tonumber(ts) or 0, os.time()),
|
||||||
|
macaddr = mac,
|
||||||
|
ipaddr = ip,
|
||||||
|
hostname = (name ~= "*") and name
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
fd:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
luci.http.prepare_content("application/json")
|
||||||
|
luci.http.write_json(rv)
|
||||||
|
end
|
||||||
|
|
|
@ -12,49 +12,14 @@ You may obtain a copy of the License at
|
||||||
$Id$
|
$Id$
|
||||||
]]--
|
]]--
|
||||||
|
|
||||||
local uci = require "luci.model.uci".cursor()
|
|
||||||
local sys = require "luci.sys"
|
local sys = require "luci.sys"
|
||||||
local wa = require "luci.tools.webadmin"
|
|
||||||
local fs = require "nixio.fs"
|
|
||||||
|
|
||||||
m2 = Map("dhcp", translate("DHCP Leases"),
|
m2 = Map("dhcp", translate("DHCP Leases"),
|
||||||
translate("Static leases are used to assign fixed IP addresses and symbolic hostnames to " ..
|
translate("Static leases are used to assign fixed IP addresses and symbolic hostnames to " ..
|
||||||
"DHCP clients. They are also required for non-dynamic interface configurations where " ..
|
"DHCP clients. They are also required for non-dynamic interface configurations where " ..
|
||||||
"only hosts with a corresponding lease are served."))
|
"only hosts with a corresponding lease are served."))
|
||||||
|
|
||||||
local leasefn, leasefp, leases
|
m2:section(SimpleSection).template = "admin_network/lease_status"
|
||||||
uci:foreach("dhcp", "dnsmasq",
|
|
||||||
function(section)
|
|
||||||
leasefn = section.leasefile
|
|
||||||
end
|
|
||||||
)
|
|
||||||
local leasefp = leasefn and fs.access(leasefn) and io.lines(leasefn)
|
|
||||||
if leasefp then
|
|
||||||
leases = {}
|
|
||||||
for lease in leasefp do
|
|
||||||
table.insert(leases, luci.util.split(lease, " "))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if leases then
|
|
||||||
v = m2:section(Table, leases, translate("Active Leases"))
|
|
||||||
|
|
||||||
name = v:option(DummyValue, 4, translate("Hostname"))
|
|
||||||
function name.cfgvalue(self, ...)
|
|
||||||
local value = DummyValue.cfgvalue(self, ...)
|
|
||||||
return (value == "*") and "?" or value
|
|
||||||
end
|
|
||||||
|
|
||||||
ip = v:option(DummyValue, 3, translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address"))
|
|
||||||
|
|
||||||
mac = v:option(DummyValue, 2, translate("<abbr title=\"Media Access Control\">MAC</abbr>-Address"))
|
|
||||||
|
|
||||||
ltime = v:option(DummyValue, 1, translate("Leasetime remaining"))
|
|
||||||
function ltime.cfgvalue(self, ...)
|
|
||||||
local value = DummyValue.cfgvalue(self, ...)
|
|
||||||
return wa.date_format(os.difftime(tonumber(value), os.time()))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
s = m2:section(TypedSection, "host", translate("Static Leases"),
|
s = m2:section(TypedSection, "host", translate("Static Leases"),
|
||||||
translate("Use the <em>Add</em> Button to add a new lease entry. The <em>MAC-Address</em> " ..
|
translate("Use the <em>Add</em> Button to add a new lease entry. The <em>MAC-Address</em> " ..
|
||||||
|
@ -66,8 +31,13 @@ s.anonymous = true
|
||||||
s.template = "cbi/tblsection"
|
s.template = "cbi/tblsection"
|
||||||
|
|
||||||
name = s:option(Value, "name", translate("Hostname"))
|
name = s:option(Value, "name", translate("Hostname"))
|
||||||
|
|
||||||
mac = s:option(Value, "mac", translate("<abbr title=\"Media Access Control\">MAC</abbr>-Address"))
|
mac = s:option(Value, "mac", translate("<abbr title=\"Media Access Control\">MAC</abbr>-Address"))
|
||||||
|
mac.datatype = "macaddr"
|
||||||
|
|
||||||
ip = s:option(Value, "ip", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address"))
|
ip = s:option(Value, "ip", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address"))
|
||||||
|
ip.datatype = "ip4addr"
|
||||||
|
|
||||||
sys.net.arptable(function(entry)
|
sys.net.arptable(function(entry)
|
||||||
ip:value(entry["IP address"])
|
ip:value(entry["IP address"])
|
||||||
mac:value(
|
mac:value(
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
<script type="text/javascript"><![CDATA[
|
||||||
|
var stxhr = new XHR();
|
||||||
|
(function() {
|
||||||
|
stxhr.get('<%=luci.dispatcher.build_url("admin", "network", "dhcplease_status")%>', null,
|
||||||
|
function(x)
|
||||||
|
{
|
||||||
|
var st = x.responseText ? eval('(' + x.responseText + ')') : null;
|
||||||
|
var tb = document.getElementById('lease_status_table');
|
||||||
|
|
||||||
|
if (st && tb)
|
||||||
|
{
|
||||||
|
/* clear all rows */
|
||||||
|
while( tb.rows.length > 1 )
|
||||||
|
tb.rows[1].parentNode.removeChild(tb.rows[1]);
|
||||||
|
|
||||||
|
for( var i = 0; i < st.length; i++ )
|
||||||
|
{
|
||||||
|
var timestr;
|
||||||
|
|
||||||
|
if (st[i].expires <= 0)
|
||||||
|
{
|
||||||
|
timestr = '<em><%:expired%></em>';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var d = 0;
|
||||||
|
var h = 0;
|
||||||
|
var m = 0;
|
||||||
|
var s = st[i].expires;
|
||||||
|
|
||||||
|
if (s > 60) {
|
||||||
|
m = Math.floor(s / 60);
|
||||||
|
s = (s % 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m > 60) {
|
||||||
|
h = Math.floor(m / 60);
|
||||||
|
m = (m % 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h > 24) {
|
||||||
|
d = Math.floor(h / 24);
|
||||||
|
h = (h % 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
timestr = (d > 0)
|
||||||
|
? String.format('%dd %dh %dm %ds', d, h, m, s)
|
||||||
|
: String.format('%dh %dm %ds', h, m, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
var tr = document.createElement('tr');
|
||||||
|
tr.className = 'cbi-section-table-row cbi-rowstyle-' + ((i % 2) + 1);
|
||||||
|
|
||||||
|
tr.innerHTML = String.format(
|
||||||
|
'<td class="cbi-section-table-cell">%s</td>' +
|
||||||
|
'<td class="cbi-section-table-cell">%s</td>' +
|
||||||
|
'<td class="cbi-section-table-cell">%s</td>' +
|
||||||
|
'<td class="cbi-section-table-cell">%s</td>',
|
||||||
|
st[i].hostname ? st[i].hostname : '?',
|
||||||
|
st[i].ipaddr,
|
||||||
|
st[i].macaddr,
|
||||||
|
timestr
|
||||||
|
);
|
||||||
|
|
||||||
|
tb.rows[0].parentNode.appendChild(tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( tb.rows.length == 1 )
|
||||||
|
{
|
||||||
|
var tr = document.createElement('tr');
|
||||||
|
tr.className = 'cbi-section-table-row';
|
||||||
|
tr.innerHTML = '<td colspan="5"><em><br /><%:There are no active leases.%></em></td>';
|
||||||
|
|
||||||
|
tb.rows[0].parentNode.appendChild(tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
window.setTimeout(arguments.callee, 5000);
|
||||||
|
})();
|
||||||
|
]]></script>
|
||||||
|
|
||||||
|
<fieldset class="cbi-section">
|
||||||
|
<legend><%:Active Leases%></legend>
|
||||||
|
<table class="cbi-section-table" id="lease_status_table">
|
||||||
|
<tr class="cbi-section-table-titles">
|
||||||
|
<th class="cbi-section-table-cell"><%:Hostname%></th>
|
||||||
|
<th class="cbi-section-table-cell"><%:IPv4-Address%></th>
|
||||||
|
<th class="cbi-section-table-cell"><%:MAC-Address%></th>
|
||||||
|
<th class="cbi-section-table-cell"><%:Leasetime remaining%></th>
|
||||||
|
</tr>
|
||||||
|
<tr class="cbi-section-table-row">
|
||||||
|
<td colspan="5"><em><br /><%:Collecting data...%></em></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</fieldset>
|
Loading…
Reference in a new issue