fix: start auth & acl mongo with availability check

This commit is contained in:
DDDHuang 2022-04-07 18:04:15 +08:00
parent 16dc0d6555
commit 3c34cb3b6a
4 changed files with 117 additions and 16 deletions

View File

@ -1,6 +1,6 @@
{application, emqx_auth_mongo,
[{description, "EMQ X Authentication/ACL with MongoDB"},
{vsn, "4.3.2"}, % strict semver, bump manually!
{vsn, "4.3.3"}, % strict semver, bump manually!
{modules, []},
{registered, [emqx_auth_mongo_sup]},
{applications, [kernel,stdlib,mongodb,ecpool]},

View File

@ -1,17 +1,25 @@
%% -*- mode: erlang -*-
%% Unless you know what you are doing, DO NOT edit manually!!
{VSN,
[{"4.3.1",
[{load_module,emqx_auth_mongo,brutal_purge,soft_purge,[]}]},
[{"4.3.2",
[{load_module,emqx_auth_mongo_app,brutal_purge,soft_purge,[]},
{load_module,emqx_auth_mongo,brutal_purge,soft_purge,[]}]},
{"4.3.1",
[{load_module,emqx_auth_mongo_app,brutal_purge,soft_purge,[]},
{load_module,emqx_auth_mongo,brutal_purge,soft_purge,[]}]},
{"4.3.0",
[{load_module,emqx_auth_mongo_app,brutal_purge,soft_purge,[]},
{load_module,emqx_auth_mongo,brutal_purge,soft_purge,[]},
{load_module,emqx_acl_mongo,brutal_purge,soft_purge,[]}]},
{<<".*">>,[]}],
[{"4.3.1",
[{load_module,emqx_auth_mongo,brutal_purge,soft_purge,[]}]},
[{"4.3.2",
[{load_module,emqx_auth_mongo_app,brutal_purge,soft_purge,[]},
{load_module,emqx_auth_mongo,brutal_purge,soft_purge,[]}]},
{"4.3.1",
[{load_module,emqx_auth_mongo_app,brutal_purge,soft_purge,[]},
{load_module,emqx_auth_mongo,brutal_purge,soft_purge,[]}]},
{"4.3.0",
[{load_module,emqx_auth_mongo_app,brutal_purge,soft_purge,[]},
{load_module,emqx_auth_mongo,brutal_purge,soft_purge,[]},
{load_module,emqx_acl_mongo,brutal_purge,soft_purge,[]}]},
{<<".*">>,[]}]
}.
{<<".*">>,[]}]}.

View File

@ -35,6 +35,10 @@
, query_multi/3
]).
-export([ available/2
, available/3
]).
-spec(register_metrics() -> ok).
register_metrics() ->
lists:foreach(fun emqx_metrics:ensure/1, ?AUTH_METRICS).
@ -97,6 +101,56 @@ is_superuser(Pool, #superquery{collection = Coll, field = Field, selector = Sele
end
end.
%%--------------------------------------------------------------------
%% Availability Test
%%--------------------------------------------------------------------
available(Pool, #superquery{collection = Collection, selector = Selector}) ->
available(Pool, Collection, maps:from_list(replvars(Selector, test_client_info())));
available(Pool, #authquery{collection = Collection, selector = Selector}) ->
available(Pool, Collection, maps:from_list(replvars(Selector, test_client_info())));
available(Pool, #aclquery{collection = Collection, selector = Selectors}) ->
Fun =
fun(Selector) ->
maps:from_list(emqx_auth_mongo:replvars(Selector, test_client_info()))
end,
available(Pool, Collection, lists:map(Fun, Selectors), fun query_multi/3).
available(Pool, Collection, Query) ->
available(Pool, Collection, Query, fun query/3).
available(Pool, Collection, Query, Fun) ->
try Fun(Pool, Collection, Query) of
{error, Reason} ->
?LOG(error, "[MongoDB] ~p availability test error: ~0p", [Collection, Reason]),
{error, Reason};
Error = #{<<"code">> := Code} ->
CodeName = maps:get(<<"codeName">>, Error, undefined),
ErrorMessage = maps:get(<<"errmsg">>, Error, undefined),
?LOG(error, "[MongoDB] ~p availability test error, code: ~p Name: ~0p Message: ~0p",
[Collection, Code, CodeName, ErrorMessage]),
{error, {mongo_error, Code}};
_Return ->
%% Any success result is fine.
ok
catch E:R:S ->
?LOG(error, "[MongoDB] ~p availability test error, ~p: ~0p: ~0p", [Collection, E, R, S]),
{error, R}
end.
%% Test client info
test_client_info() ->
#{
clientid => <<"EMQX_availability_test_client">>,
username => <<"EMQX_availability_test_username">>,
cn => <<"EMQX_availability_test_cn">>,
dn => <<"EMQX_availability_test_dn">>
}.
%%--------------------------------------------------------------------
%% Internal func
%%--------------------------------------------------------------------
replvars(VarList, ClientInfo) ->
lists:map(fun(Var) -> replvar(Var, ClientInfo) end, VarList).

View File

@ -36,26 +36,65 @@
start(_StartType, _StartArgs) ->
{ok, Sup} = emqx_auth_mongo_sup:start_link(),
with_env(auth_query, fun reg_authmod/1),
with_env(acl_query, fun reg_aclmod/1),
ok = safe_start(),
{ok, Sup}.
prep_stop(State) ->
ok = emqx:unhook('client.authenticate', fun emqx_auth_mongo:check/3),
ok = emqx:unhook('client.check_acl', fun emqx_acl_mongo:check_acl/5),
ok = unload_hook(),
_ = stop_pool(),
State.
stop(_State) ->
ok.
unload_hook() ->
ok = emqx:unhook('client.authenticate', fun emqx_auth_mongo:check/3),
ok = emqx:unhook('client.check_acl', fun emqx_acl_mongo:check_acl/5).
stop_pool() ->
ecpool:stop_sup_pool(?APP).
safe_start() ->
try
ok = with_env(auth_query, fun reg_authmod/1),
ok = with_env(acl_query, fun reg_aclmod/1),
ok
catch _E:R:_S ->
unload_hook(),
_ = stop_pool(),
{error, R}
end.
reg_authmod(AuthQuery) ->
emqx_auth_mongo:register_metrics(),
SuperQuery = r(super_query, application:get_env(?APP, super_query, undefined)),
ok = emqx:hook('client.authenticate', fun emqx_auth_mongo:check/3,
[#{authquery => AuthQuery, superquery => SuperQuery, pool => ?APP}]).
case emqx_auth_mongo:available(?APP, AuthQuery) of
ok ->
emqx_auth_mongo:register_metrics(),
HookFun = fun emqx_auth_mongo:check/3,
HookOptions = #{authquery => AuthQuery, superquery => undefined, pool => ?APP},
case r(super_query, application:get_env(?APP, super_query, undefined)) of
undefined ->
ok = emqx:hook('client.authenticate', HookFun, [HookOptions]);
SuperQuery ->
case emqx_auth_mongo:available(?APP, SuperQuery) of
ok ->
ok = emqx:hook('client.authenticate', HookFun,
[HookOptions#{superquery => SuperQuery}]);
{error, Reason} ->
{error, Reason}
end
end;
{error, Reason} ->
{error, Reason}
end.
reg_aclmod(AclQuery) ->
ok = emqx:hook('client.check_acl', fun emqx_acl_mongo:check_acl/5, [#{aclquery => AclQuery, pool => ?APP}]).
case emqx_auth_mongo:available(?APP, AclQuery) of
ok ->
ok = emqx:hook('client.check_acl', fun emqx_acl_mongo:check_acl/5,
[#{aclquery => AclQuery, pool => ?APP}]);
{error, Reason} ->
{error, Reason}
end.
%%--------------------------------------------------------------------
%% Internal functions