gluon-scheduled-domain-switch: add package (#1555)
This package allows to automatically switch to another domain, either at a given point in time or after the node was offline long enough.
This commit is contained in:
parent
131548580e
commit
c1b9ea2d9c
38
docs/package/gluon-scheduled-domain-switch.rst
Normal file
38
docs/package/gluon-scheduled-domain-switch.rst
Normal file
@ -0,0 +1,38 @@
|
||||
gluon-scheduled-domain-switch
|
||||
=============================
|
||||
|
||||
This package allows to switch a routers domain at a given point
|
||||
in time. This is needed for switching between incompatible transport
|
||||
protocols (e.g. 802.11s and IBSS or VXLAN).
|
||||
|
||||
Nodes will switch when the defined *switch-time* has passed. In case the node was
|
||||
powered off while this was supposed to happen, it might not be able to aquire the
|
||||
correct time. In this case, the node will switch after it has not seen any gateway
|
||||
for a given period of time.
|
||||
|
||||
site.conf
|
||||
---------
|
||||
All those settings have to be defined exclusively in the domain, not the site.
|
||||
|
||||
domain_switch : optional (needed for domains to switch)
|
||||
target_domain :
|
||||
- target domain to switch to
|
||||
switch_after_offline_mins :
|
||||
- amount of time without reachable gateway to switch unconditionally
|
||||
switch_time :
|
||||
- UNIX epoch after which domain will be switched
|
||||
connection_check_targets :
|
||||
- array of IPv6 addresses which are probed to determine if the node is
|
||||
connected to the mesh
|
||||
|
||||
Example::
|
||||
|
||||
domain_switch = {
|
||||
target_domain = 'new_domain',
|
||||
switch_after_offline_mins = 120,
|
||||
switch_time = 1546344000, -- 01.01.2019 - 12:00 UTC
|
||||
connection_check_targets = {
|
||||
'2001:4860:4860::8888',
|
||||
'2001:4860:4860::8844',
|
||||
},
|
||||
},
|
@ -3,15 +3,6 @@ need_string(in_site({'site_name'}))
|
||||
|
||||
-- this_domain() returns nil when multidomain support is disabled
|
||||
if this_domain() then
|
||||
function need_domain_name(path)
|
||||
need_string(path)
|
||||
need(path, function(default_domain)
|
||||
local f = io.open(os.getenv('IPKG_INSTROOT') .. '/lib/gluon/domains/' .. default_domain .. '.json')
|
||||
if not f then return false end
|
||||
f:close()
|
||||
return true
|
||||
end, nil, 'be a valid domain name')
|
||||
end
|
||||
need_domain_name(in_site({'default_domain'}))
|
||||
|
||||
need_table(in_domain({'domain_names'}), function(domain)
|
||||
|
@ -260,3 +260,12 @@ function foreach_radio(uci, f)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function get_uptime()
|
||||
local uptime_file = readfile("/proc/uptime")
|
||||
if uptime_file == nil then
|
||||
-- Something went wrong reading "/proc/uptime"
|
||||
return nil
|
||||
end
|
||||
return tonumber(uptime_file:match('^[^ ]+'))
|
||||
end
|
||||
|
13
package/gluon-scheduled-domain-switch/Makefile
Normal file
13
package/gluon-scheduled-domain-switch/Makefile
Normal file
@ -0,0 +1,13 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gluon-scheduled-domain-switch
|
||||
PKG_VERSION:=1
|
||||
|
||||
include ../gluon.mk
|
||||
|
||||
define Package/gluon-scheduled-domain-switch
|
||||
TITLE:=Allows scheduled migrations between domains
|
||||
DEPENDS:=+gluon-core @GLUON_MULTIDOMAIN
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackageGluon,gluon-scheduled-domain-switch))
|
6
package/gluon-scheduled-domain-switch/check_site.lua
Normal file
6
package/gluon-scheduled-domain-switch/check_site.lua
Normal file
@ -0,0 +1,6 @@
|
||||
if need_table(in_domain({'domain_switch'}), check_domain_switch, false) then
|
||||
need_domain_name(in_domain({'domain_switch', 'target_domain'}))
|
||||
need_number(in_domain({'domain_switch', 'switch_after_offline_mins'}))
|
||||
need_number(in_domain({'domain_switch', 'switch_time'}))
|
||||
need_string_array_match(in_domain({'domain_switch', 'connection_check_targets'}), '^[%x:]+$')
|
||||
end
|
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local json = require 'jsonc'
|
||||
local site = require 'gluon.site'
|
||||
local unistd = require 'posix.unistd'
|
||||
|
||||
local cronfile = "/usr/lib/micron.d/gluon-scheduled-domain-switch"
|
||||
|
||||
-- Check if domain switch is scheduled
|
||||
if site.domain_switch() == nil then
|
||||
-- In case no domain switch is scheduled, remove cronfile
|
||||
os.remove(cronfile)
|
||||
os.exit(0)
|
||||
end
|
||||
|
||||
-- Only in case domain switch is scheduled
|
||||
local f = io.open(cronfile, "w")
|
||||
f:write("* * * * * /usr/bin/gluon-check-connection\n")
|
||||
f:write("*/5 * * * * /usr/bin/gluon-switch-domain\n")
|
||||
f:close()
|
36
package/gluon-scheduled-domain-switch/luasrc/usr/bin/gluon-check-connection
Executable file
36
package/gluon-scheduled-domain-switch/luasrc/usr/bin/gluon-check-connection
Executable file
@ -0,0 +1,36 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local unistd = require 'posix.unistd'
|
||||
local util = require 'gluon.util'
|
||||
local site = require 'gluon.site'
|
||||
|
||||
local offline_flag_file = "/tmp/gluon_offline"
|
||||
local is_offline = true
|
||||
|
||||
-- Check if domain-switch is scheduled
|
||||
if site.domain_switch() == nil then
|
||||
-- Switch not applicable for current domain
|
||||
os.exit(0)
|
||||
end
|
||||
|
||||
-- Check reachability of pre-defined targets
|
||||
for _, ip in ipairs(site.domain_switch.connection_check_targets()) do
|
||||
local exit_code = os.execute("ping -c 1 -w 10 " .. ip)
|
||||
if exit_code == 0 then
|
||||
is_offline = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if is_offline then
|
||||
-- Check if we were previously offline
|
||||
if unistd.access(offline_flag_file) then
|
||||
os.exit(0)
|
||||
end
|
||||
-- Create offline flag
|
||||
local f = io.open(offline_flag_file, "w")
|
||||
f:write(tostring(util.get_uptime()))
|
||||
f:close()
|
||||
else
|
||||
os.remove(offline_flag_file)
|
||||
end
|
67
package/gluon-scheduled-domain-switch/luasrc/usr/bin/gluon-switch-domain
Executable file
67
package/gluon-scheduled-domain-switch/luasrc/usr/bin/gluon-switch-domain
Executable file
@ -0,0 +1,67 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local uci = require('simple-uci').cursor()
|
||||
local unistd = require 'posix.unistd'
|
||||
local util = require 'gluon.util'
|
||||
local site = require 'gluon.site'
|
||||
|
||||
-- Returns true if node was offline long enough to perform domain switch
|
||||
function switch_after_min_reached()
|
||||
if not unistd.access("/tmp/gluon_offline") then
|
||||
return false
|
||||
end
|
||||
|
||||
local switch_after_sec = site.domain_switch.switch_after_offline_mins() * 60
|
||||
|
||||
local current_uptime = util.get_uptime()
|
||||
if current_uptime == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
local f = util.readfile("/tmp/gluon_offline")
|
||||
if f == nil then
|
||||
return false
|
||||
end
|
||||
local offline_since = tonumber(f)
|
||||
|
||||
local offline_time_sec = current_uptime - offline_since
|
||||
|
||||
if offline_time_sec > switch_after_sec then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Returns true in case switch time has passed
|
||||
function switch_time_passed()
|
||||
local current_time = os.time()
|
||||
local switch_time = site.domain_switch.switch_time()
|
||||
|
||||
return switch_time < current_time
|
||||
end
|
||||
|
||||
if site.domain_switch() == nil then
|
||||
-- Switch not applicable for current domain
|
||||
print("No domain switch defined for the current domain.")
|
||||
os.exit(0)
|
||||
end
|
||||
|
||||
local current_domain = uci:get("gluon", "core", "domain")
|
||||
local target_domain = site.domain_switch.target_domain()
|
||||
|
||||
if target_domain == current_domain then
|
||||
-- Current and target domain are equal
|
||||
print("Domain '" .. target_domain .. "' equals current domain.")
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
if not switch_after_min_reached() and not switch_time_passed() then
|
||||
-- Neither switch-time passed nor switch_after_min reached
|
||||
os.exit(0)
|
||||
end
|
||||
|
||||
uci:set("gluon", "core", "domain", target_domain)
|
||||
uci:commit("gluon")
|
||||
|
||||
os.execute("gluon-reconfigure")
|
||||
os.execute("reboot")
|
@ -305,6 +305,15 @@ function need_array_of(path, array, required)
|
||||
return need_array(path, function(e) need_one_of(e, array) end, required)
|
||||
end
|
||||
|
||||
function need_domain_name(path)
|
||||
need_string(path)
|
||||
need(path, function(domain_name)
|
||||
local f = io.open(os.getenv('IPKG_INSTROOT') .. '/lib/gluon/domains/' .. domain_name .. '.json')
|
||||
if not f then return false end
|
||||
f:close()
|
||||
return true
|
||||
end, nil, 'be a valid domain name')
|
||||
end
|
||||
|
||||
local check = assert(loadfile())
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user