diff --git a/CHANGELOG.md b/CHANGELOG.md index a6d729bd..d68533f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. * `crud.readview` resource cleanup on garbage collect (#379). * `doc/playground.lua` does not work with Tarantool 3 (#371). * Tests with Tarantool 3 (#364). +* VShard storage user have not execution rights for internal functions (#366). ## [1.3.0] - 27-09-23 diff --git a/README.md b/README.md index c938caad..e871893c 100644 --- a/README.md +++ b/README.md @@ -86,11 +86,14 @@ The CRUD operations should be called from router. All VShard storages should call `crud.init_storage()` after `vshard.storage.cfg()` (or enable the `crud-storage` role for Cartridge) first to initialize storage-side functions that are used to manipulate data -across the cluster. +across the cluster. The storage-side functions have the same access +as a user calling `crud.init_storage()`. Therefore, if `crud` do not have +enough access to modify some space, then you need to give access to the user. All VShard routers should call `crud.init_router()` after `vshard.router.cfg()` (or enable the `crud-router` role for Cartridge) to make `crud` functions -callable via `net.box`. +callable via `net.box`. If a user is allowed to execute `crud` functions on +the router-side then the user does not need additional access on storages. You can check out an example of the configuration for local development (a single instance that combines router and storage) in diff --git a/crud.lua b/crud.lua index d2edb907..80c46828 100644 --- a/crud.lua +++ b/crud.lua @@ -23,6 +23,9 @@ local stats = require('crud.stats') local readview = require('crud.readview') local schema = require('crud.schema') +local vshard = require('vshard') +local luri = require('uri') + local crud = {} -- @refer crud.version @@ -165,28 +168,54 @@ crud.schema = schema.call -- @function init -- function crud.init_storage() + if type(box.cfg) ~= 'table' then + error('box.cfg() must be called first') + end + + local ok, storage_info = pcall(vshard.storage.info) + if not ok then + error('vshard.storage.cfg() must be called first') + end + + local box_info = box.info() + local replicaset_uuid + if box_info.replicaset ~= nil then + replicaset_uuid = box_info.replicaset.uuid + else + replicaset_uuid = box_info.cluster.uuid + end + local replicaset_info = storage_info.replicasets[replicaset_uuid] + if replicaset_info == nil or replicaset_info.master == nil then + error(string.format('Failed to find a vshard configuration for ' .. + ' replicaset with replicaset_uuid %s.', + replicaset_uuid)) + end + local user = luri.parse(replicaset_info.master.uri).login or 'guest' + if rawget(_G, '_crud') == nil then rawset(_G, '_crud', {}) end - insert.init() - insert_many.init() - get.init() - replace.init() - replace_many.init() - update.init() - upsert.init() - upsert_many.init() - delete.init() - select.init() - truncate.init() - len.init() - count.init() - borders.init() - sharding_metadata.init() - readview.init() - - _G._crud.storage_info_on_storage = utils.storage_info_on_storage + insert.init(user) + insert_many.init(user) + get.init(user) + replace.init(user) + replace_many.init(user) + update.init(user) + upsert.init(user) + upsert_many.init(user) + delete.init(user) + select.init(user) + truncate.init(user) + len.init(user) + count.init(user) + borders.init(user) + sharding_metadata.init(user) + readview.init(user) + + utils.init_storage_call(user, 'storage_info_on_storage', + utils.storage_info_on_storage + ) end function crud.init_router() diff --git a/crud/borders.lua b/crud/borders.lua index 68a579e1..5604105a 100644 --- a/crud/borders.lua +++ b/crud/borders.lua @@ -13,7 +13,8 @@ local BorderError = errors.new_class('BorderError', {capture_stack = false}) local borders = {} -local STAT_FUNC_NAME = '_crud.get_border_on_storage' +local STAT_FUNC_NAME = 'get_border_on_storage' +local CRUD_STAT_FUNC_NAME = utils.get_storage_call(STAT_FUNC_NAME) local function get_border_on_storage(border_name, space_name, index_id, field_names, fetch_latest_metadata) @@ -42,8 +43,8 @@ local function get_border_on_storage(border_name, space_name, index_id, field_na }) end -function borders.init() - _G._crud.get_border_on_storage = get_border_on_storage +function borders.init(user) + utils.init_storage_call(user, STAT_FUNC_NAME, get_border_on_storage) end local is_closer @@ -111,7 +112,7 @@ local function call_get_border_on_router(vshard_router, border_name, space_name, timeout = opts.timeout, } local results, err, storages_info = call.map(vshard_router, - STAT_FUNC_NAME, + CRUD_STAT_FUNC_NAME, {border_name, space_name, index.id, field_names, opts.fetch_latest_metadata}, call_opts ) diff --git a/crud/common/sharding/sharding_metadata.lua b/crud/common/sharding/sharding_metadata.lua index cc5a2212..10e77e09 100644 --- a/crud/common/sharding/sharding_metadata.lua +++ b/crud/common/sharding/sharding_metadata.lua @@ -4,6 +4,7 @@ local log = require('log') local call = require('crud.common.call') local const = require('crud.common.const') +local utils = require('crud.common.utils') local dev_checks = require('crud.common.dev_checks') local router_cache = require('crud.common.sharding.router_metadata_cache') local storage_cache = require('crud.common.sharding.storage_metadata_cache') @@ -13,7 +14,8 @@ local sharding_utils = require('crud.common.sharding.utils') local FetchShardingMetadataError = errors.new_class('FetchShardingMetadataError', {capture_stack = false}) -local FETCH_FUNC_NAME = '_crud.fetch_on_storage' +local FETCH_FUNC_NAME = 'fetch_on_storage' +local CRUD_FETCH_FUNC_NAME = utils.get_storage_call(FETCH_FUNC_NAME) local sharding_metadata_module = {} @@ -107,7 +109,7 @@ local _fetch_on_router = locked(function(vshard_router, space_name, metadata_map return end - local metadata_map, err = call.any(vshard_router, FETCH_FUNC_NAME, {}, { + local metadata_map, err = call.any(vshard_router, CRUD_FETCH_FUNC_NAME, {}, { timeout = timeout }) if err ~= nil then @@ -212,8 +214,8 @@ function sharding_metadata_module.reload_sharding_cache(vshard_router, space_nam end end -function sharding_metadata_module.init() - _G._crud.fetch_on_storage = sharding_metadata_module.fetch_on_storage +function sharding_metadata_module.init(user) + utils.init_storage_call(user, FETCH_FUNC_NAME, sharding_metadata_module.fetch_on_storage) end return sharding_metadata_module diff --git a/crud/common/utils.lua b/crud/common/utils.lua index 38163718..b92478b1 100644 --- a/crud/common/utils.lua +++ b/crud/common/utils.lua @@ -27,6 +27,19 @@ local fiber = require('fiber') local utils = {} +--- Returns a full call string for a storage function name. +-- +-- @param string name a base name of the storage function. +-- +-- @return a full string for the call. +function utils.get_storage_call(name) + dev_checks('string') + + return '_crud.' .. name +end + +local CRUD_STORAGE_INFO_FUNC_NAME = utils.get_storage_call('storage_info_on_storage') + local space_format_cache = setmetatable({}, {__mode = 'k'}) -- copy from LuaJIT lj_char.c @@ -1034,8 +1047,11 @@ function utils.update_storage_call_error_description(err, func_name, replicaset_ return nil end - if err.type == 'ClientError' and type(err.message) == 'string' then - if err.message == string.format("Procedure '%s' is not defined", func_name) then + if (err.type == 'ClientError' or err.type == 'AccessDeniedError') + and type(err.message) == 'string' then + local not_defined_str = string.format("Procedure '%s' is not defined", func_name) + local access_denied_str = string.format("Execute access to function '%s' is denied", func_name) + if err.message == not_defined_str or err.message:startswith(access_denied_str) then if func_name:startswith('_crud.') then err = NotInitializedError:new("Function %s is not registered: " .. "crud isn't initialized on replicaset %q or crud module versions mismatch " .. @@ -1121,7 +1137,7 @@ function utils.storage_info(opts) status = "error", is_master = replicaset.master == replica } - local ok, res = pcall(replica.conn.call, replica.conn, "_crud.storage_info_on_storage", + local ok, res = pcall(replica.conn.call, replica.conn, CRUD_STORAGE_INFO_FUNC_NAME, {}, async_opts) if ok then futures_by_replicas[replica_uuid] = res @@ -1177,6 +1193,31 @@ function utils.storage_info_on_storage() return {status = "running"} end +--- Initializes a storage function by its name. +-- +-- It adds the function into the global scope by its name and required +-- rights to a vshard storage user. +-- +-- @function init_storage_call +-- +-- @param string name a name of the function. +-- @param function func the function. +-- +-- @return nil +function utils.init_storage_call(user, name, func) + dev_checks('string', 'string', 'function') + + rawset(_G['_crud'], name, func) + + if box.info().ro then + return + end + + name = utils.get_storage_call(name) + box.schema.func.create(name, {setuid = true, if_not_exists = true}) + box.schema.user.grant(user, 'execute', 'function', name, {if_not_exists=true}) +end + local expected_vshard_api = { 'routeall', 'route', 'bucket_id_strcrc32', 'callrw', 'callro', 'callbro', 'callre', diff --git a/crud/count.lua b/crud/count.lua index 8c5252e6..b79581cd 100644 --- a/crud/count.lua +++ b/crud/count.lua @@ -17,7 +17,8 @@ local compare_conditions = require('crud.compare.conditions') local CountError = errors.new_class('CountError', {capture_stack = false}) -local COUNT_FUNC_NAME = '_crud.count_on_storage' +local COUNT_FUNC_NAME = 'count_on_storage' +local CRUD_COUNT_FUNC_NAME = utils.get_storage_call(COUNT_FUNC_NAME) local count = {} @@ -85,8 +86,8 @@ local function count_on_storage(space_name, index_id, conditions, opts) return tuples_count end -function count.init() - _G._crud.count_on_storage = count_on_storage +function count.init(user) + utils.init_storage_call(user, COUNT_FUNC_NAME, count_on_storage) end local check_count_safety_rl = ratelimit.new() @@ -240,7 +241,7 @@ local function call_count_on_router(vshard_router, space_name, user_conditions, skip_sharding_hash_check = skip_sharding_hash_check, } - local results, err = call.map(vshard_router, COUNT_FUNC_NAME, { + local results, err = call.map(vshard_router, CRUD_COUNT_FUNC_NAME, { space_name, plan.index_id, plan.conditions, count_opts }, call_opts) diff --git a/crud/delete.lua b/crud/delete.lua index 28a7ceca..1916c14e 100644 --- a/crud/delete.lua +++ b/crud/delete.lua @@ -14,7 +14,8 @@ local DeleteError = errors.new_class('DeleteError', {capture_stack = false}) local delete = {} -local DELETE_FUNC_NAME = '_crud.delete_on_storage' +local DELETE_FUNC_NAME = 'delete_on_storage' +local CRUD_DELETE_FUNC_NAME = utils.get_storage_call(DELETE_FUNC_NAME) local function delete_on_storage(space_name, key, field_names, opts) dev_checks('string', '?', '?table', { @@ -51,8 +52,8 @@ local function delete_on_storage(space_name, key, field_names, opts) }) end -function delete.init() - _G._crud.delete_on_storage = delete_on_storage +function delete.init(user) + utils.init_storage_call(user, DELETE_FUNC_NAME, delete_on_storage) end -- returns result, err, need_reload @@ -127,7 +128,7 @@ local function call_delete_on_router(vshard_router, space_name, key, opts) } local storage_result, err = call.single(vshard_router, - bucket_id_data.bucket_id, DELETE_FUNC_NAME, + bucket_id_data.bucket_id, CRUD_DELETE_FUNC_NAME, {space_name, key, opts.fields, delete_on_storage_opts}, call_opts ) diff --git a/crud/get.lua b/crud/get.lua index 300c2c33..2c154ddf 100644 --- a/crud/get.lua +++ b/crud/get.lua @@ -14,7 +14,8 @@ local GetError = errors.new_class('GetError', {capture_stack = false}) local get = {} -local GET_FUNC_NAME = '_crud.get_on_storage' +local GET_FUNC_NAME = 'get_on_storage' +local CRUD_GET_FUNC_NAME = utils.get_storage_call(GET_FUNC_NAME) local function get_on_storage(space_name, key, field_names, opts) dev_checks('string', '?', '?table', { @@ -49,8 +50,8 @@ local function get_on_storage(space_name, key, field_names, opts) }) end -function get.init() - _G._crud.get_on_storage = get_on_storage +function get.init(user) + utils.init_storage_call(user, GET_FUNC_NAME, get_on_storage) end -- returns result, err, need_reload @@ -125,7 +126,7 @@ local function call_get_on_router(vshard_router, space_name, key, opts) } local storage_result, err = call.single(vshard_router, - bucket_id_data.bucket_id, GET_FUNC_NAME, + bucket_id_data.bucket_id, CRUD_GET_FUNC_NAME, {space_name, key, opts.fields, get_on_storage_opts}, call_opts ) diff --git a/crud/insert.lua b/crud/insert.lua index e931bf0f..c04cca24 100644 --- a/crud/insert.lua +++ b/crud/insert.lua @@ -12,7 +12,8 @@ local InsertError = errors.new_class('InsertError', {capture_stack = false}) local insert = {} -local INSERT_FUNC_NAME = '_crud.insert_on_storage' +local INSERT_FUNC_NAME = 'insert_on_storage' +local CRUD_INSERT_FUNC_NAME = utils.get_storage_call(INSERT_FUNC_NAME) local function insert_on_storage(space_name, tuple, opts) dev_checks('string', 'table', { @@ -52,8 +53,8 @@ local function insert_on_storage(space_name, tuple, opts) }) end -function insert.init() - _G._crud.insert_on_storage = insert_on_storage +function insert.init(user) + utils.init_storage_call(user, INSERT_FUNC_NAME, insert_on_storage) end -- returns result, err, need_reload @@ -102,7 +103,7 @@ local function call_insert_on_router(vshard_router, space_name, original_tuple, } local storage_result, err = call.single(vshard_router, - sharding_data.bucket_id, INSERT_FUNC_NAME, + sharding_data.bucket_id, CRUD_INSERT_FUNC_NAME, {space_name, tuple, insert_on_storage_opts}, call_opts ) diff --git a/crud/insert_many.lua b/crud/insert_many.lua index 255b834b..87c89f86 100644 --- a/crud/insert_many.lua +++ b/crud/insert_many.lua @@ -16,7 +16,8 @@ local InsertManyError = errors.new_class('InsertManyError', {capture_stack = fal local insert_many = {} -local INSERT_MANY_FUNC_NAME = '_crud.insert_many_on_storage' +local INSERT_MANY_FUNC_NAME = 'insert_many_on_storage' +local CRUD_INSERT_MANY_FUNC_NAME = utils.get_storage_call(INSERT_MANY_FUNC_NAME) local function insert_many_on_storage(space_name, tuples, opts) dev_checks('string', 'table', { @@ -122,8 +123,8 @@ local function insert_many_on_storage(space_name, tuples, opts) return inserted_tuples, nil, replica_schema_version end -function insert_many.init() - _G._crud.insert_many_on_storage = insert_many_on_storage +function insert_many.init(user) + utils.init_storage_call(user, INSERT_MANY_FUNC_NAME, insert_many_on_storage) end -- returns result, err, need_reload @@ -175,7 +176,7 @@ local function call_insert_many_on_router(vshard_router, space_name, original_tu local postprocessor = BatchPostprocessor:new(vshard_router) - local rows, errs, storages_info = call.map(vshard_router, INSERT_MANY_FUNC_NAME, nil, { + local rows, errs, storages_info = call.map(vshard_router, CRUD_INSERT_MANY_FUNC_NAME, nil, { timeout = opts.timeout, mode = 'write', iter = iter, diff --git a/crud/len.lua b/crud/len.lua index 7387a13b..6fcc7b2b 100644 --- a/crud/len.lua +++ b/crud/len.lua @@ -8,7 +8,8 @@ local LenError = errors.new_class('LenError', {capture_stack = false}) local len = {} -local LEN_FUNC_NAME = '_crud.len_on_storage' +local LEN_FUNC_NAME = 'len_on_storage' +local CRUD_LEN_FUNC_NAME = utils.get_storage_call(LEN_FUNC_NAME) local function len_on_storage(space_name) dev_checks('string|number') @@ -16,8 +17,8 @@ local function len_on_storage(space_name) return box.space[space_name]:len() end -function len.init() - _G._crud.len_on_storage = len_on_storage +function len.init(user) + utils.init_storage_call(user, LEN_FUNC_NAME, len_on_storage) end --- Calculates the number of tuples in the space for memtx engine @@ -61,7 +62,7 @@ function len.call(space_name, opts) return nil, LenError:new("Space %q doesn't exist", space_name) end - local results, err = vshard_router:map_callrw(LEN_FUNC_NAME, {space_name}, opts) + local results, err = vshard_router:map_callrw(CRUD_LEN_FUNC_NAME, {space_name}, opts) if err ~= nil then return nil, LenError:new("Failed to call len on storage-side: %s", err) diff --git a/crud/readview.lua b/crud/readview.lua index 5a9d7251..79766465 100644 --- a/crud/readview.lua +++ b/crud/readview.lua @@ -18,6 +18,12 @@ local ReadviewError = errors.new_class('ReadviewError', {capture_stack = false}) local has_merger = (utils.tarantool_supports_external_merger() and package.search('tuple.merger')) or utils.tarantool_has_builtin_merger() +local OPEN_FUNC_NAME = 'readview_open_on_storage' +local CRUD_OPEN_FUNC_NAME = utils.get_storage_call(OPEN_FUNC_NAME) +local SELECT_FUNC_NAME = 'select_readview_on_storage' +local CLOSE_FUNC_NAME = 'readview_close_on_storage' +local CRUD_CLOSE_FUNC_NAME = utils.get_storage_call(CLOSE_FUNC_NAME) + if (not utils.tarantool_version_at_least(2, 11, 0)) or (tarantool.package ~= 'Tarantool Enterprise') or (not has_merger) then return { @@ -223,10 +229,10 @@ function Readview_obj:pairs(space_name, user_conditions, opts) return pairs_call(space_name, user_conditions, opts) end -function readview.init() - _G._crud.readview_open_on_storage = readview_open_on_storage - _G._crud.readview_close_on_storage = readview_close_on_storage - _G._crud.select_readview_on_storage = select_readview_on_storage +function readview.init(user) + utils.init_storage_call(user, OPEN_FUNC_NAME, readview_open_on_storage) + utils.init_storage_call(user, CLOSE_FUNC_NAME, readview_close_on_storage) + utils.init_storage_call(user, SELECT_FUNC_NAME, select_readview_on_storage) end function Readview_obj:close(opts) @@ -257,7 +263,7 @@ function Readview_obj:close(opts) for replica_uuid, replica in pairs(replicaset.replicas) do for _, value in pairs(self._uuid) do if replica_uuid == value.uuid then - local replica_result, replica_err = replica.conn:call('_crud.readview_close_on_storage', + local replica_result, replica_err = replica.conn:call(CRUD_CLOSE_FUNC_NAME, {self._uuid}, {timeout = opts.timeout}) if replica_err ~= nil then table.insert(errors, ReadviewError:new("Failed to close Readview on storage: %s", replica_err)) @@ -297,7 +303,7 @@ function Readview_obj.create(vshard_router, opts) setmetatable(readview, Readview_obj) readview._name = opts.name - local results, err, err_uuid = vshard_router:map_callrw('_crud.readview_open_on_storage', + local results, err, err_uuid = vshard_router:map_callrw(CRUD_OPEN_FUNC_NAME, {readview._name}, {timeout = opts.timeout}) if err ~= nil then return nil, diff --git a/crud/replace.lua b/crud/replace.lua index eb400a96..0533641e 100644 --- a/crud/replace.lua +++ b/crud/replace.lua @@ -12,7 +12,8 @@ local ReplaceError = errors.new_class('ReplaceError', { capture_stack = false }) local replace = {} -local REPLACE_FUNC_NAME = '_crud.replace_on_storage' +local REPLACE_FUNC_NAME = 'replace_on_storage' +local CRUD_REPLACE_FUNC_NAME = utils.get_storage_call(REPLACE_FUNC_NAME) local function replace_on_storage(space_name, tuple, opts) dev_checks('string', 'table', { @@ -52,8 +53,8 @@ local function replace_on_storage(space_name, tuple, opts) }) end -function replace.init() - _G._crud.replace_on_storage = replace_on_storage +function replace.init(user) + utils.init_storage_call(user, REPLACE_FUNC_NAME, replace_on_storage) end -- returns result, err, need_reload @@ -101,7 +102,7 @@ local function call_replace_on_router(vshard_router, space_name, original_tuple, timeout = opts.timeout, } local storage_result, err = call.single(vshard_router, - sharding_data.bucket_id, REPLACE_FUNC_NAME, + sharding_data.bucket_id, CRUD_REPLACE_FUNC_NAME, {space_name, tuple, replace_on_storage_opts}, call_opts ) diff --git a/crud/replace_many.lua b/crud/replace_many.lua index c808e607..e9dcb5e0 100644 --- a/crud/replace_many.lua +++ b/crud/replace_many.lua @@ -16,7 +16,8 @@ local ReplaceManyError = errors.new_class('ReplaceManyError', {capture_stack = f local replace_many = {} -local REPLACE_MANY_FUNC_NAME = '_crud.replace_many_on_storage' +local REPLACE_MANY_FUNC_NAME = 'replace_many_on_storage' +local CRUD_REPLACE_MANY_FUNC_NAME = utils.get_storage_call(REPLACE_MANY_FUNC_NAME) local function replace_many_on_storage(space_name, tuples, opts) dev_checks('string', 'table', { @@ -125,8 +126,8 @@ local function replace_many_on_storage(space_name, tuples, opts) return inserted_tuples, nil, replica_schema_version end -function replace_many.init() - _G._crud.replace_many_on_storage = replace_many_on_storage +function replace_many.init(user) + utils.init_storage_call(user, REPLACE_MANY_FUNC_NAME, replace_many_on_storage) end -- returns result, err, need_reload @@ -178,7 +179,7 @@ local function call_replace_many_on_router(vshard_router, space_name, original_t local postprocessor = BatchPostprocessor:new(vshard_router) - local rows, errs, storages_info = call.map(vshard_router, REPLACE_MANY_FUNC_NAME, nil, { + local rows, errs, storages_info = call.map(vshard_router, CRUD_REPLACE_MANY_FUNC_NAME, nil, { timeout = opts.timeout, mode = 'write', iter = iter, diff --git a/crud/select.lua b/crud/select.lua index 74bffdfa..be0ce8ea 100644 --- a/crud/select.lua +++ b/crud/select.lua @@ -12,6 +12,8 @@ local SelectError = errors.new_class('SelectError') local select_module +local SELECT_FUNC_NAME = 'select_on_storage' + local select_module_compat_info = stash.get(stash.name.select_module_compat_info) local has_merger = (utils.tarantool_supports_external_merger() and package.search('tuple.merger')) or utils.tarantool_has_builtin_merger() @@ -123,8 +125,8 @@ local function select_on_storage(space_name, index_id, conditions, opts) return unpack(result) end -function select_module.init() - _G._crud.select_on_storage = select_on_storage +function select_module.init(user) + utils.init_storage_call(user, SELECT_FUNC_NAME, select_on_storage) end return select_module diff --git a/crud/select/compat/common.lua b/crud/select/compat/common.lua index 6d27b956..6d98e490 100644 --- a/crud/select/compat/common.lua +++ b/crud/select/compat/common.lua @@ -1,10 +1,11 @@ local ratelimit = require('crud.ratelimit') +local utils = require('crud.common.utils') local check_select_safety_rl = ratelimit.new() local common = {} -common.SELECT_FUNC_NAME = '_crud.select_on_storage' -common.READVIEW_SELECT_FUNC_NAME ='_crud.select_readview_on_storage' +common.SELECT_FUNC_NAME = utils.get_storage_call('select_on_storage') +common.READVIEW_SELECT_FUNC_NAME = utils.get_storage_call('select_readview_on_storage') common.DEFAULT_BATCH_SIZE = 100 common.check_select_safety = function(space_name, plan, opts) diff --git a/crud/truncate.lua b/crud/truncate.lua index 31cc5842..d3a31d6a 100644 --- a/crud/truncate.lua +++ b/crud/truncate.lua @@ -9,7 +9,8 @@ local TruncateError = errors.new_class('TruncateError', {capture_stack = false}) local truncate = {} -local TRUNCATE_FUNC_NAME = '_crud.truncate_on_storage' +local TRUNCATE_FUNC_NAME = 'truncate_on_storage' +local CRUD_TRUNCATE_FUNC_NAME = utils.get_storage_call(TRUNCATE_FUNC_NAME) local function truncate_on_storage(space_name) dev_checks('string') @@ -22,8 +23,8 @@ local function truncate_on_storage(space_name) return space:truncate() end -function truncate.init() - _G._crud.truncate_on_storage = truncate_on_storage +function truncate.init(user) + utils.init_storage_call(user, TRUNCATE_FUNC_NAME, truncate_on_storage) end --- Truncates specified space @@ -59,7 +60,7 @@ function truncate.call(space_name, opts) end local replicasets = vshard_router:routeall() - local _, err = call.map(vshard_router, TRUNCATE_FUNC_NAME, {space_name}, { + local _, err = call.map(vshard_router, CRUD_TRUNCATE_FUNC_NAME, {space_name}, { mode = 'write', replicasets = replicasets, timeout = opts.timeout, diff --git a/crud/update.lua b/crud/update.lua index cd31f149..80c3f9ee 100644 --- a/crud/update.lua +++ b/crud/update.lua @@ -14,7 +14,8 @@ local UpdateError = errors.new_class('UpdateError', {capture_stack = false}) local update = {} -local UPDATE_FUNC_NAME = '_crud.update_on_storage' +local UPDATE_FUNC_NAME = 'update_on_storage' +local CRUD_UPDATE_FUNC_NAME = utils.get_storage_call(UPDATE_FUNC_NAME) local function update_on_storage(space_name, key, operations, field_names, opts) dev_checks('string', '?', 'table', '?table', { @@ -73,8 +74,8 @@ local function update_on_storage(space_name, key, operations, field_names, opts) return res, err end -function update.init() - _G._crud.update_on_storage = update_on_storage +function update.init(user) + utils.init_storage_call(user, UPDATE_FUNC_NAME, update_on_storage) end -- returns result, err, need_reload @@ -156,7 +157,7 @@ local function call_update_on_router(vshard_router, space_name, key, user_operat } local storage_result, err = call.single(vshard_router, - bucket_id_data.bucket_id, UPDATE_FUNC_NAME, + bucket_id_data.bucket_id, CRUD_UPDATE_FUNC_NAME, {space_name, key, operations, opts.fields, update_on_storage_opts}, call_opts ) diff --git a/crud/upsert.lua b/crud/upsert.lua index 9300915a..71da9da1 100644 --- a/crud/upsert.lua +++ b/crud/upsert.lua @@ -12,7 +12,8 @@ local UpsertError = errors.new_class('UpsertError', { capture_stack = false}) local upsert = {} -local UPSERT_FUNC_NAME = '_crud.upsert_on_storage' +local UPSERT_FUNC_NAME = 'upsert_on_storage' +local CRUD_UPSERT_FUNC_NAME = utils.get_storage_call(UPSERT_FUNC_NAME) local function upsert_on_storage(space_name, tuple, operations, opts) dev_checks('string', 'table', 'table', { @@ -49,8 +50,8 @@ local function upsert_on_storage(space_name, tuple, operations, opts) }) end -function upsert.init() - _G._crud.upsert_on_storage = upsert_on_storage +function upsert.init(user) + utils.init_storage_call(user, UPSERT_FUNC_NAME, upsert_on_storage) end -- returns result, err, need_reload @@ -107,7 +108,7 @@ local function call_upsert_on_router(vshard_router, space_name, original_tuple, } local storage_result, err = call.single(vshard_router, - sharding_data.bucket_id, UPSERT_FUNC_NAME, + sharding_data.bucket_id, CRUD_UPSERT_FUNC_NAME, {space_name, tuple, operations, upsert_on_storage_opts}, call_opts ) diff --git a/crud/upsert_many.lua b/crud/upsert_many.lua index cc0e7aad..c287bfd9 100644 --- a/crud/upsert_many.lua +++ b/crud/upsert_many.lua @@ -16,7 +16,8 @@ local UpsertManyError = errors.new_class('UpsertManyError', {capture_stack = fal local upsert_many = {} -local UPSERT_MANY_FUNC_NAME = '_crud.upsert_many_on_storage' +local UPSERT_MANY_FUNC_NAME = 'upsert_many_on_storage' +local CRUD_UPSERT_MANY_FUNC_NAME = utils.get_storage_call(UPSERT_MANY_FUNC_NAME) local function upsert_many_on_storage(space_name, tuples, operations, opts) dev_checks('string', 'table', 'table', { @@ -119,8 +120,8 @@ local function upsert_many_on_storage(space_name, tuples, operations, opts) return nil, nil, replica_schema_version end -function upsert_many.init() - _G._crud.upsert_many_on_storage = upsert_many_on_storage +function upsert_many.init(user) + utils.init_storage_call(user, UPSERT_MANY_FUNC_NAME, upsert_many_on_storage) end -- returns result, err, need_reload @@ -189,7 +190,7 @@ local function call_upsert_many_on_router(vshard_router, space_name, original_tu local postprocessor = BatchPostprocessor:new(vshard_router) - local _, errs, storages_info = call.map(vshard_router, UPSERT_MANY_FUNC_NAME, nil, { + local _, errs, storages_info = call.map(vshard_router, CRUD_UPSERT_MANY_FUNC_NAME, nil, { timeout = opts.timeout, mode = 'write', iter = iter, diff --git a/doc/playground.lua b/doc/playground.lua index 2453c063..d4e547f0 100755 --- a/doc/playground.lua +++ b/doc/playground.lua @@ -43,9 +43,6 @@ end -- Setup vshard. _G.vshard = vshard -box.once('guest', function() - box.schema.user.grant('guest', 'super') -end) local uri = 'guest@localhost:3301' local cfg = { bucket_count = 3000, diff --git a/test/entrypoint/srv_say_hi/all_init.lua b/test/entrypoint/srv_say_hi/all_init.lua index dee0c40d..01c0edcb 100644 --- a/test/entrypoint/srv_say_hi/all_init.lua +++ b/test/entrypoint/srv_say_hi/all_init.lua @@ -1,11 +1,24 @@ local fiber = require('fiber') +-- Adds execution rights to a function for a vshard storage user. +local function add_storage_execute(func_name) + if type(box.cfg) ~= 'table' then + -- Cartridge, unit tests. + return + end + if box.cfg.read_only == false and box.schema.user.exists('storage') then + box.schema.func.create(func_name, {setuid = true}) + box.schema.user.grant('storage', 'execute', 'function', func_name) + end +end + return function() rawset(_G, 'say_hi_politely', function (to_name) to_name = to_name or "handsome" local my_alias = box.info.id return string.format("HI, %s! I am %s", to_name, my_alias) end) + add_storage_execute('say_hi_politely') rawset(_G, 'say_hi_sleepily', function (time_to_sleep) if time_to_sleep ~= nil then @@ -14,12 +27,14 @@ return function() return "HI" end) + add_storage_execute('say_hi_sleepily') rawset(_G, 'vshard_calls', {}) rawset(_G, 'clear_vshard_calls', function() table.clear(_G.vshard_calls) end) + add_storage_execute('clear_vshard_calls') rawset(_G, 'patch_vshard_calls', function(vshard_call_names) local vshard = require('vshard') @@ -42,4 +57,7 @@ return function() end end end) + add_storage_execute('patch_vshard_calls') + + add_storage_execute('non_existent_func') end diff --git a/test/integration/storages_state_test.lua b/test/integration/storages_state_test.lua index 172baabc..10ccf41a 100644 --- a/test/integration/storages_state_test.lua +++ b/test/integration/storages_state_test.lua @@ -76,10 +76,9 @@ pgroup.test_crud_storage_status_of_stopped_servers = function(g) end pgroup.after_test('test_crud_storage_status_of_stopped_servers', function(g) - g.cluster:server("s2-replica"):start() - g.cluster:server("s2-replica"):exec(function() - require('crud').init_storage() - end) + helpers.stop_cluster(g.cluster, g.params.backend) + g.cluster = nil + helpers.start_default_cluster(g, 'srv_select') end) pgroup.test_disabled_storage_role = function(g) diff --git a/test/performance/perf_test.lua b/test/performance/perf_test.lua index aa01647f..7f8ecc8a 100644 --- a/test/performance/perf_test.lua +++ b/test/performance/perf_test.lua @@ -520,6 +520,14 @@ local vshard_prepare = function(g) for _, server in ipairs(g.cluster.servers) do server.net_box:eval([[ + local function add_storage_execute(func_name) + if box.cfg.read_only == false and box.schema.user.exists('storage') then + box.schema.func.create(func_name, {setuid = true, if_not_exists = true}) + box.schema.user.grant('storage', 'execute', 'function', func_name, + {if_not_exists = true}) + end + end + local function _vshard_insert_storage(space_name, tuple, bucket_id) local space = box.space[space_name] assert(space ~= nil) @@ -529,7 +537,7 @@ local vshard_prepare = function(g) end rawset(_G, '_vshard_insert_storage', _vshard_insert_storage) - + add_storage_execute('_vshard_insert_storage') local function _vshard_select_storage(space_name, key, index_name, iterator, limit) local space = box.space[space_name] @@ -548,7 +556,7 @@ local vshard_prepare = function(g) end rawset(_G, '_vshard_select_storage', _vshard_select_storage) - + add_storage_execute('_vshard_select_storage') local function _vshard_select_customer_by_name_and_age_storage(key) local space = box.space.customers_name_age_key_different_indexes @@ -564,6 +572,7 @@ local vshard_prepare = function(g) rawset(_G, '_vshard_select_customer_by_name_and_age_storage', _vshard_select_customer_by_name_and_age_storage) + add_storage_execute('_vshard_select_customer_by_name_and_age_storage') ]]) end end diff --git a/test/unit/not_initialized_test.lua b/test/unit/not_initialized_test.lua index d7f16657..9c8202f9 100644 --- a/test/unit/not_initialized_test.lua +++ b/test/unit/not_initialized_test.lua @@ -1,6 +1,7 @@ local fio = require('fio') local helpers = require('test.helper') local t = require('luatest') +local server = require('luatest.server') local pgroup = t.group('not-initialized', helpers.backend_matrix({ {}, @@ -62,3 +63,44 @@ pgroup.test_insert = function(g) t.assert_str_contains(err.err, "Failed for %w+%-0000%-0000%-0000%-00000000000%d", true) t.assert_str_contains(err.err, "crud isn't initialized on replicaset") end + +pgroup.test_no_box_cfg = function() + t.assert_error_msg_contains('box.cfg() must be called first', function() + require('crud').init_storage() + end) +end + +pgroup.before_test('test_no_vshard_storage_cfg', function(g) + g.test_server = server:new({alias = 'master'}) + g.test_server:start({wait_until_ready = true}) + + local appdir = fio.abspath(debug.sourcedir() .. '/../../') + g.test_server:exec(function(appdir) + if package.setsearchroot ~= nil then + package.setsearchroot(appdir) + else + package.path = package.path .. appdir .. '/?.lua;' + package.path = package.path .. appdir .. '/?/init.lua;' + package.path = package.path .. appdir .. '/.rocks/share/tarantool/?.lua;' + package.path = package.path .. appdir .. '/.rocks/share/tarantool/?/init.lua;' + package.cpath = package.cpath .. appdir .. '/?.so;' + package.cpath = package.cpath .. appdir .. '/?.dylib;' + package.cpath = package.cpath .. appdir .. '/.rocks/lib/tarantool/?.so;' + package.cpath = package.cpath .. appdir .. '/.rocks/lib/tarantool/?.dylib;' + end + end, {appdir}) +end) + +pgroup.test_no_vshard_storage_cfg = function(g) + t.assert_error_msg_contains('vshard.storage.cfg() must be called first', function() + g.test_server:exec(function() + box.cfg({}) + require('crud').init_storage() + end) + end) +end + +pgroup.after_test('test_no_vshard_storage_cfg', function(g) + g.test_server:stop() + g.test_server = nil +end) diff --git a/test/unit/select_executor_test.lua b/test/unit/select_executor_test.lua index da014875..2623b744 100644 --- a/test/unit/select_executor_test.lua +++ b/test/unit/select_executor_test.lua @@ -1,5 +1,3 @@ -local crud = require('crud') - local select_plan = require('crud.compare.plan') local select_executor = require('crud.select.executor') local select_filters = require('crud.compare.filters') @@ -56,8 +54,6 @@ g.before_all = function() unique = false, if_not_exists = true, }) - - crud.init_storage() end g.after_each(function() diff --git a/test/vshard_helpers/vtest.lua b/test/vshard_helpers/vtest.lua index dc717c77..b0662010 100644 --- a/test/vshard_helpers/vtest.lua +++ b/test/vshard_helpers/vtest.lua @@ -393,7 +393,7 @@ local function cluster_new(g, cfg) cfg.engine = nil require('vshard.storage').cfg(cfg, box.info.uuid) - box.schema.user.grant('storage', 'super') + box.schema.user.grant('storage', 'write,read', 'universe') box.session.su(user) end, {cfg})