refactor(action_api): prepare for `/sources` HTTP API
This commit is contained in:
parent
12dc9fbeb9
commit
6511693b2e
|
@ -8,6 +8,7 @@
|
||||||
{emqx_bridge,3}.
|
{emqx_bridge,3}.
|
||||||
{emqx_bridge,4}.
|
{emqx_bridge,4}.
|
||||||
{emqx_bridge,5}.
|
{emqx_bridge,5}.
|
||||||
|
{emqx_bridge,6}.
|
||||||
{emqx_broker,1}.
|
{emqx_broker,1}.
|
||||||
{emqx_cm,1}.
|
{emqx_cm,1}.
|
||||||
{emqx_cm,2}.
|
{emqx_cm,2}.
|
||||||
|
|
|
@ -49,6 +49,11 @@
|
||||||
-export([lookup_from_local_node/2]).
|
-export([lookup_from_local_node/2]).
|
||||||
-export([get_metrics_from_local_node/2]).
|
-export([get_metrics_from_local_node/2]).
|
||||||
|
|
||||||
|
%% only for testting/mocking
|
||||||
|
-export([supported_versions/1]).
|
||||||
|
|
||||||
|
-define(BPAPI_NAME, emqx_bridge).
|
||||||
|
|
||||||
-define(BRIDGE_NOT_ENABLED,
|
-define(BRIDGE_NOT_ENABLED,
|
||||||
?BAD_REQUEST(<<"Forbidden operation, bridge not enabled">>)
|
?BAD_REQUEST(<<"Forbidden operation, bridge not enabled">>)
|
||||||
).
|
).
|
||||||
|
@ -1102,18 +1107,18 @@ maybe_try_restart(_, _, _) ->
|
||||||
|
|
||||||
do_bpapi_call(all, Call, Args) ->
|
do_bpapi_call(all, Call, Args) ->
|
||||||
maybe_unwrap(
|
maybe_unwrap(
|
||||||
do_bpapi_call_vsn(emqx_bpapi:supported_version(emqx_bridge), Call, Args)
|
do_bpapi_call_vsn(emqx_bpapi:supported_version(?BPAPI_NAME), Call, Args)
|
||||||
);
|
);
|
||||||
do_bpapi_call(Node, Call, Args) ->
|
do_bpapi_call(Node, Call, Args) ->
|
||||||
case lists:member(Node, mria:running_nodes()) of
|
case lists:member(Node, mria:running_nodes()) of
|
||||||
true ->
|
true ->
|
||||||
do_bpapi_call_vsn(emqx_bpapi:supported_version(Node, emqx_bridge), Call, Args);
|
do_bpapi_call_vsn(emqx_bpapi:supported_version(Node, ?BPAPI_NAME), Call, Args);
|
||||||
false ->
|
false ->
|
||||||
{error, {node_not_found, Node}}
|
{error, {node_not_found, Node}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
do_bpapi_call_vsn(SupportedVersion, Call, Args) ->
|
do_bpapi_call_vsn(SupportedVersion, Call, Args) ->
|
||||||
case lists:member(SupportedVersion, supported_versions(Call)) of
|
case lists:member(SupportedVersion, ?MODULE:supported_versions(Call)) of
|
||||||
true ->
|
true ->
|
||||||
apply(emqx_bridge_proto_v4, Call, Args);
|
apply(emqx_bridge_proto_v4, Call, Args);
|
||||||
false ->
|
false ->
|
||||||
|
@ -1125,10 +1130,15 @@ maybe_unwrap({error, not_implemented}) ->
|
||||||
maybe_unwrap(RpcMulticallResult) ->
|
maybe_unwrap(RpcMulticallResult) ->
|
||||||
emqx_rpc:unwrap_erpc(RpcMulticallResult).
|
emqx_rpc:unwrap_erpc(RpcMulticallResult).
|
||||||
|
|
||||||
supported_versions(start_bridge_to_node) -> [2, 3, 4, 5];
|
supported_versions(start_bridge_to_node) -> bpapi_version_range(2, latest);
|
||||||
supported_versions(start_bridges_to_all_nodes) -> [2, 3, 4, 5];
|
supported_versions(start_bridges_to_all_nodes) -> bpapi_version_range(2, latest);
|
||||||
supported_versions(get_metrics_from_all_nodes) -> [4, 5];
|
supported_versions(get_metrics_from_all_nodes) -> bpapi_version_range(4, latest);
|
||||||
supported_versions(_Call) -> [1, 2, 3, 4, 5].
|
supported_versions(_Call) -> bpapi_version_range(1, latest).
|
||||||
|
|
||||||
|
%% [From, To] (inclusive on both ends)
|
||||||
|
bpapi_version_range(From, latest) ->
|
||||||
|
ThisNodeVsn = emqx_bpapi:supported_version(node(), ?BPAPI_NAME),
|
||||||
|
lists:seq(From, ThisNodeVsn).
|
||||||
|
|
||||||
redact(Term) ->
|
redact(Term) ->
|
||||||
emqx_utils:redact(Term).
|
emqx_utils:redact(Term).
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
lookup/2,
|
lookup/2,
|
||||||
lookup/3,
|
lookup/3,
|
||||||
create/3,
|
create/3,
|
||||||
|
create/4,
|
||||||
%% The remove/2 function is only for internal use as it may create
|
%% The remove/2 function is only for internal use as it may create
|
||||||
%% rules with broken dependencies
|
%% rules with broken dependencies
|
||||||
remove/2,
|
remove/2,
|
||||||
|
@ -50,7 +51,8 @@
|
||||||
%% The following is the remove function that is called by the HTTP API
|
%% The following is the remove function that is called by the HTTP API
|
||||||
%% It also checks for rule action dependencies and optionally removes
|
%% It also checks for rule action dependencies and optionally removes
|
||||||
%% them
|
%% them
|
||||||
check_deps_and_remove/3
|
check_deps_and_remove/3,
|
||||||
|
check_deps_and_remove/4
|
||||||
]).
|
]).
|
||||||
|
|
||||||
%% Operations
|
%% Operations
|
||||||
|
@ -62,9 +64,11 @@
|
||||||
send_message/4,
|
send_message/4,
|
||||||
query/4,
|
query/4,
|
||||||
start/2,
|
start/2,
|
||||||
|
start/3,
|
||||||
reset_metrics/2,
|
reset_metrics/2,
|
||||||
reset_metrics/3,
|
reset_metrics/3,
|
||||||
create_dry_run/2,
|
create_dry_run/2,
|
||||||
|
create_dry_run/3,
|
||||||
get_metrics/2,
|
get_metrics/2,
|
||||||
get_metrics/3
|
get_metrics/3
|
||||||
]).
|
]).
|
||||||
|
@ -150,6 +154,10 @@
|
||||||
-type bridge_v2_type() :: binary() | atom() | [byte()].
|
-type bridge_v2_type() :: binary() | atom() | [byte()].
|
||||||
-type bridge_v2_name() :: binary() | atom() | [byte()].
|
-type bridge_v2_name() :: binary() | atom() | [byte()].
|
||||||
|
|
||||||
|
-type root_cfg_key() :: ?ROOT_KEY_ACTIONS | ?ROOT_KEY_SOURCES.
|
||||||
|
|
||||||
|
-export_type([root_cfg_key/0]).
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
|
@ -212,7 +220,7 @@ unload_bridges(ConfRooKey) ->
|
||||||
lookup(Type, Name) ->
|
lookup(Type, Name) ->
|
||||||
lookup(?ROOT_KEY_ACTIONS, Type, Name).
|
lookup(?ROOT_KEY_ACTIONS, Type, Name).
|
||||||
|
|
||||||
-spec lookup(sources | actions, bridge_v2_type(), bridge_v2_name()) ->
|
-spec lookup(root_cfg_key(), bridge_v2_type(), bridge_v2_name()) ->
|
||||||
{ok, bridge_v2_info()} | {error, not_found}.
|
{ok, bridge_v2_info()} | {error, not_found}.
|
||||||
lookup(ConfRootName, Type, Name) ->
|
lookup(ConfRootName, Type, Name) ->
|
||||||
case emqx:get_raw_config([ConfRootName, Type, Name], not_found) of
|
case emqx:get_raw_config([ConfRootName, Type, Name], not_found) of
|
||||||
|
@ -315,6 +323,11 @@ remove(ConfRootKey, BridgeType, BridgeName) ->
|
||||||
|
|
||||||
-spec check_deps_and_remove(bridge_v2_type(), bridge_v2_name(), boolean()) -> ok | {error, any()}.
|
-spec check_deps_and_remove(bridge_v2_type(), bridge_v2_name(), boolean()) -> ok | {error, any()}.
|
||||||
check_deps_and_remove(BridgeType, BridgeName, AlsoDeleteActions) ->
|
check_deps_and_remove(BridgeType, BridgeName, AlsoDeleteActions) ->
|
||||||
|
check_deps_and_remove(?ROOT_KEY_ACTIONS, BridgeType, BridgeName, AlsoDeleteActions).
|
||||||
|
|
||||||
|
-spec check_deps_and_remove(root_cfg_key(), bridge_v2_type(), bridge_v2_name(), boolean()) ->
|
||||||
|
ok | {error, any()}.
|
||||||
|
check_deps_and_remove(ConfRooKey, BridgeType, BridgeName, AlsoDeleteActions) ->
|
||||||
AlsoDelete =
|
AlsoDelete =
|
||||||
case AlsoDeleteActions of
|
case AlsoDeleteActions of
|
||||||
true -> [rule_actions];
|
true -> [rule_actions];
|
||||||
|
@ -328,7 +341,7 @@ check_deps_and_remove(BridgeType, BridgeName, AlsoDeleteActions) ->
|
||||||
)
|
)
|
||||||
of
|
of
|
||||||
ok ->
|
ok ->
|
||||||
remove(BridgeType, BridgeName);
|
remove(ConfRooKey, BridgeType, BridgeName);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
end.
|
end.
|
||||||
|
@ -539,11 +552,14 @@ disable_enable(ConfRootKey, Action, BridgeType, BridgeName) when ?ENABLE_OR_DISA
|
||||||
%% is something else than connected after starting the connector or if an
|
%% is something else than connected after starting the connector or if an
|
||||||
%% error occurred when the connector was started.
|
%% error occurred when the connector was started.
|
||||||
-spec start(term(), term()) -> ok | {error, Reason :: term()}.
|
-spec start(term(), term()) -> ok | {error, Reason :: term()}.
|
||||||
start(BridgeV2Type, Name) ->
|
start(ActionOrSourceType, Name) ->
|
||||||
|
start(?ROOT_KEY_ACTIONS, ActionOrSourceType, Name).
|
||||||
|
|
||||||
|
-spec start(root_cfg_key(), term(), term()) -> ok | {error, Reason :: term()}.
|
||||||
|
start(ConfRootKey, BridgeV2Type, Name) ->
|
||||||
ConnectorOpFun = fun(ConnectorType, ConnectorName) ->
|
ConnectorOpFun = fun(ConnectorType, ConnectorName) ->
|
||||||
emqx_connector_resource:start(ConnectorType, ConnectorName)
|
emqx_connector_resource:start(ConnectorType, ConnectorName)
|
||||||
end,
|
end,
|
||||||
ConfRootKey = ?ROOT_KEY_ACTIONS,
|
|
||||||
connector_operation_helper(ConfRootKey, BridgeV2Type, Name, ConnectorOpFun, true).
|
connector_operation_helper(ConfRootKey, BridgeV2Type, Name, ConnectorOpFun, true).
|
||||||
|
|
||||||
connector_operation_helper(ConfRootKey, BridgeV2Type, Name, ConnectorOpFun, DoHealthCheck) ->
|
connector_operation_helper(ConfRootKey, BridgeV2Type, Name, ConnectorOpFun, DoHealthCheck) ->
|
||||||
|
@ -694,10 +710,15 @@ health_check(ConfRootKey, BridgeType, BridgeName) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec create_dry_run(bridge_v2_type(), Config :: map()) -> ok | {error, term()}.
|
-spec create_dry_run(bridge_v2_type(), Config :: map()) -> ok | {error, term()}.
|
||||||
create_dry_run(Type, Conf0) ->
|
create_dry_run(Type, Conf) ->
|
||||||
|
create_dry_run(?ROOT_KEY_ACTIONS, Type, Conf).
|
||||||
|
|
||||||
|
-spec create_dry_run(root_cfg_key(), bridge_v2_type(), Config :: map()) -> ok | {error, term()}.
|
||||||
|
create_dry_run(ConfRootKey, Type, Conf0) ->
|
||||||
Conf1 = maps:without([<<"name">>], Conf0),
|
Conf1 = maps:without([<<"name">>], Conf0),
|
||||||
TypeBin = bin(Type),
|
TypeBin = bin(Type),
|
||||||
RawConf = #{<<"actions">> => #{TypeBin => #{<<"temp_name">> => Conf1}}},
|
ConfRootKeyBin = bin(ConfRootKey),
|
||||||
|
RawConf = #{ConfRootKeyBin => #{TypeBin => #{<<"temp_name">> => Conf1}}},
|
||||||
%% Check config
|
%% Check config
|
||||||
try
|
try
|
||||||
_ =
|
_ =
|
||||||
|
@ -722,6 +743,9 @@ create_dry_run(Type, Conf0) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
create_dry_run_helper(BridgeType, ConnectorRawConf, BridgeV2RawConf) ->
|
create_dry_run_helper(BridgeType, ConnectorRawConf, BridgeV2RawConf) ->
|
||||||
|
create_dry_run_helper(?ROOT_KEY_ACTIONS, BridgeType, ConnectorRawConf, BridgeV2RawConf).
|
||||||
|
|
||||||
|
create_dry_run_helper(ConfRootKey, BridgeType, ConnectorRawConf, BridgeV2RawConf) ->
|
||||||
BridgeName = iolist_to_binary([?TEST_ID_PREFIX, emqx_utils:gen_id(8)]),
|
BridgeName = iolist_to_binary([?TEST_ID_PREFIX, emqx_utils:gen_id(8)]),
|
||||||
ConnectorType = connector_type(BridgeType),
|
ConnectorType = connector_type(BridgeType),
|
||||||
OnReadyCallback =
|
OnReadyCallback =
|
||||||
|
@ -730,7 +754,7 @@ create_dry_run_helper(BridgeType, ConnectorRawConf, BridgeV2RawConf) ->
|
||||||
ChannelTestId = id(BridgeType, BridgeName, ConnectorName),
|
ChannelTestId = id(BridgeType, BridgeName, ConnectorName),
|
||||||
Conf = emqx_utils_maps:unsafe_atom_key_map(BridgeV2RawConf),
|
Conf = emqx_utils_maps:unsafe_atom_key_map(BridgeV2RawConf),
|
||||||
AugmentedConf = augment_channel_config(
|
AugmentedConf = augment_channel_config(
|
||||||
?ROOT_KEY_ACTIONS,
|
ConfRootKey,
|
||||||
BridgeType,
|
BridgeType,
|
||||||
BridgeName,
|
BridgeName,
|
||||||
Conf
|
Conf
|
||||||
|
@ -756,6 +780,8 @@ create_dry_run_helper(BridgeType, ConnectorRawConf, BridgeV2RawConf) ->
|
||||||
get_metrics(Type, Name) ->
|
get_metrics(Type, Name) ->
|
||||||
get_metrics(?ROOT_KEY_ACTIONS, Type, Name).
|
get_metrics(?ROOT_KEY_ACTIONS, Type, Name).
|
||||||
|
|
||||||
|
-spec get_metrics(root_cfg_key(), bridge_v2_type(), bridge_v2_name()) ->
|
||||||
|
emqx_metrics_worker:metrics().
|
||||||
get_metrics(ConfRootKey, Type, Name) ->
|
get_metrics(ConfRootKey, Type, Name) ->
|
||||||
emqx_resource:get_metrics(id_with_root_name(ConfRootKey, Type, Name)).
|
emqx_resource:get_metrics(id_with_root_name(ConfRootKey, Type, Name)).
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,9 @@
|
||||||
-import(hoconsc, [mk/2, array/1, enum/1]).
|
-import(hoconsc, [mk/2, array/1, enum/1]).
|
||||||
-import(emqx_utils, [redact/1]).
|
-import(emqx_utils, [redact/1]).
|
||||||
|
|
||||||
|
-define(ROOT_KEY_ACTIONS, actions).
|
||||||
|
-define(ROOT_KEY_SOURCES, sources).
|
||||||
|
|
||||||
%% Swagger specs from hocon schema
|
%% Swagger specs from hocon schema
|
||||||
-export([
|
-export([
|
||||||
api_spec/0,
|
api_spec/0,
|
||||||
|
@ -48,7 +51,14 @@
|
||||||
]).
|
]).
|
||||||
|
|
||||||
%% BpAPI / RPC Targets
|
%% BpAPI / RPC Targets
|
||||||
-export([lookup_from_local_node/2, get_metrics_from_local_node/2]).
|
-export([
|
||||||
|
lookup_from_local_node/2,
|
||||||
|
get_metrics_from_local_node/2,
|
||||||
|
lookup_from_local_node_v6/3,
|
||||||
|
get_metrics_from_local_node_v6/3
|
||||||
|
]).
|
||||||
|
|
||||||
|
-define(BPAPI_NAME, emqx_bridge).
|
||||||
|
|
||||||
-define(BRIDGE_NOT_FOUND(BRIDGE_TYPE, BRIDGE_NAME),
|
-define(BRIDGE_NOT_FOUND(BRIDGE_TYPE, BRIDGE_NAME),
|
||||||
?NOT_FOUND(
|
?NOT_FOUND(
|
||||||
|
@ -393,16 +403,51 @@ schema("/action_types") ->
|
||||||
}.
|
}.
|
||||||
|
|
||||||
'/actions'(post, #{body := #{<<"type">> := BridgeType, <<"name">> := BridgeName} = Conf0}) ->
|
'/actions'(post, #{body := #{<<"type">> := BridgeType, <<"name">> := BridgeName} = Conf0}) ->
|
||||||
case emqx_bridge_v2:lookup(BridgeType, BridgeName) of
|
handle_create(?ROOT_KEY_ACTIONS, BridgeType, BridgeName, Conf0);
|
||||||
{ok, _} ->
|
|
||||||
?BAD_REQUEST('ALREADY_EXISTS', <<"bridge already exists">>);
|
|
||||||
{error, not_found} ->
|
|
||||||
Conf = filter_out_request_body(Conf0),
|
|
||||||
create_bridge(BridgeType, BridgeName, Conf)
|
|
||||||
end;
|
|
||||||
'/actions'(get, _Params) ->
|
'/actions'(get, _Params) ->
|
||||||
Nodes = mria:running_nodes(),
|
handle_list(?ROOT_KEY_ACTIONS).
|
||||||
NodeReplies = emqx_bridge_proto_v5:v2_list_bridges_on_nodes(Nodes),
|
|
||||||
|
'/actions/:id'(get, #{bindings := #{id := Id}}) ->
|
||||||
|
?TRY_PARSE_ID(Id, lookup_from_all_nodes(?ROOT_KEY_ACTIONS, BridgeType, BridgeName, 200));
|
||||||
|
'/actions/:id'(put, #{bindings := #{id := Id}, body := Conf0}) ->
|
||||||
|
handle_update(?ROOT_KEY_ACTIONS, Id, Conf0);
|
||||||
|
'/actions/:id'(delete, #{bindings := #{id := Id}, query_string := Qs}) ->
|
||||||
|
handle_delete(?ROOT_KEY_ACTIONS, Id, Qs).
|
||||||
|
|
||||||
|
'/actions/:id/metrics'(get, #{bindings := #{id := Id}}) ->
|
||||||
|
?TRY_PARSE_ID(Id, get_metrics_from_all_nodes(?ROOT_KEY_ACTIONS, BridgeType, BridgeName)).
|
||||||
|
|
||||||
|
'/actions/:id/metrics/reset'(put, #{bindings := #{id := Id}}) ->
|
||||||
|
handle_reset_metrics(?ROOT_KEY_ACTIONS, Id).
|
||||||
|
|
||||||
|
'/actions/:id/enable/:enable'(put, #{bindings := #{id := Id, enable := Enable}}) ->
|
||||||
|
handle_disable_enable(?ROOT_KEY_ACTIONS, Id, Enable).
|
||||||
|
|
||||||
|
'/actions/:id/:operation'(post, #{
|
||||||
|
bindings :=
|
||||||
|
#{id := Id, operation := Op}
|
||||||
|
}) ->
|
||||||
|
handle_operation(?ROOT_KEY_ACTIONS, Id, Op).
|
||||||
|
|
||||||
|
'/nodes/:node/actions/:id/:operation'(post, #{
|
||||||
|
bindings :=
|
||||||
|
#{id := Id, operation := Op, node := Node}
|
||||||
|
}) ->
|
||||||
|
handle_node_operation(?ROOT_KEY_ACTIONS, Node, Id, Op).
|
||||||
|
|
||||||
|
'/actions_probe'(post, Request) ->
|
||||||
|
handle_probe(?ROOT_KEY_ACTIONS, Request).
|
||||||
|
|
||||||
|
'/action_types'(get, _Request) ->
|
||||||
|
?OK(emqx_bridge_v2_schema:types()).
|
||||||
|
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
%% Handlers
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
handle_list(ConfRootKey) ->
|
||||||
|
Nodes = emqx:running_nodes(),
|
||||||
|
NodeReplies = emqx_bridge_proto_v6:v2_list_bridges_on_nodes_v6(Nodes, ConfRootKey),
|
||||||
case is_ok(NodeReplies) of
|
case is_ok(NodeReplies) of
|
||||||
{ok, NodeBridges} ->
|
{ok, NodeBridges} ->
|
||||||
AllBridges = [
|
AllBridges = [
|
||||||
|
@ -414,34 +459,44 @@ schema("/action_types") ->
|
||||||
?INTERNAL_ERROR(Reason)
|
?INTERNAL_ERROR(Reason)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
'/actions/:id'(get, #{bindings := #{id := Id}}) ->
|
handle_create(ConfRootKey, Type, Name, Conf0) ->
|
||||||
?TRY_PARSE_ID(Id, lookup_from_all_nodes(BridgeType, BridgeName, 200));
|
case emqx_bridge_v2:lookup(ConfRootKey, Type, Name) of
|
||||||
'/actions/:id'(put, #{bindings := #{id := Id}, body := Conf0}) ->
|
{ok, _} ->
|
||||||
|
?BAD_REQUEST('ALREADY_EXISTS', <<"bridge already exists">>);
|
||||||
|
{error, not_found} ->
|
||||||
|
Conf = filter_out_request_body(Conf0),
|
||||||
|
create_bridge(ConfRootKey, Type, Name, Conf)
|
||||||
|
end.
|
||||||
|
|
||||||
|
handle_update(ConfRootKey, Id, Conf0) ->
|
||||||
Conf1 = filter_out_request_body(Conf0),
|
Conf1 = filter_out_request_body(Conf0),
|
||||||
?TRY_PARSE_ID(
|
?TRY_PARSE_ID(
|
||||||
Id,
|
Id,
|
||||||
case emqx_bridge_v2:lookup(BridgeType, BridgeName) of
|
case emqx_bridge_v2:lookup(ConfRootKey, BridgeType, BridgeName) of
|
||||||
{ok, _} ->
|
{ok, _} ->
|
||||||
RawConf = emqx:get_raw_config([bridges, BridgeType, BridgeName], #{}),
|
RawConf = emqx:get_raw_config([bridges, BridgeType, BridgeName], #{}),
|
||||||
Conf = emqx_utils:deobfuscate(Conf1, RawConf),
|
Conf = emqx_utils:deobfuscate(Conf1, RawConf),
|
||||||
update_bridge(BridgeType, BridgeName, Conf);
|
update_bridge(ConfRootKey, BridgeType, BridgeName, Conf);
|
||||||
{error, not_found} ->
|
{error, not_found} ->
|
||||||
?BRIDGE_NOT_FOUND(BridgeType, BridgeName)
|
?BRIDGE_NOT_FOUND(BridgeType, BridgeName)
|
||||||
end
|
end
|
||||||
);
|
).
|
||||||
'/actions/:id'(delete, #{bindings := #{id := Id}, query_string := Qs}) ->
|
|
||||||
|
handle_delete(ConfRootKey, Id, QueryStringOpts) ->
|
||||||
?TRY_PARSE_ID(
|
?TRY_PARSE_ID(
|
||||||
Id,
|
Id,
|
||||||
case emqx_bridge_v2:lookup(BridgeType, BridgeName) of
|
case emqx_bridge_v2:lookup(BridgeType, BridgeName) of
|
||||||
{ok, _} ->
|
{ok, _} ->
|
||||||
AlsoDeleteActions =
|
AlsoDeleteActions =
|
||||||
case maps:get(<<"also_delete_dep_actions">>, Qs, <<"false">>) of
|
case maps:get(<<"also_delete_dep_actions">>, QueryStringOpts, <<"false">>) of
|
||||||
<<"true">> -> true;
|
<<"true">> -> true;
|
||||||
true -> true;
|
true -> true;
|
||||||
_ -> false
|
_ -> false
|
||||||
end,
|
end,
|
||||||
case
|
case
|
||||||
emqx_bridge_v2:check_deps_and_remove(BridgeType, BridgeName, AlsoDeleteActions)
|
emqx_bridge_v2:check_deps_and_remove(
|
||||||
|
ConfRootKey, BridgeType, BridgeName, AlsoDeleteActions
|
||||||
|
)
|
||||||
of
|
of
|
||||||
ok ->
|
ok ->
|
||||||
?NO_CONTENT;
|
?NO_CONTENT;
|
||||||
|
@ -465,23 +520,22 @@ schema("/action_types") ->
|
||||||
end
|
end
|
||||||
).
|
).
|
||||||
|
|
||||||
'/actions/:id/metrics'(get, #{bindings := #{id := Id}}) ->
|
handle_reset_metrics(ConfRootKey, Id) ->
|
||||||
?TRY_PARSE_ID(Id, get_metrics_from_all_nodes(BridgeType, BridgeName)).
|
|
||||||
|
|
||||||
'/actions/:id/metrics/reset'(put, #{bindings := #{id := Id}}) ->
|
|
||||||
?TRY_PARSE_ID(
|
?TRY_PARSE_ID(
|
||||||
Id,
|
Id,
|
||||||
begin
|
begin
|
||||||
ActionType = emqx_bridge_v2:bridge_v2_type_to_connector_type(BridgeType),
|
ActionType = emqx_bridge_v2:bridge_v2_type_to_connector_type(BridgeType),
|
||||||
ok = emqx_bridge_v2:reset_metrics(ActionType, BridgeName),
|
ok = emqx_bridge_v2:reset_metrics(ConfRootKey, ActionType, BridgeName),
|
||||||
?NO_CONTENT
|
?NO_CONTENT
|
||||||
end
|
end
|
||||||
).
|
).
|
||||||
|
|
||||||
'/actions/:id/enable/:enable'(put, #{bindings := #{id := Id, enable := Enable}}) ->
|
handle_disable_enable(ConfRootKey, Id, Enable) ->
|
||||||
?TRY_PARSE_ID(
|
?TRY_PARSE_ID(
|
||||||
Id,
|
Id,
|
||||||
case emqx_bridge_v2:disable_enable(enable_func(Enable), BridgeType, BridgeName) of
|
case
|
||||||
|
emqx_bridge_v2:disable_enable(ConfRootKey, enable_func(Enable), BridgeType, BridgeName)
|
||||||
|
of
|
||||||
{ok, _} ->
|
{ok, _} ->
|
||||||
?NO_CONTENT;
|
?NO_CONTENT;
|
||||||
{error, {pre_config_update, _, bridge_not_found}} ->
|
{error, {pre_config_update, _, bridge_not_found}} ->
|
||||||
|
@ -495,41 +549,37 @@ schema("/action_types") ->
|
||||||
end
|
end
|
||||||
).
|
).
|
||||||
|
|
||||||
'/actions/:id/:operation'(post, #{
|
handle_operation(ConfRootKey, Id, Op) ->
|
||||||
bindings :=
|
|
||||||
#{id := Id, operation := Op}
|
|
||||||
}) ->
|
|
||||||
?TRY_PARSE_ID(
|
?TRY_PARSE_ID(
|
||||||
Id,
|
Id,
|
||||||
begin
|
begin
|
||||||
OperFunc = operation_func(all, Op),
|
OperFunc = operation_func(all, Op),
|
||||||
Nodes = mria:running_nodes(),
|
Nodes = emqx:running_nodes(),
|
||||||
call_operation_if_enabled(all, OperFunc, [Nodes, BridgeType, BridgeName])
|
call_operation_if_enabled(all, OperFunc, [Nodes, ConfRootKey, BridgeType, BridgeName])
|
||||||
end
|
end
|
||||||
).
|
).
|
||||||
|
|
||||||
'/nodes/:node/actions/:id/:operation'(post, #{
|
handle_node_operation(ConfRootKey, Node, Id, Op) ->
|
||||||
bindings :=
|
|
||||||
#{id := Id, operation := Op, node := Node}
|
|
||||||
}) ->
|
|
||||||
?TRY_PARSE_ID(
|
?TRY_PARSE_ID(
|
||||||
Id,
|
Id,
|
||||||
case emqx_utils:safe_to_existing_atom(Node, utf8) of
|
case emqx_utils:safe_to_existing_atom(Node, utf8) of
|
||||||
{ok, TargetNode} ->
|
{ok, TargetNode} ->
|
||||||
OperFunc = operation_func(TargetNode, Op),
|
OperFunc = operation_func(TargetNode, Op),
|
||||||
call_operation_if_enabled(TargetNode, OperFunc, [TargetNode, BridgeType, BridgeName]);
|
call_operation_if_enabled(TargetNode, OperFunc, [
|
||||||
|
TargetNode, ConfRootKey, BridgeType, BridgeName
|
||||||
|
]);
|
||||||
{error, _} ->
|
{error, _} ->
|
||||||
?NOT_FOUND(<<"Invalid node name: ", Node/binary>>)
|
?NOT_FOUND(<<"Invalid node name: ", Node/binary>>)
|
||||||
end
|
end
|
||||||
).
|
).
|
||||||
|
|
||||||
'/actions_probe'(post, Request) ->
|
handle_probe(ConfRootKey, Request) ->
|
||||||
RequestMeta = #{module => ?MODULE, method => post, path => "/actions_probe"},
|
RequestMeta = #{module => ?MODULE, method => post, path => "/actions_probe"},
|
||||||
case emqx_dashboard_swagger:filter_check_request_and_translate_body(Request, RequestMeta) of
|
case emqx_dashboard_swagger:filter_check_request_and_translate_body(Request, RequestMeta) of
|
||||||
{ok, #{body := #{<<"type">> := ConnType} = Params}} ->
|
{ok, #{body := #{<<"type">> := Type} = Params}} ->
|
||||||
Params1 = maybe_deobfuscate_bridge_probe(Params),
|
Params1 = maybe_deobfuscate_bridge_probe(Params),
|
||||||
Params2 = maps:remove(<<"type">>, Params1),
|
Params2 = maps:remove(<<"type">>, Params1),
|
||||||
case emqx_bridge_v2:create_dry_run(ConnType, Params2) of
|
case emqx_bridge_v2:create_dry_run(ConfRootKey, Type, Params2) of
|
||||||
ok ->
|
ok ->
|
||||||
?NO_CONTENT;
|
?NO_CONTENT;
|
||||||
{error, #{kind := validation_error} = Reason0} ->
|
{error, #{kind := validation_error} = Reason0} ->
|
||||||
|
@ -548,9 +598,7 @@ schema("/action_types") ->
|
||||||
redact(BadRequest)
|
redact(BadRequest)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
'/action_types'(get, _Request) ->
|
%%% API helpers
|
||||||
?OK(emqx_bridge_v2_schema:types()).
|
|
||||||
|
|
||||||
maybe_deobfuscate_bridge_probe(#{<<"type">> := ActionType, <<"name">> := BridgeName} = Params) ->
|
maybe_deobfuscate_bridge_probe(#{<<"type">> := ActionType, <<"name">> := BridgeName} = Params) ->
|
||||||
case emqx_bridge_v2:lookup(ActionType, BridgeName) of
|
case emqx_bridge_v2:lookup(ActionType, BridgeName) of
|
||||||
{ok, #{raw_config := RawConf}} ->
|
{ok, #{raw_config := RawConf}} ->
|
||||||
|
@ -564,7 +612,6 @@ maybe_deobfuscate_bridge_probe(#{<<"type">> := ActionType, <<"name">> := BridgeN
|
||||||
maybe_deobfuscate_bridge_probe(Params) ->
|
maybe_deobfuscate_bridge_probe(Params) ->
|
||||||
Params.
|
Params.
|
||||||
|
|
||||||
%%% API helpers
|
|
||||||
is_ok(ok) ->
|
is_ok(ok) ->
|
||||||
ok;
|
ok;
|
||||||
is_ok(OkResult = {ok, _}) ->
|
is_ok(OkResult = {ok, _}) ->
|
||||||
|
@ -587,9 +634,16 @@ is_ok(ResL) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% bridge helpers
|
%% bridge helpers
|
||||||
lookup_from_all_nodes(BridgeType, BridgeName, SuccCode) ->
|
-spec lookup_from_all_nodes(emqx_bridge_v2:root_cfg_key(), _, _, _) -> _.
|
||||||
Nodes = mria:running_nodes(),
|
lookup_from_all_nodes(ConfRootKey, BridgeType, BridgeName, SuccCode) ->
|
||||||
case is_ok(emqx_bridge_proto_v5:v2_lookup_from_all_nodes(Nodes, BridgeType, BridgeName)) of
|
Nodes = emqx:running_nodes(),
|
||||||
|
case
|
||||||
|
is_ok(
|
||||||
|
emqx_bridge_proto_v6:v2_lookup_from_all_nodes_v6(
|
||||||
|
Nodes, ConfRootKey, BridgeType, BridgeName
|
||||||
|
)
|
||||||
|
)
|
||||||
|
of
|
||||||
{ok, [{ok, _} | _] = Results} ->
|
{ok, [{ok, _} | _] = Results} ->
|
||||||
{SuccCode, format_bridge_info([R || {ok, R} <- Results])};
|
{SuccCode, format_bridge_info([R || {ok, R} <- Results])};
|
||||||
{ok, [{error, not_found} | _]} ->
|
{ok, [{error, not_found} | _]} ->
|
||||||
|
@ -598,10 +652,10 @@ lookup_from_all_nodes(BridgeType, BridgeName, SuccCode) ->
|
||||||
?INTERNAL_ERROR(Reason)
|
?INTERNAL_ERROR(Reason)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_metrics_from_all_nodes(ActionType, ActionName) ->
|
get_metrics_from_all_nodes(ConfRootKey, Type, Name) ->
|
||||||
Nodes = emqx:running_nodes(),
|
Nodes = emqx:running_nodes(),
|
||||||
Result = maybe_unwrap(
|
Result = maybe_unwrap(
|
||||||
emqx_bridge_proto_v5:v2_get_metrics_from_all_nodes(Nodes, ActionType, ActionName)
|
emqx_bridge_proto_v6:v2_get_metrics_from_all_nodes_v6(Nodes, ConfRootKey, Type, Name)
|
||||||
),
|
),
|
||||||
case Result of
|
case Result of
|
||||||
Metrics when is_list(Metrics) ->
|
Metrics when is_list(Metrics) ->
|
||||||
|
@ -610,22 +664,25 @@ get_metrics_from_all_nodes(ActionType, ActionName) ->
|
||||||
?INTERNAL_ERROR(Reason)
|
?INTERNAL_ERROR(Reason)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
operation_func(all, start) -> v2_start_bridge_to_all_nodes;
|
operation_func(all, start) -> v2_start_bridge_to_all_nodes_v6;
|
||||||
operation_func(_Node, start) -> v2_start_bridge_to_node.
|
operation_func(_Node, start) -> v2_start_bridge_to_node_v6;
|
||||||
|
operation_func(all, lookup) -> v2_lookup_from_all_nodes_v6;
|
||||||
|
operation_func(all, list) -> v2_list_bridges_on_nodes_v6;
|
||||||
|
operation_func(all, get_metrics) -> v2_get_metrics_from_all_nodes_v6.
|
||||||
|
|
||||||
call_operation_if_enabled(NodeOrAll, OperFunc, [Nodes, BridgeType, BridgeName]) ->
|
call_operation_if_enabled(NodeOrAll, OperFunc, [Nodes, ConfRootKey, BridgeType, BridgeName]) ->
|
||||||
try is_enabled_bridge(BridgeType, BridgeName) of
|
try is_enabled_bridge(ConfRootKey, BridgeType, BridgeName) of
|
||||||
false ->
|
false ->
|
||||||
?BRIDGE_NOT_ENABLED;
|
?BRIDGE_NOT_ENABLED;
|
||||||
true ->
|
true ->
|
||||||
call_operation(NodeOrAll, OperFunc, [Nodes, BridgeType, BridgeName])
|
call_operation(NodeOrAll, OperFunc, [Nodes, ConfRootKey, BridgeType, BridgeName])
|
||||||
catch
|
catch
|
||||||
throw:not_found ->
|
throw:not_found ->
|
||||||
?BRIDGE_NOT_FOUND(BridgeType, BridgeName)
|
?BRIDGE_NOT_FOUND(BridgeType, BridgeName)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
is_enabled_bridge(BridgeType, BridgeName) ->
|
is_enabled_bridge(ConfRootKey, BridgeType, BridgeName) ->
|
||||||
try emqx_bridge_v2:lookup(BridgeType, binary_to_existing_atom(BridgeName)) of
|
try emqx_bridge_v2:lookup(ConfRootKey, BridgeType, binary_to_existing_atom(BridgeName)) of
|
||||||
{ok, #{raw_config := ConfMap}} ->
|
{ok, #{raw_config := ConfMap}} ->
|
||||||
maps:get(<<"enable">>, ConfMap, false);
|
maps:get(<<"enable">>, ConfMap, false);
|
||||||
{error, not_found} ->
|
{error, not_found} ->
|
||||||
|
@ -637,7 +694,7 @@ is_enabled_bridge(BridgeType, BridgeName) ->
|
||||||
throw(not_found)
|
throw(not_found)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
call_operation(NodeOrAll, OperFunc, Args = [_Nodes, BridgeType, BridgeName]) ->
|
call_operation(NodeOrAll, OperFunc, Args = [_Nodes, _ConfRootKey, BridgeType, BridgeName]) ->
|
||||||
case is_ok(do_bpapi_call(NodeOrAll, OperFunc, Args)) of
|
case is_ok(do_bpapi_call(NodeOrAll, OperFunc, Args)) of
|
||||||
Ok when Ok =:= ok; is_tuple(Ok), element(1, Ok) =:= ok ->
|
Ok when Ok =:= ok; is_tuple(Ok), element(1, Ok) =:= ok ->
|
||||||
?NO_CONTENT;
|
?NO_CONTENT;
|
||||||
|
@ -668,12 +725,12 @@ call_operation(NodeOrAll, OperFunc, Args = [_Nodes, BridgeType, BridgeName]) ->
|
||||||
|
|
||||||
do_bpapi_call(all, Call, Args) ->
|
do_bpapi_call(all, Call, Args) ->
|
||||||
maybe_unwrap(
|
maybe_unwrap(
|
||||||
do_bpapi_call_vsn(emqx_bpapi:supported_version(emqx_bridge), Call, Args)
|
do_bpapi_call_vsn(emqx_bpapi:supported_version(?BPAPI_NAME), Call, Args)
|
||||||
);
|
);
|
||||||
do_bpapi_call(Node, Call, Args) ->
|
do_bpapi_call(Node, Call, Args) ->
|
||||||
case lists:member(Node, mria:running_nodes()) of
|
case lists:member(Node, emqx:running_nodes()) of
|
||||||
true ->
|
true ->
|
||||||
do_bpapi_call_vsn(emqx_bpapi:supported_version(Node, emqx_bridge), Call, Args);
|
do_bpapi_call_vsn(emqx_bpapi:supported_version(Node, ?BPAPI_NAME), Call, Args);
|
||||||
false ->
|
false ->
|
||||||
{error, {node_not_found, Node}}
|
{error, {node_not_found, Node}}
|
||||||
end.
|
end.
|
||||||
|
@ -681,7 +738,7 @@ do_bpapi_call(Node, Call, Args) ->
|
||||||
do_bpapi_call_vsn(Version, Call, Args) ->
|
do_bpapi_call_vsn(Version, Call, Args) ->
|
||||||
case is_supported_version(Version, Call) of
|
case is_supported_version(Version, Call) of
|
||||||
true ->
|
true ->
|
||||||
apply(emqx_bridge_proto_v5, Call, Args);
|
apply(emqx_bridge_proto_v6, Call, Args);
|
||||||
false ->
|
false ->
|
||||||
{error, not_implemented}
|
{error, not_implemented}
|
||||||
end.
|
end.
|
||||||
|
@ -689,7 +746,12 @@ do_bpapi_call_vsn(Version, Call, Args) ->
|
||||||
is_supported_version(Version, Call) ->
|
is_supported_version(Version, Call) ->
|
||||||
lists:member(Version, supported_versions(Call)).
|
lists:member(Version, supported_versions(Call)).
|
||||||
|
|
||||||
supported_versions(_Call) -> [5].
|
supported_versions(_Call) -> bpapi_version_range(6, latest).
|
||||||
|
|
||||||
|
%% [From, To] (inclusive on both ends)
|
||||||
|
bpapi_version_range(From, latest) ->
|
||||||
|
ThisNodeVsn = emqx_bpapi:supported_version(node(), ?BPAPI_NAME),
|
||||||
|
lists:seq(From, ThisNodeVsn).
|
||||||
|
|
||||||
maybe_unwrap({error, not_implemented}) ->
|
maybe_unwrap({error, not_implemented}) ->
|
||||||
{error, not_implemented};
|
{error, not_implemented};
|
||||||
|
@ -767,10 +829,22 @@ lookup_from_local_node(BridgeType, BridgeName) ->
|
||||||
Error -> Error
|
Error -> Error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%% RPC Target
|
||||||
|
-spec lookup_from_local_node_v6(emqx_bridge_v2:root_cfg_key(), _, _) -> _.
|
||||||
|
lookup_from_local_node_v6(ConfRootKey, BridgeType, BridgeName) ->
|
||||||
|
case emqx_bridge_v2:lookup(ConfRootKey, BridgeType, BridgeName) of
|
||||||
|
{ok, Res} -> {ok, format_resource(Res, node())};
|
||||||
|
Error -> Error
|
||||||
|
end.
|
||||||
|
|
||||||
%% RPC Target
|
%% RPC Target
|
||||||
get_metrics_from_local_node(ActionType, ActionName) ->
|
get_metrics_from_local_node(ActionType, ActionName) ->
|
||||||
format_metrics(emqx_bridge_v2:get_metrics(ActionType, ActionName)).
|
format_metrics(emqx_bridge_v2:get_metrics(ActionType, ActionName)).
|
||||||
|
|
||||||
|
%% RPC Target
|
||||||
|
get_metrics_from_local_node_v6(ConfRootKey, Type, Name) ->
|
||||||
|
format_metrics(emqx_bridge_v2:get_metrics(ConfRootKey, Type, Name)).
|
||||||
|
|
||||||
%% resource
|
%% resource
|
||||||
format_resource(
|
format_resource(
|
||||||
#{
|
#{
|
||||||
|
@ -938,13 +1012,13 @@ format_resource_data(error, Error, Result) ->
|
||||||
format_resource_data(K, V, Result) ->
|
format_resource_data(K, V, Result) ->
|
||||||
Result#{K => V}.
|
Result#{K => V}.
|
||||||
|
|
||||||
create_bridge(BridgeType, BridgeName, Conf) ->
|
create_bridge(ConfRootKey, BridgeType, BridgeName, Conf) ->
|
||||||
create_or_update_bridge(BridgeType, BridgeName, Conf, 201).
|
create_or_update_bridge(ConfRootKey, BridgeType, BridgeName, Conf, 201).
|
||||||
|
|
||||||
update_bridge(BridgeType, BridgeName, Conf) ->
|
update_bridge(ConfRootKey, BridgeType, BridgeName, Conf) ->
|
||||||
create_or_update_bridge(BridgeType, BridgeName, Conf, 200).
|
create_or_update_bridge(ConfRootKey, BridgeType, BridgeName, Conf, 200).
|
||||||
|
|
||||||
create_or_update_bridge(BridgeType, BridgeName, Conf, HttpStatusCode) ->
|
create_or_update_bridge(ConfRootKey, BridgeType, BridgeName, Conf, HttpStatusCode) ->
|
||||||
Check =
|
Check =
|
||||||
try
|
try
|
||||||
is_binary(BridgeType) andalso emqx_resource:validate_type(BridgeType),
|
is_binary(BridgeType) andalso emqx_resource:validate_type(BridgeType),
|
||||||
|
@ -955,15 +1029,15 @@ create_or_update_bridge(BridgeType, BridgeName, Conf, HttpStatusCode) ->
|
||||||
end,
|
end,
|
||||||
case Check of
|
case Check of
|
||||||
ok ->
|
ok ->
|
||||||
do_create_or_update_bridge(BridgeType, BridgeName, Conf, HttpStatusCode);
|
do_create_or_update_bridge(ConfRootKey, BridgeType, BridgeName, Conf, HttpStatusCode);
|
||||||
BadRequest ->
|
BadRequest ->
|
||||||
BadRequest
|
BadRequest
|
||||||
end.
|
end.
|
||||||
|
|
||||||
do_create_or_update_bridge(BridgeType, BridgeName, Conf, HttpStatusCode) ->
|
do_create_or_update_bridge(ConfRootKey, BridgeType, BridgeName, Conf, HttpStatusCode) ->
|
||||||
case emqx_bridge_v2:create(BridgeType, BridgeName, Conf) of
|
case emqx_bridge_v2:create(ConfRootKey, BridgeType, BridgeName, Conf) of
|
||||||
{ok, _} ->
|
{ok, _} ->
|
||||||
lookup_from_all_nodes(BridgeType, BridgeName, HttpStatusCode);
|
lookup_from_all_nodes(ConfRootKey, BridgeType, BridgeName, HttpStatusCode);
|
||||||
{error, {PreOrPostConfigUpdate, _HandlerMod, Reason}} when
|
{error, {PreOrPostConfigUpdate, _HandlerMod, Reason}} when
|
||||||
PreOrPostConfigUpdate =:= pre_config_update;
|
PreOrPostConfigUpdate =:= pre_config_update;
|
||||||
PreOrPostConfigUpdate =:= post_config_update
|
PreOrPostConfigUpdate =:= post_config_update
|
||||||
|
|
|
@ -0,0 +1,196 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Copyright (c) 2022-2023 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_bridge_proto_v6).
|
||||||
|
|
||||||
|
-behaviour(emqx_bpapi).
|
||||||
|
|
||||||
|
-export([
|
||||||
|
introduced_in/0,
|
||||||
|
|
||||||
|
list_bridges_on_nodes/1,
|
||||||
|
restart_bridge_to_node/3,
|
||||||
|
start_bridge_to_node/3,
|
||||||
|
stop_bridge_to_node/3,
|
||||||
|
lookup_from_all_nodes/3,
|
||||||
|
get_metrics_from_all_nodes/3,
|
||||||
|
restart_bridges_to_all_nodes/3,
|
||||||
|
start_bridges_to_all_nodes/3,
|
||||||
|
stop_bridges_to_all_nodes/3,
|
||||||
|
|
||||||
|
%% introduced in v6
|
||||||
|
v2_lookup_from_all_nodes_v6/4,
|
||||||
|
v2_list_bridges_on_nodes_v6/2,
|
||||||
|
v2_get_metrics_from_all_nodes_v6/4,
|
||||||
|
v2_start_bridge_to_node_v6/4,
|
||||||
|
v2_start_bridge_to_all_nodes_v6/4
|
||||||
|
]).
|
||||||
|
|
||||||
|
-include_lib("emqx/include/bpapi.hrl").
|
||||||
|
|
||||||
|
-define(TIMEOUT, 15000).
|
||||||
|
|
||||||
|
introduced_in() ->
|
||||||
|
"5.5.0".
|
||||||
|
|
||||||
|
-spec list_bridges_on_nodes([node()]) ->
|
||||||
|
emqx_rpc:erpc_multicall([emqx_resource:resource_data()]).
|
||||||
|
list_bridges_on_nodes(Nodes) ->
|
||||||
|
erpc:multicall(Nodes, emqx_bridge, list, [], ?TIMEOUT).
|
||||||
|
|
||||||
|
-type key() :: atom() | binary() | [byte()].
|
||||||
|
|
||||||
|
-spec restart_bridge_to_node(node(), key(), key()) ->
|
||||||
|
term().
|
||||||
|
restart_bridge_to_node(Node, BridgeType, BridgeName) ->
|
||||||
|
rpc:call(
|
||||||
|
Node,
|
||||||
|
emqx_bridge_resource,
|
||||||
|
restart,
|
||||||
|
[BridgeType, BridgeName],
|
||||||
|
?TIMEOUT
|
||||||
|
).
|
||||||
|
|
||||||
|
-spec start_bridge_to_node(node(), key(), key()) ->
|
||||||
|
term().
|
||||||
|
start_bridge_to_node(Node, BridgeType, BridgeName) ->
|
||||||
|
rpc:call(
|
||||||
|
Node,
|
||||||
|
emqx_bridge_resource,
|
||||||
|
start,
|
||||||
|
[BridgeType, BridgeName],
|
||||||
|
?TIMEOUT
|
||||||
|
).
|
||||||
|
|
||||||
|
-spec stop_bridge_to_node(node(), key(), key()) ->
|
||||||
|
term().
|
||||||
|
stop_bridge_to_node(Node, BridgeType, BridgeName) ->
|
||||||
|
rpc:call(
|
||||||
|
Node,
|
||||||
|
emqx_bridge_resource,
|
||||||
|
stop,
|
||||||
|
[BridgeType, BridgeName],
|
||||||
|
?TIMEOUT
|
||||||
|
).
|
||||||
|
|
||||||
|
-spec restart_bridges_to_all_nodes([node()], key(), key()) ->
|
||||||
|
emqx_rpc:erpc_multicall(ok).
|
||||||
|
restart_bridges_to_all_nodes(Nodes, BridgeType, BridgeName) ->
|
||||||
|
erpc:multicall(
|
||||||
|
Nodes,
|
||||||
|
emqx_bridge_resource,
|
||||||
|
restart,
|
||||||
|
[BridgeType, BridgeName],
|
||||||
|
?TIMEOUT
|
||||||
|
).
|
||||||
|
|
||||||
|
-spec start_bridges_to_all_nodes([node()], key(), key()) ->
|
||||||
|
emqx_rpc:erpc_multicall(ok).
|
||||||
|
start_bridges_to_all_nodes(Nodes, BridgeType, BridgeName) ->
|
||||||
|
erpc:multicall(
|
||||||
|
Nodes,
|
||||||
|
emqx_bridge_resource,
|
||||||
|
start,
|
||||||
|
[BridgeType, BridgeName],
|
||||||
|
?TIMEOUT
|
||||||
|
).
|
||||||
|
|
||||||
|
-spec stop_bridges_to_all_nodes([node()], key(), key()) ->
|
||||||
|
emqx_rpc:erpc_multicall(ok).
|
||||||
|
stop_bridges_to_all_nodes(Nodes, BridgeType, BridgeName) ->
|
||||||
|
erpc:multicall(
|
||||||
|
Nodes,
|
||||||
|
emqx_bridge_resource,
|
||||||
|
stop,
|
||||||
|
[BridgeType, BridgeName],
|
||||||
|
?TIMEOUT
|
||||||
|
).
|
||||||
|
|
||||||
|
-spec lookup_from_all_nodes([node()], key(), key()) ->
|
||||||
|
emqx_rpc:erpc_multicall(term()).
|
||||||
|
lookup_from_all_nodes(Nodes, BridgeType, BridgeName) ->
|
||||||
|
erpc:multicall(
|
||||||
|
Nodes,
|
||||||
|
emqx_bridge_api,
|
||||||
|
lookup_from_local_node,
|
||||||
|
[BridgeType, BridgeName],
|
||||||
|
?TIMEOUT
|
||||||
|
).
|
||||||
|
|
||||||
|
-spec get_metrics_from_all_nodes([node()], key(), key()) ->
|
||||||
|
emqx_rpc:erpc_multicall(emqx_metrics_worker:metrics()).
|
||||||
|
get_metrics_from_all_nodes(Nodes, BridgeType, BridgeName) ->
|
||||||
|
erpc:multicall(
|
||||||
|
Nodes,
|
||||||
|
emqx_bridge_api,
|
||||||
|
get_metrics_from_local_node,
|
||||||
|
[BridgeType, BridgeName],
|
||||||
|
?TIMEOUT
|
||||||
|
).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------------------
|
||||||
|
%% introduced in v6
|
||||||
|
%%--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
%% V2 Calls
|
||||||
|
-spec v2_lookup_from_all_nodes_v6([node()], emqx_bridge_v2:root_cfg_key(), key(), key()) ->
|
||||||
|
emqx_rpc:erpc_multicall(term()).
|
||||||
|
v2_lookup_from_all_nodes_v6(Nodes, ConfRootKey, BridgeType, BridgeName) ->
|
||||||
|
erpc:multicall(
|
||||||
|
Nodes,
|
||||||
|
emqx_bridge_v2_api,
|
||||||
|
lookup_from_local_node_v6,
|
||||||
|
[ConfRootKey, BridgeType, BridgeName],
|
||||||
|
?TIMEOUT
|
||||||
|
).
|
||||||
|
|
||||||
|
-spec v2_list_bridges_on_nodes_v6([node()], emqx_bridge_v2:root_cfg_key()) ->
|
||||||
|
emqx_rpc:erpc_multicall([emqx_resource:resource_data()]).
|
||||||
|
v2_list_bridges_on_nodes_v6(Nodes, ConfRootKey) ->
|
||||||
|
erpc:multicall(Nodes, emqx_bridge_v2, list, [ConfRootKey], ?TIMEOUT).
|
||||||
|
|
||||||
|
-spec v2_get_metrics_from_all_nodes_v6([node()], emqx_bridge_v2:root_cfg_key(), key(), key()) ->
|
||||||
|
emqx_rpc:erpc_multicall(term()).
|
||||||
|
v2_get_metrics_from_all_nodes_v6(Nodes, ConfRootKey, ActionType, ActionName) ->
|
||||||
|
erpc:multicall(
|
||||||
|
Nodes,
|
||||||
|
emqx_bridge_v2_api,
|
||||||
|
get_metrics_from_local_node_v6,
|
||||||
|
[ConfRootKey, ActionType, ActionName],
|
||||||
|
?TIMEOUT
|
||||||
|
).
|
||||||
|
|
||||||
|
-spec v2_start_bridge_to_all_nodes_v6([node()], emqx_bridge_v2:root_cfg_key(), key(), key()) ->
|
||||||
|
emqx_rpc:erpc_multicall(ok).
|
||||||
|
v2_start_bridge_to_all_nodes_v6(Nodes, ConfRootKey, BridgeType, BridgeName) ->
|
||||||
|
erpc:multicall(
|
||||||
|
Nodes,
|
||||||
|
emqx_bridge_v2,
|
||||||
|
start,
|
||||||
|
[ConfRootKey, BridgeType, BridgeName],
|
||||||
|
?TIMEOUT
|
||||||
|
).
|
||||||
|
|
||||||
|
-spec v2_start_bridge_to_node_v6(node(), emqx_bridge_v2:root_cfg_key(), key(), key()) ->
|
||||||
|
term().
|
||||||
|
v2_start_bridge_to_node_v6(Node, ConfRootKey, BridgeType, BridgeName) ->
|
||||||
|
rpc:call(
|
||||||
|
Node,
|
||||||
|
emqx_bridge_v2,
|
||||||
|
start,
|
||||||
|
[ConfRootKey, BridgeType, BridgeName],
|
||||||
|
?TIMEOUT
|
||||||
|
).
|
|
@ -160,8 +160,9 @@ end_per_group(_, Config) ->
|
||||||
|
|
||||||
init_per_testcase(t_broken_bpapi_vsn, Config) ->
|
init_per_testcase(t_broken_bpapi_vsn, Config) ->
|
||||||
meck:new(emqx_bpapi, [passthrough]),
|
meck:new(emqx_bpapi, [passthrough]),
|
||||||
meck:expect(emqx_bpapi, supported_version, 1, -1),
|
|
||||||
meck:expect(emqx_bpapi, supported_version, 2, -1),
|
meck:expect(emqx_bpapi, supported_version, 2, -1),
|
||||||
|
meck:new(emqx_bridge_api, [passthrough]),
|
||||||
|
meck:expect(emqx_bridge_api, supported_versions, 1, []),
|
||||||
init_per_testcase(common, Config);
|
init_per_testcase(common, Config);
|
||||||
init_per_testcase(t_old_bpapi_vsn, Config) ->
|
init_per_testcase(t_old_bpapi_vsn, Config) ->
|
||||||
meck:new(emqx_bpapi, [passthrough]),
|
meck:new(emqx_bpapi, [passthrough]),
|
||||||
|
@ -173,10 +174,10 @@ init_per_testcase(_, Config) ->
|
||||||
[{port, Port}, {sock, Sock}, {acceptor, Acceptor} | Config].
|
[{port, Port}, {sock, Sock}, {acceptor, Acceptor} | Config].
|
||||||
|
|
||||||
end_per_testcase(t_broken_bpapi_vsn, Config) ->
|
end_per_testcase(t_broken_bpapi_vsn, Config) ->
|
||||||
meck:unload([emqx_bpapi]),
|
meck:unload(),
|
||||||
end_per_testcase(common, Config);
|
end_per_testcase(common, Config);
|
||||||
end_per_testcase(t_old_bpapi_vsn, Config) ->
|
end_per_testcase(t_old_bpapi_vsn, Config) ->
|
||||||
meck:unload([emqx_bpapi]),
|
meck:unload(),
|
||||||
end_per_testcase(common, Config);
|
end_per_testcase(common, Config);
|
||||||
end_per_testcase(_, Config) ->
|
end_per_testcase(_, Config) ->
|
||||||
Sock = ?config(sock, Config),
|
Sock = ?config(sock, Config),
|
||||||
|
|
|
@ -196,20 +196,10 @@ delete_bridge_http_api_v1(Opts) ->
|
||||||
op_bridge_api(Op, BridgeType, BridgeName) ->
|
op_bridge_api(Op, BridgeType, BridgeName) ->
|
||||||
BridgeId = emqx_bridge_resource:bridge_id(BridgeType, BridgeName),
|
BridgeId = emqx_bridge_resource:bridge_id(BridgeType, BridgeName),
|
||||||
Path = emqx_mgmt_api_test_util:api_path(["bridges", BridgeId, Op]),
|
Path = emqx_mgmt_api_test_util:api_path(["bridges", BridgeId, Op]),
|
||||||
AuthHeader = emqx_mgmt_api_test_util:auth_header_(),
|
|
||||||
Opts = #{return_all => true},
|
|
||||||
ct:pal("calling bridge ~p (via http): ~p", [BridgeId, Op]),
|
ct:pal("calling bridge ~p (via http): ~p", [BridgeId, Op]),
|
||||||
Res =
|
Method = post,
|
||||||
case emqx_mgmt_api_test_util:request_api(post, Path, "", AuthHeader, "", Opts) of
|
Params = [],
|
||||||
{ok, {Status = {_, 204, _}, Headers, Body}} ->
|
Res = emqx_bridge_v2_testlib:request(Method, Path, Params),
|
||||||
{ok, {Status, Headers, Body}};
|
|
||||||
{ok, {Status, Headers, Body}} ->
|
|
||||||
{ok, {Status, Headers, emqx_utils_json:decode(Body, [return_maps])}};
|
|
||||||
{error, {Status, Headers, Body}} ->
|
|
||||||
{error, {Status, Headers, emqx_utils_json:decode(Body, [return_maps])}};
|
|
||||||
Error ->
|
|
||||||
Error
|
|
||||||
end,
|
|
||||||
ct:pal("bridge op result: ~p", [Res]),
|
ct:pal("bridge op result: ~p", [Res]),
|
||||||
Res.
|
Res.
|
||||||
|
|
||||||
|
|
|
@ -308,21 +308,11 @@ update_bridge_api(Config, Overrides) ->
|
||||||
op_bridge_api(Op, BridgeType, BridgeName) ->
|
op_bridge_api(Op, BridgeType, BridgeName) ->
|
||||||
BridgeId = emqx_bridge_resource:bridge_id(BridgeType, BridgeName),
|
BridgeId = emqx_bridge_resource:bridge_id(BridgeType, BridgeName),
|
||||||
Path = emqx_mgmt_api_test_util:api_path(["actions", BridgeId, Op]),
|
Path = emqx_mgmt_api_test_util:api_path(["actions", BridgeId, Op]),
|
||||||
AuthHeader = emqx_mgmt_api_test_util:auth_header_(),
|
|
||||||
Opts = #{return_all => true},
|
|
||||||
ct:pal("calling bridge ~p (via http): ~p", [BridgeId, Op]),
|
ct:pal("calling bridge ~p (via http): ~p", [BridgeId, Op]),
|
||||||
Res =
|
Method = post,
|
||||||
case emqx_mgmt_api_test_util:request_api(post, Path, "", AuthHeader, "", Opts) of
|
Params = [],
|
||||||
{ok, {Status = {_, 204, _}, Headers, Body}} ->
|
Res = request(Method, Path, Params),
|
||||||
{ok, {Status, Headers, Body}};
|
ct:pal("bridge op result:\n ~p", [Res]),
|
||||||
{ok, {Status, Headers, Body}} ->
|
|
||||||
{ok, {Status, Headers, emqx_utils_json:decode(Body, [return_maps])}};
|
|
||||||
{error, {Status, Headers, Body}} ->
|
|
||||||
{error, {Status, Headers, emqx_utils_json:decode(Body, [return_maps])}};
|
|
||||||
Error ->
|
|
||||||
Error
|
|
||||||
end,
|
|
||||||
ct:pal("bridge op result: ~p", [Res]),
|
|
||||||
Res.
|
Res.
|
||||||
|
|
||||||
probe_bridge_api(Config) ->
|
probe_bridge_api(Config) ->
|
||||||
|
|
Loading…
Reference in New Issue