Explorar o código

refactor: alarms api; add: alarms format function

DDDHuang %!s(int64=4) %!d(string=hai) anos
pai
achega
e96bac87ce

+ 23 - 0
apps/emqx/src/emqx_alarm.erl

@@ -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
 %%--------------------------------------------------------------------

+ 115 - 118
apps/emqx_management/src/emqx_mgmt_api_alarms.erl

@@ -16,122 +16,119 @@
 
 -module(emqx_mgmt_api_alarms).
 
--include("emqx_mgmt.hrl").
-
--include_lib("emqx/include/emqx.hrl").
-
--rest_api(#{name   => list_all_alarms,
-            method => 'GET',
-            path   => "/alarms",
-            func   => list,
-            descr  => "List all alarms in the cluster"}).
-
--rest_api(#{name   => list_node_alarms,
-            method => 'GET',
-            path   => "nodes/:atom:node/alarms",
-            func   => list,
-            descr  => "List all alarms on a node"}).
-
--rest_api(#{name   => list_all_activated_alarms,
-            method => 'GET',
-            path   => "/alarms/activated",
-            func   => list_activated,
-            descr  => "List all activated alarm in the cluster"}).
-
--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"}).
-
--rest_api(#{name   => list_all_deactivated_alarms,
-            method => 'GET',
-            path   => "/alarms/deactivated",
-            func   => list_deactivated,
-            descr  => "List all deactivated alarm in the cluster"}).
-
--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"}).
-
--rest_api(#{name   => deactivate_alarm,
-            method => 'POST',
-            path   => "/alarms/deactivated",
-            func   => deactivate,
-            descr  => "Delete the special alarm on a node"}).
-
--rest_api(#{name   => delete_all_deactivated_alarms,
-            method => 'DELETE',
-            path   => "/alarms/deactivated",
-            func   => delete_deactivated,
-            descr  => "Delete all deactivated alarm in the cluster"}).
-
--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 ->
+-behavior(minirest_api).
+
+-export([api_spec/0]).
+
+-export([alarms/2]).
+
+-export([ query_activated/3
+        , query_deactivated/3]).
+%% notice: from emqx_alarms
+-define(ACTIVATED_ALARM, emqx_activated_alarm).
+-define(DEACTIVATED_ALARM, emqx_deactivated_alarm).
+
+api_spec() ->
+    {[alarms_api()], [alarm_schema()]}.
+
+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">>}
+            }
+        }
+    }.
+
+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}.
+
+%%%==============================================================================================
+%% 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;
+
+alarms(delete, _Request) ->
+    delete().
+
+%%%==============================================================================================
+%% api apply
+list(#{activated := true}) ->
+    do_list(activated);
+list(#{activated := false}) ->
+    do_list(deactivated);
+list(#{activated := undefined}) ->
+    do_list(activated).
+
+delete() ->
     _ = emqx_mgmt:delete_all_deactivated_alarms(),
-    {ok, #{code => ?SUCCESS}};
-
-delete_deactivated(#{node := Node}, _Params) ->
-    emqx_mgmt:delete_all_deactivated_alarms(Node),
-    {ok, #{code => ?SUCCESS}}.
-
-get_node(Params) ->
-    binary_to_atom(proplists:get_value(<<"node">>, Params, undefined), utf8).
-
-get_name(Params) ->
-    binary_to_atom(proplists:get_value(<<"name">>, Params, undefined), utf8).
-
-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.
+    {200}.
+
+%%%==============================================================================================
+%% 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}.
+
+query_activated(_, Start, Limit) ->
+    query(?ACTIVATED_ALARM, Start, Limit).
+
+query_deactivated(_, Start, Limit) ->
+    query(?DEACTIVATED_ALARM, Start, Limit).
+
+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).

+ 73 - 0
apps/emqx_management/test/emqx_mgmt_alarms_api_SUITE.erl

@@ -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).