Skip to content

Commit c106a7a

Browse files
roles: introduce router configuration
This patch introduces `roles.crud-router` role configuration through `roles_cfg`, similar to existing Cartridge clusterwide configuration support. For now, storages don't have any configuration, so they remain unchanged. After this patch, Tarantool 3 roles have all features supported in Cartridge roles. Closes #415
1 parent 5cbb3c5 commit c106a7a

File tree

7 files changed

+168
-25
lines changed

7 files changed

+168
-25
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1010
### Added
1111
* Asynchronous bootstrap support for storages (#412).
1212
* Tarantool 3 roles for setting up crud routers and storages (#415).
13+
* Ability to configure crud through Tarantool 3 roles configuration (#415).
1314

1415
### Changed
1516
* Explicitly forbid datetime interval conditions (#373).

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2102,6 +2102,21 @@ issues.
21022102
5. Start the application cluster. You can check whether asynchronous bootstrap
21032103
had finished through `crud.storage_info()` calls on router.
21042104

2105+
6. Configure the statistics with roles configuration
2106+
(see `crud.cfg` options in [statistics](#statistics) section):
2107+
```yaml
2108+
roles:
2109+
- roles.crud-router
2110+
roles_cfg:
2111+
roles.crud-router:
2112+
stats: true
2113+
stats_driver: metrics
2114+
stats_quantiles: false
2115+
stats_quantile_tolerated_error: 0.001
2116+
stats_quantile_age_buckets_count: 5
2117+
stats_quantile_max_age_time: 180
2118+
```
2119+
21052120
Now your cluster contains storages that are configured to be used for
21062121
CRUD-operations.
21072122
You can simply call CRUD functions on the router to insert, select, and update

roles/crud-router.lua

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ local errors = require('errors')
33
local crud = require('crud')
44
local common_role_utils = require('crud.common.roles')
55
local common_utils = require('crud.common.utils')
6+
local stats = require('crud.stats')
67

78
local TarantoolRoleConfigurationError = errors.new_class('TarantoolRoleConfigurationError')
89

@@ -12,15 +13,71 @@ TarantoolRoleConfigurationError:assert(
1213
('Tarantool 3 role is not supported for Tarantool %s, use 3.0.2 or newer'):format(tarantool_version)
1314
)
1415

15-
local function validate()
16+
17+
local function validate_enabled_on_sharding_router()
1618
TarantoolRoleConfigurationError:assert(
1719
common_role_utils.is_sharding_role_enabled('router'),
1820
'Instance must be a sharding router to enable roles.crud-router'
1921
)
2022
end
2123

22-
local function apply()
24+
local cfg_types = {
25+
stats = 'boolean',
26+
stats_driver = 'string',
27+
stats_quantiles = 'boolean',
28+
stats_quantile_tolerated_error = 'number',
29+
stats_quantile_age_buckets_count = 'number',
30+
stats_quantile_max_age_time = 'number',
31+
}
32+
33+
local cfg_values = {
34+
stats_driver = function(value)
35+
TarantoolRoleConfigurationError:assert(
36+
stats.is_driver_supported(value),
37+
'Invalid "stats_driver" field value: %q is not supported',
38+
value
39+
)
40+
end,
41+
}
42+
43+
local function validate_roles_cfg(roles_cfg)
44+
if roles_cfg == nil then
45+
return
46+
end
47+
48+
TarantoolRoleConfigurationError:assert(
49+
type(roles_cfg) == 'table',
50+
'roles_cfg must be a table'
51+
)
52+
53+
for name, value in pairs(roles_cfg) do
54+
TarantoolRoleConfigurationError:assert(
55+
cfg_types[name] ~= nil,
56+
'Unknown field %q', name
57+
)
58+
59+
TarantoolRoleConfigurationError:assert(
60+
type(value) == cfg_types[name],
61+
'Invalid %q field type: expected %s, got %s',
62+
name, cfg_types[name], type(value)
63+
)
64+
65+
if cfg_values[name] ~= nil then
66+
cfg_values[name](value)
67+
end
68+
end
69+
end
70+
71+
local function validate(roles_cfg)
72+
validate_enabled_on_sharding_router()
73+
74+
validate_roles_cfg(roles_cfg)
75+
end
76+
77+
local function apply(roles_cfg)
2378
crud.init_router()
79+
80+
crud.cfg(roles_cfg)
2481
end
2582

2683
local function stop()

test/helper.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,4 +1468,8 @@ function helpers.skip_if_tarantool3_crud_roles_unsupported()
14681468
("Tarantool %s does not support crud roles"):format(version))
14691469
end
14701470

1471+
function helpers.skip_if_not_config_backend(backend)
1472+
t.skip_if(backend ~= helpers.backend.CONFIG, "The test is for Tarantool 3 with config only")
1473+
end
1474+
14711475
return helpers

test/integration/cfg_test.lua

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -180,32 +180,59 @@ end
180180

181181
local role_cfg_error_cases = {
182182
wrong_section_type = {
183-
args = {crud = 'enabled'},
184-
err = 'Configuration \\\"crud\\\" section must be a table',
183+
args = 'enabled',
184+
err_cartridge = 'Configuration \\\"crud\\\" section must be a table',
185+
err_tarantool3 = 'Wrong config for role roles.crud-router: TarantoolRoleConfigurationError: '..
186+
'roles_cfg must be a table',
185187
},
186188
wrong_structure = {
187-
args = {crud = {crud = {stats = true}}},
188-
err = '\\\"crud\\\" section is already presented as a name of \\\"crud.yml\\\", ' ..
189-
'do not use it as a top-level section name',
189+
args = {crud = {stats = true}},
190+
err_cartridge = '\\\"crud\\\" section is already presented as a name of \\\"crud.yml\\\", ' ..
191+
'do not use it as a top-level section name',
192+
err_tarantool3 = 'Wrong config for role roles.crud-router: TarantoolRoleConfigurationError: '..
193+
'Unknown field \"crud\"',
190194
},
191195
wrong_type = {
192-
args = {crud = {stats = 'enabled'}},
193-
err = 'Invalid crud configuration field \\\"stats\\\" type: expected boolean, got string',
196+
args = {stats = 'enabled'},
197+
err_cartridge = 'Invalid crud configuration field \\\"stats\\\" type: expected boolean, got string',
198+
err_tarantool3 = 'Wrong config for role roles.crud-router: TarantoolRoleConfigurationError: '..
199+
'Invalid \"stats\" field type: expected boolean, got string',
194200
},
195201
wrong_value = {
196-
args = {crud = {stats_driver = 'prometheus'}},
197-
err = 'Invalid crud configuration field \\\"stats_driver\\\" value: \\\"prometheus\\\" is not supported',
202+
args = {stats_driver = 'prometheus'},
203+
err_cartridge = 'Invalid crud configuration field \\\"stats_driver\\\" value: '..
204+
'\\\"prometheus\\\" is not supported',
205+
err_tarantool3 = 'Wrong config for role roles.crud-router: TarantoolRoleConfigurationError: '..
206+
'Invalid \"stats_driver\" field value: \"prometheus\" is not supported',
198207
}
199208
}
200209

201210
for name, case in pairs(role_cfg_error_cases) do
202-
group['test_role_cfg_' .. name] = function(g)
211+
group['test_cartridge_role_cfg_' .. name] = function(g)
203212
helpers.skip_not_cartridge_backend(g.params.backend)
204213
local success, error = pcall(function()
205-
g.router:upload_config(case.args)
214+
g.router:upload_config({
215+
crud = case.args,
216+
})
206217
end)
207218

208219
t.assert_equals(success, false)
209-
t.assert_str_contains(error.response.body, case.err)
220+
t.assert_str_contains(error.response.body, case.err_cartridge)
221+
end
222+
223+
group['test_tarantool3_role_cfg_' .. name] = function(g)
224+
helpers.skip_if_not_config_backend(g.params.backend)
225+
local success, error = pcall(function()
226+
local cfg = g.cluster:cfg()
227+
228+
cfg.groups['routers'].roles_cfg = {
229+
['roles.crud-router'] = case.args,
230+
}
231+
232+
g.cluster:reload_config(cfg)
233+
end)
234+
235+
t.assert_equals(success, false)
236+
t.assert_str_contains(tostring(error), case.err_tarantool3)
210237
end
211238
end

test/integration/stats_test.lua

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,19 @@ local matrix = helpers.backend_matrix({
99
{ way = 'call', args = { driver = 'metrics', quantiles = false }},
1010
{ way = 'call', args = { driver = 'metrics', quantiles = true }},
1111
})
12-
table.insert(matrix, {backend = helpers.backend.CARTRIDGE,
13-
way = 'role', args = { driver = 'local' },
14-
})
15-
table.insert(matrix, {backend = helpers.backend.CARTRIDGE,
16-
way = 'role', args = { driver = 'metrics', quantiles = false },
17-
})
18-
table.insert(matrix, {backend = helpers.backend.CARTRIDGE,
19-
way = 'role', args = { driver = 'metrics', quantiles = true },
20-
})
12+
13+
for _, backend in ipairs({helpers.backend.CARTRIDGE, helpers.backend.CONFIG}) do
14+
table.insert(matrix, {backend = backend,
15+
way = 'role', args = { driver = 'local' },
16+
})
17+
table.insert(matrix, {backend = backend,
18+
way = 'role', args = { driver = 'metrics', quantiles = false },
19+
})
20+
table.insert(matrix, {backend = backend,
21+
way = 'role', args = { driver = 'metrics', quantiles = true },
22+
})
23+
end
24+
2125
local pgroup = t.group('stats_integration', matrix)
2226

2327
matrix = helpers.backend_matrix({
@@ -57,7 +61,17 @@ local call_cfg = function(g, way, cfg)
5761
require('crud').cfg(...)
5862
]], { cfg })
5963
elseif way == 'role' then
60-
g.router:upload_config{crud = cfg}
64+
if g.params.backend == helpers.backend.CARTRIDGE then
65+
g.router:upload_config{crud = cfg}
66+
elseif g.params.backend == helpers.backend.CONFIG then
67+
local cluster_cfg = g.cluster:cfg()
68+
69+
cluster_cfg.groups['routers'].roles_cfg = {
70+
['roles.crud-router'] = cfg,
71+
}
72+
73+
g.cluster:reload_config(cluster_cfg)
74+
end
6175
end
6276
end
6377

test/tarantool3_helpers/cluster.lua

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,8 +297,33 @@ function Cluster:cfg(new_config)
297297
return table.deepcopy(self.config)
298298
end
299299

300+
local function strip_all_entries(t, name)
301+
if type(t) ~= 'table' then
302+
return t
303+
end
304+
305+
t[name] = nil
306+
307+
for k, v in pairs(t) do
308+
t[k] = strip_all_entries(v, name)
309+
end
310+
311+
return t
312+
end
313+
314+
local function check_only_roles_cfg_changed_in_groups(old_groups, new_groups)
315+
old_groups = table.deepcopy(old_groups)
316+
new_groups = table.deepcopy(new_groups)
317+
318+
local old_groups_no_roles_cfg = strip_all_entries(old_groups, 'roles_cfg')
319+
local new_groups_no_roles_cfg = strip_all_entries(new_groups, 'roles_cfg')
320+
321+
t.assert_equals(new_groups_no_roles_cfg, old_groups_no_roles_cfg,
322+
'groups reload supports only roles_cfg reload')
323+
end
324+
300325
function Cluster:reload_config(new_config)
301-
t.assert_equals(new_config.groups, self.config.groups, 'groups reload is not supported yet')
326+
check_only_roles_cfg_changed_in_groups(self.config.groups, new_config.groups)
302327

303328
for _, server in ipairs(self.servers) do
304329
write_config(self.dirs[server], new_config)

0 commit comments

Comments
 (0)