diff --git a/apps/emqx_gateway/i18n/emqx_gateway_api_i18n.conf b/apps/emqx_gateway/i18n/emqx_gateway_api_i18n.conf index 468a88b7b..5ab9277b2 100644 --- a/apps/emqx_gateway/i18n/emqx_gateway_api_i18n.conf +++ b/apps/emqx_gateway/i18n/emqx_gateway_api_i18n.conf @@ -118,4 +118,19 @@ emqx_gateway_api { zh: """监听器类型""" } } + + gateway_node_status { + desc { + en: """The status of the gateway on each node in the cluster""" + zh: """网关在集群中每个节点上的状态""" + } + } + + node { + desc { + en: """Node Name""" + zh: """节点名称""" + } + } + } diff --git a/apps/emqx_gateway/src/emqx_gateway_api.erl b/apps/emqx_gateway/src/emqx_gateway_api.erl index 86e2a946d..162fa2b62 100644 --- a/apps/emqx_gateway/src/emqx_gateway_api.erl +++ b/apps/emqx_gateway/src/emqx_gateway_api.erl @@ -302,7 +302,9 @@ fields(gateway_overview) -> required => {false, recursively}, desc => ?DESC(gateway_listeners) } - )} + )}, + {node_status, + mk(hoconsc:array(ref(gateway_node_status)), #{desc => ?DESC(gateway_node_status)})} ]; fields(gateway_listener_overview) -> [ @@ -322,6 +324,25 @@ fields(gateway_listener_overview) -> #{desc => ?DESC(gateway_listener_type)} )} ]; +fields(gateway_node_status) -> + [ + {node, mk(node(), #{desc => ?DESC(node)})}, + {status, + mk( + hoconsc:enum([running, stopped, unloaded]), + #{desc => ?DESC(gateway_status)} + )}, + {max_connections, + mk( + pos_integer(), + #{desc => ?DESC(gateway_max_connections)} + )}, + {current_connections, + mk( + non_neg_integer(), + #{desc => ?DESC(gateway_current_connections)} + )} + ]; fields(Gw) when Gw == stomp; Gw == mqttsn; @@ -472,7 +493,15 @@ examples_gateway_overview() -> } ], created_at => <<"2021-12-08T14:41:26.171+08:00">>, - started_at => <<"2021-12-08T14:41:26.202+08:00">> + started_at => <<"2021-12-08T14:41:26.202+08:00">>, + node_status => [ + #{ + node => <<"node@127.0.0.1">>, + status => <<"running">>, + current_connections => 0, + max_connections => 1024000 + } + ] }, #{ name => <<"mqttsn">>, @@ -489,7 +518,15 @@ examples_gateway_overview() -> } ], created_at => <<"2021-12-08T14:41:45.071+08:00">>, - stopped_at => <<"2021-12-08T14:56:35.576+08:00">> + stopped_at => <<"2021-12-08T14:56:35.576+08:00">>, + node_status => [ + #{ + node => <<"node@127.0.0.1">>, + status => <<"running">>, + current_connections => 0, + max_connections => 1024000 + } + ] }, #{ name => <<"stomp">>, @@ -506,7 +543,15 @@ examples_gateway_overview() -> } ], created_at => <<"2021-12-08T14:42:15.272+08:00">>, - started_at => <<"2021-12-08T14:42:15.274+08:00">> + started_at => <<"2021-12-08T14:42:15.274+08:00">>, + node_status => [ + #{ + node => <<"node@127.0.0.1">>, + status => <<"running">>, + current_connections => 0, + max_connections => 1024000 + } + ] } ]. diff --git a/apps/emqx_gateway/src/emqx_gateway_http.erl b/apps/emqx_gateway/src/emqx_gateway_http.erl index f104c6629..48f92b6d3 100644 --- a/apps/emqx_gateway/src/emqx_gateway_http.erl +++ b/apps/emqx_gateway/src/emqx_gateway_http.erl @@ -66,6 +66,9 @@ reason2msg/1 ]). +%% RPC +-export([gateway_status/1, cluster_gateway_status/1]). + -type gateway_summary() :: #{ name := binary(), @@ -116,7 +119,8 @@ gateways(Status) -> GwInfo1#{ max_connections => max_connections_count(Config), current_connections => current_connections_count(GwName), - listeners => get_listeners_status(GwName, Config) + listeners => get_listeners_status(GwName, Config), + node_status => cluster_gateway_status(GwName) } end end, @@ -127,6 +131,28 @@ gateways(Status) -> _ -> [Gw || Gw = #{status := S} <- Gateways, S == Status] end. +gateway_status(GwName) -> + case emqx_gateway:lookup(GwName) of + undefined -> + #{node => node(), status => unloaded}; + #{status := Status, config := Config} -> + #{ + node => node(), + status => Status, + max_connections => max_connections_count(Config), + current_connections => current_connections_count(GwName) + } + end. + +cluster_gateway_status(GwName) -> + Nodes = mria_mnesia:running_nodes(), + case emqx_gateway_http_proto_v1:get_node_status(Nodes, GwName) of + {Results, []} -> + Results; + {_, _BadNodes} -> + error(badrpc) + end. + %% @private max_connections_count(Config) -> Listeners = emqx_gateway_utils:normalize_config(Config), diff --git a/apps/emqx_gateway/src/proto/emqx_gateway_http_proto_v1.erl b/apps/emqx_gateway/src/proto/emqx_gateway_http_proto_v1.erl new file mode 100644 index 000000000..6609adba5 --- /dev/null +++ b/apps/emqx_gateway/src/proto/emqx_gateway_http_proto_v1.erl @@ -0,0 +1,35 @@ +%%-------------------------------------------------------------------- +%% 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_gateway_http_proto_v1). + +-behaviour(emqx_bpapi). + +-export([ + introduced_in/0, + + get_cluster_status/2 +]). + +-include_lib("emqx/include/bpapi.hrl"). + +introduced_in() -> + "5.0.0". + +-spec get_cluster_status([node()], emqx_gateway_cm:gateway_name()) -> + emqx_rpc:multicall_result([map()]). +get_cluster_status(Nodes, GwName) -> + rpc:multicall(Nodes, emqx_gateway_http, gateway_status, [GwName]).