luci-app-vnstat2: add application 3458/head
authorJan Hoffmann <jan@3e8.eu>
Thu, 2 Jan 2020 22:20:37 +0000 (23:20 +0100)
committerJan Hoffmann <jan@3e8.eu>
Thu, 23 Jan 2020 11:44:22 +0000 (12:44 +0100)
This adds an application for vnStat version 2.

Signed-off-by: Jan Hoffmann <jan@3e8.eu>
applications/luci-app-vnstat2/Makefile [new file with mode: 0644]
applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js [new file with mode: 0644]
applications/luci-app-vnstat2/luasrc/controller/vnstat2.lua [new file with mode: 0644]
applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm [new file with mode: 0644]
applications/luci-app-vnstat2/po/templates/vnstat2.pot [new file with mode: 0644]
applications/luci-app-vnstat2/root/usr/share/rpcd/acl.d/luci-app-vnstat2.json [new file with mode: 0644]

diff --git a/applications/luci-app-vnstat2/Makefile b/applications/luci-app-vnstat2/Makefile
new file mode 100644 (file)
index 0000000..420bf54
--- /dev/null
@@ -0,0 +1,13 @@
+# This is free software, licensed under the Apache License, Version 2.0
+
+include $(TOPDIR)/rules.mk
+
+LUCI_TITLE:=LuCI Support for vnStat 2
+LUCI_DEPENDS:=+luci-lib-jsonc +vnstat2 +vnstati2
+
+PKG_LICENSE:=Apache-2.0
+PKG_MAINTAINER:=Jan Hoffmann <jan@3e8.eu>
+
+include ../../luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
diff --git a/applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js b/applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js
new file mode 100644 (file)
index 0000000..0b01239
--- /dev/null
@@ -0,0 +1,109 @@
+// This is free software, licensed under the Apache License, Version 2.0
+
+'use strict';
+'require fs';
+'require ui';
+'require uci';
+'require form';
+'require tools.widgets as widgets';
+
+return L.view.extend({
+       handleDeleteModal: function(m, iface, ev) {
+               L.showModal(_('Delete interface <em>%h</em>').format(iface), [
+                       E('p', _('The interface will be removed from the database permanently. This cannot be undone.')),
+                       E('div', { 'class': 'right' }, [
+                               E('div', {
+                                       'class': 'btn',
+                                       'click': L.hideModal
+                               }, _('Cancel')),
+                               ' ',
+                               E('div', {
+                                       'class': 'btn cbi-button-negative',
+                                       'click': ui.createHandlerFn(this, 'handleDelete', m, iface)
+                               }, _('Delete'))
+                       ])
+               ]);
+       },
+
+       handleDelete: function(m, iface, ev) {
+               return fs.exec('/usr/bin/vnstat', ['--remove', '-i', iface, '--force'])
+                       .then(L.bind(m.render, m))
+                       .catch(function(e) {
+                               ui.addNotification(null, E('p', e.message));
+                       })
+                       .finally(L.hideModal);
+       },
+
+       render: function() {
+               var m, s, o;
+
+               m = new form.Map('vnstat', _('vnStat'), _('vnStat is a network traffic monitor for Linux that keeps a log of network traffic for the selected interface(s).'));
+
+               s = m.section(form.TypedSection, 'vnstat', _('Interfaces'));
+               s.anonymous = true;
+               s.addremove = false;
+
+               o = s.option(widgets.DeviceSelect, 'interface', _('Monitor interfaces'), _('The selected interfaces are automatically added to the vnStat database upon startup.'));
+               o.rmempty = true;
+               o.multiple = true;
+               o.noaliases = true;
+               o.nobridges = false;
+               o.noinactive = false;
+               o.nocreate = false;
+
+
+               o = s.option(form.DummyValue, '_database');
+
+               o.load = function(section_id) {
+                       return fs.exec('/usr/bin/vnstat', ['--json', 'f', '1']).then(L.bind(function(result) {
+                               var databaseInterfaces = [];
+                               if (result.code == 0) {
+                                       var vnstatData = JSON.parse(result.stdout);
+                                       for (var i = 0; i < vnstatData.interfaces.length; i++) {
+                                               databaseInterfaces.push(vnstatData.interfaces[i].name);
+                                       }
+                               }
+
+                               var configInterfaces = uci.get_first('vnstat', 'vnstat', 'interface') || [];
+
+                               this.interfaces = databaseInterfaces.filter(function(iface) {
+                                       return configInterfaces.indexOf(iface) == -1;
+                               });
+                       }, this));
+               };
+
+               o.render = L.bind(function(view, section_id) {
+                       var table = E('div', { 'class': 'table' }, [
+                               E('div', { 'class': 'tr table-titles' }, [
+                                       E('div', { 'class': 'th' }, _('Interface')),
+                                       E('div', { 'class': 'th right' }, _('Delete'))
+                               ])
+                       ]);
+
+                       var rows = [];
+
+                       for (var i = 0; i < this.interfaces.length; i++) {
+                               rows.push([
+                                       this.interfaces[i],
+                                       E('button', {
+                                               'class': 'btn cbi-button-remove',
+                                               'click': ui.createHandlerFn(view, 'handleDeleteModal', m, this.interfaces[i])
+                                       }, [ _('Delete…') ])
+                               ]);
+                       }
+
+                       cbi_update_table(table, rows, E('em', _('No unconfigured interfaces found in database.')));
+
+                       return E([], [
+                               E('h3', _('Unconfigured interfaces')),
+                               E('div', { 'class': 'cbi-section-descr' },
+                                        _('These interfaces are present in the vnStat database, but are not configured above.')),
+                               table
+                       ]);
+               }, o, this);
+
+
+               return m.render();
+       }
+});
+
diff --git a/applications/luci-app-vnstat2/luasrc/controller/vnstat2.lua b/applications/luci-app-vnstat2/luasrc/controller/vnstat2.lua
new file mode 100644 (file)
index 0000000..139c1f4
--- /dev/null
@@ -0,0 +1,50 @@
+module("luci.controller.vnstat2", package.seeall)
+
+function index()
+       if not nixio.fs.access("/etc/config/vnstat") then
+               return
+       end
+
+       entry({"admin", "status", "vnstat2"}, alias("admin", "status", "vnstat2", "graphs"), _("vnStat Traffic Monitor"), 90)
+       entry({"admin", "status", "vnstat2", "graphs"}, template("vnstat2/graphs"), _("Graphs"), 1)
+       entry({"admin", "status", "vnstat2", "config"}, view("vnstat2/config"), _("Configuration"), 2)
+       entry({"admin", "status", "vnstat2", "graph"}, call("action_graph"), nil, 3)
+end
+
+function action_graph()
+       local util = require "luci.util"
+
+       local param = luci.http.formvalue
+
+       local iface = param("iface")
+       local style = param("style")
+
+       if not iface or not style then
+               luci.http.status(404, "Not Found")
+               return
+       end
+
+       local style_valid = false
+       for _, v in ipairs({"s", "t", "5", "h", "d", "m", "y"}) do
+               if v == style then
+                       style_valid = true
+                       break
+               end
+       end
+
+       if not style_valid then
+               luci.http.status(404, "Not Found")
+               return
+       end
+
+       luci.http.prepare_content("image/png")
+
+       local cmd = "vnstati -i %s -%s -o -" % {
+               util.shellquote(iface),
+               util.shellquote(style)
+       }
+
+       local image = io.popen(cmd)
+       luci.http.write(image:read("*a"))
+       image:close()
+end
diff --git a/applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm b/applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm
new file mode 100644 (file)
index 0000000..318611a
--- /dev/null
@@ -0,0 +1,55 @@
+<%#
+ This is free software, licensed under the Apache License, Version 2.0
+-%>
+
+<%-
+
+local util = require "luci.util"
+local json = require "luci.jsonc"
+
+
+local ifaces = {}
+
+local data = util.exec("vnstat --json f 1 2>/dev/null")
+local content = json.parse(data)
+if type(content) == "table" then
+       for _, iface in pairs(content["interfaces"]) do
+               table.insert(ifaces, iface["name"])
+       end
+end
+
+
+local function render_section(style, title)
+       %><div class="cbi-section" data-tab="<%=style%>" data-tab-title="<%=title%>"><%
+
+       for _, iface in ipairs(ifaces) do
+               %><p><img src="<%=url("admin/status/vnstat2/graph")%>?iface=<%=iface%>&amp;style=<%=style%>" alt="" style="max-width:100%" /></p><%
+       end
+
+       %></div><%
+end
+
+
+-%>
+
+<%+header%>
+
+<h2 name="content"><%:vnStat Graphs%></h2>
+
+<div>
+       <%
+       if #ifaces == 0 then
+               %><p><em><%:No monitored interfaces have been found. Go to the configuration to enable monitoring for one or more interfaces.%></em></p><%
+       else
+               render_section("s", translate("Summary"))
+               render_section("t", translate("Top"))
+               render_section("5", translate("5 Minute"))
+               render_section("h", translate("Hourly"))
+               render_section("d", translate("Daily"))
+               render_section("m", translate("Monthly"))
+               render_section("y", translate("Yearly"))
+       end
+       %>
+</div>
+
+<%+footer%>
diff --git a/applications/luci-app-vnstat2/po/templates/vnstat2.pot b/applications/luci-app-vnstat2/po/templates/vnstat2.pot
new file mode 100644 (file)
index 0000000..f178b9e
--- /dev/null
@@ -0,0 +1,117 @@
+msgid ""
+msgstr "Content-Type: text/plain; charset=UTF-8"
+
+#: applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm:46
+msgid "5 Minute"
+msgstr ""
+
+#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:18
+msgid "Cancel"
+msgstr ""
+
+#: applications/luci-app-vnstat2/luasrc/controller/vnstat2.lua:10
+msgid "Configuration"
+msgstr ""
+
+#: applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm:48
+msgid "Daily"
+msgstr ""
+
+#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:23
+#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:80
+msgid "Delete"
+msgstr ""
+
+#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:12
+msgid "Delete interface <em>%h</em>"
+msgstr ""
+
+#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:92
+msgid "Delete…"
+msgstr ""
+
+#: applications/luci-app-vnstat2/luasrc/controller/vnstat2.lua:9
+msgid "Graphs"
+msgstr ""
+
+#: applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm:47
+msgid "Hourly"
+msgstr ""
+
+#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:79
+msgid "Interface"
+msgstr ""
+
+#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:43
+msgid "Interfaces"
+msgstr ""
+
+#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:47
+msgid "Monitor interfaces"
+msgstr ""
+
+#: applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm:49
+msgid "Monthly"
+msgstr ""
+
+#: applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm:42
+msgid ""
+"No monitored interfaces have been found. Go to the configuration to enable "
+"monitoring for one or more interfaces."
+msgstr ""
+
+#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:96
+msgid "No unconfigured interfaces found in database."
+msgstr ""
+
+#: applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm:44
+msgid "Summary"
+msgstr ""
+
+#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:13
+msgid ""
+"The interface will be removed from the database permanently. This cannot be "
+"undone."
+msgstr ""
+
+#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:47
+msgid ""
+"The selected interfaces are automatically added to the vnStat database upon "
+"startup."
+msgstr ""
+
+#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:101
+msgid ""
+"These interfaces are present in the vnStat database, but are not configured "
+"above."
+msgstr ""
+
+#: applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm:45
+msgid "Top"
+msgstr ""
+
+#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:99
+msgid "Unconfigured interfaces"
+msgstr ""
+
+#: applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm:50
+msgid "Yearly"
+msgstr ""
+
+#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:41
+msgid "vnStat"
+msgstr ""
+
+#: applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm:37
+msgid "vnStat Graphs"
+msgstr ""
+
+#: applications/luci-app-vnstat2/luasrc/controller/vnstat2.lua:8
+msgid "vnStat Traffic Monitor"
+msgstr ""
+
+#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:41
+msgid ""
+"vnStat is a network traffic monitor for Linux that keeps a log of network "
+"traffic for the selected interface(s)."
+msgstr ""
diff --git a/applications/luci-app-vnstat2/root/usr/share/rpcd/acl.d/luci-app-vnstat2.json b/applications/luci-app-vnstat2/root/usr/share/rpcd/acl.d/luci-app-vnstat2.json
new file mode 100644 (file)
index 0000000..58a2aa5
--- /dev/null
@@ -0,0 +1,12 @@
+{
+       "luci-app-vnstat2": {
+               "description": "Grant access to LuCI app vnstat2",
+               "write": {
+                       "file": {
+                               "/usr/bin/vnstat": [ "exec" ]
+                       },
+                       "uci": [ "vnstat" ]
+               }
+       }
+}
+