Merge pull request #7545 from DDDHuang/start_mongo_auth
fix: start auth & acl mongo with availability check
This commit is contained in:
commit
f80a2e345c
|
@ -1,6 +1,6 @@
|
||||||
{application, emqx_auth_mongo,
|
{application, emqx_auth_mongo,
|
||||||
[{description, "EMQ X Authentication/ACL with MongoDB"},
|
[{description, "EMQ X Authentication/ACL with MongoDB"},
|
||||||
{vsn, "4.3.2"}, % strict semver, bump manually!
|
{vsn, "4.3.3"}, % strict semver, bump manually!
|
||||||
{modules, []},
|
{modules, []},
|
||||||
{registered, [emqx_auth_mongo_sup]},
|
{registered, [emqx_auth_mongo_sup]},
|
||||||
{applications, [kernel,stdlib,mongodb,ecpool]},
|
{applications, [kernel,stdlib,mongodb,ecpool]},
|
||||||
|
|
|
@ -1,17 +1,25 @@
|
||||||
%% -*- mode: erlang -*-
|
%% -*- mode: erlang -*-
|
||||||
|
%% Unless you know what you are doing, DO NOT edit manually!!
|
||||||
{VSN,
|
{VSN,
|
||||||
[{"4.3.1",
|
[{"4.3.2",
|
||||||
[{load_module,emqx_auth_mongo,brutal_purge,soft_purge,[]}]},
|
[{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",
|
{"4.3.0",
|
||||||
[{load_module,emqx_auth_mongo_app,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_auth_mongo_app,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_auth_mongo,brutal_purge,soft_purge,[]},
|
{load_module,emqx_auth_mongo,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_acl_mongo,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_acl_mongo,brutal_purge,soft_purge,[]}]},
|
||||||
{<<".*">>,[]}],
|
{<<".*">>,[]}],
|
||||||
[{"4.3.1",
|
[{"4.3.2",
|
||||||
[{load_module,emqx_auth_mongo,brutal_purge,soft_purge,[]}]},
|
[{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",
|
{"4.3.0",
|
||||||
[{load_module,emqx_auth_mongo_app,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_auth_mongo_app,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_auth_mongo,brutal_purge,soft_purge,[]},
|
{load_module,emqx_auth_mongo,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_acl_mongo,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_acl_mongo,brutal_purge,soft_purge,[]}]},
|
||||||
{<<".*">>,[]}]
|
{<<".*">>,[]}]}.
|
||||||
}.
|
|
||||||
|
|
|
@ -35,6 +35,10 @@
|
||||||
, query_multi/3
|
, query_multi/3
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
-export([ available/2
|
||||||
|
, available/3
|
||||||
|
]).
|
||||||
|
|
||||||
-spec(register_metrics() -> ok).
|
-spec(register_metrics() -> ok).
|
||||||
register_metrics() ->
|
register_metrics() ->
|
||||||
lists:foreach(fun emqx_metrics:ensure/1, ?AUTH_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
|
||||||
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) ->
|
replvars(VarList, ClientInfo) ->
|
||||||
lists:map(fun(Var) -> replvar(Var, ClientInfo) end, VarList).
|
lists:map(fun(Var) -> replvar(Var, ClientInfo) end, VarList).
|
||||||
|
|
||||||
|
|
|
@ -36,26 +36,65 @@
|
||||||
|
|
||||||
start(_StartType, _StartArgs) ->
|
start(_StartType, _StartArgs) ->
|
||||||
{ok, Sup} = emqx_auth_mongo_sup:start_link(),
|
{ok, Sup} = emqx_auth_mongo_sup:start_link(),
|
||||||
with_env(auth_query, fun reg_authmod/1),
|
ok = safe_start(),
|
||||||
with_env(acl_query, fun reg_aclmod/1),
|
|
||||||
{ok, Sup}.
|
{ok, Sup}.
|
||||||
|
|
||||||
prep_stop(State) ->
|
prep_stop(State) ->
|
||||||
ok = emqx:unhook('client.authenticate', fun emqx_auth_mongo:check/3),
|
ok = unload_hook(),
|
||||||
ok = emqx:unhook('client.check_acl', fun emqx_acl_mongo:check_acl/5),
|
_ = stop_pool(),
|
||||||
State.
|
State.
|
||||||
|
|
||||||
stop(_State) ->
|
stop(_State) ->
|
||||||
ok.
|
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) ->
|
reg_authmod(AuthQuery) ->
|
||||||
emqx_auth_mongo:register_metrics(),
|
case emqx_auth_mongo:available(?APP, AuthQuery) of
|
||||||
SuperQuery = r(super_query, application:get_env(?APP, super_query, undefined)),
|
ok ->
|
||||||
ok = emqx:hook('client.authenticate', fun emqx_auth_mongo:check/3,
|
emqx_auth_mongo:register_metrics(),
|
||||||
[#{authquery => AuthQuery, superquery => SuperQuery, pool => ?APP}]).
|
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) ->
|
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
|
%% Internal functions
|
||||||
|
|
Loading…
Reference in New Issue