diff --git a/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo.app.src b/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo.app.src index ed5078432..a4b372056 100644 --- a/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo.app.src +++ b/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo.app.src @@ -1,6 +1,6 @@ {application, emqx_bridge_dynamo, [ {description, "EMQX Enterprise Dynamo Bridge"}, - {vsn, "0.1.3"}, + {vsn, "0.1.4"}, {registered, []}, {applications, [ kernel, diff --git a/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo_connector.erl b/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo_connector.erl index 0d62845fd..9cdb8886c 100644 --- a/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo_connector.erl +++ b/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo_connector.erl @@ -45,12 +45,10 @@ fields(config) -> #{required => true, desc => ?DESC("aws_access_key_id")} )}, {aws_secret_access_key, - mk( - binary(), + emqx_schema_secret:mk( #{ required => true, - desc => ?DESC("aws_secret_access_key"), - sensitive => true + desc => ?DESC("aws_secret_access_key") } )}, {pool_size, fun emqx_connector_schema_lib:pool_size/1}, @@ -89,7 +87,7 @@ on_start( host => Host, port => Port, aws_access_key_id => to_str(AccessKeyID), - aws_secret_access_key => to_str(SecretAccessKey), + aws_secret_access_key => SecretAccessKey, schema => Schema }}, {pool_size, PoolSize} @@ -182,9 +180,8 @@ do_query( end. connect(Opts) -> - Options = proplists:get_value(config, Opts), - {ok, _Pid} = Result = emqx_bridge_dynamo_connector_client:start_link(Options), - Result. + Config = proplists:get_value(config, Opts), + {ok, _Pid} = emqx_bridge_dynamo_connector_client:start_link(Config). parse_template(Config) -> Templates = diff --git a/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo_connector_client.erl b/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo_connector_client.erl index 1b379298f..1cb326cf7 100644 --- a/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo_connector_client.erl +++ b/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo_connector_client.erl @@ -20,8 +20,7 @@ handle_cast/2, handle_info/2, terminate/2, - code_change/3, - format_status/2 + code_change/3 ]). -ifdef(TEST). @@ -62,11 +61,13 @@ start_link(Options) -> %% Initialize dynamodb data bridge init(#{ aws_access_key_id := AccessKeyID, - aws_secret_access_key := SecretAccessKey, + aws_secret_access_key := Secret, host := Host, port := Port, schema := Schema }) -> + %% TODO: teach `erlcloud` to to accept 0-arity closures as passwords. + SecretAccessKey = to_str(emqx_secret:unwrap(Secret)), erlcloud_ddb2:configure(AccessKeyID, SecretAccessKey, Host, Port, Schema), {ok, #{}}. @@ -101,13 +102,6 @@ terminate(_Reason, _State) -> code_change(_OldVsn, State, _Extra) -> {ok, State}. --spec format_status( - Opt :: normal | terminate, - Status :: list() -) -> Status :: term(). -format_status(_Opt, Status) -> - Status. - %%%=================================================================== %%% Internal functions %%%=================================================================== @@ -184,3 +178,8 @@ convert2binary(Value) when is_list(Value) -> unicode:characters_to_binary(Value); convert2binary(Value) when is_map(Value) -> emqx_utils_json:encode(Value). + +to_str(List) when is_list(List) -> + List; +to_str(Bin) when is_binary(Bin) -> + erlang:binary_to_list(Bin). diff --git a/apps/emqx_bridge_dynamo/test/emqx_bridge_dynamo_SUITE.erl b/apps/emqx_bridge_dynamo/test/emqx_bridge_dynamo_SUITE.erl index 9490e6455..936d2d506 100644 --- a/apps/emqx_bridge_dynamo/test/emqx_bridge_dynamo_SUITE.erl +++ b/apps/emqx_bridge_dynamo/test/emqx_bridge_dynamo_SUITE.erl @@ -22,8 +22,6 @@ -define(BATCH_SIZE, 10). -define(PAYLOAD, <<"HELLO">>). --define(GET_CONFIG(KEY__, CFG__), proplists:get_value(KEY__, CFG__)). - %% How to run it locally (all commands are run in $PROJ_ROOT dir): %% run ct in docker container %% run script: @@ -84,7 +82,9 @@ end_per_group(_Group, _Config) -> ok. init_per_suite(Config) -> - Config. + SecretFile = filename:join(?config(priv_dir, Config), "secret"), + ok = file:write_file(SecretFile, <>), + [{dynamo_secretfile, SecretFile} | Config]. end_per_suite(_Config) -> emqx_mgmt_api_test_util:end_suite(), @@ -158,32 +158,35 @@ common_init(ConfigT) -> end. dynamo_config(BridgeType, Config) -> - Port = integer_to_list(?GET_CONFIG(port, Config)), - Url = "http://" ++ ?GET_CONFIG(host, Config) ++ ":" ++ Port, + Host = ?config(host, Config), + Port = ?config(port, Config), Name = atom_to_binary(?MODULE), - BatchSize = ?GET_CONFIG(batch_size, Config), - QueryMode = ?GET_CONFIG(query_mode, Config), + BatchSize = ?config(batch_size, Config), + QueryMode = ?config(query_mode, Config), + SecretFile = ?config(dynamo_secretfile, Config), ConfigString = io_lib:format( - "bridges.~s.~s {\n" - " enable = true\n" - " url = ~p\n" - " table = ~p\n" - " aws_access_key_id = ~p\n" - " aws_secret_access_key = ~p\n" - " resource_opts = {\n" - " request_ttl = 500ms\n" - " batch_size = ~b\n" - " query_mode = ~s\n" - " }\n" - "}", + "bridges.~s.~s {" + "\n enable = true" + "\n url = \"http://~s:~p\"" + "\n table = ~p" + "\n aws_access_key_id = ~p" + "\n aws_secret_access_key = ~p" + "\n resource_opts = {" + "\n request_ttl = 500ms" + "\n batch_size = ~b" + "\n query_mode = ~s" + "\n }" + "\n }", [ BridgeType, Name, - Url, + Host, + Port, ?TABLE, ?ACCESS_KEY_ID, - ?SECRET_ACCESS_KEY, + %% NOTE: using file-based secrets with HOCON configs + "file://" ++ SecretFile, BatchSize, QueryMode ] @@ -252,8 +255,8 @@ delete_table(_Config) -> erlcloud_ddb2:delete_table(?TABLE_BIN). setup_dynamo(Config) -> - Host = ?GET_CONFIG(host, Config), - Port = ?GET_CONFIG(port, Config), + Host = ?config(host, Config), + Port = ?config(port, Config), erlcloud_ddb2:configure(?ACCESS_KEY_ID, ?SECRET_ACCESS_KEY, Host, Port, ?SCHEMA). directly_setup_dynamo() -> @@ -313,7 +316,9 @@ t_setup_via_http_api_and_publish(Config) -> PgsqlConfig0 = ?config(dynamo_config, Config), PgsqlConfig = PgsqlConfig0#{ <<"name">> => Name, - <<"type">> => BridgeType + <<"type">> => BridgeType, + %% NOTE: using literal secret with HTTP API requests. + <<"aws_secret_access_key">> => <> }, ?assertMatch( {ok, _}, @@ -400,7 +405,7 @@ t_simple_query(Config) -> ), Request = {get_item, {<<"id">>, <<"not_exists">>}}, Result = query_resource(Config, Request), - case ?GET_CONFIG(batch_size, Config) of + case ?config(batch_size, Config) of ?BATCH_SIZE -> ?assertMatch({error, {unrecoverable_error, {invalid_request, _}}}, Result); 1 ->