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
|
:caption: Packages
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
|
package/gluon-check-connection
|
||||||
package/gluon-client-bridge
|
package/gluon-client-bridge
|
||||||
package/gluon-config-mode-domain-select
|
package/gluon-config-mode-domain-select
|
||||||
package/gluon-ebtables-filter-multicast
|
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
|
roles \: optional
|
||||||
Optional role definitions. Nodes will announce their role inside the mesh.
|
Optional role definitions. Nodes will announce their role inside the mesh.
|
||||||
This will allow in the backend to distinguish between normal, backbone and
|
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