-
Notifications
You must be signed in to change notification settings - Fork 20
/
netjson-monitoring.lua
executable file
·188 lines (173 loc) · 6.51 KB
/
netjson-monitoring.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#!/usr/bin/env lua
-- retrieve monitoring information
-- and return it as NetJSON Output
package.path = package.path .. ";../files/lib/?.lua"
local cjson = require('cjson')
local io = require('io')
local ubus_lib = require('ubus')
local ubus = ubus_lib.connect()
if not ubus then error('Failed to connect to ubusd') end
local monitoring = require('openwisp-monitoring.monitoring')
-- collect system info
local system_info = ubus:call('system', 'info', {})
local board = ubus:call('system', 'board', {})
local loadavg_file = io.popen('cat /proc/loadavg')
local loadavg_output = loadavg_file:read()
loadavg_file:close()
loadavg_output = monitoring.utils.split(loadavg_output, ' ')
local load_average = {
tonumber(loadavg_output[1]), tonumber(loadavg_output[2]),
tonumber(loadavg_output[3])
}
-- init netjson data structure
local netjson = {
type = 'DeviceMonitoring',
general = {
hostname = board.hostname,
local_time = system_info.localtime,
uptime = system_info.uptime
},
resources = {
load = load_average,
memory = system_info.memory,
swap = system_info.swap,
cpus = monitoring.resources.get_cpus(),
disk = monitoring.resources.parse_disk_usage()
}
}
local dhcp_leases = monitoring.dhcp.get_dhcp_leases()
if not monitoring.utils.is_table_empty(dhcp_leases) then
netjson.dhcp_leases = dhcp_leases
end
local host_neighbors = monitoring.neighbors.get_neighbors()
if not monitoring.utils.is_table_empty(host_neighbors) then
netjson.neighbors = host_neighbors
end
-- determine the interfaces to monitor
local arg = {...}
local traffic_monitored = arg[1]
local include_stats = {}
if traffic_monitored and traffic_monitored ~= '*' then
traffic_monitored = monitoring.utils.split(traffic_monitored, ' ')
for _, name in pairs(traffic_monitored) do include_stats[name] = true end
end
-- collect device data
local network_status = ubus:call('network.device', 'status', {})
local wireless_status = ubus:call('network.wireless', 'status', {})
local vpn_interfaces = monitoring.interfaces.get_vpn_interfaces()
local wireless_interfaces = {}
local host_interfaces = {}
local dns_servers = {}
local dns_search = {}
-- collect relevant wireless interface stats
-- (traffic and connected clients)
for _, radio in pairs(wireless_status) do
for _, interface in ipairs(radio.interfaces) do
local name = interface.ifname
local is_mesh = false
local clients = nil
if name and not monitoring.utils.is_excluded(name) then
local iwinfo = ubus:call('iwinfo', 'info', {device = name})
local netjson_interface = {
name = name,
type = 'wireless',
wireless = {
ssid = iwinfo.ssid,
mode = monitoring.wifi.iwinfo_modes[iwinfo.mode] or iwinfo.mode,
channel = iwinfo.channel,
frequency = iwinfo.frequency,
tx_power = iwinfo.txpower,
signal = iwinfo.signal,
noise = iwinfo.noise,
country = iwinfo.country
}
}
if iwinfo.mode == 'Ad-Hoc' or iwinfo.mode == 'Mesh Point' then
clients = ubus:call('iwinfo', 'assoclist', {device = name}).results
is_mesh = true
else
local hostapd_output = ubus:call('hostapd.' .. name, 'get_clients', {})
if hostapd_output then clients = hostapd_output.clients end
end
if not monitoring.utils.is_table_empty(clients) then
netjson_interface.wireless.clients =
monitoring.wifi.netjson_clients(clients, is_mesh)
end
wireless_interfaces[name] = netjson_interface
end
end
end
-- collect interface stats
for name, interface in pairs(network_status) do
-- only collect data from iterfaces which have not been excluded
if not monitoring.utils.is_excluded(name) then
local netjson_interface = {
name = name,
type = string.lower(interface.type),
up = interface.up,
mac = interface.macaddr,
txqueuelen = interface.txqueuelen,
mtu = interface.mtu,
speed = interface.speed,
bridge_members = interface['bridge-members'],
multicast = interface.multicast
}
-- add existing bridge members only
if interface['bridge-members'] ~= nil then
local bridge_members = {}
for _, bridge_member in ipairs(interface['bridge-members']) do
if network_status[bridge_member] then
local network_interface = network_status[bridge_member]
if network_interface.up and network_interface.present then
table.insert(bridge_members, bridge_member)
end
end
end
netjson_interface['bridge_members'] = bridge_members
end
if wireless_interfaces[name] then
monitoring.utils.dict_merge(wireless_interfaces[name], netjson_interface)
interface.type = netjson_interface.type
end
if interface.type == 'Network device' then
local link_supported = interface['link-supported']
if link_supported and next(link_supported) then
netjson_interface.type = 'ethernet'
netjson_interface.link_supported = link_supported
elseif vpn_interfaces[name] then
netjson_interface.type = 'virtual'
else
netjson_interface.type = 'other'
end
end
if include_stats[name] or traffic_monitored == '*' then
if monitoring.wifi.needs_inversion(netjson_interface) then
--- ensure wifi access point interfaces
--- show download and upload values from
--- the user's perspective and not from the router perspective
interface.statistics = monitoring.wifi.invert_rx_tx(interface.statistics)
end
netjson_interface.statistics = interface.statistics
end
local addresses = monitoring.interfaces.get_addresses(name)
if next(addresses) then netjson_interface.addresses = addresses end
local info = monitoring.interfaces.get_interface_info(name, netjson_interface)
if info.stp ~= nil then netjson_interface.stp = info.stp end
if info.specialized then
for key, value in pairs(info.specialized) do netjson_interface[key] = value end
end
table.insert(host_interfaces, netjson_interface)
-- DNS info is independent from interface
if info.dns_servers then
monitoring.utils.array_concat(info.dns_servers, dns_servers)
end
if info.dns_search then
monitoring.utils.array_concat(info.dns_search, dns_search)
end
end
end
if next(host_interfaces) ~= nil then netjson.interfaces = host_interfaces end
if next(dns_servers) ~= nil then netjson.dns_servers = dns_servers end
if next(dns_search) ~= nil then netjson.dns_search = dns_search end
io.write(cjson.encode(netjson))
return cjson.encode(netjson)