feat(config): support deleting a config entry
This commit is contained in:
parent
5b83193413
commit
c0c5bcc698
|
@ -18,6 +18,7 @@
|
|||
-compile({no_auto_import, [get/0, get/1]}).
|
||||
|
||||
-export([ load/0
|
||||
, read_override_conf/0
|
||||
, save_configs/2
|
||||
, save_to_app_env/1
|
||||
, save_to_emqx_config/2
|
||||
|
@ -47,6 +48,7 @@
|
|||
]).
|
||||
|
||||
-export([ update/2
|
||||
, remove/1
|
||||
]).
|
||||
|
||||
%% raw configs is the config that is now parsed and tranlated by hocon schema
|
||||
|
@ -129,7 +131,11 @@ put(KeyPath, Config) ->
|
|||
-spec update(emqx_map_lib:config_key_path(), update_request()) ->
|
||||
ok | {error, term()}.
|
||||
update(ConfKeyPath, UpdateReq) ->
|
||||
emqx_config_handler:update_config(ConfKeyPath, UpdateReq, get_raw()).
|
||||
emqx_config_handler:update_config(ConfKeyPath, UpdateReq).
|
||||
|
||||
-spec remove(emqx_map_lib:config_key_path()) -> ok | {error, term()}.
|
||||
remove(ConfKeyPath) ->
|
||||
emqx_config_handler:remove_config(ConfKeyPath).
|
||||
|
||||
-spec get_raw() -> map().
|
||||
get_raw() ->
|
||||
|
@ -164,22 +170,18 @@ load() ->
|
|||
{_MappedEnvs, RichConf} = hocon_schema:map_translate(emqx_schema, RawRichConf, #{}),
|
||||
ok = save_to_emqx_config(to_plainmap(RichConf), to_plainmap(RawRichConf)).
|
||||
|
||||
-spec save_configs(raw_config(), Opts) -> ok | {error, term()}
|
||||
when Opts :: #{overridden_keys => all | [binary()]}.
|
||||
save_configs(RawConf, Opts) ->
|
||||
{_MappedEnvs, RichConf} = hocon_schema:map_translate(emqx_schema, to_richmap(RawConf), #{}),
|
||||
save_to_emqx_config(to_plainmap(RichConf), RawConf),
|
||||
-spec read_override_conf() -> raw_config().
|
||||
read_override_conf() ->
|
||||
load_hocon_file(emqx_override_conf_name(), map).
|
||||
|
||||
-spec save_configs(raw_config(), raw_config()) -> ok | {error, term()}.
|
||||
save_configs(RawConf, OverrideConf) ->
|
||||
{_MappedEnvs, RichConf} = hocon_schema:map_translate(emqx_schema, to_richmap(RawConf), #{}),
|
||||
%% 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 application env
|
||||
%save_to_app_env(_MappedEnvs),
|
||||
|
||||
%% We don't save the entire config to emqx_override.conf, but only the sub configs
|
||||
%% specified by RootKeys
|
||||
case maps:get(overridden_keys, Opts, all) of
|
||||
all -> save_to_override_conf(RawConf);
|
||||
RootKeys -> save_to_override_conf(maps:with(RootKeys, RawConf))
|
||||
end.
|
||||
save_to_emqx_config(to_plainmap(RichConf), RawConf),
|
||||
save_to_override_conf(OverrideConf).
|
||||
|
||||
-spec save_to_app_env([tuple()]) -> ok.
|
||||
save_to_app_env(AppEnvs) ->
|
||||
|
@ -192,13 +194,11 @@ save_to_emqx_config(Conf, RawConf) ->
|
|||
emqx_config:put(emqx_map_lib:unsafe_atom_key_map(Conf)),
|
||||
emqx_config:put_raw(RawConf).
|
||||
|
||||
-spec save_to_override_conf(config()) -> ok | {error, term()}.
|
||||
save_to_override_conf(Conf) ->
|
||||
-spec save_to_override_conf(raw_config()) -> ok | {error, term()}.
|
||||
save_to_override_conf(RawConf) ->
|
||||
FileName = emqx_override_conf_name(),
|
||||
OldConf = load_hocon_file(FileName, map),
|
||||
MergedConf = maps:merge(OldConf, Conf),
|
||||
ok = filelib:ensure_dir(FileName),
|
||||
case file:write_file(FileName, jsx:prettify(jsx:encode(MergedConf))) of
|
||||
case file:write_file(FileName, jsx:prettify(jsx:encode(RawConf))) of
|
||||
ok -> ok;
|
||||
{error, Reason} ->
|
||||
logger:error("write to ~s failed, ~p", [FileName, Reason]),
|
||||
|
|
|
@ -24,14 +24,11 @@
|
|||
%% API functions
|
||||
-export([ start_link/0
|
||||
, add_handler/2
|
||||
, update_config/3
|
||||
, update_config/2
|
||||
, remove_config/1
|
||||
, merge_to_old_config/2
|
||||
]).
|
||||
|
||||
%% emqx_config_handler callbacks
|
||||
-export([ pre_config_update/2
|
||||
]).
|
||||
|
||||
%% gen_server callbacks
|
||||
-export([init/1,
|
||||
handle_call/3,
|
||||
|
@ -62,11 +59,15 @@
|
|||
start_link() ->
|
||||
gen_server:start_link({local, ?MODULE}, ?MODULE, {}, []).
|
||||
|
||||
-spec update_config(emqx_config:config_key_path(), emqx_config:update_request(),
|
||||
emqx_config:raw_config()) ->
|
||||
-spec update_config(emqx_config:config_key_path(), emqx_config:update_request()) ->
|
||||
ok | {error, term()}.
|
||||
update_config(ConfKeyPath, UpdateReq, RawConfig) ->
|
||||
gen_server:call(?MODULE, {update_config, ConfKeyPath, UpdateReq, RawConfig}).
|
||||
update_config(ConfKeyPath, UpdateReq) ->
|
||||
gen_server:call(?MODULE, {update_config, ConfKeyPath, UpdateReq}).
|
||||
|
||||
-spec remove_config(emqx_config:config_key_path()) ->
|
||||
ok | {error, term()}.
|
||||
remove_config(ConfKeyPath) ->
|
||||
gen_server:call(?MODULE, {remove_config, ConfKeyPath}).
|
||||
|
||||
-spec add_handler(emqx_config:config_key_path(), handler_name()) -> ok.
|
||||
add_handler(ConfKeyPath, HandlerName) ->
|
||||
|
@ -83,11 +84,28 @@ handle_call({add_child, ConfKeyPath, HandlerName}, _From,
|
|||
{reply, ok, State#{handlers =>
|
||||
emqx_map_lib:deep_put(ConfKeyPath, Handlers, #{?MOD => HandlerName})}};
|
||||
|
||||
handle_call({update_config, ConfKeyPath, UpdateReq, RawConf}, _From,
|
||||
handle_call({update_config, ConfKeyPath, UpdateReq}, _From,
|
||||
#{handlers := Handlers} = State) ->
|
||||
OldConf = emqx_config:get(),
|
||||
try {RootKeys, Conf} = do_update_config(ConfKeyPath, Handlers, RawConf, UpdateReq),
|
||||
Result = emqx_config:save_configs(Conf, #{overridden_keys => RootKeys}),
|
||||
OldRawConf = emqx_config:get_raw(),
|
||||
try NewRawConf = do_update_config(ConfKeyPath, Handlers, OldRawConf, UpdateReq),
|
||||
OverrideConf = update_override_config(ConfKeyPath, NewRawConf),
|
||||
Result = emqx_config:save_configs(NewRawConf, OverrideConf),
|
||||
do_post_config_update(ConfKeyPath, Handlers, OldConf, emqx_config:get()),
|
||||
{reply, Result, State}
|
||||
catch
|
||||
Error : Reason : ST ->
|
||||
?LOG(error, "update config failed: ~p", [{Error, Reason, ST}]),
|
||||
{reply, {error, Reason}, State}
|
||||
end;
|
||||
|
||||
handle_call({remove_config, ConfKeyPath}, _From, #{handlers := Handlers} = State) ->
|
||||
OldConf = emqx_config:get(),
|
||||
OldRawConf = emqx_config:get_raw(),
|
||||
BinKeyPath = bin_path(ConfKeyPath),
|
||||
try NewRawConf = emqx_map_lib:deep_remove(BinKeyPath, OldRawConf),
|
||||
OverrideConf = emqx_map_lib:deep_remove(BinKeyPath, emqx_config:read_override_conf()),
|
||||
Result = emqx_config:save_configs(NewRawConf, OverrideConf),
|
||||
do_post_config_update(ConfKeyPath, Handlers, OldConf, emqx_config:get()),
|
||||
{reply, Result, State}
|
||||
catch
|
||||
|
@ -148,11 +166,6 @@ call_post_config_update(Handlers, OldConf, NewConf) ->
|
|||
false -> ok
|
||||
end.
|
||||
|
||||
%% callbacks for the top-level handler
|
||||
pre_config_update(UpdateReq, OldConf) ->
|
||||
FullRawConf = merge_to_old_config(UpdateReq, OldConf),
|
||||
{maps:keys(UpdateReq), FullRawConf}.
|
||||
|
||||
%% The default callback of config handlers
|
||||
%% the behaviour is overwriting the old config if:
|
||||
%% 1. the old config is undefined
|
||||
|
@ -163,6 +176,18 @@ merge_to_old_config(UpdateReq, RawConf) when is_map(UpdateReq), is_map(RawConf)
|
|||
merge_to_old_config(UpdateReq, _RawConf) ->
|
||||
UpdateReq.
|
||||
|
||||
update_override_config(ConfKeyPath, RawConf) ->
|
||||
%% We don't save the entire config to emqx_override.conf, but only the part
|
||||
%% specified by the ConfKeyPath
|
||||
PartialConf = maps:with(root_keys(ConfKeyPath), RawConf),
|
||||
OldConf = emqx_config:read_override_conf(),
|
||||
maps:merge(OldConf, PartialConf).
|
||||
|
||||
root_keys([]) -> [];
|
||||
root_keys([RootKey | _]) -> [bin(RootKey)].
|
||||
|
||||
bin_path(ConfKeyPath) -> [bin(Key) || Key <- ConfKeyPath].
|
||||
|
||||
bin(A) when is_atom(A) -> list_to_binary(atom_to_list(A));
|
||||
bin(B) when is_binary(B) -> B;
|
||||
bin(S) when is_list(S) -> list_to_binary(S).
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
, deep_get/3
|
||||
, deep_find/2
|
||||
, deep_put/3
|
||||
, deep_remove/2
|
||||
, deep_merge/2
|
||||
, safe_atom_key_map/1
|
||||
, unsafe_atom_key_map/1
|
||||
|
@ -64,6 +65,19 @@ deep_put([Key | KeyPath], Map, Config) ->
|
|||
SubMap = deep_put(KeyPath, maps:get(Key, Map, #{}), Config),
|
||||
Map#{Key => SubMap}.
|
||||
|
||||
-spec deep_remove(config_key_path(), map()) -> map().
|
||||
deep_remove([], Map) ->
|
||||
Map;
|
||||
deep_remove([Key], Map) ->
|
||||
maps:remove(Key, Map);
|
||||
deep_remove([Key | KeyPath], Map) ->
|
||||
case maps:find(Key, Map) of
|
||||
{ok, SubMap} when is_map(SubMap) ->
|
||||
Map#{Key => deep_remove(KeyPath, SubMap)};
|
||||
{ok, _Val} -> Map;
|
||||
error -> Map
|
||||
end.
|
||||
|
||||
%% #{a => #{b => 3, c => 2}, d => 4}
|
||||
%% = deep_merge(#{a => #{b => 1, c => 2}, d => 4}, #{a => #{b => 3}}).
|
||||
-spec deep_merge(map(), map()) -> map().
|
||||
|
|
Loading…
Reference in New Issue