Skip to content

Commit

Permalink
storage: introduce user_management_mode cfg
Browse files Browse the repository at this point in the history
Closes #435

@TarantoolBot document
Title: vshard: `user_management_mode` cfg option
The option can be specified at the root level and regulates how
much vshard is involved into the user management.

When specified to 'auto' (default), vshard will create the user
as specified in the config URIs, and will grant it all needed
rights to public and internal APIs.

When specified to 'manual', vshard will neither create the user,
nor grant it any rights. It is all expected to be done externally
outside of vshard.
  • Loading branch information
Gerold103 committed Nov 9, 2023
1 parent a4e5315 commit 153067e
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 10 deletions.
8 changes: 8 additions & 0 deletions test/luatest_helpers/vtest.lua
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,14 @@ local function cluster_new(g, cfg)
ivtest.clear_test_cfg_options(cfg)
ivshard.storage.cfg(cfg, box.info.uuid)

if cfg.user_management_mode == 'manual' then
box.schema.user.create('storage', {
password = 'storage',
-- Yes, intentionally false to ensure that the user wasn't
-- created by vshard.
if_not_exists = false,
})
end
if grant_range ~= nil then
box.schema.user.grant('storage', grant_range, nil, nil,
{if_not_exists = true})
Expand Down
138 changes: 138 additions & 0 deletions test/storage-luatest/user_management_mode_test.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
local t = require('luatest')
local vtest = require('test.luatest_helpers.vtest')

local test_group = t.group('storage')

test_group.after_each(function(g)
g.cluster:drop()
g.cluster = nil
end)

test_group.test_user_management_mode_boot_auto = function(g)
local cfg_template = {
sharding = {
{
replicas = {
replica_1_a = {master = true},
replica_1_b = {},
},
},
{
replicas = {
replica_2_a = {master = true},
},
},
},
bucket_count = 2,
user_management_mode = 'auto',
}
local cfg = vtest.config_new(cfg_template)
vtest.cluster_new(g, cfg)
vtest.cluster_bootstrap(g, cfg)
local bid = g.replica_1_a:exec(function(uuid)
local bid = _G.get_first_bucket()
local ok, err = ivshard.storage.bucket_send(bid, uuid,
{timeout = iwait_timeout})
ilt.assert_equals(err, nil)
ilt.assert(ok)
_G.bucket_gc_wait()
return bid
end, {g.replica_2_a:replicaset_uuid()})
--
-- Switch to manual. Still works fine.
--
cfg_template.user_management_mode = 'manual'
cfg = vtest.config_new(cfg_template)
vtest.cluster_cfg(g, cfg)
g.replica_2_a:exec(function(bid, uuid)
local ok, err = ivshard.storage.bucket_send(bid, uuid,
{timeout = iwait_timeout})
ilt.assert_equals(err, nil)
ilt.assert(ok)
_G.bucket_gc_wait()
end, {bid, g.replica_1_a:replicaset_uuid()})
end

test_group.test_user_management_mode_boot_manual_only_replication = function(g)
local cfg_template = {
sharding = {
{
replicas = {
replica_1_a = {master = true},
replica_1_b = {},
},
},
{
replicas = {
replica_2_a = {master = true},
},
},
},
bucket_count = 2,
user_management_mode = 'manual',
test_user_grant_range = 'replication',
}
local cfg = vtest.config_new(cfg_template)
vtest.cluster_new(g, cfg)
vtest.cluster_bootstrap(g, cfg)
--
-- Just replication rights are not enough for vshard operation. It will
-- boot, but any vshard operations between instances won't work.
--
g.replica_1_a:exec(function(uuid)
local bid = _G.get_first_bucket()
local ok, err = ivshard.storage.bucket_send(bid, uuid,
{timeout = iwait_timeout})
if ivutil.version_is_at_least(2, 7, 0, nil, 0, 0) then
ilt.assert_equals(err.type, 'AccessDeniedError')
end
ilt.assert_str_contains(err.message, 'bucket_recv')
ilt.assert(not ok)
end, {g.replica_2_a:replicaset_uuid()})
end

test_group.test_user_management_mode_boot_manual_super = function(g)
local cfg_template = {
sharding = {
{
replicas = {
replica_1_a = {master = true},
replica_1_b = {},
},
},
{
replicas = {
replica_2_a = {master = true},
},
},
},
bucket_count = 2,
user_management_mode = 'manual',
test_user_grant_range = 'super',
}
local cfg = vtest.config_new(cfg_template)
vtest.cluster_new(g, cfg)
vtest.cluster_bootstrap(g, cfg)
local bid = g.replica_1_a:exec(function(uuid)
local bid = _G.get_first_bucket()
local ok, err = ivshard.storage.bucket_send(bid, uuid,
{timeout = iwait_timeout})
ilt.assert_equals(err, nil)
ilt.assert(ok)
_G.bucket_gc_wait()
return bid
end, {g.replica_2_a:replicaset_uuid()})
--
-- Switch to auto. Still works fine.
--
cfg_template.user_management_mode = 'auto'
cfg = vtest.config_new(cfg_template)
vtest.cluster_cfg(g, cfg)
g.replica_2_a:exec(function(bid, uuid)
local ok, err = ivshard.storage.bucket_send(bid, uuid,
{timeout = iwait_timeout})
ilt.assert_equals(err, nil)
ilt.assert(ok)
_G.bucket_gc_wait()
end, {bid, g.replica_1_a:replicaset_uuid()})
end
10 changes: 10 additions & 0 deletions test/unit-luatest/config_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,14 @@ g.test_enum = function()
"Discovery mode must be enum {'on', 'off', 'once', nil}",
vcfg.check, config)
config.discovery_mode = nil

for _, v in pairs({'auto', 'manual'}) do
config.user_management_mode = v
t.assert(vcfg.check(config))
end
config.user_management_mode = 'bad'
t.assert_error_msg_content_equals(
"User management mode must be enum {'auto', 'manual', nil}",
vcfg.check, config)
config.user_management_mode = nil
end
4 changes: 4 additions & 0 deletions vshard/cfg.lua
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,10 @@ local cfg_template = {
name = 'Scheduler bucket move quota', type = 'non-negative number',
is_optional = true, default = consts.DEFAULT_SCHED_MOVE_QUOTA
},
user_management_mode = {
name = 'User management mode', type = 'enum', is_optional = true,
default = 'auto', enum = {'auto', 'manual'},
},
}

--
Expand Down
26 changes: 16 additions & 10 deletions vshard/storage/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -755,13 +755,15 @@ end
-- describes schema before that - 0.1.15.
local function schema_init_0_1_15_0(ctx)
log.info("Initializing schema %s", schema_version_make({0, 1, 15, 0}))
box.schema.user.create(ctx.username, {
password = ctx.password,
if_not_exists = true,
})
-- Replication may has not been granted, if user exists.
box.schema.user.grant(ctx.username, 'replication', nil, nil,
{if_not_exists = true})
if ctx.is_user_auto then
box.schema.user.create(ctx.username, {
password = ctx.password,
if_not_exists = true,
})
-- Replication may has not been granted, if user exists.
box.schema.user.grant(ctx.username, 'replication', nil, nil,
{if_not_exists = true})
end

local bucket = box.schema.space.create('_bucket')
bucket:format({
Expand All @@ -787,10 +789,11 @@ local function schema_init_0_1_15_0(ctx)
'vshard.storage.rebalancer_request_state',
'vshard.storage.rebalancer_apply_routes',
}

for _, name in ipairs(storage_api) do
box.schema.func.create(name, {setuid = true})
box.schema.user.grant(ctx.username, 'execute', 'function', name)
if ctx.is_user_auto then
box.schema.user.grant(ctx.username, 'execute', 'function', name)
end
end

box.space._schema:replace({'vshard_version', 0, 1, 15, 0})
Expand All @@ -811,7 +814,9 @@ local function schema_upgrade_to_0_1_16_0(ctx)
local func = 'vshard.storage._call'
log.info('Create function %s()', func)
box.schema.func.create(func, {setuid = true})
box.schema.user.grant(ctx.username, 'execute', 'function', func)
if ctx.is_user_auto then
box.schema.user.grant(ctx.username, 'execute', 'function', func)
end
-- Don't drop old functions in the same version. Removal can
-- happen only after 0.1.16. Or there should appear support of
-- rebalancing from too old versions. Drop of these functions
Expand Down Expand Up @@ -3473,6 +3478,7 @@ local function storage_cfg(cfg, this_replica_uuid, is_reload)
is_master = is_master,
username = uri.login,
password = uri.password,
is_user_auto = vshard_cfg.user_management_mode == 'auto',
}
schema_upgrade(upgrade_ctx)

Expand Down

0 comments on commit 153067e

Please sign in to comment.