Merge pull request #11862 from kjellwinblad/kjell/shared_con/del_rules/EMQX-11293
fix(bridge_v2 API): optional cascading delete operation
This commit is contained in:
commit
34ec7375ba
|
@ -38,7 +38,11 @@
|
|||
list/0,
|
||||
lookup/2,
|
||||
create/3,
|
||||
remove/2
|
||||
remove/2,
|
||||
%% The following is the remove function that is called by the HTTP API
|
||||
%% It also checks for rule action dependencies and optionally removes
|
||||
%% them
|
||||
check_deps_and_remove/3
|
||||
]).
|
||||
|
||||
%% Operations
|
||||
|
@ -231,6 +235,25 @@ remove(BridgeType, BridgeName) ->
|
|||
{error, Reason} -> {error, Reason}
|
||||
end.
|
||||
|
||||
check_deps_and_remove(BridgeType, BridgeName, AlsoDeleteActions) ->
|
||||
AlsoDelete =
|
||||
case AlsoDeleteActions of
|
||||
true -> [rule_actions];
|
||||
false -> []
|
||||
end,
|
||||
case
|
||||
emqx_bridge_lib:maybe_withdraw_rule_action(
|
||||
BridgeType,
|
||||
BridgeName,
|
||||
AlsoDelete
|
||||
)
|
||||
of
|
||||
ok ->
|
||||
remove(BridgeType, BridgeName);
|
||||
{error, Reason} ->
|
||||
{error, Reason}
|
||||
end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Helpers for CRUD API
|
||||
%%--------------------------------------------------------------------
|
||||
|
|
|
@ -123,6 +123,18 @@ param_path_id() ->
|
|||
}
|
||||
)}.
|
||||
|
||||
param_qs_delete_cascade() ->
|
||||
{also_delete_dep_actions,
|
||||
mk(
|
||||
boolean(),
|
||||
#{
|
||||
in => query,
|
||||
required => false,
|
||||
default => false,
|
||||
desc => ?DESC("desc_qs_also_delete_dep_actions")
|
||||
}
|
||||
)}.
|
||||
|
||||
param_path_operation_cluster() ->
|
||||
{operation,
|
||||
mk(
|
||||
|
@ -231,7 +243,7 @@ schema("/bridges_v2/:id") ->
|
|||
tags => [<<"bridges_v2">>],
|
||||
summary => <<"Delete bridge">>,
|
||||
description => ?DESC("desc_api5"),
|
||||
parameters => [param_path_id()],
|
||||
parameters => [param_path_id(), param_qs_delete_cascade()],
|
||||
responses => #{
|
||||
204 => <<"Bridge deleted">>,
|
||||
400 => error_schema(
|
||||
|
@ -365,19 +377,35 @@ schema("/bridges_v2_probe") ->
|
|||
?BRIDGE_NOT_FOUND(BridgeType, BridgeName)
|
||||
end
|
||||
);
|
||||
'/bridges_v2/:id'(delete, #{bindings := #{id := Id}}) ->
|
||||
'/bridges_v2/:id'(delete, #{bindings := #{id := Id}, query_string := Qs}) ->
|
||||
?TRY_PARSE_ID(
|
||||
Id,
|
||||
case emqx_bridge_v2:lookup(BridgeType, BridgeName) of
|
||||
{ok, _} ->
|
||||
case emqx_bridge_v2:remove(BridgeType, BridgeName) of
|
||||
AlsoDeleteActions =
|
||||
case maps:get(<<"also_delete_dep_actions">>, Qs, <<"false">>) of
|
||||
<<"true">> -> true;
|
||||
true -> true;
|
||||
_ -> false
|
||||
end,
|
||||
case
|
||||
emqx_bridge_v2:check_deps_and_remove(BridgeType, BridgeName, AlsoDeleteActions)
|
||||
of
|
||||
ok ->
|
||||
?NO_CONTENT;
|
||||
{error, {active_channels, Channels}} ->
|
||||
?BAD_REQUEST(
|
||||
{<<"Cannot delete bridge while there are active channels defined for this bridge">>,
|
||||
Channels}
|
||||
);
|
||||
{error, #{
|
||||
reason := rules_depending_on_this_bridge,
|
||||
rule_ids := RuleIds
|
||||
}} ->
|
||||
RuleIdLists = [binary_to_list(iolist_to_binary(X)) || X <- RuleIds],
|
||||
RulesStr = string:join(RuleIdLists, ", "),
|
||||
Msg = io_lib:format(
|
||||
"Cannot delete bridge while active rules are depending on it: ~s\n"
|
||||
"Append ?also_delete_dep_actions=true to the request URL to delete "
|
||||
"rule actions that depend on this bridge as well.",
|
||||
[RulesStr]
|
||||
),
|
||||
?BAD_REQUEST(iolist_to_binary(Msg));
|
||||
{error, timeout} ->
|
||||
?SERVICE_UNAVAILABLE(<<"request timeout">>);
|
||||
{error, Reason} ->
|
||||
|
|
|
@ -147,7 +147,8 @@
|
|||
emqx,
|
||||
emqx_auth,
|
||||
emqx_management,
|
||||
{emqx_bridge, "bridges_v2 {}"}
|
||||
{emqx_bridge, "bridges_v2 {}"},
|
||||
{emqx_rule_engine, "rule_engine { rules {} }"}
|
||||
]).
|
||||
|
||||
-define(APPSPEC_DASHBOARD,
|
||||
|
@ -667,6 +668,73 @@ t_bridges_probe(Config) ->
|
|||
),
|
||||
ok.
|
||||
|
||||
t_cascade_delete_actions(Config) ->
|
||||
%% assert we there's no bridges at first
|
||||
{ok, 200, []} = request_json(get, uri([?ROOT]), Config),
|
||||
%% then we add a a bridge, using POST
|
||||
%% POST /bridges_v2/ will create a bridge
|
||||
BridgeID = emqx_bridge_resource:bridge_id(?BRIDGE_TYPE, ?BRIDGE_NAME),
|
||||
{ok, 201, _} = request(
|
||||
post,
|
||||
uri([?ROOT]),
|
||||
?KAFKA_BRIDGE(?BRIDGE_NAME),
|
||||
Config
|
||||
),
|
||||
{ok, 201, #{<<"id">> := RuleId}} = request_json(
|
||||
post,
|
||||
uri(["rules"]),
|
||||
#{
|
||||
<<"name">> => <<"t_http_crud_apis">>,
|
||||
<<"enable">> => true,
|
||||
<<"actions">> => [BridgeID],
|
||||
<<"sql">> => <<"SELECT * from \"t\"">>
|
||||
},
|
||||
Config
|
||||
),
|
||||
%% delete the bridge will also delete the actions from the rules
|
||||
{ok, 204, _} = request(
|
||||
delete,
|
||||
uri([?ROOT, BridgeID]) ++ "?also_delete_dep_actions=true",
|
||||
Config
|
||||
),
|
||||
{ok, 200, []} = request_json(get, uri([?ROOT]), Config),
|
||||
?assertMatch(
|
||||
{ok, 200, #{<<"actions">> := []}},
|
||||
request_json(get, uri(["rules", RuleId]), Config)
|
||||
),
|
||||
{ok, 204, <<>>} = request(delete, uri(["rules", RuleId]), Config),
|
||||
|
||||
{ok, 201, _} = request(
|
||||
post,
|
||||
uri([?ROOT]),
|
||||
?KAFKA_BRIDGE(?BRIDGE_NAME),
|
||||
Config
|
||||
),
|
||||
{ok, 201, _} = request(
|
||||
post,
|
||||
uri(["rules"]),
|
||||
#{
|
||||
<<"name">> => <<"t_http_crud_apis">>,
|
||||
<<"enable">> => true,
|
||||
<<"actions">> => [BridgeID],
|
||||
<<"sql">> => <<"SELECT * from \"t\"">>
|
||||
},
|
||||
Config
|
||||
),
|
||||
{ok, 400, _} = request(
|
||||
delete,
|
||||
uri([?ROOT, BridgeID]),
|
||||
Config
|
||||
),
|
||||
{ok, 200, [_]} = request_json(get, uri([?ROOT]), Config),
|
||||
%% Cleanup
|
||||
{ok, 204, _} = request(
|
||||
delete,
|
||||
uri([?ROOT, BridgeID]) ++ "?also_delete_dep_actions=true",
|
||||
Config
|
||||
),
|
||||
{ok, 200, []} = request_json(get, uri([?ROOT]), Config).
|
||||
|
||||
%%% helpers
|
||||
listen_on_random_port() ->
|
||||
SockOpts = [binary, {active, false}, {packet, raw}, {reuseaddr, true}, {backlog, 1000}],
|
||||
|
|
|
@ -79,6 +79,12 @@ desc_param_path_id.desc:
|
|||
desc_param_path_id.label:
|
||||
"""Bridge ID"""
|
||||
|
||||
desc_qs_also_delete_dep_actions.desc:
|
||||
"""Whether to cascade delete dependent actions."""
|
||||
|
||||
desc_qs_also_delete_dep_actions.label:
|
||||
"""Cascade delete dependent actions?"""
|
||||
|
||||
desc_param_path_node.desc:
|
||||
"""The node name, e.g. 'emqx@127.0.0.1'."""
|
||||
|
||||
|
|
Loading…
Reference in New Issue