status-page.html 7.21 KB
Newer Older
1
2
<%-
	local ubus = require 'ubus'
3
	local unistd = require 'posix.unistd'
4
5
6
	local util = require 'gluon.util'

	local translations = {}
7
	local site_i18n = i18n 'gluon-site'
8
9
10
11
12
13
14
15
16
17
18
19
20
21

	local function _(v)
		translations[v] = translate(v)
	end

	-- i18n strings for JavaScript
	_('.') -- decimal point
	_('connected')
	_('not connected')
	_('1 day')
	_('%s days')
	_('%s used')
	_('%s packets/s')

22
23
24
25
26
27
28
29
30
31
	local function get_mesh()
		local f = loadfile('/lib/gluon/status-page/mesh.lua')
		if f then
			return f()
		end
		return {}
	end

	local mesh = get_mesh()

32
33
34
35
36
37
38
39
40
41
42
43
44
45
	local function get_interfaces()
		local uconn = ubus.connect()
		if not uconn then
			error('failed to connect to ubus')
		end
		local interfaces = util.get_mesh_devices(uconn)
		ubus.close(uconn)
		table.sort(interfaces)
		return interfaces
	end

	local function is_wireless(iface)
		while true do
			local pattern = '/sys/class/net/' .. iface .. '/lower_*'
46
			local lower = util.glob(pattern)[1]
47
48
49
50
51
			if not lower then break end

			iface = lower:sub(pattern:len())
		end

52
		return unistd.access('/sys/class/net/' .. iface .. '/wireless') ~= nil
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
	end

	local interfaces = get_interfaces()

	local function sorted(t)
		t = {unpack(t)}
		table.sort(t)
		return t
	end

	local function enabled(v)
		return v and translate('enabled') or translate('disabled')
	end

	local function statistics(key, format)
		return string.format('<span data-statistics="%s" data-format="%s"></span>', pcdata(key), pcdata(format or 'id'))
	end

	local function statisticsTraffic(key)
		return string.format('%s<br />%s<br />%s',
			statistics(key .. '/packets', 'packetsDiff'),
			statistics(key .. '/bytes', 'bytesDiff'),
			statistics(key .. '/bytes', 'bytes')
		)
	end

	http:prepare_content("application/xhtml+xml")
-%>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, user-scalable=no" />

		<title><%| nodeinfo.hostname %> - <%:Status%></title>

		<link rel="stylesheet" href="/static/status-page.css" type="text/css" />
	</head>
91
92
93
94
95
	<body data-node-address="<%| http:getenv('SERVER_ADDR') %>"<%=
		attr('data-translations', translations) ..
		attr('data-node-location', nodeinfo.location) ..
		attr('data-mesh-provider', mesh.provider)
	%>>
96
97
98
99
100
101
102
103
		<header>
			<h1><%| nodeinfo.hostname %></h1>
		</header>
		<div class="container">
			<div class="frame">
				<h2><%:Overview%></h2>
				<dl>
					<dt><%:Node name%></dt><dd><%| nodeinfo.hostname %></dd>
104
105
106
					<% if nodeinfo.owner and nodeinfo.owner.contact then -%>
						<dt><%:Contact%></dt><dd><%| nodeinfo.owner.contact %></dd>
					<%- end %>
107
108
109
110
111
112
					<% if nodeinfo.location then -%>
						<dt><%:Location%></dt>
						<dd><a href="geo:<%| nodeinfo.location.latitude %>,<%| nodeinfo.location.longitude %>">
							<%| nodeinfo.location.latitude %>, <%| nodeinfo.location.longitude %>
						</a></dd>
					<%- end %>
113
114
115
116
					<dt><%:Model%></dt><dd><%| nodeinfo.hardware.model %></dd>
					<dt><%:Primary MAC address%></dt><dd><%| nodeinfo.network.mac %></dd>
					<dt><%:IP address%></dt><dd><%= pcdata(table.concat(sorted(nodeinfo.network.addresses), '\n')):gsub('\n', '<br />') %></dd>
					<dt><%:Firmware%></dt><dd><%| nodeinfo.software.firmware.release %></dd>
117
118
119
120
121
122
123
124
					<% if nodeinfo.network.mesh_vpn then -%>
						<dt><%:Mesh VPN%></dt>
						<dd>
							<%| enabled(nodeinfo.network.mesh_vpn.enabled) %>
							<% if nodeinfo.network.mesh_vpn.provider then -%>
							<br /><%| nodeinfo.network.mesh_vpn.provider %>
							<%- end %>
						</dd>
125
					<%- end %>
126
127
					<dt><%:Site%></dt><dd><%| site.site_name() %></dd>
					<% if nodeinfo.system.domain_code then -%>
128
129
130
131
132
133
134
						<dt><%:Domain%></dt>
						<dd>
							<%| site.domain_names[nodeinfo.system.domain_code]() %>
							<% if nodeinfo.system.domain_code ~= nodeinfo.system.primary_domain_code then %>
							(<%| site.domain_names[nodeinfo.system.primary_domain_code]() %>)
							<%- end %>
						</dd>
135
					<%- end %>
136
					<% if nodeinfo.system.role then -%>
137
						<dt><%:Role%></dt><dd><%| site_i18n._translate('gluon-web-node-role:role:' .. nodeinfo.system.role) %></dd>
138
					<%- end %>
139
140
141
142
143
144
					<% if nodeinfo.software.autoupdater then -%>
						<dt><%:Automatic updates%></dt><dd><%| enabled(nodeinfo.software.autoupdater.enabled) %><%|
							nodeinfo.software.autoupdater.enabled and
								string.format(' (%s)', nodeinfo.software.autoupdater.branch)
						%></dd>
					<%- end %>
145
146
147
					<% if nodeinfo.software.babeld or nodeinfo.software['batman-adv'] then -%>
						<dt><%:Mesh protocol%></dt>
						<% if nodeinfo.software.babeld then -%>
148
						<dd>babeld <%| nodeinfo.software.babeld.version %></dd>
149
150
151
152
153
						<%- end %>
						<% if nodeinfo.software['batman-adv'] then -%>
						<dd>batman-adv <%| nodeinfo.software['batman-adv'].version %> (compat<%| nodeinfo.software['batman-adv'].compat %>)</dd>
						<%- end %>
					<%- end %>
154
155
156
157
158
159
160
161
162
				</dl>
			</div>
			<div class="frame">
				<h2><%:Monitoring%></h2>
				<table>
					<tr><th><%:Uptime%></th><td><%= statistics('uptime', 'time') %></td></tr>
					<tr><th><%:Load average%></th><td><%= statistics('loadavg', 'decimal') %></td></tr>
					<tr><th><%:RAM%></th><td><%= statistics('memory', 'memory') %></td></tr>
					<tr><th><%:Filesystem%></th><td><%= statistics('rootfs_usage', 'percent') %></td></tr>
163
					<tr><th><%:Gateway%></th><td><%= statistics('gateway') %><br /><%= statistics('gateway_nexthop', 'neighbour') %></td></tr>
164
165
166
167
168
169
170
				</table>

				<h3><%:Clients%></h3>
				<table>
					<tr><th><%:Total%></th><td><%= statistics('clients/total') %></td></tr>
					<tr><th><%:Wireless 2.4 GHz%></th><td><%= statistics('clients/wifi24') %></td></tr>
					<tr><th><%:Wireless 5 GHz%></th><td><%= statistics('clients/wifi5') %></td></tr>
171
				</table>
172
173
174
175
176
					<div id="radios" style="display: none">
					<h3><%:Radios%></h3>
					<table id="radio-devices">
					</table>
				</div>
177
178
179
180
181
182
183
184
185
186
187
188
189
190

				<h3><%:Traffic%></h3>
				<table>
					<tr><th><%:Transmitted%></th><td><%= statisticsTraffic('traffic/tx') %></td></tr>
					<tr><th><%:Received%></th><td><%= statisticsTraffic('traffic/rx') %></td></tr>
					<tr><th><%:Forwarded%></th><td><%= statisticsTraffic('traffic/forward') %></td></tr>
				</table>

				<div id="mesh-vpn" style="display: none">
					<h3><%:Mesh VPN%></h3>
					<table id="mesh-vpn-peers">
					</table>
				</div>
			</div>
191
			<div class="frame frame-wide">
192
193
194
195
196
				<h2><%:Neighbors%></h2>

				<%
					for _, iface in ipairs(interfaces) do
						local wireless = is_wireless(iface)
197
						local address = util.readfile('/sys/class/net/' .. iface .. '/address')
198
199
200
201
202
203
204
						if address then
				%>
					<h3><%| iface %></h3>
					<div data-interface="<%| iface %>" data-interface-address="<%| util.trim(address) %>"<%= attr('data-interface-wireless', wireless) %>>
						<table class="datatable">
							<tr>
								<th><%:Node%></th>
205
								<% for i, v in ipairs(mesh.attrs or {}) do %>
206
									<th<%= attr('class', 'row-' .. v[1] ) .. attr('data-key', v[1]) .. attr('data-suffix', v[3]) %>><%| v[2] %></th>
207
								<% end %>
208
								<% if wireless then %>
209
210
211
									<th class="row-signal">dBm</th>
									<th class="row-distance"><%:Distance%></th>
									<th class="row-inactive"><%:Last seen%></th>
212
213
214
215
216
217
218
219
220
221
222
223
224
								<% end %>
							</tr>
						</table>
					</div>
				<%
						end
					end
				%>
			</div>
		</div>
		<script src="/static/status-page.js"></script>
	</body>
</html>