From e670f92bc7b80598c3bda20447bcd9f4c6d6e746 Mon Sep 17 00:00:00 2001 From: Mergen Imeev <imeevma@tarantool.org> Date: Fri, 18 Aug 2023 16:58:40 +0300 Subject: [PATCH] config: move URI compiling instance_config This patch moves the code that compiles iproto.advertise.peer to instance_config. This will allow us to use this function for iproto.advertise.sharding. Part of #9007 NO_DOC=refactoring NO_TEST=refactoring NO_CHANGELOG=refactoring --- src/box/lua/config/applier/box_cfg.lua | 115 +---------------------- src/box/lua/config/instance_config.lua | 121 ++++++++++++++++++++++++- test/config-luatest/basic_test.lua | 2 +- 3 files changed, 121 insertions(+), 117 deletions(-) diff --git a/src/box/lua/config/applier/box_cfg.lua b/src/box/lua/config/applier/box_cfg.lua index c1eb682592..619cf7ed48 100644 --- a/src/box/lua/config/applier/box_cfg.lua +++ b/src/box/lua/config/applier/box_cfg.lua @@ -1,121 +1,10 @@ -local urilib = require('uri') local fio = require('fio') local log = require('internal.config.utils.log') local instance_config = require('internal.config.instance_config') --- Accept a comma separated list of URIs and return the first one --- that is suitable to create a client socket (not just to listen --- on the server as, say, 0.0.0.0:3301 or localhost:0). --- --- See the uri_is_suitable_to_connect() method in the instance --- schema object for details. -local function find_suitable_uri_to_connect(uris) - for _, u in ipairs(urilib.parse_many(uris)) do - if instance_config:uri_is_suitable_to_connect(u) then - -- The urilib.format() call has the second optional - -- argument `write_password`. Let's assume that the - -- given URIs are to listen on them and so have no - -- user/password. - return urilib.format(u) - end - end - return nil -end - -local function find_password(configdata, username) - -- The guest user can't have a password. - if username == 'guest' then - return nil - end - - -- Find a user definition in the config. - local user_def = configdata:get('credentials.users.' .. username, - {use_default = true}) - if user_def == nil then - error(('box_cfg.apply: cannot find user %s in the config to use its ' .. - 'password in a replication peer URI'):format(username), 0) - end - - -- There is a user definition without a password. Let's assume - -- that the user has no password. - if user_def.password ~= nil then - return user_def.password - end - return nil -end - local function peer_uri(configdata, peer_name) - local opts = {peer = peer_name, use_default = true} - local listen = configdata:get('iproto.listen', opts) - local advertise = configdata:get('iproto.advertise.peer', opts) - - if advertise ~= nil and not advertise:endswith('@') then - -- The iproto.advertise.peer option contains an URI. - -- - -- There are the following cases. - -- - -- * host:port - -- * user@host:port - -- * user:pass@host:port - -- - -- Note: the host:port part may represent a Unix domain - -- socket: host = 'unix/', port = '/path/to/socket'. - -- - -- The second case needs additional handling: we should - -- find password for the given user in the 'credential' - -- section of the config. - -- - -- Otherwise, the URI is returned as is. - local u, err = urilib.parse(advertise) - -- NB: The URI is validated, so the parsing can't fail. - assert(u ~= nil, err) - if u.login ~= nil and u.password == nil then - u.password = find_password(configdata, u.login) - return urilib.format(u, true) - end - return advertise - elseif listen ~= nil then - -- The iproto.advertise.peer option has no URI. - -- - -- There are the following cases. - -- - -- * <no iproto.advertise.peer> - -- * user@ - -- * user:pass@ - -- - -- In any case we should find an URI suitable to create a - -- client socket in iproto.listen option. After this, add - -- the auth information if any. - local uri = find_suitable_uri_to_connect(listen) - if uri == nil then - return nil - end - - -- No additional auth information in iproto.advertise.peer: - -- return the listen URI as is. - if advertise == nil then - return uri - end - - -- Extract user and password from the iproto.advertise - -- option. If no password given, find it in the - -- 'credentials' section of the config. - assert(advertise:endswith('@')) - local auth = advertise:sub(1, -2):split(':', 1) - local username = auth[1] - local password = auth[2] or find_password(configdata, username) - - -- Rebuild the listen URI with the given username and - -- password, - local u, err = urilib.parse(uri) - -- NB: The URI is validated, so the parsing can't fail. - assert(u ~= nil, err) - u.login = username - u.password = password - return urilib.format(u, true) - end - - return nil + local iconfig = configdata._peers[peer_name].iconfig_def + return instance_config:instance_uri(iconfig, 'peer') end local function peer_uris(configdata) diff --git a/src/box/lua/config/instance_config.lua b/src/box/lua/config/instance_config.lua index 7d2a86ded0..c0ddfd655f 100644 --- a/src/box/lua/config/instance_config.lua +++ b/src/box/lua/config/instance_config.lua @@ -180,7 +180,7 @@ end -- -- It means 'bind to a random free port' for the bind() call, -- but it has no meaning at the connect() call on a client. -local function uri_is_suitable_to_connect(_, uri) +local function uri_is_suitable_to_connect(uri) assert(uri ~= nil) if uri.ipv4 == '0.0.0.0' then @@ -222,7 +222,7 @@ local function advertise_peer_uri_validate(data, w) end w.error('Unable to parse an URI: %s', err) end - local ok, err = uri_is_suitable_to_connect(nil, uri) + local ok, err = uri_is_suitable_to_connect(uri) if not ok then w.error(err) end @@ -232,6 +232,121 @@ local function advertise_peer_uri_validate(data, w) return uri end +-- Accept a comma separated list of URIs and return the first one +-- that is suitable to create a client socket (not just to listen +-- on the server as, say, 0.0.0.0:3301 or localhost:0). +-- +-- See the uri_is_suitable_to_connect() method in the instance +-- schema object for details. +local function find_suitable_uri_to_connect(uris) + for _, u in ipairs(urilib.parse_many(uris)) do + if uri_is_suitable_to_connect(u) then + -- The urilib.format() call has the second optional + -- argument `write_password`. Let's assume that the + -- given URIs are to listen on them and so have no + -- user/password. + return urilib.format(u) + end + end + return nil +end + +local function find_password(self, iconfig, username) + -- The guest user can't have a password. + if username == 'guest' then + return nil + end + + -- Find a user definition in the config. + local user_def = self:get(iconfig, 'credentials.users.' .. username) + if user_def == nil then + error(('Cannot find user %s in the config to use its password in a '.. + 'replication peer URI'):format(username), 0) + end + + -- There is a user definition without a password. Let's assume + -- that the user has no password. + if user_def.password ~= nil then + return user_def.password + end + return nil +end + +local function instance_uri(self, iconfig, advertise_type) + assert(advertise_type == 'peer' or advertise_type == 'sharding') + local listen = self:get(iconfig, 'iproto.listen') + local advertise = self:get(iconfig, 'iproto.advertise.'..advertise_type) + if advertise == nil and advertise_type == 'sharding' then + advertise = self:get(iconfig, 'iproto.advertise.peer') + end + if advertise ~= nil and not advertise:endswith('@') then + -- The iproto.advertise.* option contains an URI. + -- + -- There are the following cases. + -- + -- * host:port + -- * user@host:port + -- * user:pass@host:port + -- + -- Note: the host:port part may represent a Unix domain + -- socket: host = 'unix/', port = '/path/to/socket'. + -- + -- The second case needs additional handling: we should + -- find password for the given user in the 'credential' + -- section of the config. + -- + -- Otherwise, the URI is returned as is. + local u, err = urilib.parse(advertise) + -- NB: The URI is validated, so the parsing can't fail. + assert(u ~= nil, err) + if u.login ~= nil and u.password == nil then + u.password = find_password(self, iconfig, u.login) + return urilib.format(u, true) + end + return advertise + elseif listen ~= nil then + -- The iproto.advertise.* option has no URI. + -- + -- There are the following cases. + -- + -- * <no iproto.advertise.*> + -- * user@ + -- * user:pass@ + -- + -- In any case we should find an URI suitable to create a + -- client socket in iproto.listen option. After this, add + -- the auth information if any. + local uri = find_suitable_uri_to_connect(listen) + if uri == nil then + return nil + end + + -- No additional auth information in iproto.advertise.*: + -- return the listen URI as is. + if advertise == nil then + return uri + end + + -- Extract user and password from the iproto.advertise + -- option. If no password given, find it in the + -- 'credentials' section of the config. + assert(advertise:endswith('@')) + local auth = advertise:sub(1, -2):split(':', 1) + local username = auth[1] + local password = auth[2] or find_password(self, iconfig, username) + + -- Rebuild the listen URI with the given username and + -- password, + local u, err = urilib.parse(uri) + -- NB: The URI is validated, so the parsing can't fail. + assert(u ~= nil, err) + u.login = username + u.password = password + return urilib.format(u, true) + end + return nil +end + local function feedback_apply_default_if(_data, _w) return box.internal.feedback_daemon ~= nil end @@ -1418,6 +1533,6 @@ return schema.new('instance_config', schema.record({ config_version = CONFIG_VERSION, }), { methods = { - uri_is_suitable_to_connect = uri_is_suitable_to_connect, + instance_uri = instance_uri, }, }) diff --git a/test/config-luatest/basic_test.lua b/test/config-luatest/basic_test.lua index a7ed62eb48..b4d55396dd 100644 --- a/test/config-luatest/basic_test.lua +++ b/test/config-luatest/basic_test.lua @@ -110,7 +110,7 @@ g.test_example_replicaset_election_failover = function(g) t.assert_equals(rw_count, 1) end -local err_msg_cannot_find_user = 'box_cfg.apply: cannot find user unknown ' .. +local err_msg_cannot_find_user = 'Cannot find user unknown ' .. 'in the config to use its password in a replication peer URI' local err_msg_no_suitable_uris = 'replication.peers construction for ' .. 'instance "instance-001" of replicaset "replicaset-001" of group ' .. -- GitLab