315 lines
9.4 KiB
Erlang
315 lines
9.4 KiB
Erlang
%%--------------------------------------------------------------------
|
|
%% Copyright (c) 2020-2024 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_mgmt_api_nodes).
|
|
|
|
-behaviour(minirest_api).
|
|
|
|
-include_lib("typerefl/include/types.hrl").
|
|
-include_lib("hocon/include/hoconsc.hrl").
|
|
|
|
-import(hoconsc, [mk/2, ref/1, ref/2, enum/1, array/1]).
|
|
|
|
-define(NODE_METRICS_MODULE, emqx_mgmt_api_metrics).
|
|
-define(NODE_STATS_MODULE, emqx_mgmt_api_stats).
|
|
|
|
%% Swagger specs from hocon schema
|
|
-export([
|
|
api_spec/0,
|
|
schema/1,
|
|
paths/0,
|
|
fields/1,
|
|
namespace/0
|
|
]).
|
|
|
|
%% API callbacks
|
|
-export([
|
|
nodes/2,
|
|
node/2,
|
|
node_metrics/2,
|
|
node_stats/2
|
|
]).
|
|
|
|
%%--------------------------------------------------------------------
|
|
%% API spec funcs
|
|
%%--------------------------------------------------------------------
|
|
|
|
namespace() -> undefined.
|
|
|
|
api_spec() ->
|
|
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}).
|
|
|
|
paths() ->
|
|
[
|
|
"/nodes",
|
|
"/nodes/:node",
|
|
"/nodes/:node/metrics",
|
|
"/nodes/:node/stats"
|
|
].
|
|
|
|
schema("/nodes") ->
|
|
#{
|
|
'operationId' => nodes,
|
|
get =>
|
|
#{
|
|
description => ?DESC(list_nodes),
|
|
tags => [<<"Nodes">>],
|
|
responses =>
|
|
#{
|
|
200 => mk(
|
|
array(ref(node_info)),
|
|
#{desc => <<"List all EMQX nodes">>}
|
|
)
|
|
}
|
|
}
|
|
};
|
|
schema("/nodes/:node") ->
|
|
#{
|
|
'operationId' => node,
|
|
get =>
|
|
#{
|
|
description => ?DESC(get_node_info),
|
|
tags => [<<"Nodes">>],
|
|
parameters => [ref(node_name)],
|
|
responses =>
|
|
#{
|
|
200 => mk(
|
|
ref(node_info),
|
|
#{desc => <<"Get node info successfully">>}
|
|
),
|
|
404 => not_found()
|
|
}
|
|
}
|
|
};
|
|
schema("/nodes/:node/metrics") ->
|
|
#{
|
|
'operationId' => node_metrics,
|
|
get =>
|
|
#{
|
|
description => ?DESC(get_node_metrics),
|
|
tags => [<<"Nodes">>],
|
|
parameters => [ref(node_name)],
|
|
responses =>
|
|
#{
|
|
200 => mk(
|
|
ref(?NODE_METRICS_MODULE, node_metrics),
|
|
#{desc => <<"Get node metrics successfully">>}
|
|
),
|
|
404 => not_found()
|
|
}
|
|
}
|
|
};
|
|
schema("/nodes/:node/stats") ->
|
|
#{
|
|
'operationId' => node_stats,
|
|
get =>
|
|
#{
|
|
description => ?DESC(get_node_stats),
|
|
tags => [<<"Nodes">>],
|
|
parameters => [ref(node_name)],
|
|
responses =>
|
|
#{
|
|
200 => mk(
|
|
ref(?NODE_STATS_MODULE, aggregated_data),
|
|
#{desc => <<"Get node stats successfully">>}
|
|
),
|
|
404 => not_found()
|
|
}
|
|
}
|
|
}.
|
|
|
|
%%--------------------------------------------------------------------
|
|
%% Fields
|
|
|
|
fields(node_name) ->
|
|
[
|
|
{node,
|
|
mk(
|
|
binary(),
|
|
#{
|
|
in => path,
|
|
description => <<"Node name">>,
|
|
required => true,
|
|
example => <<"emqx@127.0.0.1">>
|
|
}
|
|
)}
|
|
];
|
|
fields(node_info) ->
|
|
[
|
|
{node,
|
|
mk(
|
|
atom(),
|
|
#{desc => <<"Node name">>, example => <<"emqx@127.0.0.1">>}
|
|
)},
|
|
{connections,
|
|
mk(
|
|
non_neg_integer(),
|
|
#{desc => <<"Number of clients session in this node">>, example => 0}
|
|
)},
|
|
{live_connections,
|
|
mk(
|
|
non_neg_integer(),
|
|
#{desc => <<"Number of clients currently connected to this node">>, example => 0}
|
|
)},
|
|
{cluster_sessions,
|
|
mk(
|
|
non_neg_integer(),
|
|
#{
|
|
desc =>
|
|
<<
|
|
"By default, it includes only those sessions that have not expired. "
|
|
"If the `broker.session_history_retain` config is set to a duration greater than `0s`, "
|
|
"this count will also include sessions that expired within the specified retain time"
|
|
>>,
|
|
example => 0
|
|
}
|
|
)},
|
|
{load1,
|
|
mk(
|
|
float(),
|
|
#{desc => <<"CPU average load in 1 minute">>, example => 2.66}
|
|
)},
|
|
{load5,
|
|
mk(
|
|
float(),
|
|
#{desc => <<"CPU average load in 5 minute">>, example => 2.66}
|
|
)},
|
|
{load15,
|
|
mk(
|
|
float(),
|
|
#{desc => <<"CPU average load in 15 minute">>, example => 2.66}
|
|
)},
|
|
{max_fds,
|
|
mk(
|
|
non_neg_integer(),
|
|
#{desc => <<"File descriptors limit">>, example => 1024}
|
|
)},
|
|
{memory_total,
|
|
mk(
|
|
emqx_schema:bytesize(),
|
|
#{desc => <<"Allocated memory">>, example => "512.00M"}
|
|
)},
|
|
{memory_used,
|
|
mk(
|
|
emqx_schema:bytesize(),
|
|
#{desc => <<"Used memory">>, example => "256.00M"}
|
|
)},
|
|
{node_status,
|
|
mk(
|
|
enum(['running', 'stopped']),
|
|
#{desc => <<"Node status">>, example => "running"}
|
|
)},
|
|
{otp_release,
|
|
mk(
|
|
string(),
|
|
#{desc => <<"Erlang/OTP version">>, example => "24.2/12.2"}
|
|
)},
|
|
{process_available,
|
|
mk(
|
|
non_neg_integer(),
|
|
#{desc => <<"Erlang processes limit">>, example => 2097152}
|
|
)},
|
|
{process_used,
|
|
mk(
|
|
non_neg_integer(),
|
|
#{desc => <<"Running Erlang processes">>, example => 1024}
|
|
)},
|
|
{uptime,
|
|
mk(
|
|
non_neg_integer(),
|
|
#{desc => <<"System uptime, milliseconds">>, example => 5120000}
|
|
)},
|
|
{version,
|
|
mk(
|
|
string(),
|
|
#{desc => <<"Release version">>, example => "5.0.0"}
|
|
)},
|
|
{edition,
|
|
mk(
|
|
enum(['Opensource', 'Enterprise']),
|
|
#{desc => <<"Release edition">>, example => "Opensource"}
|
|
)},
|
|
{sys_path,
|
|
mk(
|
|
string(),
|
|
#{desc => <<"Path to system files">>, example => "path/to/emqx"}
|
|
)},
|
|
{log_path,
|
|
mk(
|
|
string(),
|
|
#{
|
|
desc => <<"Path to log files">>,
|
|
example => "path/to/log | The log path is not yet set"
|
|
}
|
|
)},
|
|
{role,
|
|
mk(
|
|
enum([core, replicant]),
|
|
#{desc => <<"Node role">>, example => "core"}
|
|
)}
|
|
].
|
|
|
|
%%--------------------------------------------------------------------
|
|
%% API Handler funcs
|
|
%%--------------------------------------------------------------------
|
|
|
|
nodes(get, _Params) ->
|
|
list_nodes(#{}).
|
|
|
|
node(get, #{bindings := #{node := NodeName}}) ->
|
|
emqx_utils_api:with_node(NodeName, to_ok_result_fun(fun get_node/1)).
|
|
|
|
node_metrics(get, #{bindings := #{node := NodeName}}) ->
|
|
emqx_utils_api:with_node(NodeName, to_ok_result_fun(fun emqx_mgmt:get_metrics/1)).
|
|
|
|
node_stats(get, #{bindings := #{node := NodeName}}) ->
|
|
emqx_utils_api:with_node(NodeName, to_ok_result_fun(fun emqx_mgmt:get_stats/1)).
|
|
|
|
%%--------------------------------------------------------------------
|
|
%% api apply
|
|
|
|
list_nodes(#{}) ->
|
|
NodesInfo = [format(NodeInfo) || {_Node, NodeInfo} <- emqx_mgmt:list_nodes()],
|
|
{200, NodesInfo}.
|
|
|
|
get_node(Node) ->
|
|
format(emqx_mgmt:lookup_node(Node)).
|
|
|
|
%%--------------------------------------------------------------------
|
|
%% internal function
|
|
|
|
format(Info = #{memory_total := Total, memory_used := Used}) ->
|
|
Info#{
|
|
memory_total := emqx_mgmt_util:kmg(Total),
|
|
memory_used := emqx_mgmt_util:kmg(Used)
|
|
};
|
|
format(Info) when is_map(Info) ->
|
|
Info.
|
|
|
|
to_ok_result({error, _} = Error) ->
|
|
Error;
|
|
to_ok_result({ok, _} = Ok) ->
|
|
Ok;
|
|
to_ok_result(Result) ->
|
|
{ok, Result}.
|
|
|
|
to_ok_result_fun(Fun) when is_function(Fun) ->
|
|
fun(Arg) ->
|
|
to_ok_result(Fun(Arg))
|
|
end.
|
|
|
|
not_found() ->
|
|
emqx_dashboard_swagger:error_codes(['NOT_FOUND'], <<"Node not found">>).
|