luci/applications/luci-app-nlbwmon/luasrc/controller/nlbw.lua
Jo-Philipp Wich 0fe93fc3a3 luci-app-nlbwmon: new package
This commit introduces luci-app-nlbwmon, a frontend for nlbwmon, the
lightweight NetLink BandWidth Montor.

The nlbwmon daemon gathers per-host traffic statistics by querying netlink
accounting data. Due to this approach, the executable is very small and does
not rely on libpcap and CPU intensive raw sockets to monitor traffic.

Depends on PR https://github.com/openwrt/packages/pull/4646

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2017-07-28 16:26:42 +02:00

216 lines
5 KiB
Lua

-- Copyright 2017 Jo-Philipp Wich <jo@mein.io>
-- Licensed to the public under the Apache License 2.0.
module("luci.controller.nlbw", package.seeall)
function index()
entry({"admin", "nlbw"}, firstchild(), _("Bandwidth Monitor"), 80)
entry({"admin", "nlbw", "display"}, template("nlbw/display"), _("Display"), 1)
entry({"admin", "nlbw", "config"}, cbi("nlbw/config"), _("Configuration"), 2)
entry({"admin", "nlbw", "backup"}, template("nlbw/backup"), _("Backup"), 3)
entry({"admin", "nlbw", "data"}, call("action_data"), nil, 4)
entry({"admin", "nlbw", "list"}, call("action_list"), nil, 5)
entry({"admin", "nlbw", "ptr"}, call("action_ptr"), nil, 6).leaf = true
entry({"admin", "nlbw", "download"}, call("action_download"), nil, 7)
entry({"admin", "nlbw", "restore"}, post("action_restore"), nil, 8)
end
local function exec(cmd, args, writer)
local os = require "os"
local nixio = require "nixio"
local fdi, fdo = nixio.pipe()
local pid = nixio.fork()
if pid > 0 then
fdo:close()
while true do
local buffer = fdi:read(2048)
local wpid, stat, code = nixio.waitpid(pid, "nohang")
if writer and buffer and #buffer > 0 then
writer(buffer)
end
if wpid and stat == "exited" then
break
end
end
elseif pid == 0 then
nixio.dup(fdo, nixio.stdout)
fdi:close()
fdo:close()
nixio.exece(cmd, args, nil)
nixio.stdout:close()
os.exit(1)
end
end
function action_data()
local http = require "luci.http"
local types = {
csv = "text/csv",
json = "application/json"
}
local args = { }
local mtype = http.formvalue("type") or "json"
local delim = http.formvalue("delim") or ";"
local period = http.formvalue("period")
local group_by = http.formvalue("group_by")
local order_by = http.formvalue("order_by")
if types[mtype] then
args[#args+1] = "-c"
args[#args+1] = mtype
else
http.status(400, "Unsupported type")
return
end
if delim and #delim > 0 then
args[#args+1] = "-s%s" % delim
end
if period and #period > 0 then
args[#args+1] = "-t"
args[#args+1] = period
end
if group_by and #group_by > 0 then
args[#args+1] = "-g"
args[#args+1] = group_by
end
if order_by and #order_by > 0 then
args[#args+1] = "-o"
args[#args+1] = order_by
end
http.prepare_content(types[mtype])
exec("/usr/sbin/nlbw", args, http.write)
end
function action_list()
local http = require "luci.http"
local fd = io.popen("/usr/sbin/nlbw -c list")
local periods = { }
if fd then
while true do
local period = fd:read("*l")
if not period then
break
end
periods[#periods+1] = period
end
fd:close()
end
http.prepare_content("application/json")
http.write_json(periods)
end
function action_ptr(...)
local http = require "luci.http"
local util = require "luci.util"
http.prepare_content("application/json")
http.write_json(util.ubus("network.rrdns", "lookup", {
addrs = {...}, timeout = 3000
}))
end
function action_download()
local nixio = require "nixio"
local http = require "luci.http"
local sys = require "luci.sys"
local uci = require "luci.model.uci".cursor()
local dir = uci:get_first("nlbwmon", "nlbwmon", "database_directory")
or "/var/lib/nlbwmon"
if dir and nixio.fs.stat(dir, "type") == "dir" then
local n = "nlbwmon-backup-%s-%s.tar.gz"
%{ sys.hostname(), os.date("%Y-%m-%d") }
http.prepare_content("application/octet-stream")
http.header("Content-Disposition", "attachment; filename=\"%s\"" % n)
exec("/bin/tar", { "-C", dir, "-c", "-z", ".", "-f", "-" }, http.write)
else
http.status(500, "Unable to find database directory")
end
end
function action_restore()
local nixio = require "nixio"
local http = require "luci.http"
local i18n = require "luci.i18n"
local tpl = require "luci.template"
local uci = require "luci.model.uci".cursor()
local tmp = "/tmp/nlbw-restore.tar.gz"
local dir = uci:get_first("nlbwmon", "nlbwmon", "database_directory")
or "/var/lib/nlbwmon"
local fp
http.setfilehandler(
function(meta, chunk, eof)
if not fp and meta and meta.name == "archive" then
fp = io.open(tmp, "w")
end
if fp and chunk then
fp:write(chunk)
end
if fp and eof then
fp:close()
end
end)
local files = { }
local tar = io.popen("/bin/tar -tzf %s" % tmp, "r")
if tar then
while true do
local file = tar:read("*l")
if not file then
break
elseif file:match("^%d%d%d%d%d%d%d%d%.db%.gz$") or
file:match("^%./%d%d%d%d%d%d%d%d%.db%.gz$") then
files[#files+1] = file
end
end
tar:close()
end
if #files == 0 then
http.status(500, "Internal Server Error")
tpl.render("nlbw/backup", {
message = i18n.translate("Invalid or empty backup archive")
})
return
end
local output = { }
exec("/etc/init.d/nlbwmon", { "stop" })
exec("/bin/mkdir", { "-p", dir })
exec("/bin/tar", { "-C", dir, "-vxzf", tmp, unpack(files) },
function(chunk) output[#output+1] = chunk:match("%S+") end)
exec("/bin/rm", { "-f", tmp })
exec("/etc/init.d/nlbwmon", { "start" })
tpl.render("nlbw/backup", {
message = i18n.translatef(
"The following database files have been restored: %s",
table.concat(output, ", "))
})
end