-
Notifications
You must be signed in to change notification settings - Fork 376
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This patch introduces initial support for roles. Dependencies are not currently supported for roles. Part of #9078 @TarantoolBot document Title: Roles Two new options have been added: "roles" and "roles_cfg". The first one is an array and the second one is a map. Each of these can be defined per instance, replica set, group, and globally. As with almost all other options, with the exception of those defined as 'map', the 'roles' option for the lower scope will replace the roles for the higher scope. Value roles_cfg however defined as "map", so it will be merged. The "roles" option defines the roles for each instance. A role is a program that runs when a configuration is loaded or reloaded. If a role is defined more than once on an instance, it will still only be run once. Three functions must be defined in the role: validate(), apply() and stop(). Each of these functions should throw an error if it occurs. The "roles_cfg" option specifies the configuration for each role. In this option, the role name is the key and the role configuration is the value. On each run, all roles will be loaded (if necessary) in the order in which they were specified; the configuration for each role will then be validated using the corresponding validate() function in the same order; and then they will all be run with apply() function in the same order. If some roles have been removed from the instance, they will be stopped in reverse order using the stop() function. Example of a role structure: ``` local M = {} -- Validates configuration of the role. -- -- Called on initial configuration apply at startup and on -- configuration reload if the role is enabled for the given instance. -- -- The cfg argument may have arbitrary user provided value, -- including nil. -- -- Must raise an error if the validation fail. function M.validate(cfg) -- <...> end -- Applies the given configuration of the role. -- -- Called on initial configuration apply at startup and on -- configuration reload if the role is enabled for the given instance. -- -- The cfg argument may have arbitrary user provided value, -- including nil. -- -- Must raise an error if the given configuration can't be applied. function M.apply(cfg) -- <...> end -- Stops the role. -- -- Called on configuration reload if the role was enabled before -- and removed now from the list of roles of the given instance. -- -- Should cancel all background fibers and clean up hold -- resources. -- -- Must raise an error if this action can't be performed. function M.stop() -- <...> end return M ```
- Loading branch information
1 parent
0dc3735
commit 5288440
Showing
8 changed files
with
494 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
## feature/config | ||
|
||
* Introduced the initial support for roles - programs that run when | ||
a configuration is loaded or reloaded (gh-9078). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
local log = require('internal.config.utils.log') | ||
|
||
local last_loaded = {} | ||
local last_loaded_names_ordered = {} | ||
|
||
local function stop_roles(roles_to_skip) | ||
for id = #last_loaded_names_ordered, 1, -1 do | ||
local role_name = last_loaded_names_ordered[id] | ||
if roles_to_skip == nil or roles_to_skip[role_name] == nil then | ||
log.verbose('roles.apply: stop role ' .. role_name) | ||
local ok, err = pcall(last_loaded[role_name].stop) | ||
if not ok then | ||
error(('Error stopping role %s: %s'):format(role_name, err), 0) | ||
end | ||
end | ||
end | ||
end | ||
|
||
local function apply(config) | ||
local configdata = config._configdata | ||
local role_names = configdata:get('roles', {use_default = true}) | ||
if role_names == nil or next(role_names) == nil then | ||
stop_roles() | ||
return | ||
end | ||
|
||
-- Remove duplicates. | ||
local roles = {} | ||
local roles_ordered = {} | ||
for _, role_name in pairs(role_names) do | ||
if roles[role_name] == nil then | ||
table.insert(roles_ordered, role_name) | ||
end | ||
roles[role_name] = true | ||
end | ||
|
||
-- Stop removed roles. | ||
stop_roles(roles) | ||
|
||
-- Run roles. | ||
local roles_cfg = configdata:get('roles_cfg', {use_default = true}) or {} | ||
local loaded = {} | ||
local loaded_names_ordered = {} | ||
|
||
-- Load roles. | ||
for _, role_name in ipairs(roles_ordered) do | ||
local role = last_loaded[role_name] | ||
if not role then | ||
log.verbose('roles.apply: load role ' .. role_name) | ||
role = require(role_name) | ||
local funcs = {'validate', 'apply', 'stop'} | ||
for _, func_name in pairs(funcs) do | ||
if type(role[func_name]) ~= 'function' then | ||
local err = 'Role %s does not contain function %s' | ||
error(err:format(role_name, func_name), 0) | ||
end | ||
end | ||
end | ||
loaded[role_name] = role | ||
table.insert(loaded_names_ordered, role_name) | ||
end | ||
|
||
-- Validate configs for all roles. | ||
for _, role_name in ipairs(roles_ordered) do | ||
local ok, err = pcall(loaded[role_name].validate, roles_cfg[role_name]) | ||
if not ok then | ||
error(('Wrong config for role %s: %s'):format(role_name, err), 0) | ||
end | ||
end | ||
|
||
-- Apply configs for all roles. | ||
for _, role_name in ipairs(roles_ordered) do | ||
log.verbose('roles.apply: apply config for role ' .. role_name) | ||
local ok, err = pcall(loaded[role_name].apply, roles_cfg[role_name]) | ||
if not ok then | ||
error(('Error applying role %s: %s'):format(role_name, err), 0) | ||
end | ||
end | ||
|
||
last_loaded = loaded | ||
last_loaded_names_ordered = loaded_names_ordered | ||
end | ||
|
||
return { | ||
name = 'roles', | ||
apply = apply, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.