From c20da5ffa6decba63b573f78d5caf14e740fe61b Mon Sep 17 00:00:00 2001 From: Ivan Dyachkov Date: Mon, 3 Apr 2023 11:55:36 +0200 Subject: [PATCH 1/4] fix(emqx_dashboard): fix monitor_current api --- apps/emqx_dashboard/src/emqx_dashboard.app.src | 2 +- apps/emqx_dashboard/src/emqx_dashboard_monitor_api.erl | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/emqx_dashboard/src/emqx_dashboard.app.src b/apps/emqx_dashboard/src/emqx_dashboard.app.src index 3970d76e4..8a4764c84 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard.app.src +++ b/apps/emqx_dashboard/src/emqx_dashboard.app.src @@ -2,7 +2,7 @@ {application, emqx_dashboard, [ {description, "EMQX Web Dashboard"}, % strict semver, bump manually! - {vsn, "5.0.15"}, + {vsn, "5.0.16"}, {modules, []}, {registered, [emqx_dashboard_sup]}, {applications, [kernel, stdlib, mnesia, minirest, emqx, emqx_ctl]}, diff --git a/apps/emqx_dashboard/src/emqx_dashboard_monitor_api.erl b/apps/emqx_dashboard/src/emqx_dashboard_monitor_api.erl index 69f5bf34e..34a8f0231 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard_monitor_api.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard_monitor_api.erl @@ -132,6 +132,8 @@ dashboard_samplers_fun(Latest) -> end end. +monitor_current(get, #{bindings := []}) -> + with_node(erlang:node(), fun emqx_dashboard_monitor:current_rate/1); monitor_current(get, #{bindings := Bindings}) -> RawNode = maps:get(node, Bindings, all), with_node(RawNode, fun emqx_dashboard_monitor:current_rate/1). From 3d7ceb01a0ba4af0d68fee5598a7bc1f70d7b972 Mon Sep 17 00:00:00 2001 From: Ivan Dyachkov Date: Mon, 3 Apr 2023 14:14:21 +0200 Subject: [PATCH 2/4] fix(mgmt): fix stats api by applying filter to running_nodes --- apps/emqx_management/src/emqx_management.app.src | 2 +- apps/emqx_management/src/emqx_mgmt_api_stats.erl | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/emqx_management/src/emqx_management.app.src b/apps/emqx_management/src/emqx_management.app.src index 966358f47..9863f5cf6 100644 --- a/apps/emqx_management/src/emqx_management.app.src +++ b/apps/emqx_management/src/emqx_management.app.src @@ -2,7 +2,7 @@ {application, emqx_management, [ {description, "EMQX Management API and CLI"}, % strict semver, bump manually! - {vsn, "5.0.16"}, + {vsn, "5.0.17"}, {modules, []}, {registered, [emqx_management_sup]}, {applications, [kernel, stdlib, emqx_plugins, minirest, emqx, emqx_ctl]}, diff --git a/apps/emqx_management/src/emqx_mgmt_api_stats.erl b/apps/emqx_management/src/emqx_mgmt_api_stats.erl index 1d3c0e21b..105f6c047 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_stats.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_stats.erl @@ -129,7 +129,19 @@ list(get, #{query_string := Qs}) -> _ -> Data = [ maps:from_list(emqx_mgmt:get_stats(Node) ++ [{node, Node}]) - || Node <- mria:running_nodes() + || Node <- running_nodes() ], {200, Data} end. + +%%%============================================================================================== +%% Internal + +running_nodes() -> + Nodes = erlang:nodes([visible, this]), + RpcResults = erpc:multicall(Nodes, emqx, is_running, [], 15000), + [ + Node + || {Node, IsRunning} <- lists:zip(Nodes, RpcResults), + IsRunning =:= {ok, true} + ]. From 2571da368cf9ba18f07476fec32dca2fc86947eb Mon Sep 17 00:00:00 2001 From: Ivan Dyachkov Date: Mon, 3 Apr 2023 15:28:18 +0200 Subject: [PATCH 3/4] chore: add changelog --- changes/ce/fix-10314.en.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 changes/ce/fix-10314.en.md diff --git a/changes/ce/fix-10314.en.md b/changes/ce/fix-10314.en.md new file mode 100644 index 000000000..0557e714e --- /dev/null +++ b/changes/ce/fix-10314.en.md @@ -0,0 +1,2 @@ +Fix /monitor_current API so that it only looks at the current node. +Fix /stats API to not crash when one or more nodes in the cluster are down. From 9d1a16aae1c329a3fb4fe5e3fc1d9c20782d5bf2 Mon Sep 17 00:00:00 2001 From: Ivan Dyachkov Date: Tue, 4 Apr 2023 20:40:47 +0200 Subject: [PATCH 4/4] feat: add emqx_rpc:multicall_on_running also move emqx:is_running multicall to emqx_proto_v2:are_running --- apps/emqx/priv/bpapi.versions | 1 + apps/emqx/src/emqx_rpc.erl | 13 +++ apps/emqx/src/proto/emqx_proto_v2.erl | 86 +++++++++++++++++++ .../src/emqx_mgmt_api_stats.erl | 2 +- 4 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 apps/emqx/src/proto/emqx_proto_v2.erl diff --git a/apps/emqx/priv/bpapi.versions b/apps/emqx/priv/bpapi.versions index 6190925d2..c5619102c 100644 --- a/apps/emqx/priv/bpapi.versions +++ b/apps/emqx/priv/bpapi.versions @@ -1,5 +1,6 @@ %% This file is automatically generated by `make static_checks`, do not edit. {emqx,1}. +{emqx,2}. {emqx_authn,1}. {emqx_authz,1}. {emqx_bridge,1}. diff --git a/apps/emqx/src/emqx_rpc.erl b/apps/emqx/src/emqx_rpc.erl index e1b5122c4..062bde68b 100644 --- a/apps/emqx/src/emqx_rpc.erl +++ b/apps/emqx/src/emqx_rpc.erl @@ -27,6 +27,8 @@ cast/5, multicall/4, multicall/5, + multicall_on_running/5, + on_running/3, unwrap_erpc/1 ]). @@ -91,6 +93,17 @@ multicall(Nodes, Mod, Fun, Args) -> multicall(Key, Nodes, Mod, Fun, Args) -> gen_rpc:multicall(rpc_nodes([{Key, Node} || Node <- Nodes]), Mod, Fun, Args). +-spec multicall_on_running([node()], module(), atom(), list(), timeout()) -> [term() | {error, _}]. +multicall_on_running(Nodes, Mod, Fun, Args, Timeout) -> + unwrap_erpc(erpc:multicall(Nodes, emqx_rpc, on_running, [Mod, Fun, Args], Timeout)). + +-spec on_running(module(), atom(), list()) -> term(). +on_running(Mod, Fun, Args) -> + case emqx:is_running() of + true -> apply(Mod, Fun, Args); + false -> error(emqx_down) + end. + -spec cast(node(), module(), atom(), list()) -> cast_result(). cast(Node, Mod, Fun, Args) -> %% Note: using a non-ordered cast here, since the generated key is diff --git a/apps/emqx/src/proto/emqx_proto_v2.erl b/apps/emqx/src/proto/emqx_proto_v2.erl new file mode 100644 index 000000000..a11c8a10e --- /dev/null +++ b/apps/emqx/src/proto/emqx_proto_v2.erl @@ -0,0 +1,86 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2022-2023 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_proto_v2). + +-behaviour(emqx_bpapi). + +-include("bpapi.hrl"). + +-export([ + introduced_in/0, + + are_running/1, + is_running/1, + + get_alarms/2, + get_stats/1, + get_metrics/1, + + deactivate_alarm/2, + delete_all_deactivated_alarms/1, + + clean_authz_cache/1, + clean_authz_cache/2, + clean_pem_cache/1 +]). + +introduced_in() -> + "5.0.22". + +-spec is_running(node()) -> boolean() | {badrpc, term()}. +is_running(Node) -> + rpc:call(Node, emqx, is_running, []). + +-spec are_running([node()]) -> emqx_rpc:erpc_multicall(boolean()). +are_running(Nodes) when is_list(Nodes) -> + erpc:multicall(Nodes, emqx, is_running, []). + +-spec get_alarms(node(), all | activated | deactivated) -> [map()]. +get_alarms(Node, Type) -> + rpc:call(Node, emqx_alarm, get_alarms, [Type]). + +-spec get_stats(node()) -> emqx_stats:stats() | {badrpc, _}. +get_stats(Node) -> + rpc:call(Node, emqx_stats, getstats, []). + +-spec get_metrics(node()) -> [{emqx_metrics:metric_name(), non_neg_integer()}] | {badrpc, _}. +get_metrics(Node) -> + rpc:call(Node, emqx_metrics, all, []). + +-spec clean_authz_cache(node(), emqx_types:clientid()) -> + ok + | {error, not_found} + | {badrpc, _}. +clean_authz_cache(Node, ClientId) -> + rpc:call(Node, emqx_authz_cache, drain_cache, [ClientId]). + +-spec clean_authz_cache(node()) -> ok | {badrpc, _}. +clean_authz_cache(Node) -> + rpc:call(Node, emqx_authz_cache, drain_cache, []). + +-spec clean_pem_cache(node()) -> ok | {badrpc, _}. +clean_pem_cache(Node) -> + rpc:call(Node, ssl_pem_cache, clear, []). + +-spec deactivate_alarm(node(), binary() | atom()) -> + ok | {error, not_found} | {badrpc, _}. +deactivate_alarm(Node, Name) -> + rpc:call(Node, emqx_alarm, deactivate, [Name]). + +-spec delete_all_deactivated_alarms(node()) -> ok | {badrpc, _}. +delete_all_deactivated_alarms(Node) -> + rpc:call(Node, emqx_alarm, delete_all_deactivated_alarms, []). diff --git a/apps/emqx_management/src/emqx_mgmt_api_stats.erl b/apps/emqx_management/src/emqx_mgmt_api_stats.erl index 105f6c047..1e752aaac 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_stats.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_stats.erl @@ -139,7 +139,7 @@ list(get, #{query_string := Qs}) -> running_nodes() -> Nodes = erlang:nodes([visible, this]), - RpcResults = erpc:multicall(Nodes, emqx, is_running, [], 15000), + RpcResults = emqx_proto_v2:are_running(Nodes), [ Node || {Node, IsRunning} <- lists:zip(Nodes, RpcResults),