feat: support emqx_conf:update([exhook],Conf)
This commit is contained in:
parent
c1d935fd34
commit
bd29433997
|
@ -1,7 +1,7 @@
|
|||
%% -*- mode: erlang -*-
|
||||
{application, emqx_exhook, [
|
||||
{description, "EMQX Extension for Hook"},
|
||||
{vsn, "5.0.12"},
|
||||
{vsn, "5.0.13"},
|
||||
{modules, []},
|
||||
{registered, []},
|
||||
{mod, {emqx_exhook_app, []}},
|
||||
|
|
|
@ -22,8 +22,7 @@
|
|||
|
||||
-export([
|
||||
start/2,
|
||||
stop/1,
|
||||
prep_stop/1
|
||||
stop/1
|
||||
]).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
|
@ -34,10 +33,6 @@ start(_StartType, _StartArgs) ->
|
|||
{ok, Sup} = emqx_exhook_sup:start_link(),
|
||||
{ok, Sup}.
|
||||
|
||||
prep_stop(State) ->
|
||||
emqx_ctl:unregister_command(exhook),
|
||||
State.
|
||||
|
||||
stop(_State) ->
|
||||
ok.
|
||||
|
||||
|
|
|
@ -181,10 +181,14 @@ pre_config_update(_, {enable, Name, Enable}, OldConf) ->
|
|||
of
|
||||
not_found -> throw(not_found);
|
||||
NewConf -> {ok, lists:map(fun maybe_write_certs/1, NewConf)}
|
||||
end.
|
||||
end;
|
||||
pre_config_update(_, NewConf, _OldConf) when NewConf =:= #{} ->
|
||||
{ok, NewConf#{<<"servers">> => []}};
|
||||
pre_config_update(_, NewConf = #{<<"servers">> := Servers}, _OldConf) ->
|
||||
{ok, NewConf#{<<"servers">> => lists:map(fun maybe_write_certs/1, Servers)}}.
|
||||
|
||||
post_config_update(_KeyPath, UpdateReq, NewConf, OldConf, _AppEnvs) ->
|
||||
Result = call({update_config, UpdateReq, NewConf}),
|
||||
Result = call({update_config, UpdateReq, NewConf, OldConf}),
|
||||
try_clear_ssl_files(UpdateReq, NewConf, OldConf),
|
||||
{ok, Result}.
|
||||
|
||||
|
@ -197,6 +201,7 @@ post_config_update(_KeyPath, UpdateReq, NewConf, OldConf, _AppEnvs) ->
|
|||
init([]) ->
|
||||
process_flag(trap_exit, true),
|
||||
emqx_conf:add_handler([exhook, servers], ?MODULE),
|
||||
emqx_conf:add_handler([exhook], ?MODULE),
|
||||
ServerL = emqx:get_config([exhook, servers]),
|
||||
Servers = load_all_servers(ServerL),
|
||||
Servers2 = reorder(ServerL, Servers),
|
||||
|
@ -222,22 +227,16 @@ handle_call(
|
|||
OrderServers = sort_name_by_order(Infos, Servers),
|
||||
{reply, OrderServers, State};
|
||||
handle_call(
|
||||
{update_config, {move, _Name, _Position}, NewConfL},
|
||||
{update_config, {move, _Name, _Position}, NewConfL, _},
|
||||
_From,
|
||||
#{servers := Servers} = State
|
||||
) ->
|
||||
Servers2 = reorder(NewConfL, Servers),
|
||||
{reply, ok, State#{servers := Servers2}};
|
||||
handle_call({update_config, {delete, ToDelete}, _}, _From, State) ->
|
||||
emqx_exhook_metrics:on_server_deleted(ToDelete),
|
||||
|
||||
#{servers := Servers} = State2 = do_unload_server(ToDelete, State),
|
||||
|
||||
Servers2 = maps:remove(ToDelete, Servers),
|
||||
|
||||
{reply, ok, update_servers(Servers2, State2)};
|
||||
handle_call({update_config, {delete, ToDelete}, _, _}, _From, State) ->
|
||||
{reply, ok, remove_server(ToDelete, State)};
|
||||
handle_call(
|
||||
{update_config, {add, RawConf}, NewConfL},
|
||||
{update_config, {add, RawConf}, NewConfL, _},
|
||||
_From,
|
||||
#{servers := Servers} = State
|
||||
) ->
|
||||
|
@ -246,14 +245,68 @@ handle_call(
|
|||
Servers2 = Servers#{Name => Server},
|
||||
Servers3 = reorder(NewConfL, Servers2),
|
||||
{reply, Result, State#{servers := Servers3}};
|
||||
handle_call({update_config, {update, Name, _Conf}, NewConfL, _}, _From, State) ->
|
||||
{Result, State2} = restart_server(Name, NewConfL, State),
|
||||
{reply, Result, State2};
|
||||
handle_call({update_config, {enable, Name, _Enable}, NewConfL, _}, _From, State) ->
|
||||
{Result, State2} = restart_server(Name, NewConfL, State),
|
||||
{reply, Result, State2};
|
||||
handle_call({update_config, _, ConfL, ConfL}, _From, State) ->
|
||||
{reply, ok, State};
|
||||
handle_call({update_config, _, #{servers := NewConfL}, #{servers := OldConfL}}, _From, State) ->
|
||||
#{
|
||||
removed := Removed,
|
||||
added := Added,
|
||||
changed := Updated
|
||||
} = emqx_utils:diff_lists(NewConfL, OldConfL, fun(#{name := Name}) -> Name end),
|
||||
%% remove servers
|
||||
State2 = lists:foldl(
|
||||
fun(Conf, Acc) ->
|
||||
ToDelete = maps:get(name, Conf),
|
||||
remove_server(ToDelete, Acc)
|
||||
end,
|
||||
State,
|
||||
Removed
|
||||
),
|
||||
%% update servers
|
||||
{UpdateRes, State3} =
|
||||
lists:foldl(
|
||||
fun({_Old, Conf}, {ResAcc, StateAcc}) ->
|
||||
Name = maps:get(name, Conf),
|
||||
case restart_server(Name, NewConfL, StateAcc) of
|
||||
{ok, StateAcc1} -> {ResAcc, StateAcc1};
|
||||
{Err, StateAcc1} -> {[Err | ResAcc], StateAcc1}
|
||||
end
|
||||
end,
|
||||
{[], State2},
|
||||
Updated
|
||||
),
|
||||
%% Add servers
|
||||
{AddRes, State4} =
|
||||
lists:foldl(
|
||||
fun(Conf, {ResAcc, StateAcc}) ->
|
||||
case do_load_server(options_to_server(Conf)) of
|
||||
{ok, Server} ->
|
||||
#{servers := Servers} = StateAcc,
|
||||
Name = maps:get(name, Conf),
|
||||
Servers2 = Servers#{Name => Server},
|
||||
{ResAcc, update_servers(Servers2, StateAcc)};
|
||||
{Err, StateAcc1} ->
|
||||
{[Err | ResAcc], StateAcc1}
|
||||
end
|
||||
end,
|
||||
{[], State3},
|
||||
Added
|
||||
),
|
||||
%% update order
|
||||
#{servers := Servers4} = State4,
|
||||
State5 = State4#{servers => reorder(NewConfL, Servers4)},
|
||||
case lists:append([UpdateRes, AddRes]) of
|
||||
[] -> {reply, ok, State5};
|
||||
_ -> {reply, {error, #{added => AddRes, updated => UpdateRes}}, State5}
|
||||
end;
|
||||
handle_call({lookup, Name}, _From, State) ->
|
||||
{reply, where_is_server(Name, State), State};
|
||||
handle_call({update_config, {update, Name, _Conf}, NewConfL}, _From, State) ->
|
||||
{Result, State2} = restart_server(Name, NewConfL, State),
|
||||
{reply, Result, State2};
|
||||
handle_call({update_config, {enable, Name, _Enable}, NewConfL}, _From, State) ->
|
||||
{Result, State2} = restart_server(Name, NewConfL, State),
|
||||
{reply, Result, State2};
|
||||
handle_call({server_info, Name}, _From, State) ->
|
||||
case where_is_server(Name, State) of
|
||||
not_found ->
|
||||
|
@ -287,6 +340,12 @@ handle_call(_Request, _From, State) ->
|
|||
Reply = ok,
|
||||
{reply, Reply, State}.
|
||||
|
||||
remove_server(ToDelete, State) ->
|
||||
emqx_exhook_metrics:on_server_deleted(ToDelete),
|
||||
#{servers := Servers} = State2 = do_unload_server(ToDelete, State),
|
||||
Servers2 = maps:remove(ToDelete, Servers),
|
||||
update_servers(Servers2, State2).
|
||||
|
||||
handle_cast(_Msg, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
|
@ -310,6 +369,8 @@ terminate(Reason, State = #{servers := Servers}) ->
|
|||
Servers
|
||||
),
|
||||
?tp(info, exhook_mgr_terminated, #{reason => Reason, servers => Servers}),
|
||||
emqx_conf:remove_handler([exhook, servers]),
|
||||
emqx_conf:remove_handler([exhook]),
|
||||
ok.
|
||||
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
|
@ -612,8 +673,16 @@ try_clear_ssl_files({Op, Name, _}, NewConfs, OldConfs) when
|
|||
NewSSL = find_server_ssl_cfg(Name, NewConfs),
|
||||
OldSSL = find_server_ssl_cfg(Name, OldConfs),
|
||||
emqx_tls_lib:delete_ssl_files(ssl_file_path(Name), NewSSL, OldSSL);
|
||||
try_clear_ssl_files(_Req, _NewConf, _OldConf) ->
|
||||
ok.
|
||||
%% replace the whole config from the file
|
||||
try_clear_ssl_files(_Req, #{servers := NewServers}, #{servers := OldServers}) ->
|
||||
lists:foreach(
|
||||
fun(#{name := Name} = Conf) ->
|
||||
NewSSL = find_server_ssl_cfg(Name, NewServers),
|
||||
OldSSL = maps:get(ssl, Conf, undefined),
|
||||
emqx_tls_lib:delete_ssl_files(ssl_file_path(Name), NewSSL, OldSSL)
|
||||
end,
|
||||
OldServers
|
||||
).
|
||||
|
||||
search_server_cfg(Name, Confs) ->
|
||||
lists:search(
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{application, emqx_utils, [
|
||||
{description, "Miscellaneous utilities for EMQX apps"},
|
||||
% strict semver, bump manually!
|
||||
{vsn, "5.0.2"},
|
||||
{vsn, "5.0.3"},
|
||||
{modules, [
|
||||
emqx_utils,
|
||||
emqx_utils_api,
|
||||
|
|
|
@ -54,7 +54,8 @@
|
|||
safe_to_existing_atom/1,
|
||||
safe_to_existing_atom/2,
|
||||
pub_props_to_packet/1,
|
||||
safe_filename/1
|
||||
safe_filename/1,
|
||||
diff_lists/3
|
||||
]).
|
||||
|
||||
-export([
|
||||
|
@ -748,3 +749,152 @@ safe_filename(Filename) when is_binary(Filename) ->
|
|||
binary:replace(Filename, <<":">>, <<"-">>, [global]);
|
||||
safe_filename(Filename) when is_list(Filename) ->
|
||||
lists:flatten(string:replace(Filename, ":", "-", all)).
|
||||
|
||||
%% @doc Compares two lists of maps and returns the differences between them in a
|
||||
%% map containing four keys – 'removed', 'added', 'identical', and 'changed' –
|
||||
%% each holding a list of maps. Elements are compared using key function KeyFunc
|
||||
%% to extract the comparison key used for matching.
|
||||
%%
|
||||
%% The return value is a map with the following keys and the list of maps as its values:
|
||||
%% * 'removed' – a list of maps that were present in the Old list, but not found in the New list.
|
||||
%% * 'added' – a list of maps that were present in the New list, but not found in the Old list.
|
||||
%% * 'identical' – a list of maps that were present in both lists and have the same comparison key value.
|
||||
%% * 'changed' – a list of pairs of maps representing the changes between maps present in the New and Old lists.
|
||||
%% The first map in the pair represents the map in the Old list, and the second map
|
||||
%% represents the potential modification in the New list.
|
||||
|
||||
%% The KeyFunc parameter is a function that extracts the comparison key used
|
||||
%% for matching from each map. The function should return a comparable term,
|
||||
%% such as an atom, a number, or a string. This is used to determine if each
|
||||
%% element is the same in both lists.
|
||||
|
||||
-spec diff_lists(list(T), list(T), Func) ->
|
||||
#{
|
||||
added := list(T),
|
||||
identical := list(T),
|
||||
removed := list(T),
|
||||
changed := list({Old :: T, New :: T})
|
||||
}
|
||||
when
|
||||
Func :: fun((T) -> any()),
|
||||
T :: any().
|
||||
|
||||
diff_lists(New, Old, KeyFunc) when is_list(New) andalso is_list(Old) ->
|
||||
Removed =
|
||||
lists:foldl(
|
||||
fun(E, RemovedAcc) ->
|
||||
case search(KeyFunc(E), KeyFunc, New) of
|
||||
false -> [E | RemovedAcc];
|
||||
_ -> RemovedAcc
|
||||
end
|
||||
end,
|
||||
[],
|
||||
Old
|
||||
),
|
||||
{Added, Identical, Changed} =
|
||||
lists:foldl(
|
||||
fun(E, Acc) ->
|
||||
{Added0, Identical0, Changed0} = Acc,
|
||||
case search(KeyFunc(E), KeyFunc, Old) of
|
||||
false ->
|
||||
{[E | Added0], Identical0, Changed0};
|
||||
E ->
|
||||
{Added0, [E | Identical0], Changed0};
|
||||
E1 ->
|
||||
{Added0, Identical0, [{E1, E} | Changed0]}
|
||||
end
|
||||
end,
|
||||
{[], [], []},
|
||||
New
|
||||
),
|
||||
#{
|
||||
removed => lists:reverse(Removed),
|
||||
added => lists:reverse(Added),
|
||||
identical => lists:reverse(Identical),
|
||||
changed => lists:reverse(Changed)
|
||||
}.
|
||||
|
||||
search(_ExpectValue, _KeyFunc, []) ->
|
||||
false;
|
||||
search(ExpectValue, KeyFunc, [Item | List]) ->
|
||||
case KeyFunc(Item) =:= ExpectValue of
|
||||
true -> Item;
|
||||
false -> search(ExpectValue, KeyFunc, List)
|
||||
end.
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
diff_lists_test() ->
|
||||
KeyFunc = fun(#{name := Name}) -> Name end,
|
||||
?assertEqual(
|
||||
#{
|
||||
removed => [],
|
||||
added => [],
|
||||
identical => [],
|
||||
changed => []
|
||||
},
|
||||
diff_lists([], [], KeyFunc)
|
||||
),
|
||||
%% test removed list
|
||||
?assertEqual(
|
||||
#{
|
||||
removed => [#{name => a, value => 1}],
|
||||
added => [],
|
||||
identical => [],
|
||||
changed => []
|
||||
},
|
||||
diff_lists([], [#{name => a, value => 1}], KeyFunc)
|
||||
),
|
||||
%% test added list
|
||||
?assertEqual(
|
||||
#{
|
||||
removed => [],
|
||||
added => [#{name => a, value => 1}],
|
||||
identical => [],
|
||||
changed => []
|
||||
},
|
||||
diff_lists([#{name => a, value => 1}], [], KeyFunc)
|
||||
),
|
||||
%% test identical list
|
||||
?assertEqual(
|
||||
#{
|
||||
removed => [],
|
||||
added => [],
|
||||
identical => [#{name => a, value => 1}],
|
||||
changed => []
|
||||
},
|
||||
diff_lists([#{name => a, value => 1}], [#{name => a, value => 1}], KeyFunc)
|
||||
),
|
||||
Old = [
|
||||
#{name => a, value => 1},
|
||||
#{name => b, value => 4},
|
||||
#{name => e, value => 2},
|
||||
#{name => d, value => 4}
|
||||
],
|
||||
New = [
|
||||
#{name => a, value => 1},
|
||||
#{name => b, value => 2},
|
||||
#{name => e, value => 2},
|
||||
#{name => c, value => 3}
|
||||
],
|
||||
Diff = diff_lists(New, Old, KeyFunc),
|
||||
?assertEqual(
|
||||
#{
|
||||
added => [
|
||||
#{name => c, value => 3}
|
||||
],
|
||||
identical => [
|
||||
#{name => a, value => 1},
|
||||
#{name => e, value => 2}
|
||||
],
|
||||
removed => [
|
||||
#{name => d, value => 4}
|
||||
],
|
||||
changed => [{#{name => b, value => 4}, #{name => b, value => 2}}]
|
||||
},
|
||||
Diff
|
||||
),
|
||||
ok.
|
||||
|
||||
-endif.
|
||||
|
|
Loading…
Reference in New Issue