diff --git a/.luacheckrc b/.luacheckrc index 0f17ecc5..96390972 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -29,6 +29,7 @@ files["package/**/check_site.lua"] = { "need", "need_alphanumeric_key", "need_array", + "need_array_elements_exclusive", "need_array_of", "need_boolean", "need_chanlist", diff --git a/package/gluon-core/check_site.lua b/package/gluon-core/check_site.lua index 06b9ac59..cf72f05f 100644 --- a/package/gluon-core/check_site.lua +++ b/package/gluon-core/check_site.lua @@ -77,7 +77,11 @@ need_boolean(in_domain({'mesh', 'vxlan'}), false) local interfaces_roles = {'client', 'uplink', 'mesh'} for _, config in ipairs({'wan', 'lan', 'single'}) do - need_array_of(in_site({'interfaces', config, 'default_roles'}), interfaces_roles, false) + local default_roles = in_site({'interfaces', config, 'default_roles'}) + + need_array_of(default_roles, interfaces_roles, false) + need_array_elements_exclusive(default_roles, 'client', 'mesh', false) + need_array_elements_exclusive(default_roles, 'client', 'uplink', false) end obsolete({'mesh_on_wan'}, 'Use interfaces.wan.default_roles.') diff --git a/package/gluon-core/luasrc/lib/gluon/check-site.lua b/package/gluon-core/luasrc/lib/gluon/check-site.lua index 148f4968..cde55f44 100644 --- a/package/gluon-core/luasrc/lib/gluon/check-site.lua +++ b/package/gluon-core/luasrc/lib/gluon/check-site.lua @@ -55,6 +55,14 @@ local function merge(a, b) return m end +local function contains(table, val) + for i=1,#table do + if table[i] == val then + return true + end + end + return false +end local function path_to_string(path) if path.is_value then @@ -370,6 +378,21 @@ function M.need_array_of(path, array, required) return M.need_array(path, function(e) M.need_one_of(e, array) end, required) end +function M.need_array_elements_exclusive(path, a, b, required) + local val = need_type(path, 'table', required, 'be an array') + if not val then + return nil + end + + if contains(val, a) and contains(val, b) then + config_error(conf_src(path), + 'expected %s to contain only one of the elements %s and %s, but not both.', + path_to_string(path), format(a), format(b)) + end + + return val +end + function M.need_chanlist(path, channels, required) local valid_chanlist = check_chanlist(channels) return M.need(path, valid_chanlist, required,