diff --git a/changelogs/unreleased/box-info-config.md b/changelogs/unreleased/box-info-config.md new file mode 100644 index 0000000000000000000000000000000000000000..ed078dc57042f9e3f19036d948007bca8a617a82 --- /dev/null +++ b/changelogs/unreleased/box-info-config.md @@ -0,0 +1,3 @@ +## feature/config + +* Expose configuration status from `box.info.config` (gh-10044). diff --git a/src/box/lua/info.c b/src/box/lua/info.c index 97b637b3b328207d779187a63e48f6ea12461833..44d28a1725ee6ea6bfc87ea32194d42b672e015b 100644 --- a/src/box/lua/info.c +++ b/src/box/lua/info.c @@ -759,6 +759,42 @@ lbox_info_hostname(struct lua_State *L) return 1; } +static int +lbox_info_config(struct lua_State *L) +{ + /* require('config'):info('v2') */ + lua_getglobal(L, "require"); + lua_pushliteral(L, "config"); + if (lua_pcall(L, 1, 1, 0) != 0) + goto error; + /* Stack: config. */ + lua_getfield(L, -1, "info"); + /* Stack: config, config.info. */ + lua_insert(L, -2); + /* Stack: config.info, config. */ + lua_pushliteral(L, "v2"); + /* Stack: config.info, config, 'v2'. */ + if (lua_pcall(L, 2, 1, 0) != 0) + goto error; + return 1; + +error: + /* + * An error shouldn't occur by construction. + * + * However, box.info() is an important call and we + * shouldn't fail it in any circumstances, including a + * problem in the config:info() implementation. + * + * So, we don't raise an error here and place it to the + * result instead. + */ + lua_newtable(L); + lua_insert(L, -2); + lua_setfield(L, -2, "error"); + return 1; +} + static const struct luaL_Reg lbox_info_dynamic_meta[] = { {"id", lbox_info_id}, {"uuid", lbox_info_uuid}, @@ -784,6 +820,7 @@ static const struct luaL_Reg lbox_info_dynamic_meta[] = { {"synchro", lbox_info_synchro}, {"schema_version", lbox_schema_version}, {"hostname", lbox_info_hostname}, + {"config", lbox_info_config}, {NULL, NULL} }; diff --git a/test/box-luatest/box_info_config_test.lua b/test/box-luatest/box_info_config_test.lua new file mode 100644 index 0000000000000000000000000000000000000000..d429d7acaafad3904ee778aa3135d1edd51e109d --- /dev/null +++ b/test/box-luatest/box_info_config_test.lua @@ -0,0 +1,117 @@ +local t = require('luatest') +local server = require('luatest.server') +local cbuilder = require('test.config-luatest.cbuilder') +local cluster = require('test.config-luatest.cluster') + +local g = t.group() + +g.before_all(cluster.init) +g.after_each(cluster.drop) +g.after_all(cluster.clean) + +g.after_each(function(g) + if g.server ~= nil then + g.server:drop() + g.server = nil + end +end) + +-- Verify box.info.config when tarantool is started from a script. +g.test_with_script = function(g) + g.server = server:new() + g.server:start() + + g.server:exec(function() + local function verify_config(res) + t.assert_equals(res, { + status = 'uninitialized', + alerts = {}, + meta = { + -- No 'active' field, because there is no + -- active configuration. + last = {}, + }, + }) + end + + verify_config(box.info.config) + verify_config(box.info().config) + end) +end + +-- Verify box.info.config when tarantool is started from a config. +g.test_with_config = function(g) + local config = cbuilder.new() + :add_instance('i-001', {}) + :config() + local cluster = cluster.new(g, config) + cluster:start() + + cluster['i-001']:exec(function() + local function verify_config(res) + t.assert_equals(res, { + status = 'ready', + alerts = {}, + meta = { + active = {}, + last = {}, + }, + }) + end + + verify_config(box.info.config) + verify_config(box.info().config) + end) +end + +-- box.info() should work always, even if config:info() is broken. +g.test_broken_config_info = function(g) + local config = cbuilder.new() + :add_instance('i-001', {}) + :config() + local cluster = cluster.new(g, config) + cluster:start() + + cluster['i-001']:exec(function() + local config = require('config') + + local function verify_config(res) + t.assert_equals(res, { + error = 'config:info() is broken', + }) + end + + -- Break the method. + config.info = function(_self, _version) + error('config:info() is broken', 0) + end + + verify_config(box.info.config) + verify_config(box.info().config) + end) +end + +-- box.info() should work always, even if config module is broken. +g.test_broken_config_module = function(g) + local config = cbuilder.new() + :add_instance('i-001', {}) + :config() + local cluster = cluster.new(g, config) + cluster:start() + + cluster['i-001']:exec(function() + local loaders = require('internal.loaders') + + local function verify_config(res) + t.assert_type(res, 'table') + t.assert_str_contains(res.error, "module 'config' not found") + end + + -- Unload the module and break the next require('config'). + package.loaded.config = nil + loaders.builtin.config = nil + + verify_config(box.info.config) + verify_config(box.info().config) + end) +end diff --git a/test/box/info.result b/test/box/info.result index 19bb50a328a2a29daec995f54ddd1c4c3d249311..c1e00d825a9de44cebe7c7ba32f89e184f07ad6b 100644 --- a/test/box/info.result +++ b/test/box/info.result @@ -79,6 +79,7 @@ table.sort(t) t --- - - cluster + - config - election - gc - hostname