luci-app-mwan3: refactoring detail status view and controller
[project/luci.git] / applications / luci-app-mwan3 / luasrc / controller / mwan3.lua
1 module("luci.controller.mwan3", package.seeall)
2
3 sys = require "luci.sys"
4 ut = require "luci.util"
5
6 ip = "ip -4 "
7
8 function index()
9         if not nixio.fs.access("/etc/config/mwan3") then
10                 return
11         end
12
13         entry({"admin", "status", "mwan"},
14                 alias("admin", "status", "mwan", "overview"),
15                 _("Load Balancing"), 600)
16
17         entry({"admin", "status", "mwan", "overview"},
18                 template("mwan/status_interface"))
19         entry({"admin", "status", "mwan", "detail"},
20                 template("mwan/status_detail"))
21         entry({"admin", "status", "mwan", "diagnostics"},
22                 template("mwan/status_diagnostics"))
23         entry({"admin", "status", "mwan", "troubleshooting"},
24                 template("mwan/status_troubleshooting"))
25         entry({"admin", "status", "mwan", "interface_status"},
26                 call("mwan_Status"))
27         entry({"admin", "status", "mwan", "detailed_status"},
28                 call("detailedStatus"))
29         entry({"admin", "status", "mwan", "diagnostics_display"},
30                 call("diagnosticsData"), nil).leaf = true
31         entry({"admin", "status", "mwan", "troubleshooting_display"},
32                 call("troubleshootingData"))
33
34
35         entry({"admin", "network", "mwan"},
36                 alias("admin", "network", "mwan", "interface"),
37                 _("Load Balancing"), 600)
38
39         entry({"admin", "network", "mwan", "globals"},
40                 cbi("mwan/globalsconfig"),
41                 _("Globals"), 5).leaf = true
42         entry({"admin", "network", "mwan", "interface"},
43                 arcombine(cbi("mwan/interface"), cbi("mwan/interfaceconfig")),
44                 _("Interfaces"), 10).leaf = true
45         entry({"admin", "network", "mwan", "member"},
46                 arcombine(cbi("mwan/member"), cbi("mwan/memberconfig")),
47                 _("Members"), 20).leaf = true
48         entry({"admin", "network", "mwan", "policy"},
49                 arcombine(cbi("mwan/policy"), cbi("mwan/policyconfig")),
50                 _("Policies"), 30).leaf = true
51         entry({"admin", "network", "mwan", "rule"},
52                 arcombine(cbi("mwan/rule"), cbi("mwan/ruleconfig")),
53                 _("Rules"), 40).leaf = true
54         entry({"admin", "network", "mwan", "notify"},
55                 cbi("mwan/notify"),
56                 _("Notification"), 50).leaf = true
57 end
58
59 function mwan_Status()
60         local status = ut.ubus("mwan3", "status", {})
61
62         luci.http.prepare_content("application/json")
63         if status ~= nil then
64                 luci.http.write_json(status)
65         else
66                 luci.http.write_json({})
67         end
68 end
69
70 function detailedStatus()
71         local statusInfo = ut.trim(sys.exec("/usr/sbin/mwan3 status"))
72         luci.http.prepare_content("text/plain")
73         if statusInfo ~= "" then
74                 luci.http.write(statusInfo)
75         else
76                 luci.http.write("Unable to get status information")
77         end
78 end
79
80 function diagnosticsData(interface, task)
81         function getInterfaceNumber(interface)
82                 local number = 0
83                 local interfaceNumber
84                 uci.cursor():foreach("mwan3", "interface",
85                         function (section)
86                                 number = number+1
87                                 if section[".name"] == interface then
88                                         interfaceNumber = number
89                                 end
90                         end
91                 )
92                 return interfaceNumber
93         end
94
95         function diag_command(cmd, addr)
96                 if addr and addr:match("^[a-zA-Z0-9%-%.:_]+$") then
97                         local util = io.popen(cmd % addr)
98                         if util then
99                                 while true do
100                                         local ln = util:read("*l")
101                                         if not ln then break end
102                                         luci.http.write(ln)
103                                         luci.http.write("\n")
104                                 end
105                                 util:close()
106                         end
107                         return
108                 end
109         end
110
111         function get_gateway(inteface)
112                 local dump = require("luci.util").ubus("network.interface.%s" % interface, "status", {})
113                 local gateway
114                 if dump then
115                         local _, route
116                         for _, route in ipairs(dump.route) do
117                                 if dump.route[_].target == "0.0.0.0" then
118                                         gateway =  dump.route[_].nexthop
119                                 end
120                         end
121                 end
122                 return gateway
123         end
124
125         local mArray = {}
126         local results = ""
127         local number = getInterfaceNumber(interface)
128
129         local uci = uci.cursor(nil, "/var/state")
130         local device = uci:get("network", interface, "ifname")
131
132         luci.http.prepare_content("text/plain")
133         if device ~= "" then
134                 if task == "ping_gateway" then
135                         local gateway = get_gateway(interface)
136                         if gateway ~= nil then
137                                 diag_command("ping -c 5 -W 1 %q 2>&1", gateway)
138                         else
139                                 luci.http.prepare_content("text/plain")
140                                 luci.http.write(string.format("No gateway for interface %s found.", interface))
141                         end
142                 elseif task == "ping_trackips" then
143                         local trackips = uci:get("mwan3", interface, "track_ip")
144                         if #trackips > 0 then
145                                 for i in pairs(trackips) do
146                                         diag_command("ping -c 5 -W 1 %q 2>&1", trackips[i])
147                                 end
148                         else
149                                 luci.http.write(string.format("No tracking Hosts for interface %s defined.", interface))
150                         end
151                 elseif task == "check_rules" then
152                         local number = getInterfaceNumber(interface)
153                         local iif = 1000 + number
154                         local fwmark = 2000 + number
155                         local iif_rule  = sys.exec(string.format("ip rule | grep %d", iif))
156                         local fwmark_rule = sys.exec(string.format("ip rule | grep %d", fwmark))
157                         if iif_rule ~= "" and fwmark_rule ~= "" then
158                                 luci.http.write(string.format("All required IP rules for interface %s found", interface))
159                                 luci.http.write("\n")
160                                 luci.http.write(fwmark_rule)
161                                 luci.http.write(iif_rule)
162                         elseif iif_rule == "" and fwmark_rule ~= "" then
163                                 luci.http.write(string.format("Only one IP rules for interface %s found", interface))
164                                 luci.http.write("\n")
165                                 luci.http.write(fwmark_rule)
166                         elseif iif_rule ~= "" and fwmark_rule == "" then
167                                 luci.http.write(string.format("Only one IP rules for interface %s found", interface))
168                                 luci.http.write("\n")
169                                 luci.http.write(iif_rule)
170                         else
171                                 luci.http.write(string.format("Missing both IP rules for interface %s", interface))
172                         end
173                 elseif task == "check_routes" then
174                         local number = getInterfaceNumber(interface)
175                         local routeTable = sys.exec(string.format("ip route list table %s", number))
176                         if routeTable ~= "" then
177                                 luci.http.write(string.format("Routing table %s for interface %s found", number, interface))
178                                 luci.http.write("\n")
179                                 luci.http.write(routeTable)
180                         else
181                                 luci.http.write(string.format("Routing table %s for interface %s not found", number, interface))
182                         end
183                 elseif task == "hotplug_ifup" then
184                         os.execute(string.format("/usr/sbin/mwan3 ifup %s", interface))
185                         luci.http.write(string.format("Hotplug ifup sent to interface %s", interface))
186                 elseif task == "hotplug_ifdown" then
187                         os.execute(string.format("/usr/sbin/mwan3 ifdown %s", interface))
188                         luci.http.write(string.format("Hotplug ifdown sent to interface %s", interface))
189                 else
190                         luci.http.write("Unknown task")
191                 end
192         else
193                 luci.http.write(string.format("Unable to perform diagnostic tests on %s.", interface))
194                 luci.http.write("\n")
195                 luci.http.write("There is no physical or virtual device associated with this interface.")
196         end
197 end
198
199 function troubleshootingData()
200         local ver = require "luci.version"
201
202         local mArray = {}
203
204         -- software versions
205         local wrtRelease = ut.trim(ver.distversion)
206                 if wrtRelease ~= "" then
207                         wrtRelease = "OpenWrt - " .. wrtRelease
208                 else
209                         wrtRelease = "OpenWrt - unknown"
210                 end
211         local luciRelease = ut.trim(ver.luciversion)
212                 if luciRelease ~= "" then
213                         luciRelease = "\nLuCI - " .. luciRelease
214                 else
215                         luciRelease = "\nLuCI - unknown"
216                 end
217         local mwanVersion = ut.trim(sys.exec("opkg info mwan3 | grep Version | awk '{print $2}'"))
218                 if mwanVersion ~= "" then
219                         mwanVersion = "\n\nmwan3 - " .. mwanVersion
220                 else
221                         mwanVersion = "\n\nmwan3 - unknown"
222                 end
223         local mwanLuciVersion = ut.trim(sys.exec("opkg info luci-app-mwan3 | grep Version | awk '{print $2}'"))
224                 if mwanLuciVersion ~= "" then
225                         mwanLuciVersion = "\nmwan3-luci - " .. mwanLuciVersion
226                 else
227                         mwanLuciVersion = "\nmwan3-luci - unknown"
228                 end
229         mArray.versions = { wrtRelease .. luciRelease .. mwanVersion .. mwanLuciVersion }
230
231         -- mwan config
232         local mwanConfig = ut.trim(sys.exec("cat /etc/config/mwan3"))
233                 if mwanConfig == "" then
234                         mwanConfig = "No data found"
235                 end
236         mArray.mwanconfig = { mwanConfig }
237
238         -- network config
239         local networkConfig = ut.trim(sys.exec("cat /etc/config/network | sed -e 's/.*username.*/       USERNAME HIDDEN/' -e 's/.*password.*/   PASSWORD HIDDEN/'"))
240                 if networkConfig == "" then
241                         networkConfig = "No data found"
242                 end
243         mArray.netconfig = { networkConfig }
244
245         -- wireless config
246         local wirelessConfig = ut.trim(sys.exec("cat /etc/config/wireless | sed -e 's/.*username.*/     USERNAME HIDDEN/' -e 's/.*password.*/   PASSWORD HIDDEN/' -e 's/.*key.*/        KEY HIDDEN/'"))
247                 if wirelessConfig == "" then
248                         wirelessConfig = "No data found"
249                 end
250         mArray.wificonfig = { wirelessConfig }
251         
252         -- ifconfig
253         local ifconfig = ut.trim(sys.exec("ifconfig"))
254                 if ifconfig == "" then
255                         ifconfig = "No data found"
256                 end
257         mArray.ifconfig = { ifconfig }
258
259         -- route -n
260         local routeShow = ut.trim(sys.exec("route -n"))
261                 if routeShow == "" then
262                         routeShow = "No data found"
263                 end
264         mArray.routeshow = { routeShow }
265
266         -- ip rule show
267         local ipRuleShow = ut.trim(sys.exec(ip .. "rule show"))
268                 if ipRuleShow == "" then
269                         ipRuleShow = "No data found"
270                 end
271         mArray.iprule = { ipRuleShow }
272
273         -- ip route list table 1-250
274         local routeList, routeString = ut.trim(sys.exec(ip .. "rule | sed 's/://g' 2>/dev/null | awk '$1>=2001 && $1<=2250' | awk '{print $NF}'")), ""
275                 if routeList ~= "" then
276                         for line in routeList:gmatch("[^\r\n]+") do
277                                 routeString = routeString .. line .. "\n" .. sys.exec(ip .. "route list table " .. line)
278                         end
279                         routeString = ut.trim(routeString)
280                 else
281                         routeString = "No data found"
282                 end
283         mArray.routelist = { routeString }
284
285         -- default firewall output policy
286         local firewallOut = ut.trim(sys.exec("uci -q -p /var/state get firewall.@defaults[0].output"))
287                 if firewallOut == "" then
288                         firewallOut = "No data found"
289                 end
290         mArray.firewallout = { firewallOut }
291
292         -- iptables
293         local iptables = ut.trim(sys.exec("iptables -L -t mangle -v -n"))
294                 if iptables == "" then
295                         iptables = "No data found"
296                 end
297         mArray.iptables = { iptables }
298
299         luci.http.prepare_content("application/json")
300         luci.http.write_json(mArray)
301 end