refactor: alarms api; add: alarms format function

This commit is contained in:
DDDHuang 2021-07-23 09:51:47 +08:00 committed by turtleDeng
parent 9642bcce88
commit e96bac87ce
3 changed files with 197 additions and 104 deletions

View File

@ -36,6 +36,8 @@
, stop/0
]).
-export([format/1]).
%% API
-export([ activate/1
, activate/2
@ -157,6 +159,27 @@ handle_update_config(#{<<"validity_period">> := Period0} = NewConf, OldConf) ->
handle_update_config(NewConf, OldConf) ->
maps:merge(OldConf, NewConf).
format(#activated_alarm{name = Name, message = Message, activate_at = At, details = Details}) ->
Now = erlang:system_time(microsecond),
#{
node => node(),
name => Name,
message => Message,
duration => Now - At,
details => Details
};
format(#deactivated_alarm{name = Name, message = Message, activate_at = At, details = Details,
deactivate_at = DAt}) ->
#{
node => node(),
name => Name,
message => Message,
duration => DAt - At,
details => Details
};
format(_) ->
{error, unknow_alarm}.
%%--------------------------------------------------------------------
%% gen_server callbacks
%%--------------------------------------------------------------------

View File

@ -16,122 +16,119 @@
-module(emqx_mgmt_api_alarms).
-include("emqx_mgmt.hrl").
-behavior(minirest_api).
-include_lib("emqx/include/emqx.hrl").
-export([api_spec/0]).
-rest_api(#{name => list_all_alarms,
method => 'GET',
path => "/alarms",
func => list,
descr => "List all alarms in the cluster"}).
-export([alarms/2]).
-rest_api(#{name => list_node_alarms,
method => 'GET',
path => "nodes/:atom:node/alarms",
func => list,
descr => "List all alarms on a node"}).
-export([ query_activated/3
, query_deactivated/3]).
%% notice: from emqx_alarms
-define(ACTIVATED_ALARM, emqx_activated_alarm).
-define(DEACTIVATED_ALARM, emqx_deactivated_alarm).
-rest_api(#{name => list_all_activated_alarms,
method => 'GET',
path => "/alarms/activated",
func => list_activated,
descr => "List all activated alarm in the cluster"}).
api_spec() ->
{[alarms_api()], [alarm_schema()]}.
-rest_api(#{name => list_node_activated_alarms,
method => 'GET',
path => "nodes/:atom:node/alarms/activated",
func => list_activated,
descr => "List all activated alarm on a node"}).
alarm_schema() ->
#{
alarm => #{
type => object,
properties => #{
node => #{
type => string,
description => <<"Alarm in node">>},
name => #{
type => string,
description => <<"Alarm name">>},
message => #{
type => string,
description => <<"Alarm readable information">>},
details => #{
type => object,
description => <<"Alarm detail">>},
duration => #{
type => integer,
description => <<"Alarms duration time; UNIX time stamp">>}
}
}
}.
-rest_api(#{name => list_all_deactivated_alarms,
method => 'GET',
path => "/alarms/deactivated",
func => list_deactivated,
descr => "List all deactivated alarm in the cluster"}).
alarms_api() ->
Metadata = #{
get => #{
description => "EMQ X alarms",
parameters => [#{
name => activated,
in => query,
description => <<"All alarms, if not specified">>,
required => false,
schema => #{type => boolean, default => true}
}],
responses => #{
<<"200">> =>
emqx_mgmt_util:response_array_schema(<<"List all alarms">>, <<"alarm">>)}},
delete => #{
description => "Remove all deactivated alarms",
responses => #{
<<"200">> =>
emqx_mgmt_util:response_schema(<<"Remove all deactivated alarms ok">>)}}},
{"/alarms", Metadata, alarms}.
-rest_api(#{name => list_node_deactivated_alarms,
method => 'GET',
path => "nodes/:atom:node/alarms/deactivated",
func => list_deactivated,
descr => "List all deactivated alarm on a node"}).
%%%==============================================================================================
%% parameters trans
alarms(get, Request) ->
case proplists:get_value(<<"activated">>, cowboy_req:parse_qs(Request), undefined) of
undefined ->
list(#{activated => undefined});
<<"true">> ->
list(#{activated => true});
<<"false">> ->
list(#{activated => false})
end;
-rest_api(#{name => deactivate_alarm,
method => 'POST',
path => "/alarms/deactivated",
func => deactivate,
descr => "Delete the special alarm on a node"}).
alarms(delete, _Request) ->
delete().
-rest_api(#{name => delete_all_deactivated_alarms,
method => 'DELETE',
path => "/alarms/deactivated",
func => delete_deactivated,
descr => "Delete all deactivated alarm in the cluster"}).
%%%==============================================================================================
%% api apply
list(#{activated := true}) ->
do_list(activated);
list(#{activated := false}) ->
do_list(deactivated);
list(#{activated := undefined}) ->
do_list(activated).
-rest_api(#{name => delete_node_deactivated_alarms,
method => 'DELETE',
path => "nodes/:atom:node/alarms/deactivated",
func => delete_deactivated,
descr => "Delete all deactivated alarm on a node"}).
-export([ list/2
, deactivate/2
, list_activated/2
, list_deactivated/2
, delete_deactivated/2
]).
list(Bindings, _Params) when map_size(Bindings) == 0 ->
{ok, #{code => ?SUCCESS,
data => [#{node => Node, alarms => Alarms} || {Node, Alarms} <- emqx_mgmt:get_alarms(all)]}};
list(#{node := Node}, _Params) ->
{ok, #{code => ?SUCCESS,
data => emqx_mgmt:get_alarms(Node, all)}}.
list_activated(Bindings, _Params) when map_size(Bindings) == 0 ->
{ok, #{code => ?SUCCESS,
data => [#{node => Node, alarms => Alarms} || {Node, Alarms} <- emqx_mgmt:get_alarms(activated)]}};
list_activated(#{node := Node}, _Params) ->
{ok, #{code => ?SUCCESS,
data => emqx_mgmt:get_alarms(Node, activated)}}.
list_deactivated(Bindings, _Params) when map_size(Bindings) == 0 ->
{ok, #{code => ?SUCCESS,
data => [#{node => Node, alarms => Alarms} || {Node, Alarms} <- emqx_mgmt:get_alarms(deactivated)]}};
list_deactivated(#{node := Node}, _Params) ->
{ok, #{code => ?SUCCESS,
data => emqx_mgmt:get_alarms(Node, deactivated)}}.
deactivate(_Bindings, Params) ->
Node = get_node(Params),
Name = get_name(Params),
do_deactivate(Node, Name).
delete_deactivated(Bindings, _Params) when map_size(Bindings) == 0 ->
delete() ->
_ = emqx_mgmt:delete_all_deactivated_alarms(),
{ok, #{code => ?SUCCESS}};
{200}.
delete_deactivated(#{node := Node}, _Params) ->
emqx_mgmt:delete_all_deactivated_alarms(Node),
{ok, #{code => ?SUCCESS}}.
%%%==============================================================================================
%% internal
do_list(Type) ->
{Table, Function} =
case Type of
activated ->
{?ACTIVATED_ALARM, query_activated};
deactivated ->
{?DEACTIVATED_ALARM, query_deactivated}
end,
Response = emqx_mgmt_api:cluster_query([], {Table, []}, {?MODULE, Function}),
{200, Response}.
get_node(Params) ->
binary_to_atom(proplists:get_value(<<"node">>, Params, undefined), utf8).
query_activated(_, Start, Limit) ->
query(?ACTIVATED_ALARM, Start, Limit).
get_name(Params) ->
binary_to_atom(proplists:get_value(<<"name">>, Params, undefined), utf8).
query_deactivated(_, Start, Limit) ->
query(?DEACTIVATED_ALARM, Start, Limit).
do_deactivate(undefined, _) ->
emqx_mgmt:return({error, missing_param});
do_deactivate(_, undefined) ->
emqx_mgmt:return({error, missing_param});
do_deactivate(Node, Name) ->
case emqx_mgmt:deactivate(Node, Name) of
ok ->
emqx_mgmt:return();
{error, Reason} ->
emqx_mgmt:return({error, Reason})
end.
query(Table, Start, Limit) ->
Ms = [{'$1',[],['$1']}],
emqx_mgmt_api:select_table(Table, Ms, Start, Limit, fun format_alarm/1).
format_alarm(Alarms) when is_list(Alarms) ->
[emqx_alarm:format(Alarm) || Alarm <- Alarms];
format_alarm(Alarm) ->
emqx_alarm:format(Alarm).

View File

@ -0,0 +1,73 @@
%%--------------------------------------------------------------------
%% Copyright (c) 2020-2021 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_alarms_api_SUITE).
-compile(export_all).
-compile(nowarn_export_all).
-include_lib("eunit/include/eunit.hrl").
-define(ACT_ALARM, test_act_alarm).
-define(DE_ACT_ALARM, test_de_act_alarm).
all() ->
[t_alarms_api, t_delete_alarms_api].
init_per_suite(Config) ->
ekka_mnesia:start(),
emqx_mgmt_auth:mnesia(boot),
emqx_ct_helpers:start_apps([emqx_management], fun set_special_configs/1),
Config.
end_per_suite(_) ->
emqx_ct_helpers:stop_apps([emqx_management]).
set_special_configs(emqx_management) ->
emqx_config:put([emqx_management], #{listeners => [#{protocol => http, port => 8081}],
applications =>[#{id => "admin", secret => "public"}]}),
ok;
set_special_configs(_App) ->
ok.
t_alarms_api(_) ->
ok = emqx_alarm:activate(?ACT_ALARM),
ok = emqx_alarm:activate(?DE_ACT_ALARM),
ok = emqx_alarm:deactivate(?DE_ACT_ALARM),
get_alarms(1, true),
get_alarms(1, false).
t_delete_alarms_api(_) ->
Path = emqx_mgmt_api_test_util:api_path(["alarms"]),
{ok, _} = emqx_mgmt_api_test_util:request_api(delete, Path),
get_alarms(1, true),
get_alarms(0, false).
get_alarms(AssertCount, Activated) when is_atom(Activated) ->
get_alarms(AssertCount, atom_to_list(Activated));
get_alarms(AssertCount, Activated) ->
Path = emqx_mgmt_api_test_util:api_path(["alarms"]),
Qs = "activated=" ++ Activated,
Headers = emqx_mgmt_api_test_util:auth_header_(),
{ok, Response} = emqx_mgmt_api_test_util:request_api(get, Path, Qs, Headers),
Data = emqx_json:decode(Response, [return_maps]),
Meta = maps:get(<<"meta">>, Data),
Page = maps:get(<<"page">>, Meta),
Limit = maps:get(<<"limit">>, Meta),
Count = maps:get(<<"count">>, Meta),
?assertEqual(Page, 1),
?assertEqual(Limit, emqx_mgmt:max_row_limit()),
?assert(Count >= AssertCount).