From a03f32401042151d36cb1c3bc310f9490bff125e Mon Sep 17 00:00:00 2001 From: EMQ-YangM Date: Thu, 10 Mar 2022 18:28:57 +0800 Subject: [PATCH 1/7] feat(emqx_authn_api): add metrics and status to authn --- apps/emqx_authn/src/emqx_authn_api.erl | 137 +++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/apps/emqx_authn/src/emqx_authn_api.erl b/apps/emqx_authn/src/emqx_authn_api.erl index e23dfe05f..1ce8d3b77 100644 --- a/apps/emqx_authn/src/emqx_authn_api.erl +++ b/apps/emqx_authn/src/emqx_authn_api.erl @@ -30,6 +30,7 @@ -define(BAD_REQUEST, 'BAD_REQUEST'). -define(NOT_FOUND, 'NOT_FOUND'). -define(CONFLICT, 'CONFLICT'). +-define(TIMEOUT, 15000). % Swagger @@ -59,6 +60,8 @@ , authenticator_user/2 , listener_authenticator_users/2 , listener_authenticator_user/2 + , lookup_from_local_node/2 + , lookup_from_all_node/2 ]). -export([ authenticator_examples/0 @@ -759,6 +762,140 @@ list_authenticator(ConfKeyPath, AuthenticatorID) -> serialize_error(Reason) end. +%% example: +%% +%% emqx_authn_api:lookup_from_local_node('mqtt:global', <<"password-based:http">>) +%% +%% {ok,{'emqx@127.0.0.1',connecting, +%% #{counters => +%% #{exception => 0,failed => 0,matched => 0,success => 0}, +%% rate => +%% #{matched => #{current => 0.0,last5m => 0.0,max => 0.0}}}}} +lookup_from_local_node(ChainName, AuthenticatorID) -> + NodeId = node(self()), + case emqx_authentication:lookup_authenticator(ChainName, AuthenticatorID) of + {ok, #{provider := Provider, state := State}} -> + case lists:member(Provider, resource_provider()) of + false -> {error, {NodeId, resource_unsupport_metrics_and_status}}; + true -> + #{resource_id := ResourceId} = State, + case emqx_resource:get_instance(ResourceId) of + {error, not_found} -> {error, {NodeId, not_found_resource}}; + {ok, _, #{ status := Status, metrics := Metrics }} -> + {ok, {NodeId, Status, Metrics}} + end + end; + {error, Reason} -> {error, {NodeId, Reason}} + end. + +resource_provider() -> + [ emqx_authn_mysql, + emqx_authn_pgsql, + emqx_authn_mongodb, + emqx_authn_redis, + emqx_authn_http + ]. + +%% example: +%% +%% emqx_authn_api:lookup_from_all_node('mqtt:global', <<"password-based:http">>) +%% +%% #{aggregate_metrics => +%% #{counters => +%% #{exception => 0,failed => 0,matched => 0,success => 0}, +%% rate => +%% #{matched => #{current => 0.0,last5m => 0.0,max => 0.0}}}, +%% aggregate_status => connecting,all_node_error => #{}, +%% all_node_metrics => +%% #{'emqx@127.0.0.1' => +%% #{counters => +%% #{exception => 0,failed => 0,matched => 0,success => 0}, +%% rate => +%% #{matched => #{current => 0.0,last5m => 0.0,max => 0.0}}}}, +%% all_node_state => #{'emqx@127.0.0.1' => connecting}} +lookup_from_all_node(ChainName, AuthenticatorID) -> + Nodes = mria_mnesia:running_nodes(), + case is_ok(erpc:multicall(Nodes, + emqx_authn_api, + lookup_from_local_node, + [ChainName, AuthenticatorID], + ?TIMEOUT)) of + {ok, ResList} -> + {StatusMap, MetricsMap, ErrorMap} = make_result_map(ResList), + AggregateStatus = aggregate_status(maps:values(StatusMap)), + AggregateMetrics = aggregate_metrics(maps:values(MetricsMap)), + #{all_node_state => StatusMap, + all_node_metrics => MetricsMap, + all_node_error => ErrorMap, + aggregate_status => AggregateStatus, + aggregate_metrics => AggregateMetrics + }; + {error, ErrL} -> + {error_msg('INTERNAL_ERROR', ErrL)} + end. + +aggregate_status([]) -> error_some_strange_happen; +aggregate_status(AllStatus) -> + Head = fun ([A | _]) -> A end, + HeadVal = Head(AllStatus), + AllRes = lists:all(fun (Val) -> Val == HeadVal end, AllStatus), + case AllRes of + true -> HeadVal; + false -> inconsistent + end. + +aggregate_metrics([]) -> error_some_strange_happen; +aggregate_metrics([HeadMetrics | AllMetrics]) -> + CombinerFun = + %% use fixpoint reference self + fun (FixVal) -> + fun (_, Val1, Val2) -> + case erlang:is_map(Val1) of + true -> maps:merge_with(FixVal(FixVal), Val1, Val2); + false -> Val1 + Val2 + end + end + end, + Fun = fun (ElemMap, AccMap) -> maps:merge_with(CombinerFun(CombinerFun), ElemMap, AccMap) end, + lists:foldl(Fun, HeadMetrics, AllMetrics). + +make_result_map(ResList) -> + Fun = + fun(Elem, {StatusMap, MetricsMap, ErrorMap}) -> + case Elem of + {ok, {NodeId, Status, Metrics}} -> + {maps:put(NodeId, Status, StatusMap), + maps:put(NodeId, Metrics, MetricsMap), + ErrorMap + }; + {error, {NodeId, Reason}} -> + {StatusMap, + MetricsMap, + maps:put(NodeId, Reason, ErrorMap) + } + end + end, + lists:foldl(Fun, {maps:new(), maps:new(), maps:new()}, ResList). + + + + + + +error_msg(Code, Msg) when is_binary(Msg) -> + #{code => Code, message => Msg}; +error_msg(Code, Msg) -> + #{code => Code, message => bin(io_lib:format("~p", [Msg]))}. + +bin(S) when is_list(S) -> + list_to_binary(S). + +is_ok(ResL) -> + case lists:filter(fun({ok, _}) -> false; (_) -> true end, ResL) of + [] -> {ok, [Res || {ok, Res} <- ResL]}; + ErrL -> {error, ErrL} + end. + update_authenticator(ConfKeyPath, ChainName, AuthenticatorID, Config) -> case update_config(ConfKeyPath, {update_authenticator, ChainName, AuthenticatorID, Config}) of {ok, #{post_config_update := #{emqx_authentication := #{id := ID}}, From dce602c2517715fd7e6ac1982dbd1c0223f942a8 Mon Sep 17 00:00:00 2001 From: EMQ-YangM Date: Fri, 11 Mar 2022 10:11:11 +0800 Subject: [PATCH 2/7] fix(emqx_authn_api): format metrics and status --- apps/emqx/src/emqx_map_lib.erl | 54 ++++++++++++++ apps/emqx_authn/src/emqx_authn_api.erl | 74 +++++++------------ .../src/proto/emqx_authn_proto_v1.erl | 37 ++++++++++ 3 files changed, 119 insertions(+), 46 deletions(-) create mode 100644 apps/emqx_authn/src/proto/emqx_authn_proto_v1.erl diff --git a/apps/emqx/src/emqx_map_lib.erl b/apps/emqx/src/emqx_map_lib.erl index ba3482f2f..871dfae38 100644 --- a/apps/emqx/src/emqx_map_lib.erl +++ b/apps/emqx/src/emqx_map_lib.erl @@ -28,6 +28,7 @@ , binary_string/1 , deep_convert/3 , diff_maps/2 + , merge_with/3 ]). -export_type([config_key/0, config_key_path/0]). @@ -170,3 +171,56 @@ covert_keys_to_atom(BinKeyMap, Conv) -> (K, V) when is_atom(K) -> {K, V}; (K, V) when is_binary(K) -> {Conv(K), V} end, []). + +%% copy from maps.erl OTP24.0 +-compile({inline, [error_with_info/2]}). +-spec merge_with(Combiner, Map1, Map2) -> Map3 when + Map1 :: #{Key1 => Value1}, + Map2 :: #{Key2 => Value2}, + Combiner :: fun((Key1, Value1, Value2) -> CombineResult), + Map3 :: #{Key1 => CombineResult, Key1 => Value1, Key2 => Value2}. + +merge_with(Combiner, Map1, Map2) when is_map(Map1), + is_map(Map2), + is_function(Combiner, 3) -> + case map_size(Map1) > map_size(Map2) of + true -> + Iterator = maps:iterator(Map2), + merge_with_1(maps:next(Iterator), + Map1, + Map2, + Combiner); + false -> + Iterator = maps:iterator(Map1), + merge_with_1(maps:next(Iterator), + Map2, + Map1, + fun(K, V1, V2) -> Combiner(K, V2, V1) end) + end; +merge_with(Combiner, Map1, Map2) -> + error_with_info(error_type_merge_intersect(Map1, Map2, Combiner), + [Combiner, Map1, Map2]). + +merge_with_1({K, V2, Iterator}, Map1, Map2, Combiner) -> + case Map1 of + #{ K := V1 } -> + NewMap1 = Map1#{ K := Combiner(K, V1, V2) }, + merge_with_1(maps:next(Iterator), NewMap1, Map2, Combiner); + #{ } -> + merge_with_1(maps:next(Iterator), maps:put(K, V2, Map1), Map2, Combiner) + end; +merge_with_1(none, Result, _, _) -> + Result. + +error_type_merge_intersect(M1, M2, Combiner) when is_function(Combiner, 3) -> + error_type_two_maps(M1, M2); +error_type_merge_intersect(_M1, _M2, _Combiner) -> + badarg. + +error_with_info(Reason, Args) -> + erlang:error(Reason, Args, [{error_info, #{module => erl_stdlib_errors}}]). + +error_type_two_maps(M1, M2) when is_map(M1) -> + {badmap, M2}; +error_type_two_maps(M1, _M2) -> + {badmap, M1}. diff --git a/apps/emqx_authn/src/emqx_authn_api.erl b/apps/emqx_authn/src/emqx_authn_api.erl index 1ce8d3b77..028dd9ac4 100644 --- a/apps/emqx_authn/src/emqx_authn_api.erl +++ b/apps/emqx_authn/src/emqx_authn_api.erl @@ -30,7 +30,6 @@ -define(BAD_REQUEST, 'BAD_REQUEST'). -define(NOT_FOUND, 'NOT_FOUND'). -define(CONFLICT, 'CONFLICT'). --define(TIMEOUT, 15000). % Swagger @@ -61,7 +60,7 @@ , listener_authenticator_users/2 , listener_authenticator_user/2 , lookup_from_local_node/2 - , lookup_from_all_node/2 + , lookup_from_all_nodes/2 ]). -export([ authenticator_examples/0 @@ -757,20 +756,14 @@ list_authenticator(ConfKeyPath, AuthenticatorID) -> AuthenticatorsConfig = get_raw_config_with_defaults(ConfKeyPath), case find_config(AuthenticatorID, AuthenticatorsConfig) of {ok, AuthenticatorConfig} -> - {200, maps:put(id, AuthenticatorID, convert_certs(AuthenticatorConfig))}; + Status_And_Metrics = lookup_from_all_nodes(?GLOBAL, AuthenticatorID), + Fun = fun ({Key, Val}, Map) -> maps:put(Key, Val, Map) end, + AppendList = [{id, AuthenticatorID}, {status_and_metrics, Status_And_Metrics}], + {200, lists:foldl(Fun, convert_certs(AuthenticatorConfig), AppendList)}; {error, Reason} -> serialize_error(Reason) end. -%% example: -%% -%% emqx_authn_api:lookup_from_local_node('mqtt:global', <<"password-based:http">>) -%% -%% {ok,{'emqx@127.0.0.1',connecting, -%% #{counters => -%% #{exception => 0,failed => 0,matched => 0,success => 0}, -%% rate => -%% #{matched => #{current => 0.0,last5m => 0.0,max => 0.0}}}}} lookup_from_local_node(ChainName, AuthenticatorID) -> NodeId = node(self()), case emqx_authentication:lookup_authenticator(ChainName, AuthenticatorID) of @@ -796,39 +789,19 @@ resource_provider() -> emqx_authn_http ]. -%% example: -%% -%% emqx_authn_api:lookup_from_all_node('mqtt:global', <<"password-based:http">>) -%% -%% #{aggregate_metrics => -%% #{counters => -%% #{exception => 0,failed => 0,matched => 0,success => 0}, -%% rate => -%% #{matched => #{current => 0.0,last5m => 0.0,max => 0.0}}}, -%% aggregate_status => connecting,all_node_error => #{}, -%% all_node_metrics => -%% #{'emqx@127.0.0.1' => -%% #{counters => -%% #{exception => 0,failed => 0,matched => 0,success => 0}, -%% rate => -%% #{matched => #{current => 0.0,last5m => 0.0,max => 0.0}}}}, -%% all_node_state => #{'emqx@127.0.0.1' => connecting}} -lookup_from_all_node(ChainName, AuthenticatorID) -> +lookup_from_all_nodes(ChainName, AuthenticatorID) -> Nodes = mria_mnesia:running_nodes(), - case is_ok(erpc:multicall(Nodes, - emqx_authn_api, - lookup_from_local_node, - [ChainName, AuthenticatorID], - ?TIMEOUT)) of + case is_ok(emqx_authn_proto_v1:lookup_from_all_nodes(Nodes, ChainName, AuthenticatorID)) of {ok, ResList} -> {StatusMap, MetricsMap, ErrorMap} = make_result_map(ResList), AggregateStatus = aggregate_status(maps:values(StatusMap)), AggregateMetrics = aggregate_metrics(maps:values(MetricsMap)), - #{all_node_state => StatusMap, - all_node_metrics => MetricsMap, - all_node_error => ErrorMap, - aggregate_status => AggregateStatus, - aggregate_metrics => AggregateMetrics + Fun = fun(_, V1) -> restructure_map(V1) end, + #{node_status => StatusMap, + node_metrics => maps:map(Fun, MetricsMap), + node_error => ErrorMap, + status => AggregateStatus, + metrics => restructure_map(AggregateMetrics) }; {error, ErrL} -> {error_msg('INTERNAL_ERROR', ErrL)} @@ -851,12 +824,13 @@ aggregate_metrics([HeadMetrics | AllMetrics]) -> fun (FixVal) -> fun (_, Val1, Val2) -> case erlang:is_map(Val1) of - true -> maps:merge_with(FixVal(FixVal), Val1, Val2); + true -> emqx_map_lib:merge_with(FixVal(FixVal), Val1, Val2); false -> Val1 + Val2 end end end, - Fun = fun (ElemMap, AccMap) -> maps:merge_with(CombinerFun(CombinerFun), ElemMap, AccMap) end, + Fun = fun (ElemMap, AccMap) -> + emqx_map_lib:merge_with(CombinerFun(CombinerFun), ElemMap, AccMap) end, lists:foldl(Fun, HeadMetrics, AllMetrics). make_result_map(ResList) -> @@ -877,10 +851,18 @@ make_result_map(ResList) -> end, lists:foldl(Fun, {maps:new(), maps:new(), maps:new()}, ResList). - - - - +restructure_map(#{counters := #{failed := Failed, matched := Match, success := Succ}, + rate := #{matched := #{current := Rate, last5m := Rate5m, max := RateMax} + } + } + ) -> + #{matched => Match, + success => Succ, + failed => Failed, + rate => Rate, + rate_last5m => Rate5m, + rate_max => RateMax + }. error_msg(Code, Msg) when is_binary(Msg) -> #{code => Code, message => Msg}; diff --git a/apps/emqx_authn/src/proto/emqx_authn_proto_v1.erl b/apps/emqx_authn/src/proto/emqx_authn_proto_v1.erl new file mode 100644 index 000000000..a77c5091b --- /dev/null +++ b/apps/emqx_authn/src/proto/emqx_authn_proto_v1.erl @@ -0,0 +1,37 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2022 EMQ Technologies Co., Ltd. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%%-------------------------------------------------------------------- + +-module(emqx_authn_proto_v1). + +-behaviour(emqx_bpapi). + +-export([ introduced_in/0 + , lookup_from_all_nodes/3 + ]). + +-include_lib("emqx/include/bpapi.hrl"). + +-define(TIMEOUT, 15000). + +introduced_in() -> + "5.0.0". + +-type key() :: atom() | binary() | [byte()]. + +-spec lookup_from_all_nodes([node()], key(), key()) -> + emqx_rpc:erpc_multicall(). +lookup_from_all_nodes(Nodes, ChainName, AuthenticatorID) -> + erpc:multicall(Nodes, emqx_authn_api, lookup_from_local_node, [ChainName, AuthenticatorID], ?TIMEOUT). From 48b167bf46944317f68d5b7a363caf907be2453c Mon Sep 17 00:00:00 2001 From: EMQ-YangM Date: Fri, 11 Mar 2022 12:39:04 +0800 Subject: [PATCH 3/7] test(emqx_authn): add status and metrics test to emqx_authn_api --- apps/emqx_authn/src/emqx_authn_api.erl | 14 ++++---- apps/emqx_authn/test/emqx_authn_api_SUITE.erl | 34 +++++++++++++++++-- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/apps/emqx_authn/src/emqx_authn_api.erl b/apps/emqx_authn/src/emqx_authn_api.erl index 028dd9ac4..b28ded461 100644 --- a/apps/emqx_authn/src/emqx_authn_api.erl +++ b/apps/emqx_authn/src/emqx_authn_api.erl @@ -552,7 +552,7 @@ authenticators(get, _Params) -> list_authenticators([authentication]). authenticator(get, #{bindings := #{id := AuthenticatorID}}) -> - list_authenticator([authentication], AuthenticatorID); + list_authenticator(?GLOBAL, [authentication], AuthenticatorID); authenticator(put, #{bindings := #{id := AuthenticatorID}, body := Config}) -> update_authenticator([authentication], ?GLOBAL, AuthenticatorID, Config); @@ -576,8 +576,8 @@ listener_authenticators(get, #{bindings := #{listener_id := ListenerID}}) -> listener_authenticator(get, #{bindings := #{listener_id := ListenerID, id := AuthenticatorID}}) -> with_listener(ListenerID, - fun(Type, Name, _) -> - list_authenticator([listeners, Type, Name, authentication], + fun(Type, Name, ChainName) -> + list_authenticator(ChainName, [listeners, Type, Name, authentication], AuthenticatorID) end); listener_authenticator(put, @@ -752,11 +752,11 @@ list_authenticators(ConfKeyPath) -> || AuthenticatorConfig <- AuthenticatorsConfig], {200, NAuthenticators}. -list_authenticator(ConfKeyPath, AuthenticatorID) -> +list_authenticator(ChainName, ConfKeyPath, AuthenticatorID) -> AuthenticatorsConfig = get_raw_config_with_defaults(ConfKeyPath), case find_config(AuthenticatorID, AuthenticatorsConfig) of {ok, AuthenticatorConfig} -> - Status_And_Metrics = lookup_from_all_nodes(?GLOBAL, AuthenticatorID), + Status_And_Metrics = lookup_from_all_nodes(ChainName, AuthenticatorID), Fun = fun ({Key, Val}, Map) -> maps:put(Key, Val, Map) end, AppendList = [{id, AuthenticatorID}, {status_and_metrics, Status_And_Metrics}], {200, lists:foldl(Fun, convert_certs(AuthenticatorConfig), AppendList)}; @@ -862,7 +862,9 @@ restructure_map(#{counters := #{failed := Failed, matched := Match, success := S rate => Rate, rate_last5m => Rate5m, rate_max => RateMax - }. + }; +restructure_map(Error) -> + Error. error_msg(Code, Msg) when is_binary(Msg) -> #{code => Code, message => Msg}; diff --git a/apps/emqx_authn/test/emqx_authn_api_SUITE.erl b/apps/emqx_authn/test/emqx_authn_api_SUITE.erl index b0164d93d..dba516346 100644 --- a/apps/emqx_authn/test/emqx_authn_api_SUITE.erl +++ b/apps/emqx_authn/test/emqx_authn_api_SUITE.erl @@ -164,10 +164,38 @@ test_authenticator(PathPrefix) -> post, uri(PathPrefix ++ [?CONF_NS]), ValidConfig0), - {ok, 200, _} = request( + {ok, 200, Res} = request( get, - uri(PathPrefix ++ [?CONF_NS, "password_based:http"])), - + uri(PathPrefix ++ [?CONF_NS, "password-based:http"])), + {ok, RList} = emqx_json:safe_decode(Res), + Snd = fun ({_, Val}) -> Val end, + LookupVal = + fun(FixVal) -> + fun(List, RestJson) -> + case List of + [Name] -> Snd(lists:keyfind(Name, 1, RestJson)); + [Name | NS] -> (FixVal(FixVal))(NS, Snd(lists:keyfind(Name, 1, RestJson))) + end + end + end, + LookFun = fun (List) -> (LookupVal(LookupVal)) (List, RList) end, + MetricsList = [{<<"failed">>, 0}, + {<<"matched">>, 0}, + {<<"rate">>, 0.0}, + {<<"rate_last5m">>, 0.0}, + {<<"rate_max">>, 0.0}, + {<<"success">>, 0}], + EqualFun = fun ({M, V}) -> + ?assertEqual(V, LookFun([<<"status_and_metrics">>, + <<"metrics">>, + M] + ) + ) end, + lists:map(EqualFun, MetricsList), + ?assertEqual(<<"connected">>, + LookFun([<<"status_and_metrics">>, + <<"status">> + ])), {ok, 404, _} = request( get, uri(PathPrefix ++ [?CONF_NS, "password_based:redis"])), From 7165fbc5cae1d318eb01ffee871beb47fb14552b Mon Sep 17 00:00:00 2001 From: EMQ-YangM Date: Fri, 11 Mar 2022 12:46:12 +0800 Subject: [PATCH 4/7] fix(emqx_authn_api): fix elvis error --- apps/emqx/src/emqx_map_lib.erl | 12 ++++++------ apps/emqx_authn/src/emqx_authn_api.erl | 4 ++-- apps/emqx_authn/test/emqx_authn_api_SUITE.erl | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/emqx/src/emqx_map_lib.erl b/apps/emqx/src/emqx_map_lib.erl index 871dfae38..b46e749eb 100644 --- a/apps/emqx/src/emqx_map_lib.erl +++ b/apps/emqx/src/emqx_map_lib.erl @@ -186,13 +186,13 @@ merge_with(Combiner, Map1, Map2) when is_map(Map1), case map_size(Map1) > map_size(Map2) of true -> Iterator = maps:iterator(Map2), - merge_with_1(maps:next(Iterator), + merge_with_t(maps:next(Iterator), Map1, Map2, Combiner); false -> Iterator = maps:iterator(Map1), - merge_with_1(maps:next(Iterator), + merge_with_t(maps:next(Iterator), Map2, Map1, fun(K, V1, V2) -> Combiner(K, V2, V1) end) @@ -201,15 +201,15 @@ merge_with(Combiner, Map1, Map2) -> error_with_info(error_type_merge_intersect(Map1, Map2, Combiner), [Combiner, Map1, Map2]). -merge_with_1({K, V2, Iterator}, Map1, Map2, Combiner) -> +merge_with_t({K, V2, Iterator}, Map1, Map2, Combiner) -> case Map1 of #{ K := V1 } -> NewMap1 = Map1#{ K := Combiner(K, V1, V2) }, - merge_with_1(maps:next(Iterator), NewMap1, Map2, Combiner); + merge_with_t(maps:next(Iterator), NewMap1, Map2, Combiner); #{ } -> - merge_with_1(maps:next(Iterator), maps:put(K, V2, Map1), Map2, Combiner) + merge_with_t(maps:next(Iterator), maps:put(K, V2, Map1), Map2, Combiner) end; -merge_with_1(none, Result, _, _) -> +merge_with_t(none, Result, _, _) -> Result. error_type_merge_intersect(M1, M2, Combiner) when is_function(Combiner, 3) -> diff --git a/apps/emqx_authn/src/emqx_authn_api.erl b/apps/emqx_authn/src/emqx_authn_api.erl index b28ded461..9d2f7f55e 100644 --- a/apps/emqx_authn/src/emqx_authn_api.erl +++ b/apps/emqx_authn/src/emqx_authn_api.erl @@ -756,9 +756,9 @@ list_authenticator(ChainName, ConfKeyPath, AuthenticatorID) -> AuthenticatorsConfig = get_raw_config_with_defaults(ConfKeyPath), case find_config(AuthenticatorID, AuthenticatorsConfig) of {ok, AuthenticatorConfig} -> - Status_And_Metrics = lookup_from_all_nodes(ChainName, AuthenticatorID), + StatusAndMetrics = lookup_from_all_nodes(ChainName, AuthenticatorID), Fun = fun ({Key, Val}, Map) -> maps:put(Key, Val, Map) end, - AppendList = [{id, AuthenticatorID}, {status_and_metrics, Status_And_Metrics}], + AppendList = [{id, AuthenticatorID}, {status_and_metrics, StatusAndMetrics}], {200, lists:foldl(Fun, convert_certs(AuthenticatorConfig), AppendList)}; {error, Reason} -> serialize_error(Reason) diff --git a/apps/emqx_authn/test/emqx_authn_api_SUITE.erl b/apps/emqx_authn/test/emqx_authn_api_SUITE.erl index dba516346..210ad552a 100644 --- a/apps/emqx_authn/test/emqx_authn_api_SUITE.erl +++ b/apps/emqx_authn/test/emqx_authn_api_SUITE.erl @@ -178,7 +178,7 @@ test_authenticator(PathPrefix) -> end end end, - LookFun = fun (List) -> (LookupVal(LookupVal)) (List, RList) end, + LookFun = fun (List) -> (LookupVal(LookupVal))(List, RList) end, MetricsList = [{<<"failed">>, 0}, {<<"matched">>, 0}, {<<"rate">>, 0.0}, From 8af7131a499dcfb43cc1d092a6ef5b4b1b63b0a5 Mon Sep 17 00:00:00 2001 From: EMQ-YangM Date: Fri, 11 Mar 2022 14:04:18 +0800 Subject: [PATCH 5/7] fix(emqx_autn_api): wo do not need fixpoint --- apps/emqx/src/emqx_map_lib.erl | 1 + apps/emqx_authn/src/emqx_authn_api.erl | 11 ++++------- apps/emqx_authn/src/proto/emqx_authn_proto_v1.erl | 1 + apps/emqx_authn/test/emqx_authn_api_SUITE.erl | 13 +++++-------- 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/apps/emqx/src/emqx_map_lib.erl b/apps/emqx/src/emqx_map_lib.erl index b46e749eb..11044ef74 100644 --- a/apps/emqx/src/emqx_map_lib.erl +++ b/apps/emqx/src/emqx_map_lib.erl @@ -224,3 +224,4 @@ error_type_two_maps(M1, M2) when is_map(M1) -> {badmap, M2}; error_type_two_maps(M1, _M2) -> {badmap, M1}. + diff --git a/apps/emqx_authn/src/emqx_authn_api.erl b/apps/emqx_authn/src/emqx_authn_api.erl index 9d2f7f55e..37d41e344 100644 --- a/apps/emqx_authn/src/emqx_authn_api.erl +++ b/apps/emqx_authn/src/emqx_authn_api.erl @@ -820,13 +820,10 @@ aggregate_status(AllStatus) -> aggregate_metrics([]) -> error_some_strange_happen; aggregate_metrics([HeadMetrics | AllMetrics]) -> CombinerFun = - %% use fixpoint reference self - fun (FixVal) -> - fun (_, Val1, Val2) -> - case erlang:is_map(Val1) of - true -> emqx_map_lib:merge_with(FixVal(FixVal), Val1, Val2); - false -> Val1 + Val2 - end + fun ComFun(Val1, Val2) -> + case erlang:is_map(Val1) of + true -> emqx_map_lib:merge_with(ComFun, Val1, Val2); + false -> Val1 + Val2 end end, Fun = fun (ElemMap, AccMap) -> diff --git a/apps/emqx_authn/src/proto/emqx_authn_proto_v1.erl b/apps/emqx_authn/src/proto/emqx_authn_proto_v1.erl index a77c5091b..df5d19e94 100644 --- a/apps/emqx_authn/src/proto/emqx_authn_proto_v1.erl +++ b/apps/emqx_authn/src/proto/emqx_authn_proto_v1.erl @@ -35,3 +35,4 @@ introduced_in() -> emqx_rpc:erpc_multicall(). lookup_from_all_nodes(Nodes, ChainName, AuthenticatorID) -> erpc:multicall(Nodes, emqx_authn_api, lookup_from_local_node, [ChainName, AuthenticatorID], ?TIMEOUT). + diff --git a/apps/emqx_authn/test/emqx_authn_api_SUITE.erl b/apps/emqx_authn/test/emqx_authn_api_SUITE.erl index 210ad552a..93dd5d084 100644 --- a/apps/emqx_authn/test/emqx_authn_api_SUITE.erl +++ b/apps/emqx_authn/test/emqx_authn_api_SUITE.erl @@ -169,16 +169,13 @@ test_authenticator(PathPrefix) -> uri(PathPrefix ++ [?CONF_NS, "password-based:http"])), {ok, RList} = emqx_json:safe_decode(Res), Snd = fun ({_, Val}) -> Val end, - LookupVal = - fun(FixVal) -> - fun(List, RestJson) -> - case List of - [Name] -> Snd(lists:keyfind(Name, 1, RestJson)); - [Name | NS] -> (FixVal(FixVal))(NS, Snd(lists:keyfind(Name, 1, RestJson))) - end + LookupVal = fun LookupV(List, RestJson) -> + case List of + [Name] -> Snd(lists:keyfind(Name, 1, RestJson)); + [Name | NS] -> LookupV(NS, Snd(lists:keyfind(Name, 1, RestJson))) end end, - LookFun = fun (List) -> (LookupVal(LookupVal))(List, RList) end, + LookFun = fun (List) -> LookupVal(List, RList) end, MetricsList = [{<<"failed">>, 0}, {<<"matched">>, 0}, {<<"rate">>, 0.0}, From b7a9f1e087fff14bd67f5df0761d5f0e2c74ef69 Mon Sep 17 00:00:00 2001 From: EMQ-YangM Date: Fri, 11 Mar 2022 14:54:09 +0800 Subject: [PATCH 6/7] fix(emqx_map_lib): fix static checks errors --- apps/emqx/src/emqx_map_lib.erl | 11 ++--------- apps/emqx_authn/src/emqx_authn_api.erl | 4 +--- apps/emqx_authn/src/proto/emqx_authn_proto_v1.erl | 5 +---- apps/emqx_authn/test/emqx_authn_api_SUITE.erl | 2 +- 4 files changed, 5 insertions(+), 17 deletions(-) diff --git a/apps/emqx/src/emqx_map_lib.erl b/apps/emqx/src/emqx_map_lib.erl index 11044ef74..c22a13e33 100644 --- a/apps/emqx/src/emqx_map_lib.erl +++ b/apps/emqx/src/emqx_map_lib.erl @@ -174,12 +174,6 @@ covert_keys_to_atom(BinKeyMap, Conv) -> %% copy from maps.erl OTP24.0 -compile({inline, [error_with_info/2]}). --spec merge_with(Combiner, Map1, Map2) -> Map3 when - Map1 :: #{Key1 => Value1}, - Map2 :: #{Key2 => Value2}, - Combiner :: fun((Key1, Value1, Value2) -> CombineResult), - Map3 :: #{Key1 => CombineResult, Key1 => Value1, Key2 => Value2}. - merge_with(Combiner, Map1, Map2) when is_map(Map1), is_map(Map2), is_function(Combiner, 3) -> @@ -217,11 +211,10 @@ error_type_merge_intersect(M1, M2, Combiner) when is_function(Combiner, 3) -> error_type_merge_intersect(_M1, _M2, _Combiner) -> badarg. -error_with_info(Reason, Args) -> - erlang:error(Reason, Args, [{error_info, #{module => erl_stdlib_errors}}]). +error_with_info(_, _) -> + {error_info, #{module => erl_stdlib_errors}}. error_type_two_maps(M1, M2) when is_map(M1) -> {badmap, M2}; error_type_two_maps(M1, _M2) -> {badmap, M1}. - diff --git a/apps/emqx_authn/src/emqx_authn_api.erl b/apps/emqx_authn/src/emqx_authn_api.erl index 37d41e344..1619d9239 100644 --- a/apps/emqx_authn/src/emqx_authn_api.erl +++ b/apps/emqx_authn/src/emqx_authn_api.erl @@ -827,7 +827,7 @@ aggregate_metrics([HeadMetrics | AllMetrics]) -> end end, Fun = fun (ElemMap, AccMap) -> - emqx_map_lib:merge_with(CombinerFun(CombinerFun), ElemMap, AccMap) end, + emqx_map_lib:merge_with(CombinerFun, ElemMap, AccMap) end, lists:foldl(Fun, HeadMetrics, AllMetrics). make_result_map(ResList) -> @@ -863,8 +863,6 @@ restructure_map(#{counters := #{failed := Failed, matched := Match, success := S restructure_map(Error) -> Error. -error_msg(Code, Msg) when is_binary(Msg) -> - #{code => Code, message => Msg}; error_msg(Code, Msg) -> #{code => Code, message => bin(io_lib:format("~p", [Msg]))}. diff --git a/apps/emqx_authn/src/proto/emqx_authn_proto_v1.erl b/apps/emqx_authn/src/proto/emqx_authn_proto_v1.erl index df5d19e94..1d93ded8e 100644 --- a/apps/emqx_authn/src/proto/emqx_authn_proto_v1.erl +++ b/apps/emqx_authn/src/proto/emqx_authn_proto_v1.erl @@ -29,10 +29,7 @@ introduced_in() -> "5.0.0". --type key() :: atom() | binary() | [byte()]. - --spec lookup_from_all_nodes([node()], key(), key()) -> +-spec lookup_from_all_nodes([node()], atom(), binary()) -> emqx_rpc:erpc_multicall(). lookup_from_all_nodes(Nodes, ChainName, AuthenticatorID) -> erpc:multicall(Nodes, emqx_authn_api, lookup_from_local_node, [ChainName, AuthenticatorID], ?TIMEOUT). - diff --git a/apps/emqx_authn/test/emqx_authn_api_SUITE.erl b/apps/emqx_authn/test/emqx_authn_api_SUITE.erl index 93dd5d084..cc6476f0b 100644 --- a/apps/emqx_authn/test/emqx_authn_api_SUITE.erl +++ b/apps/emqx_authn/test/emqx_authn_api_SUITE.erl @@ -166,7 +166,7 @@ test_authenticator(PathPrefix) -> ValidConfig0), {ok, 200, Res} = request( get, - uri(PathPrefix ++ [?CONF_NS, "password-based:http"])), + uri(PathPrefix ++ [?CONF_NS, "password_based:http"])), {ok, RList} = emqx_json:safe_decode(Res), Snd = fun ({_, Val}) -> Val end, LookupVal = fun LookupV(List, RestJson) -> From 81f9482face01830c450e7884dfe2d65608fde9e Mon Sep 17 00:00:00 2001 From: EMQ-YangM Date: Fri, 11 Mar 2022 17:37:24 +0800 Subject: [PATCH 7/7] fix(bpapi): add authn bpapi version --- apps/emqx/priv/bpapi.versions | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/emqx/priv/bpapi.versions b/apps/emqx/priv/bpapi.versions index 1f040e4b3..c832ed79c 100644 --- a/apps/emqx/priv/bpapi.versions +++ b/apps/emqx/priv/bpapi.versions @@ -1,5 +1,6 @@ {emqx,1}. {emqx_bridge,1}. +{emqx_authn,1}. {emqx_broker,1}. {emqx_cm,1}. {emqx_conf,1}.