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