refactor: refactor es's action

This commit is contained in:
zhongwencool 2024-01-12 14:15:30 +08:00
parent e49d3ca50c
commit ace443fc18
9 changed files with 275 additions and 490 deletions

View File

@ -361,11 +361,16 @@ is_bad_schema(#{type := ?MAP(_, ?R_REF(Module, TypeName))}) ->
[] -> [] ->
false; false;
_ -> _ ->
{true, #{ %% elasticsearch is new and doesn't have local_topic
schema_module => Module, case MissingFields of
type_name => TypeName, [local_topic] when Module =:= emqx_bridge_es -> false;
missing_fields => MissingFields _ ->
}} {true, #{
schema_module => Module,
type_name => TypeName,
missing_fields => MissingFields
}}
end
end. end.
-endif. -endif.

View File

@ -1,19 +0,0 @@
.rebar3
_*
.eunit
*.o
*.beam
*.plt
*.swp
*.swo
.erlang.cookie
ebin
log
erl_crash.dump
.rebar
logs
_build
.idea
*.iml
rebar3.crashdump
*~

View File

@ -25,15 +25,15 @@ fields(action) ->
?HOCON( ?HOCON(
?MAP(action_name, ?R_REF(action_config)), ?MAP(action_name, ?R_REF(action_config)),
#{ #{
desc => <<"ElasticSearch Action Config">>, required => false,
required => false desc => ?DESC(elasticsearch)
} }
)}; )};
fields(action_config) -> fields(action_config) ->
emqx_resource_schema:override( emqx_resource_schema:override(
emqx_bridge_v2_schema:make_producer_action_schema( emqx_bridge_v2_schema:make_consumer_action_schema(
?HOCON( ?HOCON(
?R_REF(action_parameters), ?UNION(fun action_union_member_selector/1),
#{ #{
required => true, desc => ?DESC("action_parameters") required => true, desc => ?DESC("action_parameters")
} }
@ -54,200 +54,28 @@ fields(action_resource_opts) ->
end, end,
emqx_bridge_v2_schema:resource_opts_fields() emqx_bridge_v2_schema:resource_opts_fields()
); );
fields(action_parameters) -> fields(action_create) ->
[ [
{target, action(create),
?HOCON( index(),
binary(), id(false),
#{ doc(true),
desc => ?DESC("config_target"), routing(),
required => false require_alias(),
} overwrite()
)}, | http_common_opts()
{require_alias,
?HOCON(
boolean(),
#{
required => false,
default => false,
desc => ?DESC("config_require_alias")
}
)},
{routing,
?HOCON(
binary(),
#{
required => false,
desc => ?DESC("config_routing")
}
)},
{wait_for_active_shards,
?HOCON(
?UNION([pos_integer(), all]),
#{
required => false,
desc => ?DESC("config_wait_for_active_shards")
}
)},
{data,
?HOCON(
?ARRAY(
?UNION(
[
?R_REF(create),
?R_REF(delete),
?R_REF(index),
?R_REF(update)
]
)
),
#{
desc => ?DESC("action_parameters_data")
}
)}
] ++
lists:filter(
fun({K, _}) ->
not lists:member(K, [path, method, body, headers, request_timeout])
end,
emqx_bridge_http_schema:fields("parameters_opts")
);
fields(Action) when Action =:= create; Action =:= index ->
[
{action,
?HOCON(
Action,
#{
desc => atom_to_binary(Action),
required => true
}
)},
{'_index',
?HOCON(
binary(),
#{
required => false,
desc => ?DESC("config_parameters_index")
}
)},
{'_id',
?HOCON(
binary(),
#{
required => false,
desc => ?DESC("config_parameters_id")
}
)},
{require_alias,
?HOCON(
binary(),
#{
required => false,
desc => ?DESC("config_parameters_require_alias")
}
)},
{fields,
?HOCON(
binary(),
#{
required => true,
desc => ?DESC("config_parameters_fields")
}
)}
]; ];
fields(delete) -> fields(action_delete) ->
[action(delete), index(), id(true), routing() | http_common_opts()];
fields(action_update) ->
[ [
{action, action(update),
?HOCON( index(),
delete, id(true),
#{ doc(true),
desc => <<"Delete">>, routing(),
required => true require_alias()
} | http_common_opts()
)},
{'_index',
?HOCON(
binary(),
#{
required => false,
desc => ?DESC("config_parameters_index")
}
)},
{'_id',
?HOCON(
binary(),
#{
required => true,
desc => ?DESC("config_parameters_id")
}
)},
{require_alias,
?HOCON(
binary(),
#{
required => false,
desc => ?DESC("config_parameters_require_alias")
}
)}
];
fields(update) ->
[
{action,
?HOCON(
update,
#{
desc => <<"Update">>,
required => true
}
)},
{doc_as_upsert,
?HOCON(
binary(),
#{
required => false,
desc => ?DESC("config_parameters_doc_as_upsert")
}
)},
{upsert,
?HOCON(
binary(),
#{
required => false,
desc => ?DESC("config_parameters_upsert")
}
)},
{'_index',
?HOCON(
binary(),
#{
required => false,
desc => ?DESC("config_parameters_index")
}
)},
{'_id',
?HOCON(
binary(),
#{
required => true,
desc => ?DESC("config_parameters_id")
}
)},
{require_alias,
?HOCON(
binary(),
#{
required => false,
desc => ?DESC("config_parameters_require_alias")
}
)},
{fields,
?HOCON(
binary(),
#{
required => true,
desc => ?DESC("config_parameters_fields")
}
)}
]; ];
fields("post_bridge_v2") -> fields("post_bridge_v2") ->
emqx_bridge_schema:type_and_name_fields(elasticsearch) ++ fields(action_config); emqx_bridge_schema:type_and_name_fields(elasticsearch) ++ fields(action_config);
@ -256,6 +84,111 @@ fields("put_bridge_v2") ->
fields("get_bridge_v2") -> fields("get_bridge_v2") ->
emqx_bridge_schema:status_fields() ++ fields("post_bridge_v2"). emqx_bridge_schema:status_fields() ++ fields("post_bridge_v2").
action_union_member_selector(all_union_members) ->
[
?R_REF(action_create),
?R_REF(action_delete),
?R_REF(action_update)
];
action_union_member_selector({value, Value}) ->
case Value of
#{<<"action">> := <<"create">>} ->
[?R_REF(action_create)];
#{<<"action">> := <<"delete">>} ->
[?R_REF(action_delete)];
#{<<"action">> := <<"update">>} ->
[?R_REF(action_update)];
_ ->
Expected = "create | delete | update",
throw(#{
field_name => action,
expected => Expected
})
end.
action(Action) ->
{action,
?HOCON(
Action,
#{
required => true,
desc => atom_to_binary(Action)
}
)}.
overwrite() ->
{overwrite,
?HOCON(
boolean(),
#{
required => false,
default => true,
desc => ?DESC("config_overwrite")
}
)}.
index() ->
{index,
?HOCON(
binary(),
#{
required => true,
example => <<"${payload.index}">>,
desc => ?DESC("config_parameters_index")
}
)}.
id(Required) ->
{id,
?HOCON(
binary(),
#{
required => Required,
example => <<"${payload.id}">>,
desc => ?DESC("config_parameters_id")
}
)}.
doc(Required) ->
{doc,
?HOCON(
binary(),
#{
required => Required,
example => <<"${payload.doc}">>,
desc => ?DESC("config_parameters_doc")
}
)}.
http_common_opts() ->
lists:filter(
fun({K, _}) ->
not lists:member(K, [path, method, body, headers, request_timeout])
end,
emqx_bridge_http_schema:fields("parameters_opts")
).
routing() ->
{routing,
?HOCON(
binary(),
#{
required => false,
example => <<"${payload.routing}">>,
desc => ?DESC("config_routing")
}
)}.
require_alias() ->
{require_alias,
?HOCON(
boolean(),
#{
required => false,
desc => ?DESC("config_require_alias")
}
)}.
bridge_v2_examples(Method) -> bridge_v2_examples(Method) ->
[ [
#{ #{
@ -272,34 +205,10 @@ bridge_v2_examples(Method) ->
action_values() -> action_values() ->
#{ #{
parameters => #{ parameters => #{
target => <<"${target_index}">>, action => create,
data => [ index => <<"${payload.index}">>,
#{ overwrite => true,
action => index, doc => <<"${payload.doc}">>
'_index' => <<"${index}">>,
fields => <<"${fields}">>,
require_alias => <<"${require_alias}">>
},
#{
action => create,
'_index' => <<"${index}">>,
fields => <<"${fields}">>
},
#{
action => delete,
'_index' => <<"${index}">>,
'_id' => <<"${id}">>
},
#{
action => update,
'_index' => <<"${index}">>,
'_id' => <<"${id}">>,
fields => <<"${fields}">>,
require_alias => false,
doc_as_upsert => <<"${doc_as_upsert}">>,
upsert => <<"${upsert}">>
}
]
} }
}. }.
@ -309,4 +218,10 @@ unsupported_opts() ->
batch_time batch_time
]. ].
desc(elasticsearch) -> ?DESC(elasticsearch);
desc(action_config) -> ?DESC(action_config);
desc(action_create) -> ?DESC(action_create);
desc(action_delete) -> ?DESC(action_delete);
desc(action_update) -> ?DESC(action_update);
desc(action_resource_opts) -> ?DESC(action_resource_opts);
desc(_) -> undefined. desc(_) -> undefined.

View File

@ -233,7 +233,7 @@ on_get_status(InstanceId, State) ->
{ok, pos_integer(), [term()], term()} {ok, pos_integer(), [term()], term()}
| {ok, pos_integer(), [term()]} | {ok, pos_integer(), [term()]}
| {error, term()}. | {error, term()}.
on_query(InstanceId, {ChannelId, Msg} = Req, #{channels := Channels} = State) -> on_query(InstanceId, {ChannelId, Msg} = Req, State) ->
?tp(elasticsearch_bridge_on_query, #{instance_id => InstanceId}), ?tp(elasticsearch_bridge_on_query, #{instance_id => InstanceId}),
?SLOG(debug, #{ ?SLOG(debug, #{
msg => "elasticsearch_bridge_on_query_called", msg => "elasticsearch_bridge_on_query_called",
@ -241,21 +241,16 @@ on_query(InstanceId, {ChannelId, Msg} = Req, #{channels := Channels} = State) ->
send_message => Req, send_message => Req,
state => emqx_utils:redact(State) state => emqx_utils:redact(State)
}), }),
case try_render_message(Req, Channels) of handle_response(
{ok, Body} -> emqx_bridge_http_connector:on_query(
handle_response( InstanceId, {ChannelId, Msg}, State
emqx_bridge_http_connector:on_query( )
InstanceId, {ChannelId, {Msg, Body}}, State ).
)
);
Error ->
Error
end.
-spec on_query_async(manager_id(), tuple(), {function(), [term()]}, state()) -> -spec on_query_async(manager_id(), tuple(), {function(), [term()]}, state()) ->
{ok, pid()} | {error, empty_request}. {ok, pid()} | {error, empty_request}.
on_query_async( on_query_async(
InstanceId, {ChannelId, Msg} = Req, ReplyFunAndArgs0, #{channels := Channels} = State InstanceId, {ChannelId, Msg} = Req, ReplyFunAndArgs0, State
) -> ) ->
?tp(elasticsearch_bridge_on_query_async, #{instance_id => InstanceId}), ?tp(elasticsearch_bridge_on_query_async, #{instance_id => InstanceId}),
?SLOG(debug, #{ ?SLOG(debug, #{
@ -264,22 +259,17 @@ on_query_async(
send_message => Req, send_message => Req,
state => emqx_utils:redact(State) state => emqx_utils:redact(State)
}), }),
case try_render_message(Req, Channels) of ReplyFunAndArgs =
{ok, Payload} -> {
ReplyFunAndArgs = fun(Result) ->
{ Response = handle_response(Result),
fun(Result) -> emqx_resource:apply_reply_fun(ReplyFunAndArgs0, Response)
Response = handle_response(Result), end,
emqx_resource:apply_reply_fun(ReplyFunAndArgs0, Response) []
end, },
[] emqx_bridge_http_connector:on_query_async(
}, InstanceId, {ChannelId, Msg}, ReplyFunAndArgs, State
emqx_bridge_http_connector:on_query_async( ).
InstanceId, {ChannelId, {Msg, Payload}}, ReplyFunAndArgs, State
);
Error ->
Error
end.
on_add_channel( on_add_channel(
InstanceId, InstanceId,
@ -291,19 +281,17 @@ on_add_channel(
true -> true ->
{error, already_exists}; {error, already_exists};
_ -> _ ->
#{data := Data} = Parameter, Parameter1 = Parameter#{
Parameter1 = Parameter#{path => path(Parameter), method => <<"post">>}, path => path(Parameter),
method => method(Parameter),
body => get_body_template(Parameter)
},
{ok, State} = emqx_bridge_http_connector:on_add_channel( {ok, State} = emqx_bridge_http_connector:on_add_channel(
InstanceId, State0, ChannelId, #{parameters => Parameter1} InstanceId, State0, ChannelId, #{parameters => Parameter1}
), ),
case preproc_data_template(Data) of Channel = Parameter1,
[] -> Channels2 = Channels#{ChannelId => Channel},
{error, invalid_data}; {ok, State#{channels => Channels2}}
DataTemplate ->
Channel = Parameter1#{data => DataTemplate},
Channels2 = Channels#{ChannelId => Channel},
{ok, State#{channels => Channels2}}
end
end. end.
on_remove_channel(InstanceId, #{channels := Channels} = OldState0, ChannelId) -> on_remove_channel(InstanceId, #{channels := Channels} = OldState0, ChannelId) ->
@ -325,124 +313,55 @@ on_get_channel_status(_InstanceId, ChannelId, #{channels := Channels}) ->
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% Internal Functions %% Internal Functions
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
path(Param) -> %% delete DELETE /<index>/_doc/<_id>
Target = maps:get(target, Param, undefined), path(#{action := delete, id := Id, index := Index} = Action) ->
QString0 = maps:fold( BasePath = ["/", Index, "/_doc/", Id],
fun(K, V, Acc) -> Qs = add_query_string([routing], Action),
[[atom_to_list(K), "=", to_str(V)] | Acc] BasePath ++ Qs;
%% update POST /<index>/_update/<_id>
path(#{action := update, id := Id, index := Index} = Action) ->
BasePath = ["/", Index, "/_update/", Id],
Qs = add_query_string([routing, require_alias], Action),
BasePath ++ Qs;
%% create with id /<index>/_doc/_id
path(#{action := create, index := Index, id := Id} = Action) ->
BasePath = ["/", Index, "/_doc/", Id],
Qs =
case maps:get(overwrite, Action, true) of
true ->
add_query_string([routing, require_alias], Action);
false ->
Action1 = Action#{op_type => "create"},
add_query_string([routing, require_alias, op_type], Action1)
end, end,
[["_source=false"], ["filter_path=items.*.error"]], BasePath ++ Qs;
maps:with([require_alias, routing, wait_for_active_shards], Param) %% create without id POST /<index>/_doc/
), path(#{action := create, index := Index} = Action) ->
QString = "?" ++ lists:join("&", QString0), BasePath = ["/", Index, "/_doc/"],
target(Target) ++ QString. Qs = add_query_string([routing, require_alias], Action),
BasePath ++ Qs.
target(undefined) -> "/_bulk"; method(#{action := create}) -> <<"POST">>;
target(Str) -> "/" ++ binary_to_list(Str) ++ "/_bulk". method(#{action := delete}) -> <<"DELETE">>;
method(#{action := update}) -> <<"POST">>.
add_query_string(Keys, Param0) ->
Param1 = maps:with(Keys, Param0),
FoldFun = fun(K, V, Acc) -> [[atom_to_list(K), "=", to_str(V)] | Acc] end,
case maps:fold(FoldFun, [], Param1) of
"" -> "";
QString -> "?" ++ lists:join("&", QString)
end.
to_str(List) when is_list(List) -> List; to_str(List) when is_list(List) -> List;
to_str(false) -> "false"; to_str(false) -> "false";
to_str(true) -> "true"; to_str(true) -> "true";
to_str(Atom) when is_atom(Atom) -> atom_to_list(Atom). to_str(Atom) when is_atom(Atom) -> atom_to_list(Atom).
proc_data(DataList, Msg) when is_list(DataList) -> handle_response({ok, Code, _Headers, _Body} = Resp) when Code =:= 200; Code =:= 201 ->
[ Resp;
begin handle_response({ok, Code, _Body} = Resp) when Code =:= 200; Code =:= 201 ->
proc_data(Data, Msg) Resp;
end
|| Data <- DataList
];
proc_data(
#{
action := Action,
'_index' := IndexT,
'_id' := IdT,
require_alias := RequiredAliasT,
fields := FieldsT
},
Msg
) when Action =:= create; Action =:= index ->
[
emqx_utils_json:encode(
#{
Action => filter([
{'_index', emqx_placeholder:proc_tmpl(IndexT, Msg)},
{'_id', emqx_placeholder:proc_tmpl(IdT, Msg)},
{required_alias, emqx_placeholder:proc_tmpl(RequiredAliasT, Msg)}
])
}
),
"\n",
emqx_placeholder:proc_tmpl(FieldsT, Msg),
"\n"
];
proc_data(
#{
action := delete,
'_index' := IndexT,
'_id' := IdT,
require_alias := RequiredAliasT
},
Msg
) ->
[
emqx_utils_json:encode(
#{
delete => filter([
{'_index', emqx_placeholder:proc_tmpl(IndexT, Msg)},
{'_id', emqx_placeholder:proc_tmpl(IdT, Msg)},
{required_alias, emqx_placeholder:proc_tmpl(RequiredAliasT, Msg)}
])
}
),
"\n"
];
proc_data(
#{
action := update,
'_index' := IndexT,
'_id' := IdT,
require_alias := RequiredAliasT,
doc_as_upsert := DocAsUpsert,
upsert := Upsert,
fields := FieldsT
},
Msg
) ->
[
emqx_utils_json:encode(
#{
update => filter([
{'_index', emqx_placeholder:proc_tmpl(IndexT, Msg)},
{'_id', emqx_placeholder:proc_tmpl(IdT, Msg)},
{required_alias, emqx_placeholder:proc_tmpl(RequiredAliasT, Msg)},
{doc_as_upsert, emqx_placeholder:proc_tmpl(DocAsUpsert, Msg)},
{upsert, emqx_placeholder:proc_tmpl(Upsert, Msg)}
])
}
),
"\n{\"doc\":",
emqx_placeholder:proc_tmpl(FieldsT, Msg),
"}\n"
].
filter(List) ->
Fun = fun
({_K, V}) when V =:= undefined; V =:= <<"undefined">>; V =:= "undefined" ->
false;
({_K, V}) when V =:= ""; V =:= <<>> ->
false;
({_K, V}) when V =:= "false" -> {true, false};
({_K, V}) when V =:= "true" -> {true, true};
({_K, _V}) ->
true
end,
maps:from_list(lists:filtermap(Fun, List)).
handle_response({ok, 200, _Headers, Body} = Resp) ->
eval_response_body(Body, Resp);
handle_response({ok, 200, Body} = Resp) ->
eval_response_body(Body, Resp);
handle_response({ok, Code, _Headers, Body}) -> handle_response({ok, Code, _Headers, Body}) ->
{error, #{code => Code, body => Body}}; {error, #{code => Code, body => Body}};
handle_response({ok, Code, Body}) -> handle_response({ok, Code, Body}) ->
@ -450,49 +369,5 @@ handle_response({ok, Code, Body}) ->
handle_response({error, _} = Error) -> handle_response({error, _} = Error) ->
Error. Error.
eval_response_body(<<"{}">>, Resp) -> Resp; get_body_template(#{doc := Doc}) -> Doc;
eval_response_body(Body, _Resp) -> {error, emqx_utils_json:decode(Body)}. get_body_template(_) -> undefined.
preproc_data_template(DataList) when is_list(DataList) ->
[
begin
preproc_data_template(Data)
end
|| Data <- DataList
];
preproc_data_template(#{action := create} = Data) ->
Index = maps:get('_index', Data, ""),
Id = maps:get('_id', Data, ""),
RequiredAlias = maps:get(require_alias, Data, ""),
Fields = maps:get(fields, Data, ""),
#{
action => create,
'_index' => emqx_placeholder:preproc_tmpl(Index),
'_id' => emqx_placeholder:preproc_tmpl(Id),
require_alias => emqx_placeholder:preproc_tmpl(RequiredAlias),
fields => emqx_placeholder:preproc_tmpl(Fields)
};
preproc_data_template(#{action := index} = Data) ->
Data1 = preproc_data_template(Data#{action => create}),
Data1#{action => index};
preproc_data_template(#{action := delete} = Data) ->
Data1 = preproc_data_template(Data#{action => create}),
Data2 = Data1#{action => delete},
maps:remove(fields, Data2);
preproc_data_template(#{action := update} = Data) ->
Data1 = preproc_data_template(Data#{action => index}),
DocAsUpsert = maps:get(doc_as_upsert, Data, ""),
Upsert = maps:get(upsert, Data, ""),
Data1#{
action => update,
doc_as_upsert => emqx_placeholder:preproc_tmpl(DocAsUpsert),
upsert => emqx_placeholder:preproc_tmpl(Upsert)
}.
try_render_message({ChannelId, Msg}, Channels) ->
case maps:find(ChannelId, Channels) of
{ok, #{data := Data}} ->
{ok, proc_data(Data, Msg)};
_ ->
{error, {unrecoverable_error, {invalid_channel_id, ChannelId}}}
end.

View File

@ -317,7 +317,7 @@ on_query(InstId, {send_message, Msg}, State) ->
%% BridgeV2 entrypoint %% BridgeV2 entrypoint
on_query( on_query(
InstId, InstId,
{ActionId, MsgAndBody}, {ActionId, Msg},
State = #{installed_actions := InstalledActions} State = #{installed_actions := InstalledActions}
) when is_binary(ActionId) -> ) when is_binary(ActionId) ->
case {maps:get(request, State, undefined), maps:get(ActionId, InstalledActions, undefined)} of case {maps:get(request, State, undefined), maps:get(ActionId, InstalledActions, undefined)} of
@ -334,10 +334,10 @@ on_query(
body := Body, body := Body,
headers := Headers, headers := Headers,
request_timeout := Timeout request_timeout := Timeout
} = process_request_and_action(Request, ActionState, MsgAndBody), } = process_request_and_action(Request, ActionState, Msg),
%% bridge buffer worker has retry, do not let ehttpc retry %% bridge buffer worker has retry, do not let ehttpc retry
Retry = 2, Retry = 2,
ClientId = clientid(MsgAndBody), ClientId = clientid(Msg),
on_query( on_query(
InstId, InstId,
{ClientId, Method, {Path, Headers, Body}, Timeout, Retry}, {ClientId, Method, {Path, Headers, Body}, Timeout, Retry},
@ -430,7 +430,7 @@ on_query_async(InstId, {send_message, Msg}, ReplyFunAndArgs, State) ->
%% BridgeV2 entrypoint %% BridgeV2 entrypoint
on_query_async( on_query_async(
InstId, InstId,
{ActionId, MsgAndBody}, {ActionId, Msg},
ReplyFunAndArgs, ReplyFunAndArgs,
State = #{installed_actions := InstalledActions} State = #{installed_actions := InstalledActions}
) when is_binary(ActionId) -> ) when is_binary(ActionId) ->
@ -448,8 +448,8 @@ on_query_async(
body := Body, body := Body,
headers := Headers, headers := Headers,
request_timeout := Timeout request_timeout := Timeout
} = process_request_and_action(Request, ActionState, MsgAndBody), } = process_request_and_action(Request, ActionState, Msg),
ClientId = clientid(MsgAndBody), ClientId = clientid(Msg),
on_query_async( on_query_async(
InstId, InstId,
{ClientId, Method, {Path, Headers, Body}, Timeout}, {ClientId, Method, {Path, Headers, Body}, Timeout},
@ -629,7 +629,7 @@ maybe_parse_template(Key, Conf) ->
parse_template(String) -> parse_template(String) ->
emqx_template:parse(String). emqx_template:parse(String).
process_request_and_action(Request, ActionState, {Msg, Body}) -> process_request_and_action(Request, ActionState, Msg) ->
MethodTemplate = maps:get(method, ActionState), MethodTemplate = maps:get(method, ActionState),
Method = make_method(render_template_string(MethodTemplate, Msg)), Method = make_method(render_template_string(MethodTemplate, Msg)),
PathPrefix = unicode:characters_to_list(render_template(maps:get(path, Request), Msg)), PathPrefix = unicode:characters_to_list(render_template(maps:get(path, Request), Msg)),
@ -647,17 +647,15 @@ process_request_and_action(Request, ActionState, {Msg, Body}) ->
render_headers(HeadersTemplate1, Msg), render_headers(HeadersTemplate1, Msg),
render_headers(HeadersTemplate2, Msg) render_headers(HeadersTemplate2, Msg)
), ),
BodyTemplate = maps:get(body, ActionState),
Body = render_request_body(BodyTemplate, Msg),
#{ #{
method => Method, method => Method,
path => Path, path => Path,
body => Body, body => Body,
headers => Headers, headers => Headers,
request_timeout => maps:get(request_timeout, ActionState) request_timeout => maps:get(request_timeout, ActionState)
}; }.
process_request_and_action(Request, ActionState, Msg) ->
BodyTemplate = maps:get(body, ActionState),
Body = render_request_body(BodyTemplate, Msg),
process_request_and_action(Request, ActionState, {Msg, Body}).
merge_proplist(Proplist1, Proplist2) -> merge_proplist(Proplist1, Proplist2) ->
lists:foldl( lists:foldl(
@ -877,7 +875,6 @@ redact_request({Path, Headers}) ->
redact_request({Path, Headers, _Body}) -> redact_request({Path, Headers, _Body}) ->
{Path, Headers, <<"******">>}. {Path, Headers, <<"******">>}.
clientid({Msg, _Body}) -> clientid(Msg);
clientid(Msg) -> maps:get(clientid, Msg, undefined). clientid(Msg) -> maps:get(clientid, Msg, undefined).
-ifdef(TEST). -ifdef(TEST).

View File

@ -190,7 +190,7 @@ connector_structs() ->
mk( mk(
hoconsc:map(name, ref(emqx_bridge_es_connector, config)), hoconsc:map(name, ref(emqx_bridge_es_connector, config)),
#{ #{
desc => <<"Elastis Search Connector Config">>, desc => <<"ElasticSearch Connector Config">>,
required => false required => false
} }
)} )}

View File

@ -1,5 +1,10 @@
emqx_bridge_es { emqx_bridge_es {
elasticsearch.desc:
"""Elasticsearch Bridge"""
elasticsearch.label:
"""ElasticSearch"""
config_enable.desc: config_enable.desc:
"""Enable or disable this bridge""" """Enable or disable this bridge"""
@ -74,15 +79,9 @@ desc_name.desc:
desc_name.label: desc_name.label:
"""Bridge Name""" """Bridge Name"""
config_parameters_action.desc:
"""TODO"""
config_parameters_action.label:
"""Action"""
config_parameters_index.desc: config_parameters_index.desc:
"""Name of the data stream, index, or index alias to perform the action on. """Name of index, or index alias to perform the action on.
This parameter is required if a <target> is not specified in the request path.""" This parameter is required."""
config_parameters_index.label: config_parameters_index.label:
"""_index""" """_index"""
@ -97,28 +96,10 @@ config_parameters_require_alias.desc:
config_parameters_require_alias.label: config_parameters_require_alias.label:
"""_require_alias""" """_require_alias"""
config_parameters_fields.desc: config_parameters_doc.desc:
"""The document source to index. Required for create and index operations.""" """JSON document"""
config_parameters_fields.label: config_parameters_doc.label:
"""fields""" """doc"""
config_parameters_doc_as_upsert.desc:
"""Instead of sending a partial doc plus an upsert doc, you can set doc_as_upsert to true
to use the contents of doc as the upsert value."""
config_parameters_doc_as_upsert.label:
"""doc_as_upsert"""
config_parameters_upsert.desc:
"""If the document does not already exist, the contents of the upsert element are inserted as a new document."""
config_parameters_upsert.label:
"""upsert"""
action_parameters_data.desc:
"""ElasticSearch action parameter data"""
action_parameters_data.label:
"""Parameter Data"""
action_parameters.desc: action_parameters.desc:
"""ElasticSearch action parameters""" """ElasticSearch action parameters"""
@ -126,4 +107,38 @@ action_parameters.desc:
action_parameters.label: action_parameters.label:
"""Parameters""" """Parameters"""
config_overwrite.desc:
"""Set to false If a document with the specified _id already exists(conflict), the operation will fail."""
config_overwrite.label:
"""overwrite"""
action_config.desc:
"""ElasticSearch Action Configuration"""
action_config.label:
"""ElasticSearch Action Config"""
action_create.desc:
"""Adds a JSON document to the specified index and makes it searchable.
If the target is an index and the document already exists,
the request updates the document and increments its version."""
action_create.label:
"""Create Doc"""
action_delete.desc:
"""Removes a JSON document from the specified index."""
action_delete.label:
"""Delete Doc"""
action_update.desc:
"""Updates a document using the specified doc."""
action_update.label:
"""Update Doc"""
action_resource_opts.desc:
"""Resource options."""
action_resource_opts.label:
"""Resource Options"""
} }

View File

@ -24,11 +24,6 @@ config_auth_basic_password.desc:
config_auth_basic_password.label: config_auth_basic_password.label:
"""HTTP Basic Auth Password""" """HTTP Basic Auth Password"""
config_base_url.desc:
"""The base URL of the external ElasticSearch service's REST interface."""
config_base_url.label:
"""ElasticSearch REST Service Base URL"""
config_max_retries.desc: config_max_retries.desc:
"""HTTP request max retry times if failed.""" """HTTP request max retry times if failed."""

View File

@ -297,3 +297,5 @@ Syskeeper
msacc msacc
now_us now_us
ns ns
elasticsearch
ElasticSearch