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