Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Config in one persistent term #4093

Merged
merged 2 commits into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 36 additions & 64 deletions src/config/mongoose_config.erl
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@
get_opt/2,
get_opt/1]).

%% Test API, do not use outside of test suites, options set here are not cleaned up by stop/0
-export([set_opt/2,
%% Test API, do not use outside of test suites
-export([set_opts/1,
get_opts/0,
erase_opts/0,
set_opt/2,
unset_opt/1]).

%% Shell utilities intended for debugging and system inspection
-export([config_state/0,
config_states/0]).

-ignore_xref([set_opt/2, unset_opt/1, config_state/0, config_states/0]).
-ignore_xref([set_opts/1, get_opts/0, erase_opts/0, set_opt/2, unset_opt/1]).

-include("mongoose.hrl").

Expand All @@ -34,19 +33,15 @@
-spec start() -> ok.
start() ->
Path = get_config_path(),
State = mongoose_config_parser:parse_file(Path),
persistent_term:put(mongoose_config_state, State),
set_opts(State).
Opts = mongoose_config_parser:parse_file(Path),
set_opts(maps:from_list(Opts)).

-spec stop() -> ok | {error, not_started}.
stop() ->
try persistent_term:get(mongoose_config_state) of
State ->
unset_opts(State),
persistent_term:erase(mongoose_config_state),
ok
catch
_:_ ->
case erase_opts() of
true ->
ok;
false ->
{error, not_started}
end.

Expand All @@ -62,40 +57,40 @@ get_config_path() ->
end,
application:get_env(mongooseim, config, DefaultPath).

-spec set_opts(mongoose_config_parser:state()) -> ok.
set_opts(State) ->
Opts = mongoose_config_parser:get_opts(State),
lists:foreach(fun({Key, Value}) -> set_opt(Key, Value) end, Opts).
-spec set_opts(#{key() => value()}) -> ok.
set_opts(Opts) ->
persistent_term:put(?MODULE, Opts).

-spec unset_opts(mongoose_config_parser:state()) -> ok.
unset_opts(State) ->
Opts = mongoose_config_parser:get_opts(State),
lists:foreach(fun unset_opt/1, proplists:get_keys(Opts)).
-spec get_opts() -> #{key() => value()}.
get_opts() ->
persistent_term:get(?MODULE).

-spec erase_opts() -> boolean().
erase_opts() ->
persistent_term:erase(?MODULE).

-spec set_opt(key() | key_path(), value()) -> ok.
set_opt([Key], Value) ->
set_opt(Key, Value);
set_opt([Key | Rest], Value) ->
set_opt(Key, set_nested_opt(get_opt(Key), Rest, Value));
set_opt(KeyPath, Value) when is_list(KeyPath) ->
Opts = persistent_term:get(?MODULE),
NewOpts = set_nested_opt(Opts, KeyPath, Value),
persistent_term:put(?MODULE, NewOpts);
set_opt(Key, Value) ->
persistent_term:put({?MODULE, Key}, Value).
set_opt([Key], Value).

-spec unset_opt(key() | key_path()) -> ok.
unset_opt([Key]) ->
unset_opt(Key);
unset_opt([Key | Rest]) ->
set_opt(Key, unset_nested_opt(get_opt(Key), Rest));
unset_opt(KeyPath) when is_list(KeyPath) ->
Opts = persistent_term:get(?MODULE),
NewOpts = unset_nested_opt(Opts, KeyPath),
persistent_term:put(?MODULE, NewOpts);
unset_opt(Key) ->
persistent_term:erase({?MODULE, Key}),
ok.
unset_opt([Key]).

%% @doc Use instead of get_opt(Key, undefined)
-spec lookup_opt(key() | key_path()) -> {ok, value()} | {error, not_found}.
lookup_opt(Key) ->
try get_opt(Key) of
Value -> {ok, Value}
catch
error:badarg -> {error, not_found}; % missing persistent term
error:{badkey, _} -> {error, not_found} % missing map key
end.

Expand All @@ -105,39 +100,16 @@ get_opt(Key, Default) ->
try
get_opt(Key)
catch
error:badarg -> Default; % missing persistent term
error:{badkey, _} -> Default % missing map key
end.

%% @doc Fails if the option does not exist
-spec get_opt(key() | key_path()) -> value().
get_opt([Key | Rest]) ->
Config = persistent_term:get({?MODULE, Key}),
lists:foldl(fun maps:get/2, Config, Rest);
get_opt(KeyPath) when is_list(KeyPath) ->
Opts = persistent_term:get(?MODULE),
lists:foldl(fun maps:get/2, Opts, KeyPath);
get_opt(Key) ->
persistent_term:get({?MODULE, Key}).

-spec config_state() -> mongoose_config_parser:state().
config_state() ->
persistent_term:get(mongoose_config_state).

-spec config_states() -> [mongoose_config_parser:state()].
config_states() ->
config_states(mongoose_cluster:all_cluster_nodes()).

-spec config_states([node()]) -> [mongoose_config_parser:state()].
%% @doc Returns config states from all nodes in cluster
%% State from the local node comes as head of a list
config_states(Nodes) ->
{States, FailedNodes} = rpc:multicall(Nodes, ?MODULE, config_state, [], 30000),
case FailedNodes of
[] ->
States;
[_|_] ->
erlang:error(#{issue => config_state_failed,
cluster_nodes => Nodes,
failed_nodes => FailedNodes})
end.
get_opt([Key]).

%% Internal functions

Expand Down
14 changes: 10 additions & 4 deletions src/config/mongoose_config_parser.erl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
-export([parse_file/1]).

%% state API
-export([build_state/3, get_opts/1]).
-export([build_state/3]).

%% only for tests
-export([get_opts/1]).

-ignore_xref([get_opts/1]).

-callback parse_file(FileName :: string()) -> state().

Expand All @@ -25,11 +30,12 @@

%% Parser API

-spec parse_file(FileName :: string()) -> state().
-spec parse_file(FileName :: string()) -> opts().
parse_file(FileName) ->
ParserModule = parser_module(filename:extension(FileName)),
try
ParserModule:parse_file(FileName)
try ParserModule:parse_file(FileName) of
State ->
get_opts(State)
catch
error:{config_error, ExitMsg, Errors} ->
halt_with_msg(ExitMsg, Errors)
Expand Down
2 changes: 1 addition & 1 deletion src/pubsub/mod_pubsub.erl
Original file line number Diff line number Diff line change
Expand Up @@ -4078,7 +4078,7 @@ host_to_host_type(Host) ->
-spec tree(HostType :: mongooseim:host_type() | host()) -> module() | nodetree_virtual.
tree(HostType) ->
try gen_mod:get_module_opt(HostType, ?MODULE, nodetree)
catch error:badarg ->
catch error:{badkey, _} ->
%todo remove when pubsub supports dynamic domains
HT = host_to_host_type(HostType),
gen_mod:get_module_opt(HT, ?MODULE, nodetree)
Expand Down
7 changes: 2 additions & 5 deletions test/acl_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,11 @@ end_per_group(_Group, Config) ->
Config.

init_per_testcase(_TC, Config) ->
mongoose_config:set_opts(#{}),
Config.

end_per_testcase(_TC, _Config) ->
clean_config().
mongoose_config:erase_opts().

host_type() ->
<<"test host type">>.
Expand Down Expand Up @@ -287,10 +288,6 @@ different_specs_matching_the_same_user(Config) ->
acl(Spec) ->
[maps:merge(#{match => current_domain}, Spec)].

clean_config() ->
[persistent_term:erase(Key) || {Key = {mongoose_config, _}, _Value} <- persistent_term:get()],
ok.

given_registered_domains(Config, DomainsList) ->
case proplists:get_value(dynamic_domains, Config, false) of
true ->
Expand Down
8 changes: 4 additions & 4 deletions test/auth_dummy_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ all() -> [

init_per_suite(C) ->
{ok, _} = application:ensure_all_started(jid),
mongoose_config:set_opt({auth, ?HOST_TYPE}, #{methods => [dummy],
dummy => #{base_time => 5,
variance => 10}}),
AuthOpts = #{methods => [dummy],
dummy => #{base_time => 5, variance => 10}},
mongoose_config:set_opts(#{{auth, ?HOST_TYPE} => AuthOpts}),
C.

end_per_suite(_C) ->
mongoose_config:unset_opt({auth, ?HOST_TYPE}).
mongoose_config:erase_opts().

%%--------------------------------------------------------------------
%% Authentication tests
Expand Down
8 changes: 4 additions & 4 deletions test/auth_external_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ given_user_registered() ->

set_opts(Config) ->
DataDir = ?config(data_dir, Config),
mongoose_config:set_opt({auth, ?HOST_TYPE},
#{external => #{program => DataDir ++ "sample_external_auth.py",
instances => 1}}).
mongoose_config:set_opts(#{{auth, ?HOST_TYPE} =>
#{external => #{program => DataDir ++ "sample_external_auth.py",
instances => 1}}}).

unset_opts() ->
mongoose_config:unset_opt({auth, ?HOST_TYPE}).
mongoose_config:erase_opts().

gen_user() ->
U = random_binary(5),
Expand Down
10 changes: 5 additions & 5 deletions test/auth_http_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -244,13 +244,13 @@ set_opts(Config) ->
_ -> scram
end,
HttpOpts = #{basic_auth => ?BASIC_AUTH},
mongoose_config:set_opt({auth, ?HOST_TYPE}, #{methods => [http],
password => #{format => PasswordFormat,
scram_iterations => 10},
http => HttpOpts}).
mongoose_config:set_opts(#{{auth, ?HOST_TYPE} => #{methods => [http],
password => #{format => PasswordFormat,
scram_iterations => 10},
http => HttpOpts}}).

unset_opts() ->
mongoose_config:unset_opt({auth, ?HOST_TYPE}).
mongoose_config:erase_opts().

do_scram(Pass, Config) ->
case lists:keyfind(scram_group, 1, Config) of
Expand Down
10 changes: 5 additions & 5 deletions test/auth_internal_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ init_per_suite(C) ->
application:ensure_all_started(jid),
ok = mnesia:create_schema([node()]),
ok = mnesia:start(),
mongoose_config:set_opt({auth, host_type()}, #{methods => [internal],
internal => #{},
password => #{format => scram,
scram_iterations => 10}}),
AuthOpts = #{methods => [internal],
internal => #{},
password => #{format => scram, scram_iterations => 10}},
mongoose_config:set_opts(#{{auth, host_type()} => AuthOpts}),
ejabberd_auth_internal:start(host_type()),
C.

end_per_suite(_C) ->
ejabberd_auth_internal:stop(host_type()),
mongoose_config:unset_opt({auth, host_type()}),
mongoose_config:erase_opts(),
mnesia:stop(),
mnesia:delete_schema([node()]).

Expand Down
8 changes: 4 additions & 4 deletions test/auth_jwt_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,12 @@ check_password_succeeds_for_pubkey_signed_token(C) ->
%%--------------------------------------------------------------------

set_auth_opts(Secret, Algorithm, Key) ->
mongoose_config:set_opt({auth, ?HOST_TYPE}, #{jwt => #{secret => Secret,
algorithm => Algorithm,
username_key => Key}}).
mongoose_config:set_opts(#{{auth, ?HOST_TYPE} => #{jwt => #{secret => Secret,
algorithm => Algorithm,
username_key => Key}}}).

unset_auth_opts() ->
mongoose_config:unset_opt({auth, ?HOST_TYPE}).
mongoose_config:erase_opts().

generate_token(Alg, NbfDelta, Key) ->
Now = erlang:system_time(second),
Expand Down
11 changes: 6 additions & 5 deletions test/auth_tokens_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,14 @@ groups() ->

init_per_suite(C) ->
{ok, _} = application:ensure_all_started(jid),
mongoose_config:set_opt({modules, host_type()},
#{?TESTED => config_parser_helper:default_mod_config(?TESTED)}),
mongoose_config:set_opts(opts()),
C.

end_per_suite(C) ->
mongoose_config:unset_opt({modules, host_type()}),
C.
end_per_suite(_C) ->
mongoose_config:erase_opts().

opts() ->
#{{modules, host_type()} => #{?TESTED => config_parser_helper:default_mod_config(?TESTED)}}.

init_per_testcase(Test, Config)
when Test =:= serialize_deserialize_property;
Expand Down
11 changes: 5 additions & 6 deletions test/component_reg_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ init_per_suite(C) ->
{ok, _} = application:ensure_all_started(jid),
ok = mnesia:create_schema([node()]),
ok = mnesia:start(),
[mongoose_config:set_opt(Key, Value) || {Key, Value} <- opts()],
mongoose_config:set_opts(opts()),
meck:new(mongoose_domain_api, [no_link]),
meck:expect(mongoose_domain_api, get_host_type,
fun(_) -> {error, not_found} end),
Expand All @@ -31,13 +31,12 @@ end_per_suite(_C) ->
mnesia:stop(),
mnesia:delete_schema([node()]),
meck:unload(),
[mongoose_config:unset_opt(Key) || {Key, _Value} <- opts()],
ok.
mongoose_config:erase_opts().

opts() ->
[{all_metrics_are_global, false},
{component_backend, mnesia},
{routing_modules, [xmpp_router_a, xmpp_router_b, xmpp_router_c]}].
#{all_metrics_are_global => false,
component_backend => mnesia,
routing_modules => [xmpp_router_a, xmpp_router_b, xmpp_router_c]}.

registering(_C) ->
Dom = <<"aaa.bbb.com">>,
Expand Down
3 changes: 1 addition & 2 deletions test/config_parser_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -3040,8 +3040,7 @@ test_config_file(Config, File) ->
ExpectedOpts = config_parser_helper:options(File),

TOMLPath = ejabberd_helper:data(Config, File ++ ".toml"),
State = mongoose_config_parser:parse_file(TOMLPath),
TOMLOpts = mongoose_config_parser:get_opts(State),
TOMLOpts = mongoose_config_parser:parse_file(TOMLPath),

%% Save the parsed TOML options
%% - for debugging
Expand Down
Loading