Skip to content

Commit c1b9ea2

Browse files
blocktrronrotanid
authored andcommitted
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.
1 parent 1315485 commit c1b9ea2

File tree

9 files changed

+198
-9
lines changed

9 files changed

+198
-9
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
gluon-scheduled-domain-switch
2+
=============================
3+
4+
This package allows to switch a routers domain at a given point
5+
in time. This is needed for switching between incompatible transport
6+
protocols (e.g. 802.11s and IBSS or VXLAN).
7+
8+
Nodes will switch when the defined *switch-time* has passed. In case the node was
9+
powered off while this was supposed to happen, it might not be able to aquire the
10+
correct time. In this case, the node will switch after it has not seen any gateway
11+
for a given period of time.
12+
13+
site.conf
14+
---------
15+
All those settings have to be defined exclusively in the domain, not the site.
16+
17+
domain_switch : optional (needed for domains to switch)
18+
target_domain :
19+
- target domain to switch to
20+
switch_after_offline_mins :
21+
- amount of time without reachable gateway to switch unconditionally
22+
switch_time :
23+
- UNIX epoch after which domain will be switched
24+
connection_check_targets :
25+
- array of IPv6 addresses which are probed to determine if the node is
26+
connected to the mesh
27+
28+
Example::
29+
30+
domain_switch = {
31+
target_domain = 'new_domain',
32+
switch_after_offline_mins = 120,
33+
switch_time = 1546344000, -- 01.01.2019 - 12:00 UTC
34+
connection_check_targets = {
35+
'2001:4860:4860::8888',
36+
'2001:4860:4860::8844',
37+
},
38+
},

package/gluon-core/check_site.lua

-9
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,6 @@ need_string(in_site({'site_name'}))
33

44
-- this_domain() returns nil when multidomain support is disabled
55
if this_domain() then
6-
function need_domain_name(path)
7-
need_string(path)
8-
need(path, function(default_domain)
9-
local f = io.open(os.getenv('IPKG_INSTROOT') .. '/lib/gluon/domains/' .. default_domain .. '.json')
10-
if not f then return false end
11-
f:close()
12-
return true
13-
end, nil, 'be a valid domain name')
14-
end
156
need_domain_name(in_site({'default_domain'}))
167

178
need_table(in_domain({'domain_names'}), function(domain)

package/gluon-core/luasrc/usr/lib/lua/gluon/util.lua

+9
Original file line numberDiff line numberDiff line change
@@ -260,3 +260,12 @@ function foreach_radio(uci, f)
260260
end
261261
end
262262
end
263+
264+
function get_uptime()
265+
local uptime_file = readfile("/proc/uptime")
266+
if uptime_file == nil then
267+
-- Something went wrong reading "/proc/uptime"
268+
return nil
269+
end
270+
return tonumber(uptime_file:match('^[^ ]+'))
271+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
include $(TOPDIR)/rules.mk
2+
3+
PKG_NAME:=gluon-scheduled-domain-switch
4+
PKG_VERSION:=1
5+
6+
include ../gluon.mk
7+
8+
define Package/gluon-scheduled-domain-switch
9+
TITLE:=Allows scheduled migrations between domains
10+
DEPENDS:=+gluon-core @GLUON_MULTIDOMAIN
11+
endef
12+
13+
$(eval $(call BuildPackageGluon,gluon-scheduled-domain-switch))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
if need_table(in_domain({'domain_switch'}), check_domain_switch, false) then
2+
need_domain_name(in_domain({'domain_switch', 'target_domain'}))
3+
need_number(in_domain({'domain_switch', 'switch_after_offline_mins'}))
4+
need_number(in_domain({'domain_switch', 'switch_time'}))
5+
need_string_array_match(in_domain({'domain_switch', 'connection_check_targets'}), '^[%x:]+$')
6+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/usr/bin/lua
2+
3+
local json = require 'jsonc'
4+
local site = require 'gluon.site'
5+
local unistd = require 'posix.unistd'
6+
7+
local cronfile = "/usr/lib/micron.d/gluon-scheduled-domain-switch"
8+
9+
-- Check if domain switch is scheduled
10+
if site.domain_switch() == nil then
11+
-- In case no domain switch is scheduled, remove cronfile
12+
os.remove(cronfile)
13+
os.exit(0)
14+
end
15+
16+
-- Only in case domain switch is scheduled
17+
local f = io.open(cronfile, "w")
18+
f:write("* * * * * /usr/bin/gluon-check-connection\n")
19+
f:write("*/5 * * * * /usr/bin/gluon-switch-domain\n")
20+
f:close()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/lua
2+
3+
local unistd = require 'posix.unistd'
4+
local util = require 'gluon.util'
5+
local site = require 'gluon.site'
6+
7+
local offline_flag_file = "/tmp/gluon_offline"
8+
local is_offline = true
9+
10+
-- Check if domain-switch is scheduled
11+
if site.domain_switch() == nil then
12+
-- Switch not applicable for current domain
13+
os.exit(0)
14+
end
15+
16+
-- Check reachability of pre-defined targets
17+
for _, ip in ipairs(site.domain_switch.connection_check_targets()) do
18+
local exit_code = os.execute("ping -c 1 -w 10 " .. ip)
19+
if exit_code == 0 then
20+
is_offline = false
21+
break
22+
end
23+
end
24+
25+
if is_offline then
26+
-- Check if we were previously offline
27+
if unistd.access(offline_flag_file) then
28+
os.exit(0)
29+
end
30+
-- Create offline flag
31+
local f = io.open(offline_flag_file, "w")
32+
f:write(tostring(util.get_uptime()))
33+
f:close()
34+
else
35+
os.remove(offline_flag_file)
36+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/usr/bin/lua
2+
3+
local uci = require('simple-uci').cursor()
4+
local unistd = require 'posix.unistd'
5+
local util = require 'gluon.util'
6+
local site = require 'gluon.site'
7+
8+
-- Returns true if node was offline long enough to perform domain switch
9+
function switch_after_min_reached()
10+
if not unistd.access("/tmp/gluon_offline") then
11+
return false
12+
end
13+
14+
local switch_after_sec = site.domain_switch.switch_after_offline_mins() * 60
15+
16+
local current_uptime = util.get_uptime()
17+
if current_uptime == nil then
18+
return false
19+
end
20+
21+
local f = util.readfile("/tmp/gluon_offline")
22+
if f == nil then
23+
return false
24+
end
25+
local offline_since = tonumber(f)
26+
27+
local offline_time_sec = current_uptime - offline_since
28+
29+
if offline_time_sec > switch_after_sec then
30+
return true
31+
end
32+
return false
33+
end
34+
35+
-- Returns true in case switch time has passed
36+
function switch_time_passed()
37+
local current_time = os.time()
38+
local switch_time = site.domain_switch.switch_time()
39+
40+
return switch_time < current_time
41+
end
42+
43+
if site.domain_switch() == nil then
44+
-- Switch not applicable for current domain
45+
print("No domain switch defined for the current domain.")
46+
os.exit(0)
47+
end
48+
49+
local current_domain = uci:get("gluon", "core", "domain")
50+
local target_domain = site.domain_switch.target_domain()
51+
52+
if target_domain == current_domain then
53+
-- Current and target domain are equal
54+
print("Domain '" .. target_domain .. "' equals current domain.")
55+
os.exit(1)
56+
end
57+
58+
if not switch_after_min_reached() and not switch_time_passed() then
59+
-- Neither switch-time passed nor switch_after_min reached
60+
os.exit(0)
61+
end
62+
63+
uci:set("gluon", "core", "domain", target_domain)
64+
uci:commit("gluon")
65+
66+
os.execute("gluon-reconfigure")
67+
os.execute("reboot")

scripts/check_site.lua

+9
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,15 @@ function need_array_of(path, array, required)
305305
return need_array(path, function(e) need_one_of(e, array) end, required)
306306
end
307307

308+
function need_domain_name(path)
309+
need_string(path)
310+
need(path, function(domain_name)
311+
local f = io.open(os.getenv('IPKG_INSTROOT') .. '/lib/gluon/domains/' .. domain_name .. '.json')
312+
if not f then return false end
313+
f:close()
314+
return true
315+
end, nil, 'be a valid domain name')
316+
end
308317

309318
local check = assert(loadfile())
310319

0 commit comments

Comments
 (0)