gluon-check-connection: initial commit
This commit adds a new package which can be used for scheduled connectivity checks.
This commit is contained in:
parent
c97be1e18a
commit
9e5775865c
@ -59,6 +59,7 @@ Several Freifunk communities in Germany use Gluon as the foundation of their Fre
|
||||
:caption: Packages
|
||||
:maxdepth: 1
|
||||
|
||||
package/gluon-check-connection
|
||||
package/gluon-client-bridge
|
||||
package/gluon-config-mode-domain-select
|
||||
package/gluon-ebtables-filter-multicast
|
||||
|
69
docs/package/gluon-check-connection.rst
Normal file
69
docs/package/gluon-check-connection.rst
Normal file
@ -0,0 +1,69 @@
|
||||
gluon-check-connection
|
||||
======================
|
||||
|
||||
This package adds a script that checks if at least one connection to IPv6 hosts
|
||||
defined as *target groups* is working using the ping command.
|
||||
The script is called once every minute by ``micrond``.
|
||||
For example one can define a group of *local* targets to check if a connection
|
||||
to hosts in the mesh network is possible (e.g. time or update servers) and
|
||||
*global* targets for checking if a connection to the global internet is possible.
|
||||
Currently only IPv6 addresses are supported.
|
||||
This is e.g. used by the *gluon-scheduled-domain-switch* package
|
||||
|
||||
site.conf
|
||||
---------
|
||||
|
||||
Target groups can be pre-defined in the domain config.
|
||||
|
||||
::
|
||||
|
||||
check_connection = {
|
||||
targets = {
|
||||
targets_local = {
|
||||
'fe80::dead:c0de:1',
|
||||
'fe80::bad:c0de:1',
|
||||
'fe80::dead:c0de:2',
|
||||
'fe80::bad:c0de:2',
|
||||
},
|
||||
targets_global = {
|
||||
'2620:0:ccc::2', -- OpenDNS
|
||||
'2001:4860:4860::8888', -- Google DNS
|
||||
'2600::1', -- Sprint DNS
|
||||
'2620:0:ccd::2', -- OpenDNS
|
||||
'2001:4860:4860::8844', -- Google DNS
|
||||
'2600::2', -- Sprint DNS
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
Defining target groups in the site.conf will overwrite existing ones with the same
|
||||
name when performing a *sysupgrade* or by triggering *gluon-reconfigure*.
|
||||
|
||||
Configuration via UCI
|
||||
---------------------
|
||||
|
||||
Packages can use gluon-check-connection to be triggered after connection checks.
|
||||
For this they can define the following *script* attributes:
|
||||
|
||||
script : an entry for defining the ping target
|
||||
enabled :
|
||||
- a boolean defining whether the target will be considered
|
||||
interval :
|
||||
- the interval to execute the trigger script (in minutes - defaults to 1)
|
||||
command :
|
||||
- the command to execute
|
||||
groups :
|
||||
- the target groups array on which the ping test will be performed on
|
||||
onchange :
|
||||
- if set true the command is only being executed on a state change or always otherwise
|
||||
trigger :
|
||||
- on which the command is being executed (``offline``, ``online`` or unset for both)
|
||||
|
||||
|
||||
*target* groups can be defined with the following attributes:
|
||||
|
||||
target : an entry for defining the IPv6 adress to ping
|
||||
hosts :
|
||||
- array containing the IPv6 addresses to perform the ping test on
|
||||
|
@ -516,7 +516,6 @@ config_mode \: optional
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
roles \: optional
|
||||
Optional role definitions. Nodes will announce their role inside the mesh.
|
||||
This will allow in the backend to distinguish between normal, backbone and
|
||||
|
21
package/gluon-check-connection/Makefile
Normal file
21
package/gluon-check-connection/Makefile
Normal file
@ -0,0 +1,21 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gluon-check-connection
|
||||
PKG_VERSION:=1
|
||||
|
||||
include ../gluon.mk
|
||||
|
||||
define Package/$(PKG_NAME)
|
||||
TITLE:=Checks if a node can ping definable targets
|
||||
DEPENDS:=+gluon-core +micrond @GLUON_MULTIDOMAIN
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/description
|
||||
Script to check if there is a connection to any gateway and also if there is
|
||||
a connection to the global internet. This script is called once every minute
|
||||
by ``micrond``. It will trigger scripts which will be executed if a
|
||||
connection state changes or after a definable interval after which
|
||||
connections checks have been performed.
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackageGluon,$(PKG_NAME)))
|
5
package/gluon-check-connection/check_site.lua
Normal file
5
package/gluon-check-connection/check_site.lua
Normal file
@ -0,0 +1,5 @@
|
||||
local function check_target(t)
|
||||
need_string_array_match(t, '^[%x:]+$', false)
|
||||
end
|
||||
|
||||
need_table(in_domain({'check_connection', 'targets'}), check_target, false)
|
@ -0,0 +1 @@
|
||||
* * * * * /usr/sbin/gluon-check-connection
|
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local site = require 'gluon.site'
|
||||
local uci = require('simple-uci').cursor()
|
||||
|
||||
for group, hosts in pairs(site.check_connection.targets()) do
|
||||
uci:delete('gluon-check-connection', 'target', group)
|
||||
uci:section('gluon-check-connection', 'target', group, {
|
||||
hosts = hosts
|
||||
})
|
||||
end
|
||||
|
||||
uci:save('gluon-check-connection')
|
||||
|
158
package/gluon-check-connection/luasrc/usr/sbin/gluon-check-connection
Executable file
158
package/gluon-check-connection/luasrc/usr/sbin/gluon-check-connection
Executable file
@ -0,0 +1,158 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local unistd = require 'posix.unistd'
|
||||
local util = require 'gluon.util'
|
||||
local uci = require('simple-uci').cursor()
|
||||
|
||||
-- Minimal uptime (in minutes) before the checks start
|
||||
local min_uptime = 5
|
||||
|
||||
local offline_flag_file_prefix = '/tmp/gluon-offline-'
|
||||
local firstrun_file = '/tmp/gluon-check-connection-firstrun'
|
||||
local lastrun_file = '/tmp/gluon-check-connection-lastrun'
|
||||
|
||||
local function lock(file)
|
||||
exec('lock', file)
|
||||
end
|
||||
|
||||
local function unlock(file)
|
||||
exec('lock', '-u', file)
|
||||
end
|
||||
|
||||
local function shuffle(tbl)
|
||||
new_tbl = {}
|
||||
for i, ele in ipairs(tbl) do
|
||||
table.insert(new_tbl, math.random(1, #new_tbl+1), ele)
|
||||
end
|
||||
|
||||
return new_tbl
|
||||
end
|
||||
|
||||
local function ping_hosts(hosts)
|
||||
for _, host in ipairs(hosts) do
|
||||
if 0 == os.execute("ping -c 1 -w 10 " .. host) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function check_connection(group, old_state, hosts)
|
||||
local offline_flag_file = offline_flag_file_prefix .. group
|
||||
local targets = shuffle(hosts)
|
||||
|
||||
if ping_hosts(targets) then
|
||||
if not old_state then
|
||||
util.log(group .. 'connectivity available again')
|
||||
os.remove(offline_flag_file)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
if old_state then
|
||||
util.log(group .. ' connectivity lost')
|
||||
io.open(offline_flag_file, "w"):write(tostring(util.get_uptime()))
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local uptime = math.floor(util.get_uptime() / 60)
|
||||
|
||||
if uptime < min_uptime then
|
||||
os.exit(0)
|
||||
end
|
||||
|
||||
if not lock('/var/lock/gluon-check-connection.lock') then
|
||||
util.log('Unable to set lock. Is an old instance still running?')
|
||||
os.exit(0)
|
||||
end
|
||||
|
||||
math.randomseed(uptime)
|
||||
|
||||
local firstrun = uptime
|
||||
local lastrun = uptime
|
||||
if unistd.access(firstrun_file) and unistd.access(lastrun_file) then
|
||||
firstrun = tonumber(util.readfile(firstrun_file))
|
||||
lastrun = tonumber(util.readfile(lastrun_file))
|
||||
else
|
||||
io.open(firstrun_file, "w"):write(tostring(uptime))
|
||||
end
|
||||
|
||||
local runtime = lastrun - firstrun
|
||||
|
||||
local scripts = {}
|
||||
uci:foreach('gluon-check-connection', 'script', function(script)
|
||||
if not script['enabled'] then return end
|
||||
|
||||
if not runtime or uptime - lastrun >= (tonumber(script['interval']) or 1) then
|
||||
table.insert(scripts, script)
|
||||
end
|
||||
end)
|
||||
|
||||
local groups = {}
|
||||
uci:foreach('gluon-check-connection', 'target', function(group)
|
||||
-- do not perform connection checks for groups which are not in use
|
||||
for _, script in ipairs(scripts) do
|
||||
if util.contains(script['groups'], group['.name']) then
|
||||
groups[group['.name']] = group['hosts']
|
||||
break
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local old_states = {}
|
||||
for group, _ in pairs(groups) do
|
||||
if unistd.access(offline_flag_file_prefix .. group) then
|
||||
old_states[group] = false
|
||||
else
|
||||
old_states[group] = true
|
||||
end
|
||||
end
|
||||
|
||||
local states = {}
|
||||
for group, hosts in pairs(groups) do
|
||||
states[group] = check_connection(group, old_states[group], hosts)
|
||||
end
|
||||
|
||||
for _, script in ipairs(scripts) do
|
||||
local state_changed = false
|
||||
local state_offline = false
|
||||
local state_online = false
|
||||
|
||||
for _, group in ipairs(script['groups']) do
|
||||
if nil ~= states[group] then
|
||||
if states[group] ~= old_states[group] then
|
||||
state_changed = true
|
||||
end
|
||||
|
||||
if states[group] then
|
||||
state_online = true
|
||||
else
|
||||
state_offline = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not runtime or state_changed or not script['onchange'] then
|
||||
local do_run = not script['trigger']
|
||||
|
||||
if script['trigger'] == 'online' and state_online then
|
||||
do_run = true
|
||||
end
|
||||
|
||||
if script['trigger'] == 'offline' and state_offline then
|
||||
do_run = true
|
||||
end
|
||||
|
||||
if do_run then
|
||||
util.exec(script['command'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
unlock('/var/lock/gluon-check-connection.lock')
|
||||
|
||||
io.open(lastrun_file, "w"):write(tostring(math.floor(util.get_uptime() / 60)))
|
Loading…
Reference in New Issue
Block a user