bb56bc6e6eb7bc297d6c7b96203ee3e4397a21bb
[project/luci.git] / applications / luci-app-nlbwmon / luasrc / controller / nlbw.lua
1 -- Copyright 2017 Jo-Philipp Wich <jo@mein.io>
2 -- Licensed to the public under the Apache License 2.0.
3
4 module("luci.controller.nlbw", package.seeall)
5
6 function index()
7         entry({"admin", "nlbw"}, firstchild(), _("Bandwidth Monitor"), 80)
8         entry({"admin", "nlbw", "display"}, template("nlbw/display"), _("Display"), 1)
9         entry({"admin", "nlbw", "config"}, cbi("nlbw/config"), _("Configuration"), 2)
10         entry({"admin", "nlbw", "backup"}, template("nlbw/backup"), _("Backup"), 3)
11         entry({"admin", "nlbw", "data"}, call("action_data"), nil, 4)
12         entry({"admin", "nlbw", "list"}, call("action_list"), nil, 5)
13         entry({"admin", "nlbw", "ptr"}, call("action_ptr"), nil, 6).leaf = true
14         entry({"admin", "nlbw", "download"}, call("action_download"), nil, 7)
15         entry({"admin", "nlbw", "restore"}, post("action_restore"), nil, 8)
16         entry({"admin", "nlbw", "commit"}, call("action_commit"), nil, 9)
17 end
18
19 local function exec(cmd, args, writer)
20         local os = require "os"
21         local nixio = require "nixio"
22
23         local fdi, fdo = nixio.pipe()
24         local pid = nixio.fork()
25
26         if pid > 0 then
27                 fdo:close()
28
29                 while true do
30                         local buffer = fdi:read(2048)
31                         local wpid, stat, code = nixio.waitpid(pid, "nohang")
32
33                         if writer and buffer and #buffer > 0 then
34                                 writer(buffer)
35                         end
36
37                         if wpid and stat == "exited" then
38                                 break
39                         end
40                 end
41         elseif pid == 0 then
42                 nixio.dup(fdo, nixio.stdout)
43                 fdi:close()
44                 fdo:close()
45                 nixio.exece(cmd, args, nil)
46                 nixio.stdout:close()
47                 os.exit(1)
48         end
49 end
50
51 function action_data()
52         local http = require "luci.http"
53
54         local types = {
55                 csv = "text/csv",
56                 json = "application/json"
57         }
58
59         local args = { }
60         local mtype = http.formvalue("type") or "json"
61         local delim = http.formvalue("delim") or ";"
62         local period = http.formvalue("period")
63         local group_by = http.formvalue("group_by")
64         local order_by = http.formvalue("order_by")
65
66         if types[mtype] then
67                 args[#args+1] = "-c"
68                 args[#args+1] = mtype
69         else
70                 http.status(400, "Unsupported type")
71                 return
72         end
73
74         if delim and #delim > 0 then
75                 args[#args+1] = "-s%s" % delim
76         end
77
78         if period and #period > 0 then
79                 args[#args+1] = "-t"
80                 args[#args+1] = period
81         end
82
83         if group_by and #group_by > 0 then
84                 args[#args+1] = "-g"
85                 args[#args+1] = group_by
86         end
87
88         if order_by and #order_by > 0 then
89                 args[#args+1] = "-o"
90                 args[#args+1] = order_by
91         end
92
93         http.prepare_content(types[mtype])
94         exec("/usr/sbin/nlbw", args, http.write)
95 end
96
97 function action_list()
98         local http = require "luci.http"
99
100         local fd = io.popen("/usr/sbin/nlbw -c list")
101         local periods = { }
102
103         if fd then
104                 while true do
105                         local period = fd:read("*l")
106
107                         if not period then
108                                 break
109                         end
110
111                         periods[#periods+1] = period
112                 end
113
114                 fd:close()
115         end
116
117         http.prepare_content("application/json")
118         http.write_json(periods)
119 end
120
121 function action_ptr(...)
122         local http = require "luci.http"
123         local util = require "luci.util"
124
125         http.prepare_content("application/json")
126         http.write_json(util.ubus("network.rrdns", "lookup", {
127                 addrs = {...}, timeout = 3000
128         }))
129 end
130
131 function action_download()
132         local nixio = require "nixio"
133         local http = require "luci.http"
134         local sys = require "luci.sys"
135         local uci = require "luci.model.uci".cursor()
136
137         local dir = uci:get_first("nlbwmon", "nlbwmon", "database_directory")
138                 or "/var/lib/nlbwmon"
139
140         if dir and nixio.fs.stat(dir, "type") == "dir" then
141                 local n = "nlbwmon-backup-%s-%s.tar.gz"
142                         %{ sys.hostname(), os.date("%Y-%m-%d") }
143
144                 http.prepare_content("application/octet-stream")
145                 http.header("Content-Disposition", "attachment; filename=\"%s\"" % n)
146                 exec("/bin/tar", { "-C", dir, "-c", "-z", ".", "-f", "-" }, http.write)
147         else
148                 http.status(500, "Unable to find database directory")
149         end
150 end
151
152 function action_restore()
153         local nixio = require "nixio"
154         local http = require "luci.http"
155         local i18n = require "luci.i18n"
156         local tpl = require "luci.template"
157         local uci = require "luci.model.uci".cursor()
158
159         local tmp = "/tmp/nlbw-restore.tar.gz"
160         local dir = uci:get_first("nlbwmon", "nlbwmon", "database_directory")
161                 or "/var/lib/nlbwmon"
162
163         local fp
164         http.setfilehandler(
165                 function(meta, chunk, eof)
166                         if not fp and meta and meta.name == "archive" then
167                                 fp = io.open(tmp, "w")
168                         end
169                         if fp and chunk then
170                                 fp:write(chunk)
171                         end
172                         if fp and eof then
173                                 fp:close()
174                         end
175                 end)
176
177         local files = { }
178         local tar = io.popen("/bin/tar -tzf %s" % tmp, "r")
179         if tar then
180                 while true do
181                         local file = tar:read("*l")
182                         if not file then
183                                 break
184                         elseif file:match("^%d%d%d%d%d%d%d%d%.db%.gz$") or
185                                file:match("^%./%d%d%d%d%d%d%d%d%.db%.gz$") then
186                                 files[#files+1] = file
187                         end
188                 end
189                 tar:close()
190         end
191
192         if #files == 0 then
193                 http.status(500, "Internal Server Error")
194                 tpl.render("nlbw/backup", {
195                         message = i18n.translate("Invalid or empty backup archive")
196                 })
197                 return
198         end
199
200
201         local output = { }
202
203         exec("/etc/init.d/nlbwmon", { "stop" })
204         exec("/bin/mkdir", { "-p", dir })
205
206         exec("/bin/tar", { "-C", dir, "-vxzf", tmp, unpack(files) },
207                 function(chunk) output[#output+1] = chunk:match("%S+") end)
208
209         exec("/bin/rm", { "-f", tmp })
210         exec("/etc/init.d/nlbwmon", { "start" })
211
212         tpl.render("nlbw/backup", {
213                 message = i18n.translatef(
214                         "The following database files have been restored: %s",
215                         table.concat(output, ", "))
216         })
217 end
218
219 function action_commit()
220         local http = require "luci.http"
221         local disp = require "luci.dispatcher"
222
223         http.redirect(disp.build_url("admin/nlbw/display"))
224         exec("/usr/sbin/nlbw", { "-c", "commit" })
225 end