diff --git a/.gitignore b/.gitignore index 4780aab38..62e8ddc81 100644 --- a/.gitignore +++ b/.gitignore @@ -67,6 +67,7 @@ mix.lock apps/emqx/test/emqx_static_checks_data/master.bpapi # rendered configurations *.conf.rendered +*.conf.rendered.* lux_logs/ /.prepare bom.json diff --git a/apps/emqx/src/config/emqx_config_logger.erl b/apps/emqx/src/config/emqx_config_logger.erl index babf9c431..4b46e43d6 100644 --- a/apps/emqx/src/config/emqx_config_logger.erl +++ b/apps/emqx/src/config/emqx_config_logger.erl @@ -18,7 +18,7 @@ -behaviour(emqx_config_handler). %% API --export([add_handler/0, remove_handler/0]). +-export([add_handler/0, remove_handler/0, refresh_config/0]). -export([post_config_update/5]). -define(LOG, [log]). @@ -31,6 +31,21 @@ remove_handler() -> ok = emqx_config_handler:remove_handler(?LOG), ok. +%% refresh logger config when booting, the override config may have changed after node start. +%% Kernel's app env is confirmed before the node starts, +%% but we only copy cluster-override.conf from other node after this node starts, +%% so we need to refresh the logger config after this node starts. +%% It will not affect the logger config when cluster-override.conf is unchanged. +refresh_config() -> + case emqx:get_raw_config(?LOG, undefined) of + %% no logger config when CT is running. + undefined -> + ok; + Log -> + {ok, _} = emqx:update_config(?LOG, Log), + ok + end. + post_config_update(?LOG, _Req, _NewConf, _OldConf, AppEnvs) -> Kernel = proplists:get_value(kernel, AppEnvs), NewHandlers = proplists:get_value(logger, Kernel, []), diff --git a/apps/emqx/src/emqx_config.erl b/apps/emqx/src/emqx_config.erl index 2fa39d094..ba4095daa 100644 --- a/apps/emqx/src/emqx_config.erl +++ b/apps/emqx/src/emqx_config.erl @@ -333,7 +333,8 @@ init_load(SchemaMod, RawConf, Opts) when is_map(RawConf) -> RootNames = get_root_names(), RawConfAll = raw_conf_with_default(SchemaMod, RootNames, RawConfWithOverrides, Opts), %% check configs against the schema - {_AppEnvs, CheckedConf} = check_config(SchemaMod, RawConfAll, #{}), + {AppEnvs, CheckedConf} = check_config(SchemaMod, RawConfAll, #{}), + save_to_app_env(AppEnvs), ok = save_to_config_map(CheckedConf, RawConfAll). %% keep the raw and non-raw conf has the same keys to make update raw conf easier. @@ -534,23 +535,21 @@ get_root_names() -> maps:get(names, persistent_term:get(?PERSIS_SCHEMA_MODS, #{names => []})). -spec save_configs(app_envs(), config(), raw_config(), raw_config(), update_opts()) -> ok. -save_configs(_AppEnvs, Conf, RawConf, OverrideConf, Opts) -> +save_configs(AppEnvs, Conf, RawConf, OverrideConf, Opts) -> %% We first try to save to override.conf, because saving to files is more error prone %% than saving into memory. ok = save_to_override_conf(OverrideConf, Opts), - %% We may need also support hot config update for the apps that use application envs. - %% If that is the case uncomment the following line to update the configs to app env - %save_to_app_env(_AppEnvs), + save_to_app_env(AppEnvs), save_to_config_map(Conf, RawConf). +%% we ignore kernel app env, +%% because the old app env will be used in emqx_config_logger:post_config_update/5 +-define(IGNORE_APPS, [kernel]). + -spec save_to_app_env([tuple()]) -> ok. -save_to_app_env(AppEnvs) -> - lists:foreach( - fun({AppName, Envs}) -> - [application:set_env(AppName, Par, Val) || {Par, Val} <- Envs] - end, - AppEnvs - ). +save_to_app_env(AppEnvs0) -> + AppEnvs = lists:filter(fun({App, _}) -> not lists:member(App, ?IGNORE_APPS) end, AppEnvs0), + application:set_env(AppEnvs). -spec save_to_config_map(config(), raw_config()) -> ok. save_to_config_map(Conf, RawConf) -> @@ -582,6 +581,7 @@ save_to_override_conf(RawConf, Opts) -> add_handlers() -> ok = emqx_config_logger:add_handler(), emqx_sys_mon:add_handler(), + emqx_config_logger:refresh_config(), ok. remove_handlers() -> diff --git a/apps/emqx/test/emqx_common_test_helpers.erl b/apps/emqx/test/emqx_common_test_helpers.erl index f440dfc5a..e4f50f2a1 100644 --- a/apps/emqx/test/emqx_common_test_helpers.erl +++ b/apps/emqx/test/emqx_common_test_helpers.erl @@ -408,7 +408,9 @@ catch_call(F) -> C:E:S -> {crashed, {C, E, S}} end. -force_set_config_file_paths(emqx_conf, Paths) -> +force_set_config_file_paths(emqx_conf, [Path] = Paths) -> + Bin = iolist_to_binary(io_lib:format("node.config_files = [~p]~n", [Path])), + ok = file:write_file(Path, Bin, [append]), application:set_env(emqx, config_files, Paths); force_set_config_file_paths(emqx, Paths) -> application:set_env(emqx, config_files, Paths); diff --git a/apps/emqx_conf/src/emqx_conf_schema.erl b/apps/emqx_conf/src/emqx_conf_schema.erl index 90af47aca..7a20a88dc 100644 --- a/apps/emqx_conf/src/emqx_conf_schema.erl +++ b/apps/emqx_conf/src/emqx_conf_schema.erl @@ -463,7 +463,7 @@ fields("node") -> )}, {"config_files", sc( - list(string()), + hoconsc:array(string()), #{ mapping => "emqx.config_files", default => undefined, diff --git a/apps/emqx_conf/test/emqx_conf_app_SUITE.erl b/apps/emqx_conf/test/emqx_conf_app_SUITE.erl index dab4c4919..84ced5362 100644 --- a/apps/emqx_conf/test/emqx_conf_app_SUITE.erl +++ b/apps/emqx_conf/test/emqx_conf_app_SUITE.erl @@ -92,6 +92,14 @@ set_data_dir_env() -> Node = atom_to_list(node()), %% will create certs and authz dir ok = filelib:ensure_dir(Node ++ "/configs/"), + {ok, [ConfigFile]} = application:get_env(emqx, config_files), + NewConfigFile = ConfigFile ++ "." ++ Node, + {ok, _} = file:copy(ConfigFile, NewConfigFile), + Bin = iolist_to_binary(io_lib:format("node.config_files = [~p]~n", [NewConfigFile])), + ok = file:write_file(NewConfigFile, Bin, [append]), + DataDir = iolist_to_binary(io_lib:format("node.data_dir = ~p~n", [Node])), + ok = file:write_file(NewConfigFile, DataDir, [append]), + application:set_env(emqx, config_files, [NewConfigFile]), application:set_env(emqx, data_dir, Node), application:set_env(emqx, cluster_override_conf_file, Node ++ "/configs/cluster-override.conf"), ok.