Merge pull request #11478 from JimMoen/hstreamdb-tls-support

Hstreamdb tls support
This commit is contained in:
JimMoen 2023-08-22 10:40:54 +08:00 committed by GitHub
commit 13ebcd6290
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 121 additions and 81 deletions

View File

@ -10,7 +10,7 @@ CASSANDRA_TAG=3.11.6
MINIO_TAG=RELEASE.2023-03-20T20-16-18Z MINIO_TAG=RELEASE.2023-03-20T20-16-18Z
OPENTS_TAG=9aa7f88 OPENTS_TAG=9aa7f88
KINESIS_TAG=2.1 KINESIS_TAG=2.1
HSTREAMDB_TAG=v0.15.0 HSTREAMDB_TAG=v0.16.1
HSTREAMDB_ZK_TAG=3.8.1 HSTREAMDB_ZK_TAG=3.8.1
MS_IMAGE_ADDR=mcr.microsoft.com/mssql/server MS_IMAGE_ADDR=mcr.microsoft.com/mssql/server

View File

@ -1,7 +1,7 @@
%% -*- mode: erlang -*- %% -*- mode: erlang -*-
{application, emqx_bridge, [ {application, emqx_bridge, [
{description, "EMQX bridges"}, {description, "EMQX bridges"},
{vsn, "0.1.26"}, {vsn, "0.1.27"},
{registered, [emqx_bridge_sup]}, {registered, [emqx_bridge_sup]},
{mod, {emqx_bridge_app, []}}, {mod, {emqx_bridge_app, []}},
{applications, [ {applications, [

View File

@ -32,8 +32,7 @@ api_schemas(Method) ->
api_ref(emqx_bridge_mongodb, <<"mongodb_rs">>, Method ++ "_rs"), api_ref(emqx_bridge_mongodb, <<"mongodb_rs">>, Method ++ "_rs"),
api_ref(emqx_bridge_mongodb, <<"mongodb_sharded">>, Method ++ "_sharded"), api_ref(emqx_bridge_mongodb, <<"mongodb_sharded">>, Method ++ "_sharded"),
api_ref(emqx_bridge_mongodb, <<"mongodb_single">>, Method ++ "_single"), api_ref(emqx_bridge_mongodb, <<"mongodb_single">>, Method ++ "_single"),
%% TODO: un-hide for e5.2.0... api_ref(emqx_bridge_hstreamdb, <<"hstreamdb">>, Method),
%%api_ref(emqx_bridge_hstreamdb, <<"hstreamdb">>, Method),
api_ref(emqx_bridge_influxdb, <<"influxdb_api_v1">>, Method ++ "_api_v1"), api_ref(emqx_bridge_influxdb, <<"influxdb_api_v1">>, Method ++ "_api_v1"),
api_ref(emqx_bridge_influxdb, <<"influxdb_api_v2">>, Method ++ "_api_v2"), api_ref(emqx_bridge_influxdb, <<"influxdb_api_v2">>, Method ++ "_api_v2"),
api_ref(emqx_bridge_redis, <<"redis_single">>, Method ++ "_single"), api_ref(emqx_bridge_redis, <<"redis_single">>, Method ++ "_single"),
@ -147,8 +146,7 @@ fields(bridges) ->
hoconsc:map(name, ref(emqx_bridge_hstreamdb, "config")), hoconsc:map(name, ref(emqx_bridge_hstreamdb, "config")),
#{ #{
desc => <<"HStreamDB Bridge Config">>, desc => <<"HStreamDB Bridge Config">>,
required => false, required => false
importance => ?IMPORTANCE_HIDDEN
} }
)}, )},
{mysql, {mysql,

View File

@ -1,7 +1,7 @@
%% -*- mode: erlang -*- %% -*- mode: erlang -*-
{erl_opts, [debug_info]}. {erl_opts, [debug_info]}.
{deps, [ {deps, [
{hstreamdb_erl, {git, "https://github.com/hstreamdb/hstreamdb_erl.git", {tag, "0.3.1+v0.12.0"}}}, {hstreamdb_erl, {git, "https://github.com/hstreamdb/hstreamdb_erl.git", {tag, "0.4.3+v0.16.1"}}},
{emqx, {path, "../../apps/emqx"}}, {emqx, {path, "../../apps/emqx"}},
{emqx_utils, {path, "../../apps/emqx_utils"}} {emqx_utils, {path, "../../apps/emqx_utils"}}
]}. ]}.

View File

@ -1,6 +1,6 @@
{application, emqx_bridge_hstreamdb, [ {application, emqx_bridge_hstreamdb, [
{description, "EMQX Enterprise HStreamDB Bridge"}, {description, "EMQX Enterprise HStreamDB Bridge"},
{vsn, "0.1.1"}, {vsn, "0.1.2"},
{registered, []}, {registered, []},
{applications, [ {applications, [
kernel, kernel,

View File

@ -75,7 +75,7 @@ on_query(
} }
) -> ) ->
try to_record(PartitionKey, HRecordTemplate, Data) of try to_record(PartitionKey, HRecordTemplate, Data) of
Record -> append_record(Producer, Record) Record -> append_record(Producer, Record, false)
catch catch
_:_ -> ?FAILED_TO_APPLY_HRECORD_TEMPLATE _:_ -> ?FAILED_TO_APPLY_HRECORD_TEMPLATE
end. end.
@ -88,7 +88,7 @@ on_batch_query(
} }
) -> ) ->
try to_multi_part_records(PartitionKey, HRecordTemplate, BatchList) of try to_multi_part_records(PartitionKey, HRecordTemplate, BatchList) of
Records -> append_record(Producer, Records) Records -> append_record(Producer, Records, true)
catch catch
_:_ -> ?FAILED_TO_APPLY_HRECORD_TEMPLATE _:_ -> ?FAILED_TO_APPLY_HRECORD_TEMPLATE
end. end.
@ -156,16 +156,29 @@ start_client(InstId, Config) ->
{error, Error} {error, Error}
end. end.
do_start_client(InstId, Config = #{url := Server, pool_size := PoolSize}) -> do_start_client(InstId, Config = #{url := Server, pool_size := PoolSize, ssl := SSL}) ->
?SLOG(info, #{ ?SLOG(info, #{
msg => "starting hstreamdb connector: client", msg => "starting hstreamdb connector: client",
connector => InstId, connector => InstId,
config => Config config => Config
}), }),
ClientName = client_name(InstId), ClientName = client_name(InstId),
RpcOpts =
case maps:get(enable, SSL) of
false ->
#{pool_size => PoolSize};
true ->
#{
pool_size => PoolSize,
gun_opts => #{
transport => tls,
transport_opts => emqx_tls_lib:to_client_opts(SSL)
}
}
end,
ClientOptions = [ ClientOptions = [
{url, binary_to_list(Server)}, {url, binary_to_list(Server)},
{rpc_options, #{pool_size => PoolSize}} {rpc_options, RpcOpts}
], ],
case hstreamdb:start_client(ClientName, ClientOptions) of case hstreamdb:start_client(ClientName, ClientOptions) of
{ok, Client} -> {ok, Client} ->
@ -206,12 +219,7 @@ do_start_client(InstId, Config = #{url := Server, pool_size := PoolSize}) ->
end. end.
is_alive(Client) -> is_alive(Client) ->
case hstreamdb:echo(Client) of hstreamdb_client:echo(Client) =:= ok.
{ok, _Echo} ->
true;
_ErrorEcho ->
false
end.
start_producer( start_producer(
InstId, InstId,
@ -280,54 +288,52 @@ to_record(PartitionKey, RawRecord) ->
hstreamdb:to_record(PartitionKey, raw, RawRecord). hstreamdb:to_record(PartitionKey, raw, RawRecord).
to_multi_part_records(PartitionKeyTmpl, HRecordTmpl, BatchList) -> to_multi_part_records(PartitionKeyTmpl, HRecordTmpl, BatchList) ->
Records0 = lists:map( lists:map(
fun({send_message, Data}) -> fun({send_message, Data}) ->
to_record(PartitionKeyTmpl, HRecordTmpl, Data) to_record(PartitionKeyTmpl, HRecordTmpl, Data)
end, end,
BatchList BatchList
), ).
PartitionKeys = proplists:get_keys(Records0),
[
{PartitionKey, proplists:get_all_values(PartitionKey, Records0)}
|| PartitionKey <- PartitionKeys
].
append_record(Producer, MultiPartsRecords) when is_list(MultiPartsRecords) -> append_record(Producer, MultiPartsRecords, MaybeBatch) when is_list(MultiPartsRecords) ->
lists:foreach(fun(Record) -> append_record(Producer, Record) end, MultiPartsRecords); lists:foreach(
append_record(Producer, Record) when is_tuple(Record) -> fun(Record) -> append_record(Producer, Record, MaybeBatch) end, MultiPartsRecords
do_append_records(false, Producer, Record). );
append_record(Producer, Record, MaybeBatch) when is_tuple(Record) ->
do_append_records(Producer, Record, MaybeBatch).
%% TODO: only sync request supported. implement async request later. %% TODO: only sync request supported. implement async request later.
do_append_records(false, Producer, Record) -> do_append_records(Producer, Record, true = IsBatch) ->
case hstreamdb:append_flush(Producer, Record) of Result = hstreamdb:append(Producer, Record),
{ok, _Result} -> handle_result(Result, Record, IsBatch);
?tp( do_append_records(Producer, Record, false = IsBatch) ->
hstreamdb_connector_query_return, Result = hstreamdb:append_flush(Producer, Record),
#{result => _Result} handle_result(Result, Record, IsBatch).
),
?SLOG(debug, #{ handle_result(ok = Result, Record, IsBatch) ->
msg => "HStreamDB producer sync append success", handle_result({ok, Result}, Record, IsBatch);
record => Record handle_result({ok, Result}, Record, IsBatch) ->
}); ?tp(
%% the HStream is warming up or buzy, something are not ready yet, retry after a while hstreamdb_connector_query_append_return,
{error, {unavailable, _} = Reason} -> #{result => Result, is_batch => IsBatch}
{error, ),
{recoverable_error, #{ ?SLOG(debug, #{
msg => "HStreamDB is warming up or buzy, will retry after a moment", msg => "HStreamDB producer sync append success",
reason => Reason record => Record,
}}}; is_batch => IsBatch
{error, Reason} = Err -> });
?tp( handle_result({error, Reason} = Err, Record, IsBatch) ->
hstreamdb_connector_query_return, ?tp(
#{error => Reason} hstreamdb_connector_query_append_return,
), #{error => Reason, is_batch => IsBatch}
?SLOG(error, #{ ),
msg => "HStreamDB producer sync append failed", ?SLOG(error, #{
reason => Reason, msg => "HStreamDB producer sync append failed",
record => Record reason => Reason,
}), record => Record,
Err is_batch => IsBatch
end. }),
Err.
client_name(InstId) -> client_name(InstId) ->
"client:" ++ to_string(InstId). "client:" ++ to_string(InstId).

View File

@ -13,8 +13,13 @@
-include_lib("snabbkaffe/include/snabbkaffe.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl").
% SQL definitions % SQL definitions
-define(STREAM, "stream").
-define(STREAM, "demo_stream").
%% could not be "stream" in Production Environment
%% especially not in hstreamdb_sql CLI client
-define(REPLICATION_FACTOR, 1). -define(REPLICATION_FACTOR, 1).
%% in seconds %% in seconds
-define(BACKLOG_RETENTION_SECOND, (24 * 60 * 60)). -define(BACKLOG_RETENTION_SECOND, (24 * 60 * 60)).
-define(SHARD_COUNT, 1). -define(SHARD_COUNT, 1).
@ -146,16 +151,23 @@ t_setup_via_config_and_publish(Config) ->
begin begin
?wait_async_action( ?wait_async_action(
?assertEqual(ok, send_message(Config, Data)), ?assertEqual(ok, send_message(Config, Data)),
#{?snk_kind := hstreamdb_connector_query_return}, #{?snk_kind := hstreamdb_connector_query_append_return},
10_000 10_000
), ),
ok ok
end, end,
fun(Trace0) -> fun(Trace0) ->
Trace = ?of_kind(hstreamdb_connector_query_return, Trace0), Trace = ?of_kind(hstreamdb_connector_query_append_return, Trace0),
lists:foreach( lists:foreach(
fun(EachTrace) -> fun(EachTrace) ->
?assertMatch(#{result := #{streamName := <<?STREAM>>}}, EachTrace) case ?config(enable_batch, Config) of
true ->
?assertMatch(#{result := ok, is_batch := true}, EachTrace);
false ->
?assertMatch(
#{result := #{'batchId' := _}, is_batch := false}, EachTrace
)
end
end, end,
Trace Trace
), ),
@ -181,16 +193,26 @@ t_setup_via_http_api_and_publish(Config) ->
begin begin
?wait_async_action( ?wait_async_action(
?assertEqual(ok, send_message(Config, Data)), ?assertEqual(ok, send_message(Config, Data)),
#{?snk_kind := hstreamdb_connector_query_return}, #{?snk_kind := hstreamdb_connector_query_append_return},
10_000 10_000
), ),
ok ok
end, end,
fun(Trace) -> fun(Trace) ->
?assertMatch( lists:foreach(
[#{result := #{streamName := <<?STREAM>>}}], fun(EachTrace) ->
?of_kind(hstreamdb_connector_query_return, Trace) case ?config(enable_batch, Config) of
) true ->
?assertMatch(#{result := ok, is_batch := true}, EachTrace);
false ->
?assertMatch(
#{result := #{'batchId' := _}, is_batch := false}, EachTrace
)
end
end,
?of_kind(hstreamdb_connector_query_append_return, Trace)
),
ok
end end
), ),
ok. ok.
@ -240,6 +262,7 @@ t_write_failure(Config) ->
ProxyPort = ?config(proxy_port, Config), ProxyPort = ?config(proxy_port, Config),
ProxyHost = ?config(proxy_host, Config), ProxyHost = ?config(proxy_host, Config),
QueryMode = ?config(query_mode, Config), QueryMode = ?config(query_mode, Config),
EnableBatch = ?config(enable_batch, Config),
Data = rand_data(), Data = rand_data(),
{{ok, _}, {ok, _}} = {{ok, _}, {ok, _}} =
?wait_async_action( ?wait_async_action(
@ -251,10 +274,16 @@ t_write_failure(Config) ->
health_check_resource_down(Config), health_check_resource_down(Config),
case QueryMode of case QueryMode of
sync -> sync ->
?assertMatch( case EnableBatch of
{error, {resource_error, #{msg := "call resource timeout", reason := timeout}}}, true ->
send_message(Config, Data) %% append to batch always returns ok
); ?assertMatch(ok, send_message(Config, Data));
false ->
?assertMatch(
{error, {cannot_list_shards, {<<?STREAM>>, econnrefused}}},
send_message(Config, Data)
)
end;
async -> async ->
%% TODO: async mode is not supported yet, %% TODO: async mode is not supported yet,
%% but it will return ok if calling emqx_resource_buffer_worker:async_query/3, %% but it will return ok if calling emqx_resource_buffer_worker:async_query/3,
@ -282,17 +311,23 @@ t_simple_query(Config) ->
end, end,
Requests Requests
), ),
#{?snk_kind := hstreamdb_connector_query_return}, #{?snk_kind := hstreamdb_connector_query_append_return},
10_000 10_000
) )
end, end,
fun(Trace0) -> fun(Trace) ->
Trace = ?of_kind(hstreamdb_connector_query_return, Trace0),
lists:foreach( lists:foreach(
fun(EachTrace) -> fun(EachTrace) ->
?assertMatch(#{result := #{streamName := <<?STREAM>>}}, EachTrace) case ?config(enable_batch, Config) of
true ->
?assertMatch(#{result := ok, is_batch := true}, EachTrace);
false ->
?assertMatch(
#{result := #{'batchId' := _}, is_batch := false}, EachTrace
)
end
end, end,
Trace ?of_kind(hstreamdb_connector_query_append_return, Trace)
), ),
ok ok
end end
@ -432,7 +467,7 @@ client(Name, Config, N) ->
try try
_ = hstreamdb:stop_client(Name), _ = hstreamdb:stop_client(Name),
{ok, Client} = hstreamdb:start_client(Name, default_options(Config)), {ok, Client} = hstreamdb:start_client(Name, default_options(Config)),
{ok, echo} = hstreamdb:echo(Client), ok = hstreamdb_client:echo(Client),
Client Client
catch catch
Class:Error -> Class:Error ->
@ -509,7 +544,7 @@ health_check_resource_down(Config) ->
% These funs start and then stop the hstreamdb connection % These funs start and then stop the hstreamdb connection
connect_and_create_stream(Config) -> connect_and_create_stream(Config) ->
?WITH_CLIENT( ?WITH_CLIENT(
_ = hstreamdb:create_stream( _ = hstreamdb_client:create_stream(
Client, ?STREAM, ?REPLICATION_FACTOR, ?BACKLOG_RETENTION_SECOND, ?SHARD_COUNT Client, ?STREAM, ?REPLICATION_FACTOR, ?BACKLOG_RETENTION_SECOND, ?SHARD_COUNT
) )
), ),
@ -531,7 +566,7 @@ connect_and_create_stream(Config) ->
connect_and_delete_stream(Config) -> connect_and_delete_stream(Config) ->
?WITH_CLIENT( ?WITH_CLIENT(
_ = hstreamdb:delete_stream(Client, ?STREAM) _ = hstreamdb_client:delete_stream(Client, ?STREAM)
). ).
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------

View File

@ -0,0 +1 @@
Add HStreamDB bridge support (both TCP and TLS connection allowed), adapted to the HStreamDB `v0.16.1`.

View File

@ -227,7 +227,7 @@ defmodule EMQXUmbrella.MixProject do
defp enterprise_deps(_profile_info = %{edition_type: :enterprise}) do defp enterprise_deps(_profile_info = %{edition_type: :enterprise}) do
[ [
{:hstreamdb_erl, github: "hstreamdb/hstreamdb_erl", tag: "0.3.1+v0.12.0"}, {:hstreamdb_erl, github: "hstreamdb/hstreamdb_erl", tag: "0.4.3+v0.16.1"},
{:influxdb, github: "emqx/influxdb-client-erl", tag: "1.1.11", override: true}, {:influxdb, github: "emqx/influxdb-client-erl", tag: "1.1.11", override: true},
{:wolff, github: "kafka4beam/wolff", tag: "1.7.6"}, {:wolff, github: "kafka4beam/wolff", tag: "1.7.6"},
{:kafka_protocol, github: "kafka4beam/kafka_protocol", tag: "4.1.3", override: true}, {:kafka_protocol, github: "kafka4beam/kafka_protocol", tag: "4.1.3", override: true},