fix(api): DELETE success wrongly returned code 200 (#6135)

This commit is contained in:
JimMoen 2021-11-16 09:28:57 +08:00 committed by GitHub
commit c05ecdbcb8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 133 additions and 96 deletions

View File

@ -61,7 +61,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
repository: emqx/emqx-fvt repository: emqx/emqx-fvt
ref: v1.3.0 ref: v1.5.0
path: . path: .
- uses: actions/setup-java@v1 - uses: actions/setup-java@v1
with: with:

2
.gitignore vendored
View File

@ -58,3 +58,5 @@ erlang_ls.config
# Emacs temporary files # Emacs temporary files
.#* .#*
*# *#
# For direnv
.envrc

View File

@ -186,7 +186,7 @@ schema("/authentication/:id") ->
description => <<"Delete authenticator from global authentication chain">>, description => <<"Delete authenticator from global authentication chain">>,
parameters => [{id, mk(binary(), #{in => path, desc => <<"Authenticator ID">>})}], parameters => [{id, mk(binary(), #{in => path, desc => <<"Authenticator ID">>})}],
responses => #{ responses => #{
200 => <<"Authenticator deleted">>, 204 => <<"Authenticator deleted">>,
404 => error_codes([?NOT_FOUND], <<"Not Found">>) 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
} }
} }

View File

@ -148,7 +148,7 @@ schema("/authorization/sources/built-in-database/username/:username") ->
description => <<"Delete one record for username">>, description => <<"Delete one record for username">>,
parameters => [hoconsc:ref(username)], parameters => [hoconsc:ref(username)],
responses => #{ responses => #{
204 => <<"No Content">>, 204 => <<"Deleted">>,
400 => emqx_dashboard_swagger:error_codes([?BAD_REQUEST], <<"Bad username">>) 400 => emqx_dashboard_swagger:error_codes([?BAD_REQUEST], <<"Bad username">>)
} }
} }
@ -183,7 +183,7 @@ schema("/authorization/sources/built-in-database/clientid/:clientid") ->
description => <<"Delete one record for clientid">>, description => <<"Delete one record for clientid">>,
parameters => [hoconsc:ref(clientid)], parameters => [hoconsc:ref(clientid)],
responses => #{ responses => #{
204 => <<"No Content">>, 204 => <<"Deleted">>,
400 => emqx_dashboard_swagger:error_codes([?BAD_REQUEST], <<"Bad clientid">>) 400 => emqx_dashboard_swagger:error_codes([?BAD_REQUEST], <<"Bad clientid">>)
} }
} }
@ -216,7 +216,7 @@ schema("/authorization/sources/built-in-database/purge-all") ->
tags => [<<"authorization">>], tags => [<<"authorization">>],
description => <<"Purge all records">>, description => <<"Purge all records">>,
responses => #{ responses => #{
204 => <<"No Content">>, 204 => <<"Deleted">>,
400 => emqx_dashboard_swagger:error_codes([?BAD_REQUEST], <<"Bad Request">>) 400 => emqx_dashboard_swagger:error_codes([?BAD_REQUEST], <<"Bad Request">>)
} }
} }

View File

@ -32,7 +32,8 @@
-define(EXAMPLE_FILE, -define(EXAMPLE_FILE,
#{type=> file, #{type=> file,
enable => true, enable => true,
rules => <<"{allow,{username,\"^dashboard?\"},subscribe,[\"$SYS/#\"]}.\n{allow,{ipaddr,\"127.0.0.1\"},all,[\"$SYS/#\",\"#\"]}.">> rules => <<"{allow,{username,\"^dashboard?\"},subscribe,[\"$SYS/#\"]}.\n",
"{allow,{ipaddr,\"127.0.0.1\"},all,[\"$SYS/#\",\"#\"]}.">>
}). }).
-define(EXAMPLE_RETURNED, -define(EXAMPLE_RETURNED,
@ -90,7 +91,7 @@ sources_api() ->
}, },
post => #{ post => #{
description => "Add new source", description => "Add new source",
requestBody => #{ 'requestBody' => #{
content => #{ content => #{
'application/json' => #{ 'application/json' => #{
schema => minirest:ref(<<"sources">>), schema => minirest:ref(<<"sources">>),
@ -114,7 +115,7 @@ sources_api() ->
}, },
put => #{ put => #{
description => "Update all sources", description => "Update all sources",
requestBody => #{ 'requestBody' => #{
content => #{ content => #{
'application/json' => #{ 'application/json' => #{
schema => #{ schema => #{
@ -206,7 +207,7 @@ source_api() ->
required => true required => true
} }
], ],
requestBody => #{ 'requestBody' => #{
content => #{ content => #{
'application/json' => #{ 'application/json' => #{
schema => minirest:ref(<<"sources">>), schema => minirest:ref(<<"sources">>),
@ -250,7 +251,7 @@ source_api() ->
} }
], ],
responses => #{ responses => #{
<<"204">> => #{description => <<"No Content">>}, <<"204">> => #{description => <<"Deleted">>},
<<"400">> => emqx_mgmt_util:bad_request() <<"400">> => emqx_mgmt_util:bad_request()
} }
} }
@ -279,7 +280,7 @@ move_source_api() ->
required => true required => true
} }
], ],
requestBody => #{ 'requestBody' => #{
content => #{ content => #{
'application/json' => #{ 'application/json' => #{
schema => #{ schema => #{
@ -287,7 +288,7 @@ move_source_api() ->
required => [position], required => [position],
properties => #{ properties => #{
position => #{ position => #{
oneOf => [ 'oneOf' => [
#{type => string, #{type => string,
enum => [<<"top">>, <<"bottom">>] enum => [<<"top">>, <<"bottom">>]
}, },
@ -326,7 +327,8 @@ move_source_api() ->
{"/authorization/sources/:type/move", Metadata, move_source}. {"/authorization/sources/:type/move", Metadata, move_source}.
sources(get, _) -> sources(get, _) ->
Sources = lists:foldl(fun (#{<<"type">> := <<"file">>, <<"enable">> := Enable, <<"path">> := Path}, AccIn) -> Sources = lists:foldl(fun (#{<<"type">> := <<"file">>,
<<"enable">> := Enable, <<"path">> := Path}, AccIn) ->
case file:read_file(Path) of case file:read_file(Path) of
{ok, Rules} -> {ok, Rules} ->
lists:append(AccIn, [#{type => file, lists:append(AccIn, [#{type => file,
@ -345,7 +347,8 @@ sources(get, _) ->
{200, #{sources => Sources}}; {200, #{sources => Sources}};
sources(post, #{body := #{<<"type">> := <<"file">>, <<"rules">> := Rules}}) -> sources(post, #{body := #{<<"type">> := <<"file">>, <<"rules">> := Rules}}) ->
{ok, Filename} = write_file(acl_conf_file(), Rules), {ok, Filename} = write_file(acl_conf_file(), Rules),
update_config(?CMD_PREPEND, [#{<<"type">> => <<"file">>, <<"enable">> => true, <<"path">> => Filename}]); update_config(?CMD_PREPEND, [#{<<"type">> => <<"file">>,
<<"enable">> => true, <<"path">> => Filename}]);
sources(post, #{body := Body}) when is_map(Body) -> sources(post, #{body := Body}) when is_map(Body) ->
update_config(?CMD_PREPEND, [maybe_write_certs(Body)]); update_config(?CMD_PREPEND, [maybe_write_certs(Body)]);
sources(put, #{body := Body}) when is_list(Body) -> sources(put, #{body := Body}) when is_list(Body) ->
@ -377,9 +380,13 @@ source(get, #{bindings := #{type := Type}}) ->
[Source] -> [Source] ->
{200, read_certs(Source)} {200, read_certs(Source)}
end; end;
source(put, #{bindings := #{type := <<"file">>}, body := #{<<"type">> := <<"file">>, <<"rules">> := Rules, <<"enable">> := Enable}}) -> source(put, #{bindings := #{type := <<"file">>}, body := #{<<"type">> := <<"file">>,
<<"rules">> := Rules,
<<"enable">> := Enable}}) ->
{ok, Filename} = write_file(maps:get(path, emqx_authz:lookup(file), ""), Rules), {ok, Filename} = write_file(maps:get(path, emqx_authz:lookup(file), ""), Rules),
case emqx_authz:update({?CMD_REPLACE, <<"file">>}, #{<<"type">> => <<"file">>, <<"enable">> => Enable, <<"path">> => Filename}) of case emqx_authz:update({?CMD_REPLACE, <<"file">>}, #{<<"type">> => <<"file">>,
<<"enable">> => Enable,
<<"path">> => Filename}) of
{ok, _} -> {204}; {ok, _} -> {204};
{error, Reason} -> {error, Reason} ->
{400, #{code => <<"BAD_REQUEST">>, {400, #{code => <<"BAD_REQUEST">>,
@ -405,7 +412,8 @@ get_raw_sources() ->
RawSources = emqx:get_raw_config([authorization, sources], []), RawSources = emqx:get_raw_config([authorization, sources], []),
Schema = #{roots => emqx_authz_schema:fields("authorization"), fields => #{}}, Schema = #{roots => emqx_authz_schema:fields("authorization"), fields => #{}},
Conf = #{<<"sources">> => RawSources}, Conf = #{<<"sources">> => RawSources},
#{<<"sources">> := Sources} = hocon_schema:check_plain(Schema, Conf, #{only_fill_defaults => true}), #{<<"sources">> := Sources} = hocon_schema:check_plain(Schema, Conf,
#{only_fill_defaults => true}),
Sources. Sources.
get_raw_source(Type) -> get_raw_source(Type) ->

View File

@ -45,10 +45,10 @@ req_schema() ->
emqx_mgmt_api_configs:gen_schema(Conf) emqx_mgmt_api_configs:gen_schema(Conf)
end end
|| T <- ?TYPES], || T <- ?TYPES],
#{oneOf => Schema}. #{'oneOf' => Schema}.
resp_schema() -> resp_schema() ->
#{oneOf := Schema} = req_schema(), #{'oneOf' := Schema} = req_schema(),
AddMetadata = fun(Prop) -> AddMetadata = fun(Prop) ->
Prop#{is_connected => #{type => boolean}, Prop#{is_connected => #{type => boolean},
id => #{type => string}, id => #{type => string},
@ -57,7 +57,7 @@ resp_schema() ->
end, end,
Schema1 = [S#{properties => AddMetadata(Prop)} Schema1 = [S#{properties => AddMetadata(Prop)}
|| S = #{properties := Prop} <- Schema], || S = #{properties := Prop} <- Schema],
#{oneOf => Schema1}. #{'oneOf' => Schema1}.
api_spec() -> api_spec() ->
{bridge_apis(), []}. {bridge_apis(), []}.
@ -104,7 +104,7 @@ crud_bridges_apis() ->
description => <<"Delete a bridge">>, description => <<"Delete a bridge">>,
parameters => [param_path_id()], parameters => [param_path_id()],
responses => #{ responses => #{
<<"200">> => emqx_mgmt_util:schema(<<"Bridge deleted">>), <<"204">> => emqx_mgmt_util:schema(<<"Bridge deleted">>),
<<"404">> => emqx_mgmt_util:error_schema(<<"Bridge not found">>, ['NOT_FOUND']) <<"404">> => emqx_mgmt_util:error_schema(<<"Bridge not found">>, ['NOT_FOUND'])
} }
} }
@ -120,7 +120,8 @@ operation_apis() ->
param_path_id(), param_path_id(),
param_path_operation()], param_path_operation()],
responses => #{ responses => #{
<<"500">> => emqx_mgmt_util:error_schema(<<"Operation Failed">>, ['INTERNAL_ERROR']), <<"500">> => emqx_mgmt_util:error_schema(<<"Operation Failed">>,
['INTERNAL_ERROR']),
<<"200">> => emqx_mgmt_util:schema(<<"Operation success">>)}}}, <<"200">> => emqx_mgmt_util:schema(<<"Operation success">>)}}},
{"/nodes/:node/bridges/:id/operation/:operation", Metadata, manage_bridges}. {"/nodes/:node/bridges/:id/operation/:operation", Metadata, manage_bridges}.

View File

@ -48,16 +48,16 @@ paths() -> ["/login", "/logout", "/users",
schema("/login") -> schema("/login") ->
#{ #{
operationId => login, 'operationId' => login,
post => #{ post => #{
tags => [<<"dashboard">>], tags => [<<"dashboard">>],
description => <<"Dashboard Auth">>, description => <<"Dashboard Auth">>,
summary => <<"Dashboard Auth">>, summary => <<"Dashboard Auth">>,
requestBody => 'requestBody' =>
[ [
{username, mk(binary(), {username, mk(binary(),
#{desc => <<"The User for which to create the token.">>, #{desc => <<"The User for which to create the token.">>,
maxLength => 100, example => <<"admin">>})}, 'maxLength' => 100, example => <<"admin">>})},
{password, mk(binary(), {password, mk(binary(),
#{desc => "password", example => "public"})} #{desc => "password", example => "public"})}
], ],
@ -76,14 +76,14 @@ schema("/login") ->
}}; }};
schema("/logout") -> schema("/logout") ->
#{ #{
operationId => logout, 'operationId' => logout,
post => #{ post => #{
tags => [<<"dashboard">>], tags => [<<"dashboard">>],
description => <<"Dashboard User logout">>, description => <<"Dashboard User logout">>,
requestBody => [ 'requestBody' => [
{username, mk(binary(), {username, mk(binary(),
#{desc => <<"The User for which to create the token.">>, #{desc => <<"The User for which to create the token.">>,
maxLength => 100, example => <<"admin">>})} 'maxLength' => 100, example => <<"admin">>})}
], ],
responses => #{ responses => #{
200 => <<"Dashboard logout successfully">> 200 => <<"Dashboard logout successfully">>
@ -92,7 +92,7 @@ schema("/logout") ->
}; };
schema("/users") -> schema("/users") ->
#{ #{
operationId => users, 'operationId' => users,
get => #{ get => #{
tags => [<<"dashboard">>], tags => [<<"dashboard">>],
description => <<"Get dashboard users">>, description => <<"Get dashboard users">>,
@ -104,7 +104,7 @@ schema("/users") ->
post => #{ post => #{
tags => [<<"dashboard">>], tags => [<<"dashboard">>],
description => <<"Create dashboard users">>, description => <<"Create dashboard users">>,
requestBody => fields(user_password), 'requestBody' => fields(user_password),
responses => #{ responses => #{
200 => <<"Create user successfully">>, 200 => <<"Create user successfully">>,
400 => [{code, mk(string(), #{example => 'CREATE_FAIL'})}, 400 => [{code, mk(string(), #{example => 'CREATE_FAIL'})},
@ -114,13 +114,13 @@ schema("/users") ->
schema("/users/:username") -> schema("/users/:username") ->
#{ #{
operationId => user, 'operationId' => user,
put => #{ put => #{
tags => [<<"dashboard">>], tags => [<<"dashboard">>],
description => <<"Update dashboard users">>, description => <<"Update dashboard users">>,
parameters => [{username, mk(binary(), parameters => [{username, mk(binary(),
#{in => path, example => <<"admin">>})}], #{in => path, example => <<"admin">>})}],
requestBody => [{tag, mk(binary(), #{desc => <<"Tag">>})}], 'requestBody' => [{tag, mk(binary(), #{desc => <<"Tag">>})}],
responses => #{ responses => #{
200 => <<"Update User successfully">>, 200 => <<"Update User successfully">>,
400 => [{code, mk(string(), #{example => 'UPDATE_FAIL'})}, 400 => [{code, mk(string(), #{example => 'UPDATE_FAIL'})},
@ -131,20 +131,20 @@ schema("/users/:username") ->
parameters => [{username, mk(binary(), parameters => [{username, mk(binary(),
#{in => path, example => <<"admin">>})}], #{in => path, example => <<"admin">>})}],
responses => #{ responses => #{
200 => <<"Delete User successfully">>, 204 => <<"Delete User successfully">>,
400 => [ 400 => [
{code, mk(string(), #{example => 'CANNOT_DELETE_ADMIN'})}, {code, mk(string(), #{example => 'CANNOT_DELETE_ADMIN'})},
{message, mk(string(), #{example => "CANNOT DELETE ADMIN"})}]}} {message, mk(string(), #{example => "CANNOT DELETE ADMIN"})}]}}
}; };
schema("/users/:username/change_pwd") -> schema("/users/:username/change_pwd") ->
#{ #{
operationId => change_pwd, 'operationId' => change_pwd,
put => #{ put => #{
tags => [<<"dashboard">>], tags => [<<"dashboard">>],
description => <<"Update dashboard users password">>, description => <<"Update dashboard users password">>,
parameters => [{username, mk(binary(), parameters => [{username, mk(binary(),
#{in => path, required => true, example => <<"admin">>})}], #{in => path, required => true, example => <<"admin">>})}],
requestBody => [ 'requestBody' => [
{old_pwd, mk(binary(), #{required => true})}, {old_pwd, mk(binary(), #{required => true})},
{new_pwd, mk(binary(), #{required => true})} {new_pwd, mk(binary(), #{required => true})}
], ],
@ -220,7 +220,7 @@ user(delete, #{bindings := #{username := Username}}) ->
message => <<"Cannot delete admin">>}}; message => <<"Cannot delete admin">>}};
false -> false ->
_ = emqx_dashboard_admin:remove_user(Username), _ = emqx_dashboard_admin:remove_user(Username),
{200} {204}
end. end.
change_pwd(put, #{bindings := #{username := Username}, body := Params}) -> change_pwd(put, #{bindings := #{username := Username}, body := Params}) ->

View File

@ -36,7 +36,7 @@ paths() ->
schema("/alarms") -> schema("/alarms") ->
#{ #{
operationId => alarms, 'operationId' => alarms,
get => #{ get => #{
description => <<"EMQ X alarms">>, description => <<"EMQ X alarms">>,
parameters => [ parameters => [
@ -56,24 +56,28 @@ schema("/alarms") ->
delete => #{ delete => #{
description => <<"Remove all deactivated alarms">>, description => <<"Remove all deactivated alarms">>,
responses => #{ responses => #{
200 => <<"Remove all deactivated alarms ok">> 204 => <<"Remove all deactivated alarms ok">>
} }
} }
}. }.
fields(alarm) -> fields(alarm) ->
[ [
{node, hoconsc:mk(binary(), #{desc => <<"Alarm in node">>, example => atom_to_list(node())})}, {node, hoconsc:mk(binary(),
{name, hoconsc:mk(binary(), #{desc => <<"Alarm name">>, example => <<"high_system_memory_usage">>})}, #{desc => <<"Alarm in node">>, example => atom_to_list(node())})},
{name, hoconsc:mk(binary(),
#{desc => <<"Alarm name">>, example => <<"high_system_memory_usage">>})},
{message, hoconsc:mk(binary(), #{desc => <<"Alarm readable information">>, {message, hoconsc:mk(binary(), #{desc => <<"Alarm readable information">>,
example => <<"System memory usage is higher than 70%">>})}, example => <<"System memory usage is higher than 70%">>})},
{details, hoconsc:mk(map(), #{desc => <<"Alarm details information">>, {details, hoconsc:mk(map(), #{desc => <<"Alarm details information">>,
example => #{<<"high_watermark">> => 70}})}, example => #{<<"high_watermark">> => 70}})},
{duration, hoconsc:mk(integer(), #{desc => <<"Alarms duration time; UNIX time stamp, millisecond">>, {duration, hoconsc:mk(integer(),
#{desc => <<"Alarms duration time; UNIX time stamp, millisecond">>,
example => 297056})}, example => 297056})},
{activate_at, hoconsc:mk(binary(), #{desc => <<"Alarms activate time, RFC 3339">>, {activate_at, hoconsc:mk(binary(), #{desc => <<"Alarms activate time, RFC 3339">>,
example => <<"2021-10-25T11:52:52.548+08:00">>})}, example => <<"2021-10-25T11:52:52.548+08:00">>})},
{deactivate_at, hoconsc:mk(binary(), #{desc => <<"Nullable, alarms deactivate time, RFC 3339">>, {deactivate_at, hoconsc:mk(binary(),
#{desc => <<"Nullable, alarms deactivate time, RFC 3339">>,
example => <<"2021-10-31T10:52:52.548+08:00">>})} example => <<"2021-10-31T10:52:52.548+08:00">>})}
]; ];
@ -94,7 +98,7 @@ alarms(get, #{query_string := Qs}) ->
alarms(delete, _Params) -> alarms(delete, _Params) ->
_ = emqx_mgmt:delete_all_deactivated_alarms(), _ = emqx_mgmt:delete_all_deactivated_alarms(),
{200}. {204}.
%%%============================================================================================== %%%==============================================================================================
%% internal %% internal

View File

@ -82,7 +82,7 @@ schema("/banned/:as/:who") ->
example => <<"Badass">>})} example => <<"Badass">>})}
], ],
responses => #{ responses => #{
200 => <<"Delete banned success">>, 204 => <<"Delete banned success">>,
404 => emqx_dashboard_swagger:error_codes(['RESOURCE_NOT_FOUND'], 404 => emqx_dashboard_swagger:error_codes(['RESOURCE_NOT_FOUND'],
<<"Banned not found">>) <<"Banned not found">>)
} }
@ -146,7 +146,7 @@ delete_banned(delete, #{bindings := Params}) ->
{404, #{code => 'RESOURCE_NOT_FOUND', message => Message}}; {404, #{code => 'RESOURCE_NOT_FOUND', message => Message}};
_ -> _ ->
ok = emqx_banned:delete(Params), ok = emqx_banned:delete(Params),
{200} {204}
end. end.
format(Banned) -> format(Banned) ->

View File

@ -342,7 +342,7 @@ client_api() ->
}], }],
responses => #{ responses => #{
<<"404">> => emqx_mgmt_util:error_schema(<<"Client id not found">>), <<"404">> => emqx_mgmt_util:error_schema(<<"Client id not found">>),
<<"200">> => emqx_mgmt_util:schema(client, <<"List clients 200 OK">>)}}}, <<"204">> => emqx_mgmt_util:schema(<<"Kick out client successfully">>)}}},
{"/clients/:clientid", Metadata, client}. {"/clients/:clientid", Metadata, client}.
clients_authz_cache_api() -> clients_authz_cache_api() ->
@ -368,7 +368,7 @@ clients_authz_cache_api() ->
}], }],
responses => #{ responses => #{
<<"404">> => emqx_mgmt_util:error_schema(<<"Client id not found">>), <<"404">> => emqx_mgmt_util:error_schema(<<"Client id not found">>),
<<"200">> => emqx_mgmt_util:schema(<<"Delete clients 200 OK">>)}}}, <<"204">> => emqx_mgmt_util:schema(<<"Clean client authz cache successfully">>)}}},
{"/clients/:clientid/authz_cache", Metadata, authz_cache}. {"/clients/:clientid/authz_cache", Metadata, authz_cache}.
clients_subscriptions_api() -> clients_subscriptions_api() ->
@ -506,7 +506,7 @@ lookup(#{clientid := ClientID}) ->
kickout(#{clientid := ClientID}) -> kickout(#{clientid := ClientID}) ->
emqx_mgmt:kickout_client(ClientID), emqx_mgmt:kickout_client(ClientID),
{200}. {204}.
get_authz_cache(#{clientid := ClientID})-> get_authz_cache(#{clientid := ClientID})->
case emqx_mgmt:list_authz_cache(ClientID) of case emqx_mgmt:list_authz_cache(ClientID) of

View File

@ -59,10 +59,10 @@ req_schema() ->
Schema = [emqx_mgmt_api_configs:gen_schema( Schema = [emqx_mgmt_api_configs:gen_schema(
emqx:get_raw_config([listeners, T, default], #{})) emqx:get_raw_config([listeners, T, default], #{}))
|| T <- ?TYPES_ATOM], || T <- ?TYPES_ATOM],
#{oneOf => Schema}. #{'oneOf' => Schema}.
resp_schema() -> resp_schema() ->
#{oneOf := Schema} = req_schema(), #{'oneOf' := Schema} = req_schema(),
AddMetadata = fun(Prop) -> AddMetadata = fun(Prop) ->
Prop#{running => #{type => boolean}, Prop#{running => #{type => boolean},
id => #{type => string}, id => #{type => string},
@ -70,7 +70,7 @@ resp_schema() ->
end, end,
Schema1 = [S#{properties => AddMetadata(Prop)} Schema1 = [S#{properties => AddMetadata(Prop)}
|| S = #{properties := Prop} <- Schema], || S = #{properties := Prop} <- Schema],
#{oneOf => Schema1}. #{'oneOf' => Schema1}.
api_list_listeners() -> api_list_listeners() ->
Metadata = #{ Metadata = #{
@ -78,7 +78,8 @@ api_list_listeners() ->
description => <<"List listeners from all nodes in the cluster">>, description => <<"List listeners from all nodes in the cluster">>,
responses => #{ responses => #{
<<"200">> => <<"200">> =>
emqx_mgmt_util:array_schema(resp_schema(), <<"List listeners successfully">>)}}}, emqx_mgmt_util:array_schema(resp_schema(),
<<"List listeners successfully">>)}}},
{"/listeners", Metadata, list_listeners}. {"/listeners", Metadata, list_listeners}.
api_list_update_listeners_by_id() -> api_list_update_listeners_by_id() ->
@ -92,25 +93,28 @@ api_list_update_listeners_by_id() ->
<<"200">> => <<"200">> =>
emqx_mgmt_util:array_schema(resp_schema(), <<"List listeners successfully">>)}}, emqx_mgmt_util:array_schema(resp_schema(), <<"List listeners successfully">>)}},
put => #{ put => #{
description => <<"Create or update a listener by a given Id to all nodes in the cluster">>, description =>
<<"Create or update a listener by a given Id to all nodes in the cluster">>,
parameters => [param_path_id()], parameters => [param_path_id()],
requestBody => emqx_mgmt_util:schema(req_schema(), <<"Listener Config">>), 'requestBody' => emqx_mgmt_util:schema(req_schema(), <<"Listener Config">>),
responses => #{ responses => #{
<<"400">> => <<"400">> =>
emqx_mgmt_util:error_schema(?UPDATE_CONFIG_FAILED, ['BAD_LISTENER_ID', 'BAD_CONFIG_SCHEMA']), emqx_mgmt_util:error_schema(?UPDATE_CONFIG_FAILED,
['BAD_LISTENER_ID', 'BAD_CONFIG_SCHEMA']),
<<"404">> => <<"404">> =>
emqx_mgmt_util:error_schema(?LISTENER_NOT_FOUND, ['BAD_LISTENER_ID']), emqx_mgmt_util:error_schema(?LISTENER_NOT_FOUND, ['BAD_LISTENER_ID']),
<<"500">> => <<"500">> =>
emqx_mgmt_util:error_schema(?OPERATION_FAILED, ['INTERNAL_ERROR']), emqx_mgmt_util:error_schema(?OPERATION_FAILED, ['INTERNAL_ERROR']),
<<"200">> => <<"200">> =>
emqx_mgmt_util:array_schema(resp_schema(), <<"Create or update listener successfully">>)}}, emqx_mgmt_util:array_schema(resp_schema(),
<<"Create or update listener successfully">>)}},
delete => #{ delete => #{
description => <<"Delete a listener by a given Id to all nodes in the cluster">>, description => <<"Delete a listener by a given Id to all nodes in the cluster">>,
parameters => [param_path_id()], parameters => [param_path_id()],
responses => #{ responses => #{
<<"404">> => <<"404">> =>
emqx_mgmt_util:error_schema(?LISTENER_NOT_FOUND, ['BAD_LISTENER_ID']), emqx_mgmt_util:error_schema(?LISTENER_NOT_FOUND, ['BAD_LISTENER_ID']),
<<"200">> => <<"204">> =>
emqx_mgmt_util:schema(<<"Delete listener successfully">>)}} emqx_mgmt_util:schema(<<"Delete listener successfully">>)}}
}, },
{"/listeners/:id", Metadata, crud_listeners_by_id}. {"/listeners/:id", Metadata, crud_listeners_by_id}.
@ -143,10 +147,11 @@ api_get_update_listener_by_id_on_node() ->
put => #{ put => #{
description => <<"Create or update a listener by a given Id on a specific node">>, description => <<"Create or update a listener by a given Id on a specific node">>,
parameters => [param_path_node(), param_path_id()], parameters => [param_path_node(), param_path_id()],
requestBody => emqx_mgmt_util:schema(req_schema(), <<"Listener Config">>), 'requestBody' => emqx_mgmt_util:schema(req_schema(), <<"Listener Config">>),
responses => #{ responses => #{
<<"400">> => <<"400">> =>
emqx_mgmt_util:error_schema(?UPDATE_CONFIG_FAILED, ['BAD_LISTENER_ID', 'BAD_CONFIG_SCHEMA']), emqx_mgmt_util:error_schema(?UPDATE_CONFIG_FAILED,
['BAD_LISTENER_ID', 'BAD_CONFIG_SCHEMA']),
<<"404">> => <<"404">> =>
emqx_mgmt_util:error_schema(?NODE_LISTENER_NOT_FOUND, emqx_mgmt_util:error_schema(?NODE_LISTENER_NOT_FOUND,
['BAD_NODE_NAME', 'BAD_LISTENER_ID']), ['BAD_NODE_NAME', 'BAD_LISTENER_ID']),
@ -160,7 +165,7 @@ api_get_update_listener_by_id_on_node() ->
responses => #{ responses => #{
<<"404">> => <<"404">> =>
emqx_mgmt_util:error_schema(?LISTENER_NOT_FOUND, ['BAD_LISTENER_ID']), emqx_mgmt_util:error_schema(?LISTENER_NOT_FOUND, ['BAD_LISTENER_ID']),
<<"200">> => <<"204">> =>
emqx_mgmt_util:schema(<<"Delete listener successfully">>)}} emqx_mgmt_util:schema(<<"Delete listener successfully">>)}}
}, },
{"/nodes/:node/listeners/:id", Metadata, crud_listener_by_id_on_node}. {"/nodes/:node/listeners/:id", Metadata, crud_listener_by_id_on_node}.
@ -251,7 +256,7 @@ crud_listeners_by_id(put, #{bindings := #{id := Id}, body := Conf}) ->
crud_listeners_by_id(delete, #{bindings := #{id := Id}}) -> crud_listeners_by_id(delete, #{bindings := #{id := Id}}) ->
Results = emqx_mgmt:remove_listener(Id), Results = emqx_mgmt:remove_listener(Id),
case lists:filter(fun filter_errors/1, Results) of case lists:filter(fun filter_errors/1, Results) of
[] -> {200}; [] -> {204};
Errors -> {500, #{code => 'UNKNOW_ERROR', message => err_msg(Errors)}} Errors -> {500, #{code => 'UNKNOW_ERROR', message => err_msg(Errors)}}
end. end.
@ -291,7 +296,7 @@ crud_listener_by_id_on_node(put, #{bindings := #{id := Id, node := Node}, body :
end; end;
crud_listener_by_id_on_node(delete, #{bindings := #{id := Id, node := Node}}) -> crud_listener_by_id_on_node(delete, #{bindings := #{id := Id, node := Node}}) ->
case emqx_mgmt:remove_listener(atom(Node), Id) of case emqx_mgmt:remove_listener(atom(Node), Id) of
ok -> {200}; ok -> {204};
{error, Reason} -> {500, #{code => 'UNKNOW_ERROR', message => err_msg(Reason)}} {error, Reason} -> {500, #{code => 'UNKNOW_ERROR', message => err_msg(Reason)}}
end. end.

View File

@ -88,7 +88,7 @@ do_request_api(Method, Request)->
{error, socket_closed_remotely} -> {error, socket_closed_remotely} ->
{error, socket_closed_remotely}; {error, socket_closed_remotely};
{ok, {{"HTTP/1.1", Code, _}, _, Return} } {ok, {{"HTTP/1.1", Code, _}, _, Return} }
when Code =:= 200 orelse Code =:= 201 -> when Code >= 200 andalso Code =< 299 ->
{ok, Return}; {ok, Return};
{ok, {Reason, _, _}} -> {ok, {Reason, _, _}} ->
{error, Reason} {error, Reason}

View File

@ -52,7 +52,7 @@ paths() -> ["/mqtt/delayed", "/mqtt/delayed/messages", "/mqtt/delayed/messages/:
schema("/mqtt/delayed") -> schema("/mqtt/delayed") ->
#{ #{
operationId => status, 'operationId' => status,
get => #{ get => #{
tags => [<<"mqtt">>], tags => [<<"mqtt">>],
description => <<"Get delayed status">>, description => <<"Get delayed status">>,
@ -64,25 +64,28 @@ schema("/mqtt/delayed") ->
put => #{ put => #{
tags => [<<"mqtt">>], tags => [<<"mqtt">>],
description => <<"Enable or disable delayed, set max delayed messages">>, description => <<"Enable or disable delayed, set max delayed messages">>,
requestBody => ref(emqx_modules_schema, "delayed"), 'requestBody' => ref(emqx_modules_schema, "delayed"),
responses => #{ responses => #{
200 => mk(ref(emqx_modules_schema, "delayed"), 200 => mk(ref(emqx_modules_schema, "delayed"),
#{desc => <<"Enable or disable delayed successfully">>}), #{desc => <<"Enable or disable delayed successfully">>}),
400 => emqx_dashboard_swagger:error_codes([?BAD_REQUEST], <<"Max limit illegality">>) 400 => emqx_dashboard_swagger:error_codes( [?BAD_REQUEST]
, <<"Max limit illegality">>)
} }
} }
}; };
schema("/mqtt/delayed/messages/:msgid") -> schema("/mqtt/delayed/messages/:msgid") ->
#{operationId => delayed_message, #{'operationId' => delayed_message,
get => #{ get => #{
tags => [<<"mqtt">>], tags => [<<"mqtt">>],
description => <<"Get delayed message">>, description => <<"Get delayed message">>,
parameters => [{msgid, mk(binary(), #{in => path, desc => <<"delay message ID">>})}], parameters => [{msgid, mk(binary(), #{in => path, desc => <<"delay message ID">>})}],
responses => #{ responses => #{
200 => ref("message_without_payload"), 200 => ref("message_without_payload"),
400 => emqx_dashboard_swagger:error_codes([?MESSAGE_ID_SCHEMA_ERROR], <<"Bad MsgId format">>), 400 => emqx_dashboard_swagger:error_codes( [?MESSAGE_ID_SCHEMA_ERROR]
404 => emqx_dashboard_swagger:error_codes([?MESSAGE_ID_NOT_FOUND], <<"MsgId not found">>) , <<"Bad MsgId format">>),
404 => emqx_dashboard_swagger:error_codes( [?MESSAGE_ID_NOT_FOUND]
, <<"MsgId not found">>)
} }
}, },
delete => #{ delete => #{
@ -90,15 +93,17 @@ schema("/mqtt/delayed/messages/:msgid") ->
description => <<"Delete delayed message">>, description => <<"Delete delayed message">>,
parameters => [{msgid, mk(binary(), #{in => path, desc => <<"delay message ID">>})}], parameters => [{msgid, mk(binary(), #{in => path, desc => <<"delay message ID">>})}],
responses => #{ responses => #{
200 => <<"Delete delayed message success">>, 204 => <<"Delete delayed message success">>,
400 => emqx_dashboard_swagger:error_codes([?MESSAGE_ID_SCHEMA_ERROR], <<"Bad MsgId format">>), 400 => emqx_dashboard_swagger:error_codes( [?MESSAGE_ID_SCHEMA_ERROR]
404 => emqx_dashboard_swagger:error_codes([?MESSAGE_ID_NOT_FOUND], <<"MsgId not found">>) , <<"Bad MsgId format">>),
404 => emqx_dashboard_swagger:error_codes( [?MESSAGE_ID_NOT_FOUND]
, <<"MsgId not found">>)
} }
} }
}; };
schema("/mqtt/delayed/messages") -> schema("/mqtt/delayed/messages") ->
#{ #{
operationId => delayed_messages, 'operationId' => delayed_messages,
get => #{ get => #{
tags => [<<"mqtt">>], tags => [<<"mqtt">>],
description => <<"List delayed messages">>, description => <<"List delayed messages">>,
@ -130,7 +135,8 @@ fields("message_without_payload") ->
{from_username, mk(binary(), #{desc => <<"From Username">>})} {from_username, mk(binary(), #{desc => <<"From Username">>})}
]; ];
fields("message") -> fields("message") ->
PayloadDesc = io_lib:format("Payload, base64 encode. Payload will be ~p if length large than ~p", PayloadDesc = io_lib:format(
"Payload, base64 encode. Payload will be ~p if length large than ~p",
[?PAYLOAD_TOO_LARGE, ?MAX_PAYLOAD_LENGTH]), [?PAYLOAD_TOO_LARGE, ?MAX_PAYLOAD_LENGTH]),
fields("message_without_payload") ++ fields("message_without_payload") ++
[{payload, mk(binary(), #{desc => iolist_to_binary(PayloadDesc)})}]. [{payload, mk(binary(), #{desc => iolist_to_binary(PayloadDesc)})}].
@ -166,7 +172,7 @@ delayed_message(delete, #{bindings := #{msgid := Id}}) ->
case emqx_delayed:get_delayed_message(Id) of case emqx_delayed:get_delayed_message(Id) of
{ok, _Message} -> {ok, _Message} ->
_ = emqx_delayed:delete_delayed_message(Id), _ = emqx_delayed:delete_delayed_message(Id),
{200}; {204};
{error, id_schema_error} -> {error, id_schema_error} ->
{400, generate_http_code_map(id_schema_error, Id)}; {400, generate_http_code_map(id_schema_error, Id)};
{error, not_found} -> {error, not_found} ->
@ -233,9 +239,11 @@ update_config_(Node, Config) ->
rpc_call(Node, ?MODULE, ?FUNCTION_NAME, [Node, Config]). rpc_call(Node, ?MODULE, ?FUNCTION_NAME, [Node, Config]).
generate_http_code_map(id_schema_error, Id) -> generate_http_code_map(id_schema_error, Id) ->
#{code => ?MESSAGE_ID_SCHEMA_ERROR, message => iolist_to_binary(io_lib:format("Message ID ~p schema error", [Id]))}; #{code => ?MESSAGE_ID_SCHEMA_ERROR, message =>
iolist_to_binary(io_lib:format("Message ID ~p schema error", [Id]))};
generate_http_code_map(not_found, Id) -> generate_http_code_map(not_found, Id) ->
#{code => ?MESSAGE_ID_NOT_FOUND, message => iolist_to_binary(io_lib:format("Message ID ~p not found", [Id]))}. #{code => ?MESSAGE_ID_NOT_FOUND, message =>
iolist_to_binary(io_lib:format("Message ID ~p not found", [Id]))}.
rpc_call(Node, Module, Fun, Args) -> rpc_call(Node, Module, Fun, Args) ->
case rpc:call(Node, Module, Fun, Args) of case rpc:call(Node, Module, Fun, Args) of

View File

@ -96,7 +96,8 @@ topic_metrics_api() ->
responses => #{ responses => #{
<<"200">> => schema(<<"Create topic metrics success">>), <<"200">> => schema(<<"Create topic metrics success">>),
<<"409">> => error_schema(<<"Topic metrics max limit">>, [?EXCEED_LIMIT]), <<"409">> => error_schema(<<"Topic metrics max limit">>, [?EXCEED_LIMIT]),
<<"400">> => error_schema(<<"Topic metrics already exist or bad topic">>, [?BAD_REQUEST, ?BAD_TOPIC]) <<"400">> => error_schema( <<"Topic metrics already exist or bad topic">>
, [?BAD_REQUEST, ?BAD_TOPIC])
} }
} }
}, },
@ -115,7 +116,7 @@ operation_topic_metrics_api() ->
description => <<"Deregister topic metrics">>, description => <<"Deregister topic metrics">>,
parameters => [topic_param()], parameters => [topic_param()],
responses => #{ responses => #{
<<"200">> => schema(<<"Deregister topic metrics">>), <<"204">> => schema(<<"Deregister topic metrics">>),
<<"404">> => error_schema(<<"Topic not found">>, [?ERROR_TOPIC]) <<"404">> => error_schema(<<"Topic not found">>, [?ERROR_TOPIC])
} }
} }
@ -174,7 +175,9 @@ register(Topic) ->
[Topic])), [Topic])),
{400, #{code => ?BAD_TOPIC, message => Message}}; {400, #{code => ?BAD_TOPIC, message => Message}};
{error, {quota_exceeded, bad_topic}} -> {error, {quota_exceeded, bad_topic}} ->
Message = list_to_binary(io_lib:format("Max topic metrics count is ~p, and topic cannot have wildcard ~p", Message = list_to_binary(
io_lib:format(
"Max topic metrics count is ~p, and topic cannot have wildcard ~p",
[emqx_topic_metrics:max_limit(), Topic])), [emqx_topic_metrics:max_limit(), Topic])),
{400, #{code => ?BAD_REQUEST, message => Message}}; {400, #{code => ?BAD_REQUEST, message => Message}};
{error, already_existed} -> {error, already_existed} ->

View File

@ -88,7 +88,7 @@ with_topic_api() ->
description => <<"delete matching messages">>, description => <<"delete matching messages">>,
parameters => parameters(), parameters => parameters(),
responses => #{ responses => #{
<<"200">> => schema(<<"Successed">>), <<"204">> => schema(<<"Successed">>),
<<"405">> => schema(<<"NotAllowed">>) <<"405">> => schema(<<"NotAllowed">>)
} }
} }
@ -147,11 +147,11 @@ with_topic(get, #{bindings := Bindings} = Params) ->
with_topic(delete, #{bindings := Bindings}) -> with_topic(delete, #{bindings := Bindings}) ->
Topic = maps:get(topic, Bindings), Topic = maps:get(topic, Bindings),
emqx_retainer_mnesia:delete_message(undefined, Topic), emqx_retainer_mnesia:delete_message(undefined, Topic),
{200}. {204}.
-spec lookup(undefined | binary(), -spec lookup(undefined | binary(),
map(), map(),
fun((#message{}) -> map())) -> fun((emqx_types:message()) -> map())) ->
{200, map()}. {200, map()}.
lookup(Topic, #{query_string := Qs}, Formatter) -> lookup(Topic, #{query_string := Qs}, Formatter) ->
Page = maps:get(page, Qs, 1), Page = maps:get(page, Qs, 1),
@ -166,11 +166,13 @@ format_message(Messages, Formatter) when is_list(Messages)->
format_message(Message, Formatter) -> format_message(Message, Formatter) ->
Formatter(Message). Formatter(Message).
format_message(#message{id = ID, qos = Qos, topic = Topic, from = From, timestamp = Timestamp, headers = Headers}) -> format_message(#message{ id = ID, qos = Qos, topic = Topic, from = From
, timestamp = Timestamp, headers = Headers}) ->
#{msgid => emqx_guid:to_hexstr(ID), #{msgid => emqx_guid:to_hexstr(ID),
qos => Qos, qos => Qos,
topic => Topic, topic => Topic,
publish_at => list_to_binary(calendar:system_time_to_rfc3339(Timestamp, [{unit, millisecond}])), publish_at => list_to_binary(calendar:system_time_to_rfc3339(
Timestamp, [{unit, millisecond}])),
from_clientid => to_bin_string(From), from_clientid => to_bin_string(From),
from_username => maps:get(username, Headers, <<>>) from_username => maps:get(username, Headers, <<>>)
}. }.

View File

@ -62,7 +62,7 @@ api_rules_list_create() ->
emqx_mgmt_util:array_schema(resp_schema(), <<"List rules successfully">>)}}, emqx_mgmt_util:array_schema(resp_schema(), <<"List rules successfully">>)}},
post => #{ post => #{
description => <<"Create a new rule using given Id to all nodes in the cluster">>, description => <<"Create a new rule using given Id to all nodes in the cluster">>,
requestBody => emqx_mgmt_util:schema(post_req_schema(), <<"Rule parameters">>), 'requestBody' => emqx_mgmt_util:schema(post_req_schema(), <<"Rule parameters">>),
responses => #{ responses => #{
<<"400">> => <<"400">> =>
emqx_mgmt_util:error_schema(<<"Invalid Parameters">>, ['BAD_ARGS']), emqx_mgmt_util:error_schema(<<"Invalid Parameters">>, ['BAD_ARGS']),
@ -94,17 +94,18 @@ api_rules_crud() ->
put => #{ put => #{
description => <<"Create or update a rule by given Id to all nodes in the cluster">>, description => <<"Create or update a rule by given Id to all nodes in the cluster">>,
parameters => [param_path_id()], parameters => [param_path_id()],
requestBody => emqx_mgmt_util:schema(put_req_schema(), <<"Rule parameters">>), 'requestBody' => emqx_mgmt_util:schema(put_req_schema(), <<"Rule parameters">>),
responses => #{ responses => #{
<<"400">> => <<"400">> =>
emqx_mgmt_util:error_schema(<<"Invalid Parameters">>, ['BAD_ARGS']), emqx_mgmt_util:error_schema(<<"Invalid Parameters">>, ['BAD_ARGS']),
<<"200">> => <<"200">> =>
emqx_mgmt_util:schema(resp_schema(), <<"Create or update rule successfully">>)}}, emqx_mgmt_util:schema(resp_schema(),
<<"Create or update rule successfully">>)}},
delete => #{ delete => #{
description => <<"Delete a rule by given Id from all nodes in the cluster">>, description => <<"Delete a rule by given Id from all nodes in the cluster">>,
parameters => [param_path_id()], parameters => [param_path_id()],
responses => #{ responses => #{
<<"200">> => <<"204">> =>
emqx_mgmt_util:schema(<<"Delete rule successfully">>)}} emqx_mgmt_util:schema(<<"Delete rule successfully">>)}}
}, },
{"/rules/:id", Metadata, crud_rules_by_id}. {"/rules/:id", Metadata, crud_rules_by_id}.
@ -113,7 +114,7 @@ api_rule_test() ->
Metadata = #{ Metadata = #{
post => #{ post => #{
description => <<"Test a rule">>, description => <<"Test a rule">>,
requestBody => emqx_mgmt_util:schema(rule_test_req_schema(), <<"Rule parameters">>), 'requestBody' => emqx_mgmt_util:schema(rule_test_req_schema(), <<"Rule parameters">>),
responses => #{ responses => #{
<<"400">> => <<"400">> =>
emqx_mgmt_util:error_schema(<<"Invalid Parameters">>, ['BAD_ARGS']), emqx_mgmt_util:error_schema(<<"Invalid Parameters">>, ['BAD_ARGS']),
@ -141,7 +142,7 @@ put_req_schema() ->
description => <<"The outputs of the rule">>, description => <<"The outputs of the rule">>,
type => array, type => array,
items => #{ items => #{
oneOf => [ 'oneOf' => [
#{ #{
type => string, type => string,
example => <<"channel_id_of_my_bridge">>, example => <<"channel_id_of_my_bridge">>,
@ -253,7 +254,7 @@ crud_rules(post, #{body := #{<<"id">> := Id} = Params}) ->
not_found -> not_found ->
case emqx:update_config(ConfPath, maps:remove(<<"id">>, Params), #{}) of case emqx:update_config(ConfPath, maps:remove(<<"id">>, Params), #{}) of
{ok, #{post_config_update := #{emqx_rule_engine := AllRules}}} -> {ok, #{post_config_update := #{emqx_rule_engine := AllRules}}} ->
[Rule] = [R || R = #{id := Id0} <- AllRules, Id0 == Id], [Rule] = get_one_rule(AllRules, Id),
{201, format_rule_resp(Rule)}; {201, format_rule_resp(Rule)};
{error, Reason} -> {error, Reason} ->
?SLOG(error, #{msg => "create_rule_failed", ?SLOG(error, #{msg => "create_rule_failed",
@ -280,7 +281,7 @@ crud_rules_by_id(put, #{bindings := #{id := Id}, body := Params}) ->
ConfPath = emqx_rule_engine:config_key_path() ++ [Id], ConfPath = emqx_rule_engine:config_key_path() ++ [Id],
case emqx:update_config(ConfPath, maps:remove(<<"id">>, Params), #{}) of case emqx:update_config(ConfPath, maps:remove(<<"id">>, Params), #{}) of
{ok, #{post_config_update := #{emqx_rule_engine := AllRules}}} -> {ok, #{post_config_update := #{emqx_rule_engine := AllRules}}} ->
[Rule] = [R || R = #{id := Id0} <- AllRules, Id0 == Id], [Rule] = get_one_rule(AllRules, Id),
{200, format_rule_resp(Rule)}; {200, format_rule_resp(Rule)};
{error, Reason} -> {error, Reason} ->
?SLOG(error, #{msg => "update_rule_failed", ?SLOG(error, #{msg => "update_rule_failed",
@ -291,7 +292,7 @@ crud_rules_by_id(put, #{bindings := #{id := Id}, body := Params}) ->
crud_rules_by_id(delete, #{bindings := #{id := Id}}) -> crud_rules_by_id(delete, #{bindings := #{id := Id}}) ->
ConfPath = emqx_rule_engine:config_key_path() ++ [Id], ConfPath = emqx_rule_engine:config_key_path() ++ [Id],
case emqx:remove_config(ConfPath, #{}) of case emqx:remove_config(ConfPath, #{}) of
{ok, _} -> {200}; {ok, _} -> {204};
{error, Reason} -> {error, Reason} ->
?SLOG(error, #{msg => "delete_rule_failed", ?SLOG(error, #{msg => "delete_rule_failed",
id => Id, reason => Reason}), id => Id, reason => Reason}),
@ -339,3 +340,6 @@ do_format_output(BridgeChannelId) when is_binary(BridgeChannelId) ->
get_rule_metrics(Id) -> get_rule_metrics(Id) ->
[maps:put(node, Node, rpc:call(Node, emqx_rule_metrics, get_rule_metrics, [Id])) [maps:put(node, Node, rpc:call(Node, emqx_rule_metrics, get_rule_metrics, [Id]))
|| Node <- mria_mnesia:running_nodes()]. || Node <- mria_mnesia:running_nodes()].
get_one_rule(AllRules, Id) ->
[R || R = #{id := Id0} <- AllRules, Id0 == Id].

View File

@ -60,7 +60,7 @@ t_crud_rule_api(_Config) ->
?assertEqual(Rule3, Rule2), ?assertEqual(Rule3, Rule2),
?assertEqual(<<"select * from \"t/b\"">>, maps:get(sql, Rule3)), ?assertEqual(<<"select * from \"t/b\"">>, maps:get(sql, Rule3)),
?assertMatch({200}, emqx_rule_engine_api:crud_rules_by_id(delete, ?assertMatch({204}, emqx_rule_engine_api:crud_rules_by_id(delete,
#{bindings => #{id => RuleID}})), #{bindings => #{id => RuleID}})),
%ct:pal("Show After Deleted: ~p", [NotFound]), %ct:pal("Show After Deleted: ~p", [NotFound]),