Bläddra i källkod

feat(emqx_bridge): add separate endpoint for enable/disable of bridge

In order to improve the consistency with other API endpoints, we move
the enable/disable operations to a separate endpoint
/bridges/{id}/enable/[true,false].
Erik Timan 3 år sedan
förälder
incheckning
42f42de4d9

+ 27 - 8
apps/emqx_bridge/i18n/emqx_bridge_api.conf

@@ -2,8 +2,8 @@ emqx_bridge_api {
 
     desc_param_path_operation_cluster {
                    desc {
-                         en: """Operations can be one of: enable, disable, start, stop, restart"""
-                         zh: """集群可用操作:启用、禁用、启动、停止、重新启动"""
+                         en: """Operations can be one of: start, stop, restart"""
+                         zh: """"""
                         }
                    label: {
                            en: "Cluster Operation"
@@ -44,6 +44,16 @@ emqx_bridge_api {
                           }
                   }
 
+    desc_param_path_enable {
+                   desc {
+                         en: """Whether or not the bridge is enabled"""
+                         zh: """"""
+                        }
+                   label: {
+                           en: "Enable bridge"
+                           zh: ""
+                          }
+                  }
     desc_api1 {
                    desc {
                          en: """List all created bridges"""
@@ -112,8 +122,8 @@ emqx_bridge_api {
 
     desc_api7 {
                    desc {
-                         en: """Enable/Disable/Stop/Restart bridges on all nodes in the cluster."""
-                         zh: """在集群中的所有节点上启用/禁用/停止/重新启动 Bridge。"""
+                         en: """Stop/Restart bridges on all nodes in the cluster."""
+                         zh: """"""
                         }
                    label: {
                            en: "Cluster Bridge Operate"
@@ -123,10 +133,8 @@ emqx_bridge_api {
 
     desc_api8 {
                    desc {
-                         en: """Stop/Restart bridges on a specific node.
- NOTE: It's not allowed to disable/enable bridges on a single node."""
-                         zh: """在某个节点上停止/重新启动 Bridge。
-NOTE:不允许在单节点上启用/禁用 Bridge"""
+                         en: """Stop/Restart bridges on a specific node."""
+                         zh: """在某个节点上停止/重新启动 Bridge。"""
                         }
                    label: {
                            en: "Node Bridge Operate"
@@ -144,4 +152,15 @@ NOTE:不允许在单节点上启用/禁用 Bridge"""
                            zh: ""
                           }
                   }
+
+    desc_enable_bridge {
+                   desc {
+                         en: """Enable or Disable bridges on all nodes in the cluster."""
+                         zh: """"""
+                        }
+                   label: {
+                           en: "Cluster Bridge Enable"
+                           zh: ""
+                          }
+                  }
 }

+ 53 - 12
apps/emqx_bridge/src/emqx_bridge_api.erl

@@ -36,6 +36,7 @@
 -export([
     '/bridges'/2,
     '/bridges/:id'/2,
+    '/bridges/:id/enable/:enable'/2,
     '/bridges/:id/:operation'/2,
     '/nodes/:node/bridges/:id/:operation'/2,
     '/bridges/:id/metrics'/2,
@@ -67,6 +68,7 @@ paths() ->
     [
         "/bridges",
         "/bridges/:id",
+        "/bridges/:id/enable/:enable",
         "/bridges/:id/:operation",
         "/nodes/:node/bridges/:id/:operation",
         "/bridges/:id/metrics",
@@ -89,7 +91,7 @@ get_response_body_schema() ->
 param_path_operation_cluster() ->
     {operation,
         mk(
-            enum([enable, disable, stop, restart]),
+            enum([stop, restart]),
             #{
                 in => path,
                 required => true,
@@ -134,6 +136,17 @@ param_path_id() ->
             }
         )}.
 
+param_path_enable() ->
+    {enable,
+        mk(
+            boolean(),
+            #{
+                in => path,
+                desc => ?DESC("desc_param_path_enable"),
+                example => true
+            }
+        )}.
+
 bridge_info_array_example(Method, WithMetrics) ->
     [Config || #{value := Config} <- maps:values(bridge_info_examples(Method, WithMetrics))].
 
@@ -367,12 +380,29 @@ schema("/bridges/:id/metrics/reset") ->
             }
         }
     };
+schema("/bridges/:id/enable/:enable") ->
+    #{
+        'operationId' => '/bridges/:id/enable/:enable',
+        put =>
+            #{
+                tags => [<<"bridges">>],
+                summary => <<"Enable or Disable Bridge">>,
+                desc => ?DESC("desc_enable_bridge"),
+                parameters => [param_path_id(), param_path_enable()],
+                responses =>
+                    #{
+                        204 => <<"Success">>,
+                        400 => error_schema('INVALID_ID', "Bad bridge ID"),
+                        503 => error_schema('SERVICE_UNAVAILABLE', "Service unavailable")
+                    }
+            }
+    };
 schema("/bridges/:id/:operation") ->
     #{
         'operationId' => '/bridges/:id/:operation',
         post => #{
             tags => [<<"bridges">>],
-            summary => <<"Enable/Disable/Stop/Restart Bridge">>,
+            summary => <<"Stop or Restart Bridge">>,
             description => ?DESC("desc_api7"),
             parameters => [
                 param_path_id(),
@@ -515,19 +545,16 @@ lookup_from_local_node(BridgeType, BridgeName) ->
         Error -> Error
     end.
 
-'/bridges/:id/:operation'(post, #{
-    bindings :=
-        #{id := Id, operation := Op}
-}) ->
+'/bridges/:id/enable/:enable'(put, #{bindings := #{id := Id, enable := Enable}}) ->
     ?TRY_PARSE_ID(
         Id,
-        case operation_func(Op) of
+        case enable_func(Enable) of
             invalid ->
                 {400, error_msg('BAD_REQUEST', <<"invalid operation">>)};
-            OperFunc when OperFunc == enable; OperFunc == disable ->
+            OperFunc ->
                 case emqx_bridge:disable_enable(OperFunc, BridgeType, BridgeName) of
                     {ok, _} ->
-                        {200};
+                        {204};
                     {error, {pre_config_update, _, bridge_not_found}} ->
                         {404, error_msg('NOT_FOUND', <<"bridge not found">>)};
                     {error, {_, _, timeout}} ->
@@ -536,7 +563,19 @@ lookup_from_local_node(BridgeType, BridgeName) ->
                         {503, error_msg('SERVICE_UNAVAILABLE', <<"request timeout">>)};
                     {error, Reason} ->
                         {500, error_msg('INTERNAL_ERROR', Reason)}
-                end;
+                end
+        end
+    ).
+
+'/bridges/:id/:operation'(post, #{
+    bindings :=
+        #{id := Id, operation := Op}
+}) ->
+    ?TRY_PARSE_ID(
+        Id,
+        case operation_func(Op) of
+            invalid ->
+                {400, error_msg('BAD_REQUEST', <<"invalid operation">>)};
             OperFunc ->
                 Nodes = mria_mnesia:running_nodes(),
                 operation_to_all_nodes(Nodes, OperFunc, BridgeType, BridgeName)
@@ -573,10 +612,12 @@ node_operation_func(_) -> invalid.
 
 operation_func(<<"stop">>) -> stop;
 operation_func(<<"restart">>) -> restart;
-operation_func(<<"enable">>) -> enable;
-operation_func(<<"disable">>) -> disable;
 operation_func(_) -> invalid.
 
+enable_func(<<"true">>) -> enable;
+enable_func(<<"false">>) -> disable;
+enable_func(_) -> invalid.
+
 operation_to_all_nodes(Nodes, OperFunc, BridgeType, BridgeName) ->
     RpcFunc =
         case OperFunc of

+ 8 - 5
apps/emqx_bridge/test/emqx_bridge_api_SUITE.erl

@@ -498,19 +498,19 @@ t_enable_disable_bridges(Config) ->
     } = jsx:decode(Bridge),
     BridgeID = emqx_bridge_resource:bridge_id(?BRIDGE_TYPE, Name),
     %% disable it
-    {ok, 200, <<>>} = request(post, operation_path(cluster, disable, BridgeID), <<"">>),
+    {ok, 204, <<>>} = request(put, enable_path(false, BridgeID), <<"">>),
     {ok, 200, Bridge2} = request(get, uri(["bridges", BridgeID]), []),
     ?assertMatch(#{<<"status">> := <<"stopped">>}, jsx:decode(Bridge2)),
     %% enable again
-    {ok, 200, <<>>} = request(post, operation_path(cluster, enable, BridgeID), <<"">>),
+    {ok, 204, <<>>} = request(put, enable_path(true, BridgeID), <<"">>),
     {ok, 200, Bridge3} = request(get, uri(["bridges", BridgeID]), []),
     ?assertMatch(#{<<"status">> := <<"connected">>}, jsx:decode(Bridge3)),
     %% enable an already started bridge
-    {ok, 200, <<>>} = request(post, operation_path(cluster, enable, BridgeID), <<"">>),
+    {ok, 204, <<>>} = request(put, enable_path(true, BridgeID), <<"">>),
     {ok, 200, Bridge3} = request(get, uri(["bridges", BridgeID]), []),
     ?assertMatch(#{<<"status">> := <<"connected">>}, jsx:decode(Bridge3)),
     %% disable it again
-    {ok, 200, <<>>} = request(post, operation_path(cluster, disable, BridgeID), <<"">>),
+    {ok, 204, <<>>} = request(put, enable_path(false, BridgeID), <<"">>),
 
     {ok, 403, Res} = request(post, operation_path(node, restart, BridgeID), <<"">>),
     ?assertEqual(
@@ -519,7 +519,7 @@ t_enable_disable_bridges(Config) ->
     ),
 
     %% enable a stopped bridge
-    {ok, 200, <<>>} = request(post, operation_path(cluster, enable, BridgeID), <<"">>),
+    {ok, 204, <<>>} = request(put, enable_path(true, BridgeID), <<"">>),
     {ok, 200, Bridge4} = request(get, uri(["bridges", BridgeID]), []),
     ?assertMatch(#{<<"status">> := <<"connected">>}, jsx:decode(Bridge4)),
     %% delete the bridge
@@ -674,5 +674,8 @@ operation_path(node, Oper, BridgeID) ->
 operation_path(cluster, Oper, BridgeID) ->
     uri(["bridges", BridgeID, Oper]).
 
+enable_path(Enable, BridgeID) ->
+    uri(["bridges", BridgeID, "enable", Enable]).
+
 str(S) when is_list(S) -> S;
 str(S) when is_binary(S) -> binary_to_list(S).