diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index 8bee5ce4d1c1..2b6500310aad 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -1,3 +1,5 @@
+# Format rabbitmq_aws with erlfmt
+a4fffbd7e0a312fef2e514ade54fc4310a681542
# Revert "Format MQTT code with erlfmt"
209f23fa2f58e0240116b3e8e5be9cd54d34b569
# Format MQTT code with erlfmt
diff --git a/deps/rabbitmq_aws/include/rabbitmq_aws.hrl b/deps/rabbitmq_aws/include/rabbitmq_aws.hrl
index ab16d9ed49f4..6a0cacd81131 100644
--- a/deps/rabbitmq_aws/include/rabbitmq_aws.hrl
+++ b/deps/rabbitmq_aws/include/rabbitmq_aws.hrl
@@ -57,18 +57,22 @@
-type sc_error() :: {error, Reason :: atom()}.
-type security_credentials() :: sc_ok() | sc_error().
--record(imdsv2token, { token :: security_token() | undefined,
- expiration :: non_neg_integer() | undefined}).
+-record(imdsv2token, {
+ token :: security_token() | undefined,
+ expiration :: non_neg_integer() | undefined
+}).
-type imdsv2token() :: #imdsv2token{}.
--record(state, {access_key :: access_key() | undefined,
- secret_access_key :: secret_access_key() | undefined,
- expiration :: expiration() | undefined,
- security_token :: security_token() | undefined,
- region :: region() | undefined,
- imdsv2_token:: imdsv2token() | undefined,
- error :: atom() | string() | undefined}).
+-record(state, {
+ access_key :: access_key() | undefined,
+ secret_access_key :: secret_access_key() | undefined,
+ expiration :: expiration() | undefined,
+ security_token :: security_token() | undefined,
+ region :: region() | undefined,
+ imdsv2_token :: imdsv2token() | undefined,
+ error :: atom() | string() | undefined
+}).
-type state() :: #state{}.
-type scheme() :: atom().
@@ -79,17 +83,16 @@
-type query_args() :: [tuple() | string()].
-type fragment() :: string().
--type userinfo() :: {undefined | username(),
- undefined | password()}.
+-type userinfo() :: {undefined | username(), undefined | password()}.
--type authority() :: {undefined | userinfo(),
- host(),
- undefined | tcp_port()}.
--record(uri, {scheme :: undefined | scheme(),
- authority :: authority(),
- path :: undefined | path(),
- query :: undefined | query_args(),
- fragment :: undefined | fragment()}).
+-type authority() :: {undefined | userinfo(), host(), undefined | tcp_port()}.
+-record(uri, {
+ scheme :: undefined | scheme(),
+ authority :: authority(),
+ path :: undefined | path(),
+ query :: undefined | query_args(),
+ fragment :: undefined | fragment()
+}).
-type method() :: head | get | put | post | trace | options | delete | patch.
-type http_version() :: string().
@@ -104,35 +107,40 @@
-type ssl_options() :: [ssl:tls_client_option()].
--type http_option() :: {timeout, timeout()} |
- {connect_timeout, timeout()} |
- {ssl, ssl_options()} |
- {essl, ssl_options()} |
- {autoredirect, boolean()} |
- {proxy_auth, {User :: string(), Password :: string()}} |
- {version, http_version()} |
- {relaxed, boolean()} |
- {url_encode, boolean()}.
+-type http_option() ::
+ {timeout, timeout()}
+ | {connect_timeout, timeout()}
+ | {ssl, ssl_options()}
+ | {essl, ssl_options()}
+ | {autoredirect, boolean()}
+ | {proxy_auth, {User :: string(), Password :: string()}}
+ | {version, http_version()}
+ | {relaxed, boolean()}
+ | {url_encode, boolean()}.
-type http_options() :: [http_option()].
-
--record(request, {access_key :: access_key(),
- secret_access_key :: secret_access_key(),
- security_token :: security_token(),
- service :: string(),
- region = "us-east-1" :: string(),
- method = get :: method(),
- headers = [] :: headers(),
- uri :: string(),
- body = "" :: body()}).
+-record(request, {
+ access_key :: access_key(),
+ secret_access_key :: secret_access_key(),
+ security_token :: security_token(),
+ service :: string(),
+ region = "us-east-1" :: string(),
+ method = get :: method(),
+ headers = [] :: headers(),
+ uri :: string(),
+ body = "" :: body()
+}).
-type request() :: #request{}.
--type httpc_result() :: {ok, {status_line(), headers(), body()}} |
- {ok, {status_code(), body()}} |
- {error, term()}.
+-type httpc_result() ::
+ {ok, {status_line(), headers(), body()}}
+ | {ok, {status_code(), body()}}
+ | {error, term()}.
-type result_ok() :: {ok, {ResponseHeaders :: headers(), Response :: list()}}.
--type result_error() :: {'error', Message :: reason_phrase(), {ResponseHeaders :: headers(), Response :: list()} | undefined} |
- {'error', {credentials, Reason :: string()}} |
- {'error', string()}.
+-type result_error() ::
+ {'error', Message :: reason_phrase(),
+ {ResponseHeaders :: headers(), Response :: list()} | undefined}
+ | {'error', {credentials, Reason :: string()}}
+ | {'error', string()}.
-type result() :: result_ok() | result_error().
diff --git a/deps/rabbitmq_aws/src/rabbitmq_aws.erl b/deps/rabbitmq_aws/src/rabbitmq_aws.erl
index 5a45a597d851..e0c85ec55372 100644
--- a/deps/rabbitmq_aws/src/rabbitmq_aws.erl
+++ b/deps/rabbitmq_aws/src/rabbitmq_aws.erl
@@ -9,24 +9,28 @@
-behavior(gen_server).
%% API exports
--export([get/2, get/3,
- post/4,
- refresh_credentials/0,
- request/5, request/6, request/7,
- set_credentials/2,
- has_credentials/0,
- set_region/1,
- ensure_imdsv2_token_valid/0,
- api_get_request/2]).
+-export([
+ get/2, get/3,
+ post/4,
+ refresh_credentials/0,
+ request/5, request/6, request/7,
+ set_credentials/2,
+ has_credentials/0,
+ set_region/1,
+ ensure_imdsv2_token_valid/0,
+ api_get_request/2
+]).
%% gen-server exports
--export([start_link/0,
- init/1,
- terminate/2,
- code_change/3,
- handle_call/3,
- handle_cast/2,
- handle_info/2]).
+-export([
+ start_link/0,
+ init/1,
+ terminate/2,
+ code_change/3,
+ handle_call/3,
+ handle_cast/2,
+ handle_info/2
+]).
%% Export all for unit tests
-ifdef(TEST).
@@ -40,101 +44,110 @@
%% exported wrapper functions
%%====================================================================
--spec get(Service :: string(),
- Path :: path()) -> result().
+-spec get(
+ Service :: string(),
+ Path :: path()
+) -> result().
%% @doc Perform a HTTP GET request to the AWS API for the specified service. The
%% response will automatically be decoded if it is either in JSON, or XML
%% format.
%% @end
get(Service, Path) ->
- get(Service, Path, []).
+ get(Service, Path, []).
-
--spec get(Service :: string(),
- Path :: path(),
- Headers :: headers()) -> result().
+-spec get(
+ Service :: string(),
+ Path :: path(),
+ Headers :: headers()
+) -> result().
%% @doc Perform a HTTP GET request to the AWS API for the specified service. The
%% response will automatically be decoded if it is either in JSON or XML
%% format.
%% @end
get(Service, Path, Headers) ->
- request(Service, get, Path, "", Headers).
-
-
--spec post(Service :: string(),
- Path :: path(),
- Body :: body(),
- Headers :: headers()) -> result().
+ request(Service, get, Path, "", Headers).
+
+-spec post(
+ Service :: string(),
+ Path :: path(),
+ Body :: body(),
+ Headers :: headers()
+) -> result().
%% @doc Perform a HTTP Post request to the AWS API for the specified service. The
%% response will automatically be decoded if it is either in JSON or XML
%% format.
%% @end
post(Service, Path, Body, Headers) ->
- request(Service, post, Path, Body, Headers).
-
+ request(Service, post, Path, Body, Headers).
-spec refresh_credentials() -> ok | error.
%% @doc Manually refresh the credentials from the environment, filesystem or EC2 Instance Metadata Service.
%% @end
refresh_credentials() ->
- gen_server:call(rabbitmq_aws, refresh_credentials).
-
+ gen_server:call(rabbitmq_aws, refresh_credentials).
-spec refresh_credentials(state()) -> ok | error.
%% @doc Manually refresh the credentials from the environment, filesystem or EC2 Instance Metadata Service.
%% @end
refresh_credentials(State) ->
- ?LOG_DEBUG("Refreshing AWS credentials..."),
- {_, NewState} = load_credentials(State),
- ?LOG_DEBUG("AWS credentials have been refreshed"),
- set_credentials(NewState).
-
-
--spec request(Service :: string(),
- Method :: method(),
- Path :: path(),
- Body :: body(),
- Headers :: headers()) -> result().
+ ?LOG_DEBUG("Refreshing AWS credentials..."),
+ {_, NewState} = load_credentials(State),
+ ?LOG_DEBUG("AWS credentials have been refreshed"),
+ set_credentials(NewState).
+
+-spec request(
+ Service :: string(),
+ Method :: method(),
+ Path :: path(),
+ Body :: body(),
+ Headers :: headers()
+) -> result().
%% @doc Perform a HTTP request to the AWS API for the specified service. The
%% response will automatically be decoded if it is either in JSON or XML
%% format.
%% @end
request(Service, Method, Path, Body, Headers) ->
- gen_server:call(rabbitmq_aws, {request, Service, Method, Headers, Path, Body, [], undefined}).
-
-
--spec request(Service :: string(),
- Method :: method(),
- Path :: path(),
- Body :: body(),
- Headers :: headers(),
- HTTPOptions :: http_options()) -> result().
+ gen_server:call(rabbitmq_aws, {request, Service, Method, Headers, Path, Body, [], undefined}).
+
+-spec request(
+ Service :: string(),
+ Method :: method(),
+ Path :: path(),
+ Body :: body(),
+ Headers :: headers(),
+ HTTPOptions :: http_options()
+) -> result().
%% @doc Perform a HTTP request to the AWS API for the specified service. The
%% response will automatically be decoded if it is either in JSON or XML
%% format.
%% @end
request(Service, Method, Path, Body, Headers, HTTPOptions) ->
- gen_server:call(rabbitmq_aws, {request, Service, Method, Headers, Path, Body, HTTPOptions, undefined}).
-
-
--spec request(Service :: string(),
- Method :: method(),
- Path :: path(),
- Body :: body(),
- Headers :: headers(),
- HTTPOptions :: http_options(),
- Endpoint :: host()) -> result().
+ gen_server:call(
+ rabbitmq_aws, {request, Service, Method, Headers, Path, Body, HTTPOptions, undefined}
+ ).
+
+-spec request(
+ Service :: string(),
+ Method :: method(),
+ Path :: path(),
+ Body :: body(),
+ Headers :: headers(),
+ HTTPOptions :: http_options(),
+ Endpoint :: host()
+) -> result().
%% @doc Perform a HTTP request to the AWS API for the specified service, overriding
%% the endpoint URL to use when invoking the API. This is useful for local testing
%% of services such as DynamoDB. The response will automatically be decoded
%% if it is either in JSON or XML format.
%% @end
request(Service, Method, Path, Body, Headers, HTTPOptions, Endpoint) ->
- gen_server:call(rabbitmq_aws, {request, Service, Method, Headers, Path, Body, HTTPOptions, Endpoint}).
+ gen_server:call(
+ rabbitmq_aws, {request, Service, Method, Headers, Path, Body, HTTPOptions, Endpoint}
+ ).
-spec set_credentials(state()) -> ok.
set_credentials(NewState) ->
- gen_server:call(rabbitmq_aws, {set_credentials, NewState}).
+ gen_server:call(rabbitmq_aws, {set_credentials, NewState}).
-spec set_credentials(access_key(), secret_access_key()) -> ok.
%% @doc Manually set the access credentials for requests. This should
@@ -143,122 +156,113 @@ set_credentials(NewState) ->
%% configuration or the AWS Instance Metadata service.
%% @end
set_credentials(AccessKey, SecretAccessKey) ->
- gen_server:call(rabbitmq_aws, {set_credentials, AccessKey, SecretAccessKey}).
-
+ gen_server:call(rabbitmq_aws, {set_credentials, AccessKey, SecretAccessKey}).
-spec set_region(Region :: string()) -> ok.
%% @doc Manually set the AWS region to perform API requests to.
%% @end
set_region(Region) ->
- gen_server:call(rabbitmq_aws, {set_region, Region}).
+ gen_server:call(rabbitmq_aws, {set_region, Region}).
-spec set_imdsv2_token(imdsv2token()) -> ok.
%% @doc Manually set the Imdsv2Token used to perform instance metadata service requests.
%% @end
set_imdsv2_token(Imdsv2Token) ->
- gen_server:call(rabbitmq_aws, {set_imdsv2_token, Imdsv2Token}).
-
+ gen_server:call(rabbitmq_aws, {set_imdsv2_token, Imdsv2Token}).
-spec get_imdsv2_token() -> imdsv2token() | 'undefined'.
%% @doc return the current Imdsv2Token used to perform instance metadata service requests.
%% @end
get_imdsv2_token() ->
- {ok, Imdsv2Token} = gen_server:call(rabbitmq_aws, get_imdsv2_token),
- Imdsv2Token.
-
+ {ok, Imdsv2Token} = gen_server:call(rabbitmq_aws, get_imdsv2_token),
+ Imdsv2Token.
%%====================================================================
%% gen_server functions
%%====================================================================
start_link() ->
- gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
-
+ gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
-spec init(list()) -> {ok, state()}.
init([]) ->
- {ok, #state{}}.
-
+ {ok, #state{}}.
terminate(_, _) ->
- ok.
-
+ ok.
code_change(_, _, State) ->
- {ok, State}.
+ {ok, State}.
handle_call(Msg, _From, State) ->
- handle_msg(Msg, State).
+ handle_msg(Msg, State).
handle_cast(_Request, State) ->
- {noreply, State}.
-
+ {noreply, State}.
handle_info(_Info, State) ->
- {noreply, State}.
+ {noreply, State}.
%%====================================================================
%% Internal functions
%%====================================================================
handle_msg({request, Service, Method, Headers, Path, Body, Options, Host}, State) ->
- {Response, NewState} = perform_request(State, Service, Method, Headers, Path, Body, Options, Host),
+ {Response, NewState} = perform_request(
+ State, Service, Method, Headers, Path, Body, Options, Host
+ ),
{reply, Response, NewState};
-
handle_msg(get_state, State) ->
{reply, {ok, State}, State};
-
handle_msg(refresh_credentials, State) ->
{Reply, NewState} = load_credentials(State),
{reply, Reply, NewState};
-
handle_msg({set_credentials, AccessKey, SecretAccessKey}, State) ->
- {reply, ok, State#state{access_key = AccessKey,
- secret_access_key = SecretAccessKey,
- security_token = undefined,
- expiration = undefined,
- error = undefined}};
-
+ {reply, ok, State#state{
+ access_key = AccessKey,
+ secret_access_key = SecretAccessKey,
+ security_token = undefined,
+ expiration = undefined,
+ error = undefined
+ }};
handle_msg({set_credentials, NewState}, State) ->
- {reply, ok, State#state{access_key = NewState#state.access_key,
- secret_access_key = NewState#state.secret_access_key,
- security_token = NewState#state.security_token,
- expiration = NewState#state.expiration,
- error = NewState#state.error}};
-
+ {reply, ok, State#state{
+ access_key = NewState#state.access_key,
+ secret_access_key = NewState#state.secret_access_key,
+ security_token = NewState#state.security_token,
+ expiration = NewState#state.expiration,
+ error = NewState#state.error
+ }};
handle_msg({set_region, Region}, State) ->
{reply, ok, State#state{region = Region}};
-
handle_msg({set_imdsv2_token, Imdsv2Token}, State) ->
{reply, ok, State#state{imdsv2_token = Imdsv2Token}};
-
handle_msg(has_credentials, State) ->
{reply, has_credentials(State), State};
-
handle_msg(get_imdsv2_token, State) ->
{reply, {ok, State#state.imdsv2_token}, State};
-
handle_msg(_Request, State) ->
{noreply, State}.
-
--spec endpoint(State :: state(), Host :: string(),
- Service :: string(), Path :: string()) -> string().
+-spec endpoint(
+ State :: state(),
+ Host :: string(),
+ Service :: string(),
+ Path :: string()
+) -> string().
%% @doc Return the endpoint URL, either by constructing it with the service
%% information passed in, or by using the passed in Host value.
%% @ednd
endpoint(#state{region = Region}, undefined, Service, Path) ->
- lists:flatten(["https://", endpoint_host(Region, Service), Path]);
+ lists:flatten(["https://", endpoint_host(Region, Service), Path]);
endpoint(_, Host, _, Path) ->
- lists:flatten(["https://", Host, Path]).
-
+ lists:flatten(["https://", Host, Path]).
-spec endpoint_host(Region :: region(), Service :: string()) -> host().
%% @doc Construct the endpoint hostname for the request based upon the service
%% and region.
%% @end
endpoint_host(Region, Service) ->
- lists:flatten(string:join([Service, Region, endpoint_tld(Region)], ".")).
-
+ lists:flatten(string:join([Service, Region, endpoint_tld(Region)], ".")).
-spec endpoint_tld(Region :: region()) -> host().
%% @doc Construct the endpoint hostname TLD for the request based upon the region.
@@ -277,27 +281,29 @@ endpoint_tld(_Other) ->
%% maybe_decode_body/2 method.
%% @end
format_response({ok, {{_Version, 200, _Message}, Headers, Body}}) ->
- {ok, {Headers, maybe_decode_body(get_content_type(Headers), Body)}};
+ {ok, {Headers, maybe_decode_body(get_content_type(Headers), Body)}};
format_response({ok, {{_Version, StatusCode, Message}, Headers, Body}}) when StatusCode >= 400 ->
- {error, Message, {Headers, maybe_decode_body(get_content_type(Headers), Body)}};
+ {error, Message, {Headers, maybe_decode_body(get_content_type(Headers), Body)}};
format_response({error, Reason}) ->
- {error, Reason, undefined}.
+ {error, Reason, undefined}.
-spec get_content_type(Headers :: headers()) -> {Type :: string(), Subtype :: string()}.
%% @doc Fetch the content type from the headers and return it as a tuple of
%% {Type, Subtype}.
%% @end
get_content_type(Headers) ->
- Value = case proplists:get_value("content-type", Headers, undefined) of
- undefined ->
- proplists:get_value("Content-Type", Headers, "text/xml");
- Other -> Other
- end,
- parse_content_type(Value).
+ Value =
+ case proplists:get_value("content-type", Headers, undefined) of
+ undefined ->
+ proplists:get_value("Content-Type", Headers, "text/xml");
+ Other ->
+ Other
+ end,
+ parse_content_type(Value).
-spec has_credentials() -> boolean().
has_credentials() ->
- gen_server:call(rabbitmq_aws, has_credentials).
+ gen_server:call(rabbitmq_aws, has_credentials).
-spec has_credentials(state()) -> boolean().
%% @doc check to see if there are credentials made available in the current state
@@ -307,16 +313,15 @@ has_credentials(#state{error = Error}) when Error /= undefined -> false;
has_credentials(#state{access_key = Key}) when Key /= undefined -> true;
has_credentials(_) -> false.
-
-spec expired_credentials(Expiration :: calendar:datetime()) -> boolean().
%% @doc Indicates if the date that is passed in has expired.
%% end
-expired_credentials(undefined) -> false;
+expired_credentials(undefined) ->
+ false;
expired_credentials(Expiration) ->
- Now = calendar:datetime_to_gregorian_seconds(local_time()),
- Expires = calendar:datetime_to_gregorian_seconds(Expiration),
- Now >= Expires.
-
+ Now = calendar:datetime_to_gregorian_seconds(local_time()),
+ Expires = calendar:datetime_to_gregorian_seconds(Expiration),
+ Now >= Expires.
-spec load_credentials(State :: state()) -> {ok, state()} | {error, state()}.
%% @doc Load the credentials using the following order of configuration precedence:
@@ -325,138 +330,188 @@ expired_credentials(Expiration) ->
%% - EC2 Instance Metadata Service
%% @end
load_credentials(#state{region = Region}) ->
- case rabbitmq_aws_config:credentials() of
- {ok, AccessKey, SecretAccessKey, Expiration, SecurityToken} ->
- {ok, #state{region = Region,
- error = undefined,
- access_key = AccessKey,
- secret_access_key = SecretAccessKey,
- expiration = Expiration,
- security_token = SecurityToken,
- imdsv2_token = undefined}};
- {error, Reason} ->
- ?LOG_ERROR("Could not load AWS credentials from environment variables, AWS_CONFIG_FILE, AWS_SHARED_CREDENTIALS_FILE or EC2 metadata endpoint: ~tp. Will depend on config settings to be set~n", [Reason]),
- {error, #state{region = Region,
- error = Reason,
- access_key = undefined,
- secret_access_key = undefined,
- expiration = undefined,
- security_token = undefined,
- imdsv2_token = undefined}}
- end.
-
+ case rabbitmq_aws_config:credentials() of
+ {ok, AccessKey, SecretAccessKey, Expiration, SecurityToken} ->
+ {ok, #state{
+ region = Region,
+ error = undefined,
+ access_key = AccessKey,
+ secret_access_key = SecretAccessKey,
+ expiration = Expiration,
+ security_token = SecurityToken,
+ imdsv2_token = undefined
+ }};
+ {error, Reason} ->
+ ?LOG_ERROR(
+ "Could not load AWS credentials from environment variables, AWS_CONFIG_FILE, AWS_SHARED_CREDENTIALS_FILE or EC2 metadata endpoint: ~tp. Will depend on config settings to be set~n",
+ [Reason]
+ ),
+ {error, #state{
+ region = Region,
+ error = Reason,
+ access_key = undefined,
+ secret_access_key = undefined,
+ expiration = undefined,
+ security_token = undefined,
+ imdsv2_token = undefined
+ }}
+ end.
-spec local_time() -> calendar:datetime().
%% @doc Return the current local time.
%% @end
local_time() ->
- [Value] = calendar:local_time_to_universal_time_dst(calendar:local_time()),
- Value.
+ [Value] = calendar:local_time_to_universal_time_dst(calendar:local_time()),
+ Value.
-
--spec maybe_decode_body(ContentType :: {nonempty_string(), nonempty_string()}, Body :: body()) -> list() | body().
+-spec maybe_decode_body(ContentType :: {nonempty_string(), nonempty_string()}, Body :: body()) ->
+ list() | body().
%% @doc Attempt to decode the response body by its MIME
%% @end
maybe_decode_body({"application", "x-amz-json-1.0"}, Body) ->
- rabbitmq_aws_json:decode(Body);
+ rabbitmq_aws_json:decode(Body);
maybe_decode_body({"application", "json"}, Body) ->
- rabbitmq_aws_json:decode(Body);
+ rabbitmq_aws_json:decode(Body);
maybe_decode_body({_, "xml"}, Body) ->
- rabbitmq_aws_xml:parse(Body);
+ rabbitmq_aws_xml:parse(Body);
maybe_decode_body(_ContentType, Body) ->
- Body.
-
+ Body.
-spec parse_content_type(ContentType :: string()) -> {Type :: string(), Subtype :: string()}.
%% @doc parse a content type string returning a tuple of type/subtype
%% @end
parse_content_type(ContentType) ->
- Parts = string:tokens(ContentType, ";"),
- [Type, Subtype] = string:tokens(lists:nth(1, Parts), "/"),
- {Type, Subtype}.
-
-
--spec perform_request(State :: state(), Service :: string(), Method :: method(),
- Headers :: headers(), Path :: path(), Body :: body(),
- Options :: http_options(), Host :: string() | undefined)
- -> {Result :: result(), NewState :: state()}.
+ Parts = string:tokens(ContentType, ";"),
+ [Type, Subtype] = string:tokens(lists:nth(1, Parts), "/"),
+ {Type, Subtype}.
+
+-spec perform_request(
+ State :: state(),
+ Service :: string(),
+ Method :: method(),
+ Headers :: headers(),
+ Path :: path(),
+ Body :: body(),
+ Options :: http_options(),
+ Host :: string() | undefined
+) ->
+ {Result :: result(), NewState :: state()}.
%% @doc Make the API request and return the formatted response.
%% @end
perform_request(State, Service, Method, Headers, Path, Body, Options, Host) ->
- perform_request_has_creds(has_credentials(State), State, Service, Method,
- Headers, Path, Body, Options, Host).
-
-
--spec perform_request_has_creds(HasCreds :: boolean(), State :: state(),
- Service :: string(), Method :: method(),
- Headers :: headers(), Path :: path(), Body :: body(),
- Options :: http_options(), Host :: string() | undefined)
- -> {Result :: result(), NewState :: state()}.
+ perform_request_has_creds(
+ has_credentials(State),
+ State,
+ Service,
+ Method,
+ Headers,
+ Path,
+ Body,
+ Options,
+ Host
+ ).
+
+-spec perform_request_has_creds(
+ HasCreds :: boolean(),
+ State :: state(),
+ Service :: string(),
+ Method :: method(),
+ Headers :: headers(),
+ Path :: path(),
+ Body :: body(),
+ Options :: http_options(),
+ Host :: string() | undefined
+) ->
+ {Result :: result(), NewState :: state()}.
%% @doc Invoked after checking to see if there are credentials. If there are,
%% validate they have not or will not expire, performing the request if not,
%% otherwise return an error result.
%% @end
perform_request_has_creds(true, State, Service, Method, Headers, Path, Body, Options, Host) ->
- perform_request_creds_expired(expired_credentials(State#state.expiration), State,
- Service, Method, Headers, Path, Body, Options, Host);
+ perform_request_creds_expired(
+ expired_credentials(State#state.expiration),
+ State,
+ Service,
+ Method,
+ Headers,
+ Path,
+ Body,
+ Options,
+ Host
+ );
perform_request_has_creds(false, State, _, _, _, _, _, _, _) ->
- perform_request_creds_error(State).
-
-
--spec perform_request_creds_expired(CredsExp :: boolean(), State :: state(),
- Service :: string(), Method :: method(),
- Headers :: headers(), Path :: path(), Body :: body(),
- Options :: http_options(), Host :: string() | undefined)
- -> {Result :: result(), NewState :: state()}.
+ perform_request_creds_error(State).
+
+-spec perform_request_creds_expired(
+ CredsExp :: boolean(),
+ State :: state(),
+ Service :: string(),
+ Method :: method(),
+ Headers :: headers(),
+ Path :: path(),
+ Body :: body(),
+ Options :: http_options(),
+ Host :: string() | undefined
+) ->
+ {Result :: result(), NewState :: state()}.
%% @doc Invoked after checking to see if the current credentials have expired.
%% If they haven't, perform the request, otherwise try and refresh the
%% credentials before performing the request.
%% @end
perform_request_creds_expired(false, State, Service, Method, Headers, Path, Body, Options, Host) ->
- perform_request_with_creds(State, Service, Method, Headers, Path, Body, Options, Host);
+ perform_request_with_creds(State, Service, Method, Headers, Path, Body, Options, Host);
perform_request_creds_expired(true, State, _, _, _, _, _, _, _) ->
- perform_request_creds_error(State#state{error = "Credentials expired!"}).
-
-
--spec perform_request_with_creds(State :: state(), Service :: string(), Method :: method(),
- Headers :: headers(), Path :: path(), Body :: body(),
- Options :: http_options(), Host :: string() | undefined)
- -> {Result :: result(), NewState :: state()}.
+ perform_request_creds_error(State#state{error = "Credentials expired!"}).
+
+-spec perform_request_with_creds(
+ State :: state(),
+ Service :: string(),
+ Method :: method(),
+ Headers :: headers(),
+ Path :: path(),
+ Body :: body(),
+ Options :: http_options(),
+ Host :: string() | undefined
+) ->
+ {Result :: result(), NewState :: state()}.
%% @doc Once it is validated that there are credentials to try and that they have not
%% expired, perform the request and return the response.
%% @end
perform_request_with_creds(State, Service, Method, Headers, Path, Body, Options, Host) ->
- URI = endpoint(State, Host, Service, Path),
- SignedHeaders = sign_headers(State, Service, Method, URI, Headers, Body),
- ContentType = proplists:get_value("content-type", SignedHeaders, undefined),
- perform_request_with_creds(State, Method, URI, SignedHeaders, ContentType, Body, Options).
-
-
--spec perform_request_with_creds(State :: state(), Method :: method(), URI :: string(),
- Headers :: headers(), ContentType :: string() | undefined,
- Body :: body(), Options :: http_options())
- -> {Result :: result(), NewState :: state()}.
+ URI = endpoint(State, Host, Service, Path),
+ SignedHeaders = sign_headers(State, Service, Method, URI, Headers, Body),
+ ContentType = proplists:get_value("content-type", SignedHeaders, undefined),
+ perform_request_with_creds(State, Method, URI, SignedHeaders, ContentType, Body, Options).
+
+-spec perform_request_with_creds(
+ State :: state(),
+ Method :: method(),
+ URI :: string(),
+ Headers :: headers(),
+ ContentType :: string() | undefined,
+ Body :: body(),
+ Options :: http_options()
+) ->
+ {Result :: result(), NewState :: state()}.
%% @doc Once it is validated that there are credentials to try and that they have not
%% expired, perform the request and return the response.
%% @end
perform_request_with_creds(State, Method, URI, Headers, undefined, "", Options0) ->
- Options1 = ensure_timeout(Options0),
- Response = httpc:request(Method, {URI, Headers}, Options1, []),
- {format_response(Response), State};
+ Options1 = ensure_timeout(Options0),
+ Response = httpc:request(Method, {URI, Headers}, Options1, []),
+ {format_response(Response), State};
perform_request_with_creds(State, Method, URI, Headers, ContentType, Body, Options0) ->
- Options1 = ensure_timeout(Options0),
- Response = httpc:request(Method, {URI, Headers, ContentType, Body}, Options1, []),
- {format_response(Response), State}.
-
+ Options1 = ensure_timeout(Options0),
+ Response = httpc:request(Method, {URI, Headers, ContentType, Body}, Options1, []),
+ {format_response(Response), State}.
-spec perform_request_creds_error(State :: state()) ->
- {result_error(), NewState :: state()}.
+ {result_error(), NewState :: state()}.
%% @doc Return the error response when there are not any credentials to use with
%% the request.
%% @end
perform_request_creds_error(State) ->
- {{error, {credentials, State#state.error}}, State}.
-
+ {{error, {credentials, State#state.error}}, State}.
%% @doc Ensure that the timeout option is set and greater than 0 and less
%% than about 1/2 of the default gen_server:call timeout. This gives
@@ -474,52 +529,72 @@ ensure_timeout(Options) ->
Options1 ++ [{timeout, ?DEFAULT_HTTP_TIMEOUT}]
end.
-
--spec sign_headers(State :: state(), Service :: string(), Method :: method(),
- URI :: string(), Headers :: headers(), Body :: body()) -> headers().
+-spec sign_headers(
+ State :: state(),
+ Service :: string(),
+ Method :: method(),
+ URI :: string(),
+ Headers :: headers(),
+ Body :: body()
+) -> headers().
%% @doc Build the signed headers for the API request.
%% @end
-sign_headers(#state{access_key = AccessKey,
- secret_access_key = SecretKey,
- security_token = SecurityToken,
- region = Region}, Service, Method, URI, Headers, Body) ->
- rabbitmq_aws_sign:headers(#request{access_key = AccessKey,
- secret_access_key = SecretKey,
- security_token = SecurityToken,
- region = Region,
- service = Service,
- method = Method,
- uri = URI,
- headers = Headers,
- body = Body}).
+sign_headers(
+ #state{
+ access_key = AccessKey,
+ secret_access_key = SecretKey,
+ security_token = SecurityToken,
+ region = Region
+ },
+ Service,
+ Method,
+ URI,
+ Headers,
+ Body
+) ->
+ rabbitmq_aws_sign:headers(#request{
+ access_key = AccessKey,
+ secret_access_key = SecretKey,
+ security_token = SecurityToken,
+ region = Region,
+ service = Service,
+ method = Method,
+ uri = URI,
+ headers = Headers,
+ body = Body
+ }).
-spec expired_imdsv2_token('undefined' | imdsv2token()) -> boolean().
%% @doc Determine whether or not an Imdsv2Token has expired.
%% @end
expired_imdsv2_token(undefined) ->
- ?LOG_DEBUG("EC2 IMDSv2 token has not yet been obtained"),
- true;
+ ?LOG_DEBUG("EC2 IMDSv2 token has not yet been obtained"),
+ true;
expired_imdsv2_token({_, _, undefined}) ->
- ?LOG_DEBUG("EC2 IMDSv2 token is not available"),
- true;
+ ?LOG_DEBUG("EC2 IMDSv2 token is not available"),
+ true;
expired_imdsv2_token({_, _, Expiration}) ->
- Now = calendar:datetime_to_gregorian_seconds(local_time()),
- HasExpired = Now >= Expiration,
- ?LOG_DEBUG("EC2 IMDSv2 token has expired: ~tp", [HasExpired]),
- HasExpired.
-
+ Now = calendar:datetime_to_gregorian_seconds(local_time()),
+ HasExpired = Now >= Expiration,
+ ?LOG_DEBUG("EC2 IMDSv2 token has expired: ~tp", [HasExpired]),
+ HasExpired.
-spec ensure_imdsv2_token_valid() -> security_token().
ensure_imdsv2_token_valid() ->
- Imdsv2Token = get_imdsv2_token(),
- case expired_imdsv2_token(Imdsv2Token) of
- true -> Value = rabbitmq_aws_config:load_imdsv2_token(),
- Expiration = calendar:datetime_to_gregorian_seconds(local_time()) + ?METADATA_TOKEN_TTL_SECONDS,
- set_imdsv2_token(#imdsv2token{token = Value,
- expiration = Expiration}),
+ Imdsv2Token = get_imdsv2_token(),
+ case expired_imdsv2_token(Imdsv2Token) of
+ true ->
+ Value = rabbitmq_aws_config:load_imdsv2_token(),
+ Expiration =
+ calendar:datetime_to_gregorian_seconds(local_time()) + ?METADATA_TOKEN_TTL_SECONDS,
+ set_imdsv2_token(#imdsv2token{
+ token = Value,
+ expiration = Expiration
+ }),
Value;
- _ -> Imdsv2Token#imdsv2token.token
- end.
+ _ ->
+ Imdsv2Token#imdsv2token.token
+ end.
-spec ensure_credentials_valid() -> ok.
%% @doc Invoked before each AWS service API request to check if the current credentials are available and that they have not expired.
@@ -527,43 +602,49 @@ ensure_imdsv2_token_valid() ->
%% If the credentials are not available or have expired, then refresh them before performing the request.
%% @end
ensure_credentials_valid() ->
- ?LOG_DEBUG("Making sure AWS credentials are available and still valid"),
- {ok, State} = gen_server:call(rabbitmq_aws, get_state),
- case has_credentials(State) of
- true -> case expired_credentials(State#state.expiration) of
- true -> refresh_credentials(State);
- _ -> ok
+ ?LOG_DEBUG("Making sure AWS credentials are available and still valid"),
+ {ok, State} = gen_server:call(rabbitmq_aws, get_state),
+ case has_credentials(State) of
+ true ->
+ case expired_credentials(State#state.expiration) of
+ true -> refresh_credentials(State);
+ _ -> ok
end;
- _ -> refresh_credentials(State)
- end.
-
+ _ ->
+ refresh_credentials(State)
+ end.
-spec api_get_request(string(), path()) -> {'ok', list()} | {'error', term()}.
%% @doc Invoke an API call to an AWS service.
%% @end
api_get_request(Service, Path) ->
- ?LOG_DEBUG("Invoking AWS request {Service: ~tp; Path: ~tp}...", [Service, Path]),
- api_get_request_with_retries(Service, Path, ?MAX_RETRIES, ?LINEAR_BACK_OFF_MILLIS).
-
+ ?LOG_DEBUG("Invoking AWS request {Service: ~tp; Path: ~tp}...", [Service, Path]),
+ api_get_request_with_retries(Service, Path, ?MAX_RETRIES, ?LINEAR_BACK_OFF_MILLIS).
--spec api_get_request_with_retries(string(), path(), integer(), integer()) -> {'ok', list()} | {'error', term()}.
+-spec api_get_request_with_retries(string(), path(), integer(), integer()) ->
+ {'ok', list()} | {'error', term()}.
%% @doc Invoke an API call to an AWS service with retries.
%% @end
api_get_request_with_retries(_, _, 0, _) ->
- ?LOG_WARNING("Request to AWS service has failed after ~b retries", [?MAX_RETRIES]),
- {error, "AWS service is unavailable"};
+ ?LOG_WARNING("Request to AWS service has failed after ~b retries", [?MAX_RETRIES]),
+ {error, "AWS service is unavailable"};
api_get_request_with_retries(Service, Path, Retries, WaitTimeBetweenRetries) ->
- ensure_credentials_valid(),
- case get(Service, Path) of
- {ok, {_Headers, Payload}} -> ?LOG_DEBUG("AWS request: ~ts~nResponse: ~tp", [Path, Payload]),
- {ok, Payload};
- {error, {credentials, _}} -> {error, credentials};
- {error, Message, Response} -> ?LOG_WARNING("Error occurred: ~ts", [Message]),
- case Response of
- {_, Payload} -> ?LOG_WARNING("Failed AWS request: ~ts~nResponse: ~tp", [Path, Payload]);
- _ -> ok
- end,
- ?LOG_WARNING("Will retry AWS request, remaining retries: ~b", [Retries]),
- timer:sleep(WaitTimeBetweenRetries),
- api_get_request_with_retries(Service, Path, Retries - 1, WaitTimeBetweenRetries)
- end.
+ ensure_credentials_valid(),
+ case get(Service, Path) of
+ {ok, {_Headers, Payload}} ->
+ ?LOG_DEBUG("AWS request: ~ts~nResponse: ~tp", [Path, Payload]),
+ {ok, Payload};
+ {error, {credentials, _}} ->
+ {error, credentials};
+ {error, Message, Response} ->
+ ?LOG_WARNING("Error occurred: ~ts", [Message]),
+ case Response of
+ {_, Payload} ->
+ ?LOG_WARNING("Failed AWS request: ~ts~nResponse: ~tp", [Path, Payload]);
+ _ ->
+ ok
+ end,
+ ?LOG_WARNING("Will retry AWS request, remaining retries: ~b", [Retries]),
+ timer:sleep(WaitTimeBetweenRetries),
+ api_get_request_with_retries(Service, Path, Retries - 1, WaitTimeBetweenRetries)
+ end.
diff --git a/deps/rabbitmq_aws/src/rabbitmq_aws_app.erl b/deps/rabbitmq_aws/src/rabbitmq_aws_app.erl
index b01196ec30e1..543c8f56282d 100644
--- a/deps/rabbitmq_aws/src/rabbitmq_aws_app.erl
+++ b/deps/rabbitmq_aws/src/rabbitmq_aws_app.erl
@@ -16,7 +16,7 @@
%% ===================================================================
start(_StartType, _StartArgs) ->
- rabbitmq_aws_sup:start_link().
+ rabbitmq_aws_sup:start_link().
stop(_State) ->
- ok.
+ ok.
diff --git a/deps/rabbitmq_aws/src/rabbitmq_aws_config.erl b/deps/rabbitmq_aws/src/rabbitmq_aws_config.erl
index b9c722e8f1b8..3d2ae89fe918 100644
--- a/deps/rabbitmq_aws/src/rabbitmq_aws_config.erl
+++ b/deps/rabbitmq_aws/src/rabbitmq_aws_config.erl
@@ -9,20 +9,22 @@
-module(rabbitmq_aws_config).
%% API
--export([credentials/0,
- credentials/1,
- value/2,
- values/1,
- instance_metadata_url/1,
- instance_credentials_url/1,
- instance_availability_zone_url/0,
- instance_role_url/0,
- instance_id_url/0,
- instance_id/0,
- load_imdsv2_token/0,
- instance_metadata_request_headers/0,
- region/0,
- region/1]).
+-export([
+ credentials/0,
+ credentials/1,
+ value/2,
+ values/1,
+ instance_metadata_url/1,
+ instance_credentials_url/1,
+ instance_availability_zone_url/0,
+ instance_role_url/0,
+ instance_id_url/0,
+ instance_id/0,
+ load_imdsv2_token/0,
+ instance_metadata_request_headers/0,
+ region/0,
+ region/1
+]).
%% Export all for unit tests
-ifdef(TEST).
@@ -81,7 +83,7 @@
%% will be returned.
%% @end
credentials() ->
- credentials(profile()).
+ credentials(profile()).
-spec credentials(string()) -> security_credentials().
%% @doc Return the credentials from environment variables, configuration or the
@@ -129,10 +131,11 @@ credentials() ->
%% will be returned.
%% @end
credentials(Profile) ->
- lookup_credentials(Profile,
- os:getenv("AWS_ACCESS_KEY_ID"),
- os:getenv("AWS_SECRET_ACCESS_KEY")).
-
+ lookup_credentials(
+ Profile,
+ os:getenv("AWS_ACCESS_KEY_ID"),
+ os:getenv("AWS_SECRET_ACCESS_KEY")
+ ).
-spec region() -> {ok, string()}.
%% @doc Return the region as configured by ``AWS_DEFAULT_REGION`` environment
@@ -144,8 +147,7 @@ credentials(Profile) ->
%% local instance metadata server.
%% @end
region() ->
- region(profile()).
-
+ region(profile()).
-spec region(Region :: string()) -> {ok, region()}.
%% @doc Return the region as configured by ``AWS_DEFAULT_REGION`` environment
@@ -157,60 +159,61 @@ region() ->
%% local instance metadata server.
%% @end
region(Profile) ->
- case lookup_region(Profile, os:getenv("AWS_DEFAULT_REGION")) of
- {ok, Region} -> {ok, Region};
- _ -> {ok, ?DEFAULT_REGION}
- end.
-
+ case lookup_region(Profile, os:getenv("AWS_DEFAULT_REGION")) of
+ {ok, Region} -> {ok, Region};
+ _ -> {ok, ?DEFAULT_REGION}
+ end.
-spec instance_id() -> {'ok', string()} | {'error', 'undefined'}.
%% @doc Return the instance ID from the EC2 metadata service.
%% @end
instance_id() ->
- URL = instance_id_url(),
- parse_body_response(perform_http_get_instance_metadata(URL)).
-
+ URL = instance_id_url(),
+ parse_body_response(perform_http_get_instance_metadata(URL)).
--spec value(Profile :: string(), Key :: atom())
- -> Value :: any() | {error, Reason :: atom()}.
+-spec value(Profile :: string(), Key :: atom()) ->
+ Value :: any() | {error, Reason :: atom()}.
%% @doc Return the configuration data for the specified profile or an error
%% if the profile is not found.
%% @end
value(Profile, Key) ->
- get_value(Key, values(Profile)).
+ get_value(Key, values(Profile)).
-
--spec values(Profile :: string())
- -> Settings :: list()
- | {error, Reason :: atom()}.
+-spec values(Profile :: string()) ->
+ Settings ::
+ list()
+ | {error, Reason :: atom()}.
%% @doc Return the configuration data for the specified profile or an error
%% if the profile is not found.
%% @end
values(Profile) ->
- case config_file_data() of
- {error, Reason} ->
- {error, Reason};
- Settings ->
- Prefixed = lists:flatten(["profile ", Profile]),
- proplists:get_value(Profile, Settings,
- proplists:get_value(Prefixed,
- Settings, {error, undefined}))
- end.
-
+ case config_file_data() of
+ {error, Reason} ->
+ {error, Reason};
+ Settings ->
+ Prefixed = lists:flatten(["profile ", Profile]),
+ proplists:get_value(
+ Profile,
+ Settings,
+ proplists:get_value(
+ Prefixed,
+ Settings,
+ {error, undefined}
+ )
+ )
+ end.
%% -----------------------------------------------------------------------------
%% Private / Internal Methods
%% -----------------------------------------------------------------------------
-
-spec config_file() -> string().
%% @doc Return the configuration file to test using either the value of the
%% AWS_CONFIG_FILE or the default location where the file is expected to
%% exist.
%% @end
config_file() ->
- config_file(os:getenv("AWS_CONFIG_FILE")).
-
+ config_file(os:getenv("AWS_CONFIG_FILE")).
-spec config_file(Path :: false | string()) -> string().
%% @doc Return the configuration file to test using either the value of the
@@ -218,17 +221,15 @@ config_file() ->
%% exist.
%% @end
config_file(false) ->
- filename:join([home_path(), ".aws", "config"]);
+ filename:join([home_path(), ".aws", "config"]);
config_file(EnvVar) ->
- EnvVar.
-
+ EnvVar.
-spec config_file_data() -> list() | {error, Reason :: atom()}.
%% @doc Return the values from a configuration file as a proplist by section
%% @end
config_file_data() ->
- ini_file_data(config_file()).
-
+ ini_file_data(config_file()).
-spec credentials_file() -> string().
%% @doc Return the shared credentials file to test using either the value of the
@@ -236,8 +237,7 @@ config_file_data() ->
%% is expected to exist.
%% @end
credentials_file() ->
- credentials_file(os:getenv("AWS_SHARED_CREDENTIALS_FILE")).
-
+ credentials_file(os:getenv("AWS_SHARED_CREDENTIALS_FILE")).
-spec credentials_file(Path :: false | string()) -> string().
%% @doc Return the shared credentials file to test using either the value of the
@@ -245,25 +245,25 @@ credentials_file() ->
%% is expected to exist.
%% @end
credentials_file(false) ->
- filename:join([home_path(), ".aws", "credentials"]);
+ filename:join([home_path(), ".aws", "credentials"]);
credentials_file(EnvVar) ->
- EnvVar.
+ EnvVar.
-spec credentials_file_data() -> list() | {error, Reason :: atom()}.
%% @doc Return the values from a configuration file as a proplist by section
%% @end
credentials_file_data() ->
- ini_file_data(credentials_file()).
+ ini_file_data(credentials_file()).
-
--spec get_value(Key :: atom(), Settings :: list()) -> any();
- (Key :: atom(), {error, Reason :: atom()}) -> {error, Reason :: atom()}.
+-spec get_value
+ (Key :: atom(), Settings :: list()) -> any();
+ (Key :: atom(), {error, Reason :: atom()}) -> {error, Reason :: atom()}.
%% @doc Get the value for a key from a settings proplist.
%% @end
get_value(Key, Settings) when is_list(Settings) ->
- proplists:get_value(Key, Settings, {error, undefined});
-get_value(_, {error, Reason}) -> {error, Reason}.
-
+ proplists:get_value(Key, Settings, {error, undefined});
+get_value(_, {error, Reason}) ->
+ {error, Reason}.
-spec home_path() -> string().
%% @doc Return the path to the current user's home directory, checking for the
@@ -271,8 +271,7 @@ get_value(_, {error, Reason}) -> {error, Reason}.
%% directory if it's not set.
%% @end
home_path() ->
- home_path(os:getenv("HOME")).
-
+ home_path(os:getenv("HOME")).
-spec home_path(Value :: string() | false) -> string().
%% @doc Return the path to the current user's home directory, checking for the
@@ -282,404 +281,430 @@ home_path() ->
home_path(false) -> filename:absname(".");
home_path(Value) -> Value.
-
--spec ini_file_data(Path :: string())
- -> list() | {error, atom()}.
+-spec ini_file_data(Path :: string()) ->
+ list() | {error, atom()}.
%% @doc Return the parsed ini file for the specified path.
%% @end
ini_file_data(Path) ->
- ini_file_data(Path, filelib:is_file(Path)).
+ ini_file_data(Path, filelib:is_file(Path)).
-
--spec ini_file_data(Path :: string(), FileExists :: boolean())
- -> list() | {error, atom()}.
+-spec ini_file_data(Path :: string(), FileExists :: boolean()) ->
+ list() | {error, atom()}.
%% @doc Return the parsed ini file for the specified path.
%% @end
ini_file_data(Path, true) ->
- case read_file(Path) of
- {ok, Lines} -> ini_parse_lines(Lines, none, none, []);
- {error, Reason} -> {error, Reason}
- end;
-ini_file_data(_, false) -> {error, enoent}.
-
+ case read_file(Path) of
+ {ok, Lines} -> ini_parse_lines(Lines, none, none, []);
+ {error, Reason} -> {error, Reason}
+ end;
+ini_file_data(_, false) ->
+ {error, enoent}.
-spec ini_format_key(any()) -> atom() | {error, type}.
%% @doc Converts a ini file key to an atom, stripping any leading whitespace
%% @end
ini_format_key(Key) ->
- case io_lib:printable_list(Key) of
- true -> list_to_atom(string:strip(Key));
- false -> {error, type}
- end.
-
+ case io_lib:printable_list(Key) of
+ true -> list_to_atom(string:strip(Key));
+ false -> {error, type}
+ end.
--spec ini_parse_line(Section :: list(),
- Key :: atom(),
- Line :: binary())
- -> {Section :: list(), Key :: string() | none}.
+-spec ini_parse_line(
+ Section :: list(),
+ Key :: atom(),
+ Line :: binary()
+) ->
+ {Section :: list(), Key :: string() | none}.
%% @doc Parse the AWS configuration INI file, returning a proplist
%% @end
ini_parse_line(Section, Parent, <<" ", Line/binary>>) ->
- Child = proplists:get_value(Parent, Section, []),
- {ok, NewChild} = ini_parse_line_parts(Child, ini_split_line(Line)),
- {lists:keystore(Parent, 1, Section, {Parent, NewChild}), Parent};
+ Child = proplists:get_value(Parent, Section, []),
+ {ok, NewChild} = ini_parse_line_parts(Child, ini_split_line(Line)),
+ {lists:keystore(Parent, 1, Section, {Parent, NewChild}), Parent};
ini_parse_line(Section, _, Line) ->
- case ini_parse_line_parts(Section, ini_split_line(Line)) of
- {ok, NewSection} -> {NewSection, none};
- {new_parent, Parent} -> {Section, Parent}
- end.
-
+ case ini_parse_line_parts(Section, ini_split_line(Line)) of
+ {ok, NewSection} -> {NewSection, none};
+ {new_parent, Parent} -> {Section, Parent}
+ end.
--spec ini_parse_line_parts(Section :: list(),
- Parts :: list())
- -> {ok, list()} | {new_parent, atom()}.
+-spec ini_parse_line_parts(
+ Section :: list(),
+ Parts :: list()
+) ->
+ {ok, list()} | {new_parent, atom()}.
%% @doc Parse the AWS configuration INI file, returning a proplist
%% @end
-ini_parse_line_parts(Section, []) -> {ok, Section};
+ini_parse_line_parts(Section, []) ->
+ {ok, Section};
ini_parse_line_parts(Section, [RawKey, Value]) ->
- Key = ini_format_key(RawKey),
- {ok, lists:keystore(Key, 1, Section, {Key, maybe_convert_number(Value)})};
+ Key = ini_format_key(RawKey),
+ {ok, lists:keystore(Key, 1, Section, {Key, maybe_convert_number(Value)})};
ini_parse_line_parts(_, [RawKey]) ->
- {new_parent, ini_format_key(RawKey)}.
-
-
--spec ini_parse_lines(Lines::[binary()],
- SectionName :: string() | atom(),
- Parent :: atom(),
- Accumulator :: list())
- -> list().
+ {new_parent, ini_format_key(RawKey)}.
+
+-spec ini_parse_lines(
+ Lines :: [binary()],
+ SectionName :: string() | atom(),
+ Parent :: atom(),
+ Accumulator :: list()
+) ->
+ list().
%% @doc Parse the AWS configuration INI file
%% @end
-ini_parse_lines([], _, _, Settings) -> Settings;
-ini_parse_lines([H|T], SectionName, Parent, Settings) ->
- {ok, NewSectionName} = ini_parse_section_name(SectionName, H),
- {ok, NewParent, NewSettings} = ini_parse_section(H, NewSectionName,
- Parent, Settings),
- ini_parse_lines(T, NewSectionName, NewParent, NewSettings).
-
-
--spec ini_parse_section(Line :: binary(),
- SectionName :: string(),
- Parent :: atom(),
- Section :: list())
- -> {ok, NewParent :: atom(), Section :: list()}.
+ini_parse_lines([], _, _, Settings) ->
+ Settings;
+ini_parse_lines([H | T], SectionName, Parent, Settings) ->
+ {ok, NewSectionName} = ini_parse_section_name(SectionName, H),
+ {ok, NewParent, NewSettings} = ini_parse_section(
+ H,
+ NewSectionName,
+ Parent,
+ Settings
+ ),
+ ini_parse_lines(T, NewSectionName, NewParent, NewSettings).
+
+-spec ini_parse_section(
+ Line :: binary(),
+ SectionName :: string(),
+ Parent :: atom(),
+ Section :: list()
+) ->
+ {ok, NewParent :: atom(), Section :: list()}.
%% @doc Parse a line from the ini file, returning it as part of the appropriate
%% section.
%% @end
ini_parse_section(Line, SectionName, Parent, Settings) ->
- Section = proplists:get_value(SectionName, Settings, []),
- {NewSection, NewParent} = ini_parse_line(Section, Parent, Line),
- {ok, NewParent, lists:keystore(SectionName, 1, Settings,
- {SectionName, NewSection})}.
-
-
--spec ini_parse_section_name(CurrentSection :: string() | atom(),
- Line :: binary())
- -> {ok, SectionName :: string()}.
+ Section = proplists:get_value(SectionName, Settings, []),
+ {NewSection, NewParent} = ini_parse_line(Section, Parent, Line),
+ {ok, NewParent,
+ lists:keystore(
+ SectionName,
+ 1,
+ Settings,
+ {SectionName, NewSection}
+ )}.
+
+-spec ini_parse_section_name(
+ CurrentSection :: string() | atom(),
+ Line :: binary()
+) ->
+ {ok, SectionName :: string()}.
%% @doc Attempts to parse a section name from the current line, returning either
%% the new parsed section name, or the current section name.
%% @end
ini_parse_section_name(CurrentSection, Line) ->
- Value = binary_to_list(Line),
- case re:run(Value, "\\[([\\w\\s+\\-_]+)\\]", [{capture, all, list}]) of
- {match, [_, SectionName]} -> {ok, SectionName};
- nomatch -> {ok, CurrentSection}
- end.
-
+ Value = binary_to_list(Line),
+ case re:run(Value, "\\[([\\w\\s+\\-_]+)\\]", [{capture, all, list}]) of
+ {match, [_, SectionName]} -> {ok, SectionName};
+ nomatch -> {ok, CurrentSection}
+ end.
-spec ini_split_line(binary()) -> list().
%% @doc Split a key value pair delimited by ``=`` to a list of strings.
%% @end
ini_split_line(Line) ->
- string:tokens(string:strip(binary_to_list(Line)), "=").
-
+ string:tokens(string:strip(binary_to_list(Line)), "=").
-spec instance_availability_zone_url() -> string().
%% @doc Return the URL for querying the availability zone from the Instance
%% Metadata service
%% @end
instance_availability_zone_url() ->
- instance_metadata_url(string:join([?INSTANCE_METADATA_BASE, ?INSTANCE_AZ], "/")).
-
+ instance_metadata_url(string:join([?INSTANCE_METADATA_BASE, ?INSTANCE_AZ], "/")).
-spec instance_credentials_url(string()) -> string().
%% @doc Return the URL for querying temporary credentials from the Instance
%% Metadata service for the specified role
%% @end
instance_credentials_url(Role) ->
- instance_metadata_url(string:join([?INSTANCE_METADATA_BASE, ?INSTANCE_CREDENTIALS, Role], "/")).
-
+ instance_metadata_url(string:join([?INSTANCE_METADATA_BASE, ?INSTANCE_CREDENTIALS, Role], "/")).
-spec instance_metadata_url(string()) -> string().
%% @doc Build the Instance Metadata service URL for the specified path
%% @end
instance_metadata_url(Path) ->
- rabbitmq_aws_urilib:build(#uri{scheme = http,
- authority = {undefined, ?INSTANCE_HOST, undefined},
- path = Path, query = []}).
-
+ rabbitmq_aws_urilib:build(#uri{
+ scheme = http,
+ authority = {undefined, ?INSTANCE_HOST, undefined},
+ path = Path,
+ query = []
+ }).
-spec instance_role_url() -> string().
%% @doc Return the URL for querying the role associated with the current
%% instance from the Instance Metadata service
%% @end
instance_role_url() ->
- instance_metadata_url(string:join([?INSTANCE_METADATA_BASE, ?INSTANCE_CREDENTIALS], "/")).
+ instance_metadata_url(string:join([?INSTANCE_METADATA_BASE, ?INSTANCE_CREDENTIALS], "/")).
-spec imdsv2_token_url() -> string().
%% @doc Return the URL for obtaining EC2 IMDSv2 token from the Instance Metadata service.
%% @end
imdsv2_token_url() ->
- instance_metadata_url(?TOKEN_URL).
+ instance_metadata_url(?TOKEN_URL).
-spec instance_id_url() -> string().
%% @doc Return the URL for querying the id of the current instance from the Instance Metadata service.
%% @end
instance_id_url() ->
- instance_metadata_url(string:join([?INSTANCE_METADATA_BASE, ?INSTANCE_ID], "/")).
-
-
--spec lookup_credentials(Profile :: string(),
- AccessKey :: string() | false,
- SecretKey :: string() | false)
- -> security_credentials().
+ instance_metadata_url(string:join([?INSTANCE_METADATA_BASE, ?INSTANCE_ID], "/")).
+
+-spec lookup_credentials(
+ Profile :: string(),
+ AccessKey :: string() | false,
+ SecretKey :: string() | false
+) ->
+ security_credentials().
%% @doc Return the access key and secret access key if they are set in
%% environment variables, otherwise lookup the credentials from the config
%% file for the specified profile.
%% @end
lookup_credentials(Profile, false, _) ->
- lookup_credentials_from_config(Profile,
- value(Profile, aws_access_key_id),
- value(Profile, aws_secret_access_key));
+ lookup_credentials_from_config(
+ Profile,
+ value(Profile, aws_access_key_id),
+ value(Profile, aws_secret_access_key)
+ );
lookup_credentials(Profile, _, false) ->
- lookup_credentials_from_config(Profile,
- value(Profile, aws_access_key_id),
- value(Profile, aws_secret_access_key));
+ lookup_credentials_from_config(
+ Profile,
+ value(Profile, aws_access_key_id),
+ value(Profile, aws_secret_access_key)
+ );
lookup_credentials(_, AccessKey, SecretKey) ->
- {ok, AccessKey, SecretKey, undefined, undefined}.
-
-
--spec lookup_credentials_from_config(Profile :: string(),
- access_key() | {error, Reason :: atom()},
- secret_access_key()| {error, Reason :: atom()})
- -> security_credentials().
+ {ok, AccessKey, SecretKey, undefined, undefined}.
+
+-spec lookup_credentials_from_config(
+ Profile :: string(),
+ access_key() | {error, Reason :: atom()},
+ secret_access_key() | {error, Reason :: atom()}
+) ->
+ security_credentials().
%% @doc Return the access key and secret access key if they are set in
%% for the specified profile in the config file, if it exists. If it does
%% not exist or the profile is not set or the values are not set in the
%% profile, look up the values in the shared credentials file
%% @end
-lookup_credentials_from_config(Profile, {error,_}, _) ->
- lookup_credentials_from_file(Profile, credentials_file_data());
+lookup_credentials_from_config(Profile, {error, _}, _) ->
+ lookup_credentials_from_file(Profile, credentials_file_data());
lookup_credentials_from_config(_, AccessKey, SecretKey) ->
- {ok, AccessKey, SecretKey, undefined, undefined}.
-
+ {ok, AccessKey, SecretKey, undefined, undefined}.
--spec lookup_credentials_from_file(Profile :: string(),
- Credentials :: list())
- -> security_credentials().
+-spec lookup_credentials_from_file(
+ Profile :: string(),
+ Credentials :: list()
+) ->
+ security_credentials().
%% @doc Check to see if the shared credentials file exists and if it does,
%% invoke ``lookup_credentials_from_shared_creds_section/2`` to attempt to
%% get the credentials values out of it. If the file does not exist,
%% attempt to lookup the values from the EC2 instance metadata service.
%% @end
-lookup_credentials_from_file(_, {error,_}) ->
- lookup_credentials_from_instance_metadata();
+lookup_credentials_from_file(_, {error, _}) ->
+ lookup_credentials_from_instance_metadata();
lookup_credentials_from_file(Profile, Credentials) ->
- Section = proplists:get_value(Profile, Credentials),
- lookup_credentials_from_section(Section).
+ Section = proplists:get_value(Profile, Credentials),
+ lookup_credentials_from_section(Section).
-
--spec lookup_credentials_from_section(Credentials :: list() | undefined)
- -> security_credentials().
+-spec lookup_credentials_from_section(Credentials :: list() | undefined) ->
+ security_credentials().
%% @doc Return the access key and secret access key if they are set in
%% for the specified profile from the shared credentials file. If the
%% profile is not set or the values are not set in the profile, attempt to
%% lookup the values from the EC2 instance metadata service.
%% @end
lookup_credentials_from_section(undefined) ->
- lookup_credentials_from_instance_metadata();
+ lookup_credentials_from_instance_metadata();
lookup_credentials_from_section(Credentials) ->
- AccessKey = proplists:get_value(aws_access_key_id, Credentials, undefined),
- SecretKey = proplists:get_value(aws_secret_access_key, Credentials, undefined),
- lookup_credentials_from_proplist(AccessKey, SecretKey).
-
-
--spec lookup_credentials_from_proplist(AccessKey :: access_key(),
- SecretAccessKey :: secret_access_key())
- -> security_credentials().
+ AccessKey = proplists:get_value(aws_access_key_id, Credentials, undefined),
+ SecretKey = proplists:get_value(aws_secret_access_key, Credentials, undefined),
+ lookup_credentials_from_proplist(AccessKey, SecretKey).
+
+-spec lookup_credentials_from_proplist(
+ AccessKey :: access_key(),
+ SecretAccessKey :: secret_access_key()
+) ->
+ security_credentials().
%% @doc Process the contents of the Credentials proplists checking if the
%% access key and secret access key are both set.
%% @end
lookup_credentials_from_proplist(undefined, _) ->
- lookup_credentials_from_instance_metadata();
+ lookup_credentials_from_instance_metadata();
lookup_credentials_from_proplist(_, undefined) ->
- lookup_credentials_from_instance_metadata();
+ lookup_credentials_from_instance_metadata();
lookup_credentials_from_proplist(AccessKey, SecretKey) ->
- {ok, AccessKey, SecretKey, undefined, undefined}.
-
+ {ok, AccessKey, SecretKey, undefined, undefined}.
--spec lookup_credentials_from_instance_metadata()
- -> security_credentials().
+-spec lookup_credentials_from_instance_metadata() ->
+ security_credentials().
%% @spec lookup_credentials_from_instance_metadata() -> Result.
%% @doc Attempt to lookup the values from the EC2 instance metadata service.
%% @end
lookup_credentials_from_instance_metadata() ->
- Role = maybe_get_role_from_instance_metadata(),
- maybe_get_credentials_from_instance_metadata(Role).
-
-
--spec lookup_region(Profile :: string(),
- Region :: false | string())
- -> {ok, string()} | {error, undefined}.
+ Role = maybe_get_role_from_instance_metadata(),
+ maybe_get_credentials_from_instance_metadata(Role).
+
+-spec lookup_region(
+ Profile :: string(),
+ Region :: false | string()
+) ->
+ {ok, string()} | {error, undefined}.
%% @doc If Region is false, lookup the region from the config or the EC2
%% instance metadata service.
%% @end
lookup_region(Profile, false) ->
- lookup_region_from_config(values(Profile));
-lookup_region(_, Region) -> {ok, Region}.
+ lookup_region_from_config(values(Profile));
+lookup_region(_, Region) ->
+ {ok, Region}.
-
--spec lookup_region_from_config(Settings :: list() | {error, atom()})
- -> {ok, string()} | {error, undefined}.
+-spec lookup_region_from_config(Settings :: list() | {error, atom()}) ->
+ {ok, string()} | {error, undefined}.
%% @doc Return the region from the local configuration file. If local config
%% settings are not found, try to lookup the region from the EC2 instance
%% metadata service.
%% @end
lookup_region_from_config({error, _}) ->
- maybe_get_region_from_instance_metadata();
+ maybe_get_region_from_instance_metadata();
lookup_region_from_config(Settings) ->
- lookup_region_from_settings(proplists:get_value(region, Settings)).
-
+ lookup_region_from_settings(proplists:get_value(region, Settings)).
--spec lookup_region_from_settings(any() | undefined)
- -> {ok, string()} | {error, undefined}.
+-spec lookup_region_from_settings(any() | undefined) ->
+ {ok, string()} | {error, undefined}.
%% @doc Decide if the region should be loaded from the Instance Metadata service
%% of if it's already set.
%% @end
lookup_region_from_settings(undefined) ->
- maybe_get_region_from_instance_metadata();
+ maybe_get_region_from_instance_metadata();
lookup_region_from_settings(Region) ->
- {ok, Region}.
-
+ {ok, Region}.
-spec maybe_convert_number(string()) -> integer() | float().
%% @doc Returns an integer or float from a string if possible, otherwise
%% returns the string().
%% @end
maybe_convert_number(Value) ->
- Stripped = string:strip(Value),
- case string:to_float(Stripped) of
- {error,no_float} ->
- try
- list_to_integer(Stripped)
- catch
- error:badarg -> Stripped
- end;
- {F,_Rest} -> F
- end.
-
-
--spec maybe_get_credentials_from_instance_metadata({ok, Role :: string()} |
- {error, undefined})
- -> {'ok', security_credentials()} | {'error', term()}.
+ Stripped = string:strip(Value),
+ case string:to_float(Stripped) of
+ {error, no_float} ->
+ try
+ list_to_integer(Stripped)
+ catch
+ error:badarg -> Stripped
+ end;
+ {F, _Rest} ->
+ F
+ end.
+
+-spec maybe_get_credentials_from_instance_metadata(
+ {ok, Role :: string()}
+ | {error, undefined}
+) ->
+ {'ok', security_credentials()} | {'error', term()}.
%% @doc Try to query the EC2 local instance metadata service to get temporary
%% authentication credentials.
%% @end
maybe_get_credentials_from_instance_metadata({error, undefined}) ->
- {error, undefined};
+ {error, undefined};
maybe_get_credentials_from_instance_metadata({ok, Role}) ->
- URL = instance_credentials_url(Role),
- parse_credentials_response(perform_http_get_instance_metadata(URL)).
-
+ URL = instance_credentials_url(Role),
+ parse_credentials_response(perform_http_get_instance_metadata(URL)).
--spec maybe_get_region_from_instance_metadata()
- -> {ok, Region :: string()} | {error, Reason :: atom()}.
+-spec maybe_get_region_from_instance_metadata() ->
+ {ok, Region :: string()} | {error, Reason :: atom()}.
%% @doc Try to query the EC2 local instance metadata service to get the region
%% @end
maybe_get_region_from_instance_metadata() ->
- URL = instance_availability_zone_url(),
- parse_az_response(perform_http_get_instance_metadata(URL)).
-
+ URL = instance_availability_zone_url(),
+ parse_az_response(perform_http_get_instance_metadata(URL)).
%% @doc Try to query the EC2 local instance metadata service to get the role
%% assigned to the instance.
%% @end
maybe_get_role_from_instance_metadata() ->
- URL = instance_role_url(),
- parse_body_response(perform_http_get_instance_metadata(URL)).
-
+ URL = instance_role_url(),
+ parse_body_response(perform_http_get_instance_metadata(URL)).
--spec parse_az_response(httpc_result())
- -> {ok, Region :: string()} | {error, Reason :: atom()}.
+-spec parse_az_response(httpc_result()) ->
+ {ok, Region :: string()} | {error, Reason :: atom()}.
%% @doc Parse the response from the Availability Zone query to the
%% Instance Metadata service, returning the Region if successful.
%% end.
parse_az_response({error, _}) -> {error, undefined};
-parse_az_response({ok, {{_, 200, _}, _, Body}})
- -> {ok, region_from_availability_zone(Body)};
+parse_az_response({ok, {{_, 200, _}, _, Body}}) -> {ok, region_from_availability_zone(Body)};
parse_az_response({ok, {{_, _, _}, _, _}}) -> {error, undefined}.
-
--spec parse_body_response(httpc_result())
- -> {ok, Value :: string()} | {error, Reason :: atom()}.
+-spec parse_body_response(httpc_result()) ->
+ {ok, Value :: string()} | {error, Reason :: atom()}.
%% @doc Parse the return response from the Instance Metadata Service where the
%% body value is the string to process.
%% end.
-parse_body_response({error, _}) -> {error, undefined};
-parse_body_response({ok, {{_, 200, _}, _, Body}}) -> {ok, Body};
+parse_body_response({error, _}) ->
+ {error, undefined};
+parse_body_response({ok, {{_, 200, _}, _, Body}}) ->
+ {ok, Body};
parse_body_response({ok, {{_, 401, _}, _, _}}) ->
- ?LOG_ERROR(get_instruction_on_instance_metadata_error("Unauthorized instance metadata service request.")),
- {error, undefined};
+ ?LOG_ERROR(
+ get_instruction_on_instance_metadata_error(
+ "Unauthorized instance metadata service request."
+ )
+ ),
+ {error, undefined};
parse_body_response({ok, {{_, 403, _}, _, _}}) ->
- ?LOG_ERROR(get_instruction_on_instance_metadata_error("The request is not allowed or the instance metadata service is turned off.")),
- {error, undefined};
-parse_body_response({ok, {{_, _, _}, _, _}}) -> {error, undefined}.
-
+ ?LOG_ERROR(
+ get_instruction_on_instance_metadata_error(
+ "The request is not allowed or the instance metadata service is turned off."
+ )
+ ),
+ {error, undefined};
+parse_body_response({ok, {{_, _, _}, _, _}}) ->
+ {error, undefined}.
-spec parse_credentials_response(httpc_result()) -> security_credentials().
%% @doc Try to query the EC2 local instance metadata service to get the role
%% assigned to the instance.
%% @end
-parse_credentials_response({error, _}) -> {error, undefined};
-parse_credentials_response({ok, {{_, 404, _}, _, _}}) -> {error, undefined};
+parse_credentials_response({error, _}) ->
+ {error, undefined};
+parse_credentials_response({ok, {{_, 404, _}, _, _}}) ->
+ {error, undefined};
parse_credentials_response({ok, {{_, 200, _}, _, Body}}) ->
- Parsed = rabbitmq_aws_json:decode(Body),
- {ok,
- proplists:get_value("AccessKeyId", Parsed),
- proplists:get_value("SecretAccessKey", Parsed),
- parse_iso8601_timestamp(proplists:get_value("Expiration", Parsed)),
- proplists:get_value("Token", Parsed)}.
-
+ Parsed = rabbitmq_aws_json:decode(Body),
+ {ok, proplists:get_value("AccessKeyId", Parsed), proplists:get_value("SecretAccessKey", Parsed),
+ parse_iso8601_timestamp(proplists:get_value("Expiration", Parsed)),
+ proplists:get_value("Token", Parsed)}.
-spec perform_http_get_instance_metadata(string()) -> httpc_result().
%% @doc Wrap httpc:get/4 to simplify Instance Metadata service v2 requests
%% @end
perform_http_get_instance_metadata(URL) ->
- ?LOG_DEBUG("Querying instance metadata service: ~tp", [URL]),
- httpc:request(get, {URL, instance_metadata_request_headers()},
- [{timeout, ?DEFAULT_HTTP_TIMEOUT}], []).
+ ?LOG_DEBUG("Querying instance metadata service: ~tp", [URL]),
+ httpc:request(
+ get,
+ {URL, instance_metadata_request_headers()},
+ [{timeout, ?DEFAULT_HTTP_TIMEOUT}],
+ []
+ ).
-spec get_instruction_on_instance_metadata_error(string()) -> string().
%% @doc Return error message on failures related to EC2 Instance Metadata Service with a reference to AWS document.
%% end
get_instruction_on_instance_metadata_error(ErrorMessage) ->
- ErrorMessage ++
- " Please refer to the AWS documentation for details on how to configure the instance metadata service: "
- "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html.".
-
+ ErrorMessage ++
+ " Please refer to the AWS documentation for details on how to configure the instance metadata service: "
+ "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html.".
-spec parse_iso8601_timestamp(Timestamp :: string() | binary()) -> calendar:datetime().
%% @doc Parse a ISO8601 timestamp, returning a datetime() value.
%% @end
parse_iso8601_timestamp(Timestamp) when is_binary(Timestamp) ->
- parse_iso8601_timestamp(binary_to_list(Timestamp));
+ parse_iso8601_timestamp(binary_to_list(Timestamp));
parse_iso8601_timestamp(Timestamp) ->
- [Date, Time] = string:tokens(Timestamp, "T"),
- [Year, Month, Day] = string:tokens(Date, "-"),
- [Hour, Minute, Second] = string:tokens(Time, ":"),
- {{list_to_integer(Year), list_to_integer(Month), list_to_integer(Day)},
- {list_to_integer(Hour), list_to_integer(Minute), list_to_integer(string:left(Second,2))}}.
-
+ [Date, Time] = string:tokens(Timestamp, "T"),
+ [Year, Month, Day] = string:tokens(Date, "-"),
+ [Hour, Minute, Second] = string:tokens(Time, ":"),
+ {{list_to_integer(Year), list_to_integer(Month), list_to_integer(Day)}, {
+ list_to_integer(Hour), list_to_integer(Minute), list_to_integer(string:left(Second, 2))
+ }}.
-spec profile() -> string().
%% @doc Return the value of the AWS_DEFAULT_PROFILE environment variable or the
@@ -687,7 +712,6 @@ parse_iso8601_timestamp(Timestamp) ->
%% @end
profile() -> profile(os:getenv("AWS_DEFAULT_PROFILE")).
-
-spec profile(false | string()) -> string().
%% @doc Process the value passed in to determine if we will return the default
%% profile or the value from the environment variable.
@@ -695,7 +719,6 @@ profile() -> profile(os:getenv("AWS_DEFAULT_PROFILE")).
profile(false) -> ?DEFAULT_PROFILE;
profile(Value) -> Value.
-
-spec read_file(string()) -> {'ok', [binary()]} | {error, Reason :: atom()}.
%% @doc Read the specified file, returning the contents as a list of strings.
%% @end
@@ -703,54 +726,67 @@ read_file(Path) ->
case file:read_file(Path) of
{ok, Binary} ->
{ok, re:split(Binary, <<"\r\n|\n">>, [{return, binary}])};
- {error, _} = Error -> Error
+ {error, _} = Error ->
+ Error
end.
-spec region_from_availability_zone(Value :: string()) -> string().
%% @doc Strip the availability zone suffix from the region.
%% @end
region_from_availability_zone(Value) ->
- string:sub_string(Value, 1, length(Value) - 1).
-
+ string:sub_string(Value, 1, length(Value) - 1).
-spec load_imdsv2_token() -> security_token().
%% @doc Attempt to obtain EC2 IMDSv2 token.
%% @end
load_imdsv2_token() ->
- TokenUrl = imdsv2_token_url(),
- ?LOG_INFO("Attempting to obtain EC2 IMDSv2 token from ~tp ...", [TokenUrl]),
- case httpc:request(put, {TokenUrl, [{?METADATA_TOKEN_TTL_HEADER, integer_to_list(?METADATA_TOKEN_TTL_SECONDS)}]},
- [{timeout, ?DEFAULT_HTTP_TIMEOUT}], []) of
- {ok, {{_, 200, _}, _, Value}} ->
- ?LOG_DEBUG("Successfully obtained EC2 IMDSv2 token."),
- Value;
- {error, {{_, 400, _}, _, _}} ->
- ?LOG_WARNING("Failed to obtain EC2 IMDSv2 token: Missing or Invalid Parameters – The PUT request is not valid."),
- undefined;
- Other ->
- ?LOG_WARNING(
- get_instruction_on_instance_metadata_error("Failed to obtain EC2 IMDSv2 token: ~tp. "
- "Falling back to EC2 IMDSv1 for now. It is recommended to use EC2 IMDSv2."), [Other]),
- undefined
- end.
-
+ TokenUrl = imdsv2_token_url(),
+ ?LOG_INFO("Attempting to obtain EC2 IMDSv2 token from ~tp ...", [TokenUrl]),
+ case
+ httpc:request(
+ put,
+ {TokenUrl, [{?METADATA_TOKEN_TTL_HEADER, integer_to_list(?METADATA_TOKEN_TTL_SECONDS)}]},
+ [{timeout, ?DEFAULT_HTTP_TIMEOUT}],
+ []
+ )
+ of
+ {ok, {{_, 200, _}, _, Value}} ->
+ ?LOG_DEBUG("Successfully obtained EC2 IMDSv2 token."),
+ Value;
+ {error, {{_, 400, _}, _, _}} ->
+ ?LOG_WARNING(
+ "Failed to obtain EC2 IMDSv2 token: Missing or Invalid Parameters – The PUT request is not valid."
+ ),
+ undefined;
+ Other ->
+ ?LOG_WARNING(
+ get_instruction_on_instance_metadata_error(
+ "Failed to obtain EC2 IMDSv2 token: ~tp. "
+ "Falling back to EC2 IMDSv1 for now. It is recommended to use EC2 IMDSv2."
+ ),
+ [Other]
+ ),
+ undefined
+ end.
-spec instance_metadata_request_headers() -> headers().
%% @doc Return headers used for instance metadata service requests.
%% @end
instance_metadata_request_headers() ->
- case application:get_env(rabbit, aws_prefer_imdsv2) of
- {ok, false} -> [];
- _ -> %% undefined or {ok, true}
- ?LOG_DEBUG("EC2 Instance Metadata Service v2 (IMDSv2) is preferred."),
- maybe_imdsv2_token_headers()
- end.
+ case application:get_env(rabbit, aws_prefer_imdsv2) of
+ {ok, false} ->
+ [];
+ %% undefined or {ok, true}
+ _ ->
+ ?LOG_DEBUG("EC2 Instance Metadata Service v2 (IMDSv2) is preferred."),
+ maybe_imdsv2_token_headers()
+ end.
-spec maybe_imdsv2_token_headers() -> headers().
%% @doc Construct http request headers from Imdsv2Token to use with GET requests submitted to the EC2 Instance Metadata Service.
%% @end
maybe_imdsv2_token_headers() ->
- case rabbitmq_aws:ensure_imdsv2_token_valid() of
- undefined -> [];
- Value -> [{?METADATA_TOKEN, Value}]
- end.
+ case rabbitmq_aws:ensure_imdsv2_token_valid() of
+ undefined -> [];
+ Value -> [{?METADATA_TOKEN, Value}]
+ end.
diff --git a/deps/rabbitmq_aws/src/rabbitmq_aws_json.erl b/deps/rabbitmq_aws/src/rabbitmq_aws_json.erl
index 731ce3152c07..6eb994659e6b 100644
--- a/deps/rabbitmq_aws/src/rabbitmq_aws_json.erl
+++ b/deps/rabbitmq_aws/src/rabbitmq_aws_json.erl
@@ -13,46 +13,50 @@
%% @doc Decode a JSON string returning a proplist
%% @end
decode(Value) when is_list(Value) ->
- decode(list_to_binary(Value));
+ decode(list_to_binary(Value));
decode(<<>>) ->
- [];
+ [];
decode(Value) when is_binary(Value) ->
- Decoded0 = rabbit_json:decode(Value),
- Decoded = maps:to_list(Decoded0),
- convert_binary_values(Decoded, []).
-
+ Decoded0 = rabbit_json:decode(Value),
+ Decoded = maps:to_list(Decoded0),
+ convert_binary_values(Decoded, []).
-spec convert_binary_values(Value :: list(), Accumulator :: list()) -> list().
%% @doc Convert the binary key/value pairs returned by rabbit_json to strings.
%% @end
-convert_binary_values([], Value) -> Value;
-convert_binary_values([{K, V}|T], Accum) when is_map(V) ->
- convert_binary_values(
- T,
- lists:append(
- Accum,
- [{binary_to_list(K), convert_binary_values(maps:to_list(V), [])}]));
-convert_binary_values([{K, V}|T], Accum) when is_list(V) ->
- convert_binary_values(
- T,
- lists:append(
- Accum,
- [{binary_to_list(K), convert_binary_values(V, [])}]));
-convert_binary_values([{}|T],Accum) ->
- convert_binary_values(T, [{} | Accum]);
-convert_binary_values([{K, V}|T], Accum) when is_binary(V) ->
- convert_binary_values(T, lists:append(Accum, [{binary_to_list(K), binary_to_list(V)}]));
-convert_binary_values([{K, V}|T], Accum) ->
- convert_binary_values(T, lists:append(Accum, [{binary_to_list(K), V}]));
-convert_binary_values([M|T],Accum) when is_map(M) andalso map_size(M) =:= 0 ->
- convert_binary_values(T, [{} | Accum]);
-convert_binary_values([H|T], Accum) when is_map(H) ->
- convert_binary_values(T, lists:append(Accum, convert_binary_values(maps:to_list(H), [])));
-convert_binary_values([H|T], Accum) when is_binary(H) ->
- convert_binary_values(T, lists:append(Accum, [binary_to_list(H)]));
-convert_binary_values([H|T], Accum) when is_integer(H) ->
- convert_binary_values(T, lists:append(Accum, [H]));
-convert_binary_values([H|T], Accum) when is_atom(H) ->
- convert_binary_values(T, lists:append(Accum, [H]));
-convert_binary_values([H|T], Accum) ->
- convert_binary_values(T, lists:append(Accum, convert_binary_values(H, []))).
+convert_binary_values([], Value) ->
+ Value;
+convert_binary_values([{K, V} | T], Accum) when is_map(V) ->
+ convert_binary_values(
+ T,
+ lists:append(
+ Accum,
+ [{binary_to_list(K), convert_binary_values(maps:to_list(V), [])}]
+ )
+ );
+convert_binary_values([{K, V} | T], Accum) when is_list(V) ->
+ convert_binary_values(
+ T,
+ lists:append(
+ Accum,
+ [{binary_to_list(K), convert_binary_values(V, [])}]
+ )
+ );
+convert_binary_values([{} | T], Accum) ->
+ convert_binary_values(T, [{} | Accum]);
+convert_binary_values([{K, V} | T], Accum) when is_binary(V) ->
+ convert_binary_values(T, lists:append(Accum, [{binary_to_list(K), binary_to_list(V)}]));
+convert_binary_values([{K, V} | T], Accum) ->
+ convert_binary_values(T, lists:append(Accum, [{binary_to_list(K), V}]));
+convert_binary_values([M | T], Accum) when is_map(M) andalso map_size(M) =:= 0 ->
+ convert_binary_values(T, [{} | Accum]);
+convert_binary_values([H | T], Accum) when is_map(H) ->
+ convert_binary_values(T, lists:append(Accum, convert_binary_values(maps:to_list(H), [])));
+convert_binary_values([H | T], Accum) when is_binary(H) ->
+ convert_binary_values(T, lists:append(Accum, [binary_to_list(H)]));
+convert_binary_values([H | T], Accum) when is_integer(H) ->
+ convert_binary_values(T, lists:append(Accum, [H]));
+convert_binary_values([H | T], Accum) when is_atom(H) ->
+ convert_binary_values(T, lists:append(Accum, [H]));
+convert_binary_values([H | T], Accum) ->
+ convert_binary_values(T, lists:append(Accum, convert_binary_values(H, []))).
diff --git a/deps/rabbitmq_aws/src/rabbitmq_aws_sign.erl b/deps/rabbitmq_aws/src/rabbitmq_aws_sign.erl
index 86298d28ca8d..7a95a2b44e77 100644
--- a/deps/rabbitmq_aws/src/rabbitmq_aws_sign.erl
+++ b/deps/rabbitmq_aws/src/rabbitmq_aws_sign.erl
@@ -24,260 +24,292 @@
%% @doc Create the signed request headers
%% end
headers(Request) ->
- RequestTimestamp = local_time(),
- PayloadHash = sha256(Request#request.body),
- URI = rabbitmq_aws_urilib:parse(Request#request.uri),
- {_, Host, _} = URI#uri.authority,
- Headers = append_headers(RequestTimestamp,
- length(Request#request.body),
- PayloadHash,
- Host,
- Request#request.security_token,
- Request#request.headers),
- RequestHash = request_hash(Request#request.method,
- URI#uri.path,
- URI#uri.query,
- Headers,
- Request#request.body),
- AuthValue = authorization(Request#request.access_key,
- Request#request.secret_access_key,
- RequestTimestamp,
- Request#request.region,
- Request#request.service,
- Headers,
- RequestHash),
- sort_headers(lists:merge([{"authorization", AuthValue}], Headers)).
-
+ RequestTimestamp = local_time(),
+ PayloadHash = sha256(Request#request.body),
+ URI = rabbitmq_aws_urilib:parse(Request#request.uri),
+ {_, Host, _} = URI#uri.authority,
+ Headers = append_headers(
+ RequestTimestamp,
+ length(Request#request.body),
+ PayloadHash,
+ Host,
+ Request#request.security_token,
+ Request#request.headers
+ ),
+ RequestHash = request_hash(
+ Request#request.method,
+ URI#uri.path,
+ URI#uri.query,
+ Headers,
+ Request#request.body
+ ),
+ AuthValue = authorization(
+ Request#request.access_key,
+ Request#request.secret_access_key,
+ RequestTimestamp,
+ Request#request.region,
+ Request#request.service,
+ Headers,
+ RequestHash
+ ),
+ sort_headers(lists:merge([{"authorization", AuthValue}], Headers)).
-spec amz_date(AMZTimestamp :: string()) -> string().
%% @doc Extract the date from the AMZ timestamp format.
%% @end
amz_date(AMZTimestamp) ->
- [RequestDate, _] = string:tokens(AMZTimestamp, "T"),
- RequestDate.
-
-
--spec append_headers(AMZDate :: string(),
- ContentLength :: integer(),
- PayloadHash :: string(),
- Hostname :: host(),
- SecurityToken :: security_token(),
- Headers :: headers()) -> list().
+ [RequestDate, _] = string:tokens(AMZTimestamp, "T"),
+ RequestDate.
+
+-spec append_headers(
+ AMZDate :: string(),
+ ContentLength :: integer(),
+ PayloadHash :: string(),
+ Hostname :: host(),
+ SecurityToken :: security_token(),
+ Headers :: headers()
+) -> list().
%% @doc Append the headers that need to be signed to the headers passed in with
%% the request
%% @end
append_headers(AMZDate, ContentLength, PayloadHash, Hostname, SecurityToken, Headers) ->
- Defaults = default_headers(AMZDate, ContentLength, PayloadHash, Hostname, SecurityToken),
- Headers1 = [{string:to_lower(Key), Value} || {Key, Value} <- Headers],
- Keys = lists:usort(lists:append([string:to_lower(Key) || {Key, _} <- Defaults],
- [Key || {Key, _} <- Headers1])),
- sort_headers([{Key, header_value(Key, Headers1, proplists:get_value(Key, Defaults))} || Key <- Keys]).
-
-
--spec authorization(AccessKey :: access_key(),
- SecretAccessKey :: secret_access_key(),
- RequestTimestamp :: string(),
- Region :: region(),
- Service :: string(),
- Headers :: headers(),
- RequestHash :: string()) -> string().
+ Defaults = default_headers(AMZDate, ContentLength, PayloadHash, Hostname, SecurityToken),
+ Headers1 = [{string:to_lower(Key), Value} || {Key, Value} <- Headers],
+ Keys = lists:usort(
+ lists:append(
+ [string:to_lower(Key) || {Key, _} <- Defaults],
+ [Key || {Key, _} <- Headers1]
+ )
+ ),
+ sort_headers([
+ {Key, header_value(Key, Headers1, proplists:get_value(Key, Defaults))}
+ || Key <- Keys
+ ]).
+
+-spec authorization(
+ AccessKey :: access_key(),
+ SecretAccessKey :: secret_access_key(),
+ RequestTimestamp :: string(),
+ Region :: region(),
+ Service :: string(),
+ Headers :: headers(),
+ RequestHash :: string()
+) -> string().
%% @doc Return the authorization header value
%% @end
authorization(AccessKey, SecretAccessKey, RequestTimestamp, Region, Service, Headers, RequestHash) ->
- RequestDate = amz_date(RequestTimestamp),
- Scope = scope(RequestDate, Region, Service),
- Credentials = ?ALGORITHM ++ " Credential=" ++ AccessKey ++ "/" ++ Scope,
- SignedHeaders = "SignedHeaders=" ++ signed_headers(Headers),
- StringToSign = string_to_sign(RequestTimestamp, RequestDate, Region, Service, RequestHash),
- SigningKey = signing_key(SecretAccessKey, RequestDate, Region, Service),
- Signature = string:join(["Signature", signature(StringToSign, SigningKey)], "="),
- string:join([Credentials, SignedHeaders, Signature], ", ").
-
-
--spec default_headers(RequestTimestamp :: string(),
- ContentLength :: integer(),
- PayloadHash :: string(),
- Hostname :: host(),
- SecurityToken :: security_token()) -> headers().
+ RequestDate = amz_date(RequestTimestamp),
+ Scope = scope(RequestDate, Region, Service),
+ Credentials = ?ALGORITHM ++ " Credential=" ++ AccessKey ++ "/" ++ Scope,
+ SignedHeaders = "SignedHeaders=" ++ signed_headers(Headers),
+ StringToSign = string_to_sign(RequestTimestamp, RequestDate, Region, Service, RequestHash),
+ SigningKey = signing_key(SecretAccessKey, RequestDate, Region, Service),
+ Signature = string:join(["Signature", signature(StringToSign, SigningKey)], "="),
+ string:join([Credentials, SignedHeaders, Signature], ", ").
+
+-spec default_headers(
+ RequestTimestamp :: string(),
+ ContentLength :: integer(),
+ PayloadHash :: string(),
+ Hostname :: host(),
+ SecurityToken :: security_token()
+) -> headers().
%% @doc build the base headers that are merged in with the headers for every
%% request.
%% @end
default_headers(RequestTimestamp, ContentLength, PayloadHash, Hostname, undefined) ->
- [{"content-length", integer_to_list(ContentLength)},
- {"date", RequestTimestamp},
- {"host", Hostname},
- {"x-amz-content-sha256", PayloadHash}];
+ [
+ {"content-length", integer_to_list(ContentLength)},
+ {"date", RequestTimestamp},
+ {"host", Hostname},
+ {"x-amz-content-sha256", PayloadHash}
+ ];
default_headers(RequestTimestamp, ContentLength, PayloadHash, Hostname, SecurityToken) ->
- [{"content-length", integer_to_list(ContentLength)},
- {"date", RequestTimestamp},
- {"host", Hostname},
- {"x-amz-content-sha256", PayloadHash},
- {"x-amz-security-token", SecurityToken}].
-
+ [
+ {"content-length", integer_to_list(ContentLength)},
+ {"date", RequestTimestamp},
+ {"host", Hostname},
+ {"x-amz-content-sha256", PayloadHash},
+ {"x-amz-security-token", SecurityToken}
+ ].
-spec canonical_headers(Headers :: headers()) -> string().
%% @doc Convert the headers list to a line-feed delimited string in the AWZ
%% canonical headers format.
%% @end
canonical_headers(Headers) ->
- canonical_headers(sort_headers(Headers), []).
+ canonical_headers(sort_headers(Headers), []).
-spec canonical_headers(Headers :: headers(), CanonicalHeaders :: list()) -> string().
%% @doc Convert the headers list to a line-feed delimited string in the AWZ
%% canonical headers format.
%% @end
canonical_headers([], CanonicalHeaders) ->
- lists:flatten(CanonicalHeaders);
-canonical_headers([{Key, Value}|T], CanonicalHeaders) ->
- Header = string:join([string:to_lower(Key), Value], ":") ++ "\n",
- canonical_headers(T, lists:append(CanonicalHeaders, [Header])).
-
-
--spec credential_scope(RequestDate :: string(),
- Region :: region(),
- Service :: string()) -> string().
+ lists:flatten(CanonicalHeaders);
+canonical_headers([{Key, Value} | T], CanonicalHeaders) ->
+ Header = string:join([string:to_lower(Key), Value], ":") ++ "\n",
+ canonical_headers(T, lists:append(CanonicalHeaders, [Header])).
+
+-spec credential_scope(
+ RequestDate :: string(),
+ Region :: region(),
+ Service :: string()
+) -> string().
%% @doc Return the credential scope string used in creating the request string to sign.
%% @end
credential_scope(RequestDate, Region, Service) ->
- lists:flatten(string:join([RequestDate, Region, Service, "aws4_request"], "/")).
+ lists:flatten(string:join([RequestDate, Region, Service, "aws4_request"], "/")).
-
--spec header_value(Key :: string(),
- Headers :: headers(),
- Default :: string()) -> string().
+-spec header_value(
+ Key :: string(),
+ Headers :: headers(),
+ Default :: string()
+) -> string().
%% @doc Return the the header value or the default value for the header if it
%% is not specified.
%% @end
header_value(Key, Headers, Default) ->
- proplists:get_value(Key, Headers, proplists:get_value(string:to_lower(Key), Headers, Default)).
-
+ proplists:get_value(Key, Headers, proplists:get_value(string:to_lower(Key), Headers, Default)).
-spec hmac_sign(Key :: string(), Message :: string()) -> string().
%% @doc Return the SHA-256 hash for the specified value.
%% @end
hmac_sign(Key, Message) ->
- SignedValue = crypto:mac(hmac, sha256, Key, Message),
- binary_to_list(SignedValue).
-
+ SignedValue = crypto:mac(hmac, sha256, Key, Message),
+ binary_to_list(SignedValue).
-spec local_time() -> string().
%% @doc Return the current timestamp in GMT formatted in ISO8601 basic format.
%% @end
local_time() ->
- [LocalTime] = calendar:local_time_to_universal_time_dst(calendar:local_time()),
- local_time(LocalTime).
-
+ [LocalTime] = calendar:local_time_to_universal_time_dst(calendar:local_time()),
+ local_time(LocalTime).
-spec local_time(calendar:datetime()) -> string().
%% @doc Return the current timestamp in GMT formatted in ISO8601 basic format.
%% @end
-local_time({{Y,M,D},{HH,MM,SS}}) ->
- lists:flatten(io_lib:format(?ISOFORMAT_BASIC, [Y, M, D, HH, MM, SS])).
-
+local_time({{Y, M, D}, {HH, MM, SS}}) ->
+ lists:flatten(io_lib:format(?ISOFORMAT_BASIC, [Y, M, D, HH, MM, SS])).
-spec query_string(QueryArgs :: list()) -> string().
%% @doc Return the sorted query string for the specified arguments.
%% @end
query_string(undefined) -> "";
-query_string(QueryArgs) ->
- rabbitmq_aws_urilib:build_query_string(lists:keysort(1, QueryArgs)).
-
-
--spec request_hash(Method :: method(),
- Path :: path(),
- QArgs :: query_args(),
- Headers :: headers(),
- Payload :: string()) -> string().
+query_string(QueryArgs) -> rabbitmq_aws_urilib:build_query_string(lists:keysort(1, QueryArgs)).
+
+-spec request_hash(
+ Method :: method(),
+ Path :: path(),
+ QArgs :: query_args(),
+ Headers :: headers(),
+ Payload :: string()
+) -> string().
%% @doc Create the request hash value
%% @end
request_hash(Method, Path, QArgs, Headers, Payload) ->
- RawPath = case string:slice(Path, 0, 1) of
- "/" -> Path;
- _ -> "/" ++ Path
- end,
- EncodedPath = uri_string:recompose(#{path => RawPath}),
- CanonicalRequest = string:join([string:to_upper(atom_to_list(Method)),
- EncodedPath,
- query_string(QArgs),
- canonical_headers(Headers),
- signed_headers(Headers),
- sha256(Payload)], "\n"),
- sha256(CanonicalRequest).
-
-
--spec scope(AMZDate :: string(),
- Region :: region(),
- Service :: string()) -> string().
+ RawPath =
+ case string:slice(Path, 0, 1) of
+ "/" -> Path;
+ _ -> "/" ++ Path
+ end,
+ EncodedPath = uri_string:recompose(#{path => RawPath}),
+ CanonicalRequest = string:join(
+ [
+ string:to_upper(atom_to_list(Method)),
+ EncodedPath,
+ query_string(QArgs),
+ canonical_headers(Headers),
+ signed_headers(Headers),
+ sha256(Payload)
+ ],
+ "\n"
+ ),
+ sha256(CanonicalRequest).
+
+-spec scope(
+ AMZDate :: string(),
+ Region :: region(),
+ Service :: string()
+) -> string().
%% @doc Create the Scope string
%% @end
scope(AMZDate, Region, Service) ->
- string:join([AMZDate, Region, Service, "aws4_request"], "/").
-
+ string:join([AMZDate, Region, Service, "aws4_request"], "/").
-spec sha256(Value :: string()) -> string().
%% @doc Return the SHA-256 hash for the specified value.
%% @end
sha256(Value) ->
- lists:flatten(io_lib:format("~64.16.0b",
- [binary:decode_unsigned(crypto:hash(sha256, Value))])).
-
+ lists:flatten(
+ io_lib:format(
+ "~64.16.0b",
+ [binary:decode_unsigned(crypto:hash(sha256, Value))]
+ )
+ ).
-spec signed_headers(Headers :: list()) -> string().
%% @doc Return the signed headers string of delimited header key names
%% @end
signed_headers(Headers) ->
- signed_headers(sort_headers(Headers), []).
-
+ signed_headers(sort_headers(Headers), []).
-spec signed_headers(Headers :: headers(), Values :: list()) -> string().
%% @doc Return the signed headers string of delimited header key names
%% @end
-signed_headers([], SignedHeaders) -> string:join(SignedHeaders, ";");
-signed_headers([{Key,_}|T], SignedHeaders) ->
- signed_headers(T, SignedHeaders ++ [string:to_lower(Key)]).
-
-
--spec signature(StringToSign :: string(),
- SigningKey :: string()) -> string().
+signed_headers([], SignedHeaders) ->
+ string:join(SignedHeaders, ";");
+signed_headers([{Key, _} | T], SignedHeaders) ->
+ signed_headers(T, SignedHeaders ++ [string:to_lower(Key)]).
+
+-spec signature(
+ StringToSign :: string(),
+ SigningKey :: string()
+) -> string().
%% @doc Create the request signature.
%% @end
signature(StringToSign, SigningKey) ->
- SignedValue = crypto:mac(hmac, sha256, SigningKey, StringToSign),
- lists:flatten(io_lib:format("~64.16.0b", [binary:decode_unsigned(SignedValue)])).
-
-
--spec signing_key(SecretKey :: secret_access_key(),
- AMZDate :: string(),
- Region :: region(),
- Service :: string()) -> string().
+ SignedValue = crypto:mac(hmac, sha256, SigningKey, StringToSign),
+ lists:flatten(io_lib:format("~64.16.0b", [binary:decode_unsigned(SignedValue)])).
+
+-spec signing_key(
+ SecretKey :: secret_access_key(),
+ AMZDate :: string(),
+ Region :: region(),
+ Service :: string()
+) -> string().
%% @doc Create the signing key
%% @end
signing_key(SecretKey, AMZDate, Region, Service) ->
- DateKey = hmac_sign("AWS4" ++ SecretKey, AMZDate),
- RegionKey = hmac_sign(DateKey, Region),
- ServiceKey = hmac_sign(RegionKey, Service),
- hmac_sign(ServiceKey, "aws4_request").
-
-
--spec string_to_sign(RequestTimestamp :: string(),
- RequestDate :: string(),
- Region :: region(),
- Service :: string(),
- RequestHash :: string()) -> string().
+ DateKey = hmac_sign("AWS4" ++ SecretKey, AMZDate),
+ RegionKey = hmac_sign(DateKey, Region),
+ ServiceKey = hmac_sign(RegionKey, Service),
+ hmac_sign(ServiceKey, "aws4_request").
+
+-spec string_to_sign(
+ RequestTimestamp :: string(),
+ RequestDate :: string(),
+ Region :: region(),
+ Service :: string(),
+ RequestHash :: string()
+) -> string().
%% @doc Return the string to sign when creating the signed request.
%% @end
string_to_sign(RequestTimestamp, RequestDate, Region, Service, RequestHash) ->
- CredentialScope = credential_scope(RequestDate, Region, Service),
- lists:flatten(string:join([
- ?ALGORITHM,
- RequestTimestamp,
- CredentialScope,
- RequestHash
- ], "\n")).
-
+ CredentialScope = credential_scope(RequestDate, Region, Service),
+ lists:flatten(
+ string:join(
+ [
+ ?ALGORITHM,
+ RequestTimestamp,
+ CredentialScope,
+ RequestHash
+ ],
+ "\n"
+ )
+ ).
-spec sort_headers(Headers :: headers()) -> headers().
%% @doc Case-insensitive sorting of the request headers
%% @end
sort_headers(Headers) ->
- lists:sort(fun({A,_}, {B, _}) -> string:to_lower(A) =< string:to_lower(B) end, Headers).
+ lists:sort(fun({A, _}, {B, _}) -> string:to_lower(A) =< string:to_lower(B) end, Headers).
diff --git a/deps/rabbitmq_aws/src/rabbitmq_aws_sup.erl b/deps/rabbitmq_aws/src/rabbitmq_aws_sup.erl
index 6327b2029ddd..7c4900f7abb6 100644
--- a/deps/rabbitmq_aws/src/rabbitmq_aws_sup.erl
+++ b/deps/rabbitmq_aws/src/rabbitmq_aws_sup.erl
@@ -8,13 +8,15 @@
-behaviour(supervisor).
--export([start_link/0,
- init/1]).
+-export([
+ start_link/0,
+ init/1
+]).
-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5, Type, [I]}).
start_link() ->
- supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
- {ok, {{one_for_one, 5, 10}, [?CHILD(rabbitmq_aws, worker)]}}.
+ {ok, {{one_for_one, 5, 10}, [?CHILD(rabbitmq_aws, worker)]}}.
diff --git a/deps/rabbitmq_aws/src/rabbitmq_aws_urilib.erl b/deps/rabbitmq_aws/src/rabbitmq_aws_urilib.erl
index d89b372f38a5..f1bc7b5a2d2c 100644
--- a/deps/rabbitmq_aws/src/rabbitmq_aws_urilib.erl
+++ b/deps/rabbitmq_aws/src/rabbitmq_aws_urilib.erl
@@ -7,12 +7,13 @@
%% ====================================================================
-module(rabbitmq_aws_urilib).
--export([build/1,
- build_query_string/1,
- parse/1,
- parse_userinfo/1,
- parse_userinfo_result/1
- ]).
+-export([
+ build/1,
+ build_query_string/1,
+ parse/1,
+ parse_userinfo/1,
+ parse_userinfo_result/1
+]).
%% Export all for unit tests
-ifdef(TEST).
@@ -25,77 +26,83 @@
%% @doc Build a URI string
%% @end
build(URI) ->
- {UserInfo, Host, Port} = URI#uri.authority,
- UriMap = #{
- scheme => to_list(URI#uri.scheme),
- host => Host
- },
- UriMap1 = case UserInfo of
- undefined -> UriMap;
- {User, undefined} -> maps:put(userinfo, User, UriMap);
- {User, Password} -> maps:put(userinfo, User ++ ":" ++ Password, UriMap)
- end,
- UriMap2 = case Port of
- undefined -> UriMap1;
- Value1 -> maps:put(port, Value1, UriMap1)
- end,
- UriMap3 = case URI#uri.path of
- undefined -> maps:put(path, "", UriMap2);
- Value2 ->
- PrefixedPath = case string:slice(Value2, 0, 1) of
- "/" -> Value2;
- _ -> "/" ++ Value2
- end,
- maps:put(path, PrefixedPath, UriMap2)
- end,
- UriMap4 = case URI#uri.query of
- undefined -> UriMap3;
- "" -> UriMap3;
- Value3 -> maps:put(query, build_query_string(Value3), UriMap3)
- end,
- UriMap5 = case URI#uri.fragment of
- undefined -> UriMap4;
- Value4 -> maps:put(fragment, Value4, UriMap4)
- end,
- uri_string:recompose(UriMap5).
+ {UserInfo, Host, Port} = URI#uri.authority,
+ UriMap = #{
+ scheme => to_list(URI#uri.scheme),
+ host => Host
+ },
+ UriMap1 =
+ case UserInfo of
+ undefined -> UriMap;
+ {User, undefined} -> maps:put(userinfo, User, UriMap);
+ {User, Password} -> maps:put(userinfo, User ++ ":" ++ Password, UriMap)
+ end,
+ UriMap2 =
+ case Port of
+ undefined -> UriMap1;
+ Value1 -> maps:put(port, Value1, UriMap1)
+ end,
+ UriMap3 =
+ case URI#uri.path of
+ undefined ->
+ maps:put(path, "", UriMap2);
+ Value2 ->
+ PrefixedPath =
+ case string:slice(Value2, 0, 1) of
+ "/" -> Value2;
+ _ -> "/" ++ Value2
+ end,
+ maps:put(path, PrefixedPath, UriMap2)
+ end,
+ UriMap4 =
+ case URI#uri.query of
+ undefined -> UriMap3;
+ "" -> UriMap3;
+ Value3 -> maps:put(query, build_query_string(Value3), UriMap3)
+ end,
+ UriMap5 =
+ case URI#uri.fragment of
+ undefined -> UriMap4;
+ Value4 -> maps:put(fragment, Value4, UriMap4)
+ end,
+ uri_string:recompose(UriMap5).
-spec parse(string()) -> #uri{} | {error, any()}.
%% @doc Parse a URI string returning a record with the parsed results
%% @end
parse(Value) ->
- UriMap = uri_string:parse(Value),
- Scheme = maps:get(scheme, UriMap, "https"),
- Host = maps:get(host, UriMap),
+ UriMap = uri_string:parse(Value),
+ Scheme = maps:get(scheme, UriMap, "https"),
+ Host = maps:get(host, UriMap),
- DefaultPort = case Scheme of
- "http" -> 80;
- "https" -> 443;
- _ -> undefined
- end,
- Port = maps:get(port, UriMap, DefaultPort),
- UserInfo = parse_userinfo(maps:get(userinfo, UriMap, undefined)),
- Path = maps:get(path, UriMap),
- Query = maps:get(query, UriMap, ""),
- #uri{scheme = Scheme,
- authority = {parse_userinfo(UserInfo), Host, Port},
- path = Path,
- query = uri_string:dissect_query(Query),
- fragment = maps:get(fragment, UriMap, undefined)
- }.
+ DefaultPort =
+ case Scheme of
+ "http" -> 80;
+ "https" -> 443;
+ _ -> undefined
+ end,
+ Port = maps:get(port, UriMap, DefaultPort),
+ UserInfo = parse_userinfo(maps:get(userinfo, UriMap, undefined)),
+ Path = maps:get(path, UriMap),
+ Query = maps:get(query, UriMap, ""),
+ #uri{
+ scheme = Scheme,
+ authority = {parse_userinfo(UserInfo), Host, Port},
+ path = Path,
+ query = uri_string:dissect_query(Query),
+ fragment = maps:get(fragment, UriMap, undefined)
+ }.
-
--spec parse_userinfo(string() | undefined)
- -> {username() | undefined, password() | undefined} | undefined.
+-spec parse_userinfo(string() | undefined) ->
+ {username() | undefined, password() | undefined} | undefined.
parse_userinfo(undefined) -> undefined;
parse_userinfo([]) -> undefined;
parse_userinfo({User, undefined}) -> {User, undefined};
-parse_userinfo({User, Password}) -> {User, Password};
-parse_userinfo(Value) ->
- parse_userinfo_result(string:tokens(Value, ":")).
-
+parse_userinfo({User, Password}) -> {User, Password};
+parse_userinfo(Value) -> parse_userinfo_result(string:tokens(Value, ":")).
--spec parse_userinfo_result(list())
- -> {username() | undefined, password() | undefined} | undefined.
+-spec parse_userinfo_result(list()) ->
+ {username() | undefined, password() | undefined} | undefined.
parse_userinfo_result([User, Password]) -> {User, Password};
parse_userinfo_result([User]) -> {User, undefined};
parse_userinfo_result({User, undefined}) -> {User, undefined};
@@ -110,12 +117,12 @@ parse_userinfo_result(User) -> {User, undefined}.
-spec build_query_string([{any(), any()}]) -> string().
build_query_string(Args) when is_list(Args) ->
- Normalized = [{to_list(K), to_list(V)} || {K, V} <- Args],
- uri_string:compose_query(Normalized).
+ Normalized = [{to_list(K), to_list(V)} || {K, V} <- Args],
+ uri_string:compose_query(Normalized).
-spec to_list(Val :: integer() | list() | binary() | atom() | map()) -> list().
-to_list(Val) when is_list(Val) -> Val;
-to_list(Val) when is_map(Val) -> maps:to_list(Val);
-to_list(Val) when is_atom(Val) -> atom_to_list(Val);
-to_list(Val) when is_binary(Val) -> binary_to_list(Val);
+to_list(Val) when is_list(Val) -> Val;
+to_list(Val) when is_map(Val) -> maps:to_list(Val);
+to_list(Val) when is_atom(Val) -> atom_to_list(Val);
+to_list(Val) when is_binary(Val) -> binary_to_list(Val);
to_list(Val) when is_integer(Val) -> integer_to_list(Val).
diff --git a/deps/rabbitmq_aws/src/rabbitmq_aws_xml.erl b/deps/rabbitmq_aws/src/rabbitmq_aws_xml.erl
index fc3be5c642a8..250fc1fc882e 100644
--- a/deps/rabbitmq_aws/src/rabbitmq_aws_xml.erl
+++ b/deps/rabbitmq_aws/src/rabbitmq_aws_xml.erl
@@ -12,35 +12,32 @@
-spec parse(Value :: string() | binary()) -> list().
parse(Value) ->
- {Element, _} = xmerl_scan:string(Value),
- parse_node(Element).
+ {Element, _} = xmerl_scan:string(Value),
+ parse_node(Element).
+parse_node(#xmlElement{name = Name, content = Content}) ->
+ Value = parse_content(Content, []),
+ [{atom_to_list(Name), flatten_value(Value, Value)}].
-parse_node(#xmlElement{name=Name, content=Content}) ->
- Value = parse_content(Content, []),
- [{atom_to_list(Name), flatten_value(Value, Value)}].
-
-
-flatten_text([], Value) -> Value;
-flatten_text([{K,V}|T], Accum) when is_list(V) ->
+flatten_text([], Value) ->
+ Value;
+flatten_text([{K, V} | T], Accum) when is_list(V) ->
flatten_text(T, lists:append([{K, V}], Accum));
flatten_text([H | T], Accum) when is_list(H) ->
flatten_text(T, lists:append(T, Accum)).
-
flatten_value([L], _) when is_list(L) -> L;
flatten_value(L, _) when is_list(L) -> flatten_text(L, []).
-
-parse_content([], Value) -> Value;
+parse_content([], Value) ->
+ Value;
parse_content(#xmlElement{} = Element, Accum) ->
- lists:append(parse_node(Element), Accum);
-parse_content(#xmlText{value=Value}, Accum) ->
- case string:strip(Value) of
- "" -> Accum;
- "\n" -> Accum;
- Stripped ->
- lists:append([Stripped], Accum)
- end;
-parse_content([H|T], Accum) ->
- parse_content(T, parse_content(H, Accum)).
+ lists:append(parse_node(Element), Accum);
+parse_content(#xmlText{value = Value}, Accum) ->
+ case string:strip(Value) of
+ "" -> Accum;
+ "\n" -> Accum;
+ Stripped -> lists:append([Stripped], Accum)
+ end;
+parse_content([H | T], Accum) ->
+ parse_content(T, parse_content(H, Accum)).
diff --git a/deps/rabbitmq_aws/test/rabbitmq_aws_all_tests.erl b/deps/rabbitmq_aws/test/rabbitmq_aws_all_tests.erl
index 1273e14f8bfe..ad2e497eb91f 100644
--- a/deps/rabbitmq_aws/test/rabbitmq_aws_all_tests.erl
+++ b/deps/rabbitmq_aws/test/rabbitmq_aws_all_tests.erl
@@ -5,14 +5,14 @@
-include_lib("eunit/include/eunit.hrl").
run() ->
- Result = {
- eunit:test(rabbitmq_aws_app_tests, [verbose]),
- eunit:test(rabbitmq_aws_config_tests, [verbose]),
- eunit:test(rabbitmq_aws_json_tests, [verbose]),
- eunit:test(rabbitmq_aws_sign_tests, [verbose]),
- eunit:test(rabbitmq_aws_sup_tests, [verbose]),
- eunit:test(rabbitmq_aws_tests, [verbose]),
- eunit:test(rabbitmq_aws_urilib_tests, [verbose]),
- eunit:test(rabbitmq_aws_xml_tests, [verbose])
- },
- ?assertEqual({ok, ok, ok, ok, ok, ok, ok, ok}, Result).
+ Result = {
+ eunit:test(rabbitmq_aws_app_tests, [verbose]),
+ eunit:test(rabbitmq_aws_config_tests, [verbose]),
+ eunit:test(rabbitmq_aws_json_tests, [verbose]),
+ eunit:test(rabbitmq_aws_sign_tests, [verbose]),
+ eunit:test(rabbitmq_aws_sup_tests, [verbose]),
+ eunit:test(rabbitmq_aws_tests, [verbose]),
+ eunit:test(rabbitmq_aws_urilib_tests, [verbose]),
+ eunit:test(rabbitmq_aws_xml_tests, [verbose])
+ },
+ ?assertEqual({ok, ok, ok, ok, ok, ok, ok, ok}, Result).
diff --git a/deps/rabbitmq_aws/test/rabbitmq_aws_app_tests.erl b/deps/rabbitmq_aws/test/rabbitmq_aws_app_tests.erl
index ced4c0065b4d..ccb95aa52738 100644
--- a/deps/rabbitmq_aws/test/rabbitmq_aws_app_tests.erl
+++ b/deps/rabbitmq_aws/test/rabbitmq_aws_app_tests.erl
@@ -3,22 +3,23 @@
-include_lib("eunit/include/eunit.hrl").
start_test_() ->
- {foreach,
- fun() ->
- meck:new(rabbitmq_aws_sup, [passthrough])
- end,
- fun(_) ->
- meck:unload(rabbitmq_aws_sup)
- end,
- [
- {"supervisor initialized", fun() ->
- meck:expect(rabbitmq_aws_sup, start_link, fun() -> {ok, test_result} end),
- ?assertEqual({ok, test_result},
- rabbitmq_aws_app:start(temporary, [])),
- meck:validate(rabbitmq_aws_sup)
- end}
- ]
- }.
+ {foreach,
+ fun() ->
+ meck:new(rabbitmq_aws_sup, [passthrough])
+ end,
+ fun(_) ->
+ meck:unload(rabbitmq_aws_sup)
+ end,
+ [
+ {"supervisor initialized", fun() ->
+ meck:expect(rabbitmq_aws_sup, start_link, fun() -> {ok, test_result} end),
+ ?assertEqual(
+ {ok, test_result},
+ rabbitmq_aws_app:start(temporary, [])
+ ),
+ meck:validate(rabbitmq_aws_sup)
+ end}
+ ]}.
stop_test() ->
- ?assertEqual(ok, rabbitmq_aws_app:stop({})).
+ ?assertEqual(ok, rabbitmq_aws_app:stop({})).
diff --git a/deps/rabbitmq_aws/test/rabbitmq_aws_config_tests.erl b/deps/rabbitmq_aws/test/rabbitmq_aws_config_tests.erl
index c8329f280c07..cca1b4af8231 100644
--- a/deps/rabbitmq_aws/test/rabbitmq_aws_config_tests.erl
+++ b/deps/rabbitmq_aws/test/rabbitmq_aws_config_tests.erl
@@ -4,442 +4,535 @@
-include("rabbitmq_aws.hrl").
-
config_file_test_() ->
- [
- {"from environment variable", fun() ->
- os:putenv("AWS_CONFIG_FILE", "/etc/aws/config"),
- ?assertEqual("/etc/aws/config", rabbitmq_aws_config:config_file())
- end},
- {"default without environment variable", fun() ->
- os:unsetenv("AWS_CONFIG_FILE"),
- os:putenv("HOME", "/home/rrabbit"),
- ?assertEqual("/home/rrabbit/.aws/config",
- rabbitmq_aws_config:config_file())
- end}
- ].
+ [
+ {"from environment variable", fun() ->
+ os:putenv("AWS_CONFIG_FILE", "/etc/aws/config"),
+ ?assertEqual("/etc/aws/config", rabbitmq_aws_config:config_file())
+ end},
+ {"default without environment variable", fun() ->
+ os:unsetenv("AWS_CONFIG_FILE"),
+ os:putenv("HOME", "/home/rrabbit"),
+ ?assertEqual(
+ "/home/rrabbit/.aws/config",
+ rabbitmq_aws_config:config_file()
+ )
+ end}
+ ].
config_file_data_test_() ->
- [
- {"successfully parses ini", fun() ->
- setup_test_config_env_var(),
- Expectation = [
- {"default",
- [{aws_access_key_id, "default-key"},
- {aws_secret_access_key, "default-access-key"},
- {region, "us-east-4"}]},
- {"profile testing",
- [{aws_access_key_id, "foo1"},
- {aws_secret_access_key, "bar2"},
- {s3, [{max_concurrent_requests, 10},
- {max_queue_size, 1000}]},
- {region, "us-west-5"}]},
- {"profile no-region",
- [{aws_access_key_id, "foo2"},
- {aws_secret_access_key, "bar3"}]},
- {"profile only-key",
- [{aws_access_key_id, "foo3"}]},
- {"profile only-secret",
- [{aws_secret_access_key, "foo4"}]},
- {"profile bad-entry",
- [{aws_secret_access, "foo5"}]}
- ],
- ?assertEqual(Expectation,
- rabbitmq_aws_config:config_file_data())
- end},
- {"file does not exist", fun() ->
- ?assertEqual({error, enoent},
- rabbitmq_aws_config:ini_file_data(filename:join([filename:absname("."), "bad_path"]), false))
- end
- },
- {"file exists but path is invalid", fun() ->
- ?assertEqual({error, enoent},
- rabbitmq_aws_config:ini_file_data(filename:join([filename:absname("."), "bad_path"]), true))
- end
- }
- ].
-
+ [
+ {"successfully parses ini", fun() ->
+ setup_test_config_env_var(),
+ Expectation = [
+ {"default", [
+ {aws_access_key_id, "default-key"},
+ {aws_secret_access_key, "default-access-key"},
+ {region, "us-east-4"}
+ ]},
+ {"profile testing", [
+ {aws_access_key_id, "foo1"},
+ {aws_secret_access_key, "bar2"},
+ {s3, [
+ {max_concurrent_requests, 10},
+ {max_queue_size, 1000}
+ ]},
+ {region, "us-west-5"}
+ ]},
+ {"profile no-region", [
+ {aws_access_key_id, "foo2"},
+ {aws_secret_access_key, "bar3"}
+ ]},
+ {"profile only-key", [{aws_access_key_id, "foo3"}]},
+ {"profile only-secret", [{aws_secret_access_key, "foo4"}]},
+ {"profile bad-entry", [{aws_secret_access, "foo5"}]}
+ ],
+ ?assertEqual(
+ Expectation,
+ rabbitmq_aws_config:config_file_data()
+ )
+ end},
+ {"file does not exist", fun() ->
+ ?assertEqual(
+ {error, enoent},
+ rabbitmq_aws_config:ini_file_data(
+ filename:join([filename:absname("."), "bad_path"]), false
+ )
+ )
+ end},
+ {"file exists but path is invalid", fun() ->
+ ?assertEqual(
+ {error, enoent},
+ rabbitmq_aws_config:ini_file_data(
+ filename:join([filename:absname("."), "bad_path"]), true
+ )
+ )
+ end}
+ ].
instance_metadata_test_() ->
- [
- {"instance role URL", fun() ->
- ?assertEqual("http://169.254.169.254/latest/meta-data/iam/security-credentials",
- rabbitmq_aws_config:instance_role_url())
- end},
- {"availability zone URL", fun() ->
- ?assertEqual("http://169.254.169.254/latest/meta-data/placement/availability-zone",
- rabbitmq_aws_config:instance_availability_zone_url())
- end},
- {"instance id URL", fun() ->
- ?assertEqual("http://169.254.169.254/latest/meta-data/instance-id",
- rabbitmq_aws_config:instance_id_url())
- end},
- {"arbitrary paths", fun () ->
- ?assertEqual("http://169.254.169.254/a/b/c", rabbitmq_aws_config:instance_metadata_url("a/b/c")),
- ?assertEqual("http://169.254.169.254/a/b/c", rabbitmq_aws_config:instance_metadata_url("/a/b/c"))
- end}
- ].
+ [
+ {"instance role URL", fun() ->
+ ?assertEqual(
+ "http://169.254.169.254/latest/meta-data/iam/security-credentials",
+ rabbitmq_aws_config:instance_role_url()
+ )
+ end},
+ {"availability zone URL", fun() ->
+ ?assertEqual(
+ "http://169.254.169.254/latest/meta-data/placement/availability-zone",
+ rabbitmq_aws_config:instance_availability_zone_url()
+ )
+ end},
+ {"instance id URL", fun() ->
+ ?assertEqual(
+ "http://169.254.169.254/latest/meta-data/instance-id",
+ rabbitmq_aws_config:instance_id_url()
+ )
+ end},
+ {"arbitrary paths", fun() ->
+ ?assertEqual(
+ "http://169.254.169.254/a/b/c", rabbitmq_aws_config:instance_metadata_url("a/b/c")
+ ),
+ ?assertEqual(
+ "http://169.254.169.254/a/b/c", rabbitmq_aws_config:instance_metadata_url("/a/b/c")
+ )
+ end}
+ ].
credentials_file_test_() ->
- [
- {"from environment variable", fun() ->
- os:putenv("AWS_SHARED_CREDENTIALS_FILE", "/etc/aws/credentials"),
- ?assertEqual("/etc/aws/credentials", rabbitmq_aws_config:credentials_file())
- end},
- {"default without environment variable", fun() ->
- os:unsetenv("AWS_SHARED_CREDENTIALS_FILE"),
- os:putenv("HOME", "/home/rrabbit"),
- ?assertEqual("/home/rrabbit/.aws/credentials",
- rabbitmq_aws_config:credentials_file())
- end}
- ].
-
-
-credentials_test_() ->
- {
- foreach,
- fun () ->
- meck:new(httpc),
- meck:new(rabbitmq_aws),
- reset_environment(),
- [httpc, rabbitmq_aws]
- end,
- fun meck:unload/1,
[
- {"from environment variables", fun() ->
- os:putenv("AWS_ACCESS_KEY_ID", "Sésame"),
- os:putenv("AWS_SECRET_ACCESS_KEY", "ouvre-toi"),
- ?assertEqual({ok, "Sésame", "ouvre-toi", undefined, undefined},
- rabbitmq_aws_config:credentials())
- end},
- {"from config file with default profile", fun() ->
- setup_test_config_env_var(),
- ?assertEqual({ok, "default-key", "default-access-key", undefined, undefined},
- rabbitmq_aws_config:credentials())
- end},
- {"with missing environment variable", fun() ->
- os:putenv("AWS_ACCESS_KEY_ID", "Sésame"),
- meck:sequence(rabbitmq_aws, ensure_imdsv2_token_valid, 0, "secret_imdsv2_token"),
- ?assertEqual({error, undefined},
- rabbitmq_aws_config:credentials())
- end},
- {"from config file with default profile", fun() ->
- setup_test_config_env_var(),
- ?assertEqual({ok, "default-key", "default-access-key", undefined, undefined},
- rabbitmq_aws_config:credentials())
- end},
- {"from config file with profile", fun() ->
- setup_test_config_env_var(),
- ?assertEqual({ok, "foo1", "bar2", undefined, undefined},
- rabbitmq_aws_config:credentials("testing"))
- end},
- {"from config file with bad profile", fun() ->
- setup_test_config_env_var(),
- meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
- ?assertEqual({error, undefined},
- rabbitmq_aws_config:credentials("bad-profile-name"))
- end},
- {"from credentials file with default profile", fun() ->
- setup_test_credentials_env_var(),
-
- ?assertEqual({ok, "foo1", "bar1", undefined, undefined},
- rabbitmq_aws_config:credentials())
- end},
- {"from credentials file with profile", fun() ->
- setup_test_credentials_env_var(),
- ?assertEqual({ok, "foo2", "bar2", undefined, undefined},
- rabbitmq_aws_config:credentials("development"))
- end},
- {"from credentials file with bad profile", fun() ->
- setup_test_credentials_env_var(),
- meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
- ?assertEqual({error, undefined},
- rabbitmq_aws_config:credentials("bad-profile-name"))
- end},
- {"from credentials file with only the key in profile", fun() ->
- setup_test_credentials_env_var(),
- meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
- ?assertEqual({error, undefined},
- rabbitmq_aws_config:credentials("only-key"))
- end},
- {"from credentials file with only the value in profile", fun() ->
- setup_test_credentials_env_var(),
- meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
- ?assertEqual({error, undefined},
- rabbitmq_aws_config:credentials("only-value"))
- end},
- {"from credentials file with missing keys in profile", fun() ->
- setup_test_credentials_env_var(),
- meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
- ?assertEqual({error, undefined},
- rabbitmq_aws_config:credentials("bad-entry"))
- end},
- {"from instance metadata service", fun() ->
- CredsBody = "{\n \"Code\" : \"Success\",\n \"LastUpdated\" : \"2016-03-31T21:51:49Z\",\n \"Type\" : \"AWS-HMAC\",\n \"AccessKeyId\" : \"ASIAIMAFAKEACCESSKEY\",\n \"SecretAccessKey\" : \"2+t64tZZVaz0yp0x1G23ZRYn+FAKEyVALUEs/4qh\",\n \"Token\" : \"FAKE//////////wEAK/TOKEN/VALUE=\",\n \"Expiration\" : \"2016-04-01T04:13:28Z\"\n}",
- meck:sequence(httpc, request, 4,
- [{ok, {{protocol, 200, message}, headers, "Bob"}},
- {ok, {{protocol, 200, message}, headers, CredsBody}}]),
- meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
- Expectation = {ok, "ASIAIMAFAKEACCESSKEY", "2+t64tZZVaz0yp0x1G23ZRYn+FAKEyVALUEs/4qh",
- {{2016,4,1},{4,13,28}}, "FAKE//////////wEAK/TOKEN/VALUE="},
- ?assertEqual(Expectation, rabbitmq_aws_config:credentials())
- end
- },
- {"with instance metadata service role error", fun() ->
- meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
- meck:expect(httpc, request, 4, {error, timeout}),
- ?assertEqual({error, undefined}, rabbitmq_aws_config:credentials())
- end
- },
- {"with instance metadata service role http error", fun() ->
- meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
- meck:expect(httpc, request, 4,
- {ok, {{protocol, 500, message}, headers, "Internal Server Error"}}),
- ?assertEqual({error, undefined}, rabbitmq_aws_config:credentials())
- end
- },
- {"with instance metadata service credentials error", fun() ->
- meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
- meck:sequence(httpc, request, 4,
- [{ok, {{protocol, 200, message}, headers, "Bob"}},
- {error, timeout}]),
- ?assertEqual({error, undefined}, rabbitmq_aws_config:credentials())
- end
- },
- {"with instance metadata service credentials not found", fun() ->
- meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
- meck:sequence(httpc, request, 4,
- [{ok, {{protocol, 200, message}, headers, "Bob"}},
- {ok, {{protocol, 404, message}, headers, "File Not Found"}}]),
- ?assertEqual({error, undefined}, rabbitmq_aws_config:credentials())
- end
- }
-
- ]}.
+ {"from environment variable", fun() ->
+ os:putenv("AWS_SHARED_CREDENTIALS_FILE", "/etc/aws/credentials"),
+ ?assertEqual("/etc/aws/credentials", rabbitmq_aws_config:credentials_file())
+ end},
+ {"default without environment variable", fun() ->
+ os:unsetenv("AWS_SHARED_CREDENTIALS_FILE"),
+ os:putenv("HOME", "/home/rrabbit"),
+ ?assertEqual(
+ "/home/rrabbit/.aws/credentials",
+ rabbitmq_aws_config:credentials_file()
+ )
+ end}
+ ].
+credentials_test_() ->
+ {
+ foreach,
+ fun() ->
+ meck:new(httpc),
+ meck:new(rabbitmq_aws),
+ reset_environment(),
+ [httpc, rabbitmq_aws]
+ end,
+ fun meck:unload/1,
+ [
+ {"from environment variables", fun() ->
+ os:putenv("AWS_ACCESS_KEY_ID", "Sésame"),
+ os:putenv("AWS_SECRET_ACCESS_KEY", "ouvre-toi"),
+ ?assertEqual(
+ {ok, "Sésame", "ouvre-toi", undefined, undefined},
+ rabbitmq_aws_config:credentials()
+ )
+ end},
+ {"from config file with default profile", fun() ->
+ setup_test_config_env_var(),
+ ?assertEqual(
+ {ok, "default-key", "default-access-key", undefined, undefined},
+ rabbitmq_aws_config:credentials()
+ )
+ end},
+ {"with missing environment variable", fun() ->
+ os:putenv("AWS_ACCESS_KEY_ID", "Sésame"),
+ meck:sequence(rabbitmq_aws, ensure_imdsv2_token_valid, 0, "secret_imdsv2_token"),
+ ?assertEqual(
+ {error, undefined},
+ rabbitmq_aws_config:credentials()
+ )
+ end},
+ {"from config file with default profile", fun() ->
+ setup_test_config_env_var(),
+ ?assertEqual(
+ {ok, "default-key", "default-access-key", undefined, undefined},
+ rabbitmq_aws_config:credentials()
+ )
+ end},
+ {"from config file with profile", fun() ->
+ setup_test_config_env_var(),
+ ?assertEqual(
+ {ok, "foo1", "bar2", undefined, undefined},
+ rabbitmq_aws_config:credentials("testing")
+ )
+ end},
+ {"from config file with bad profile", fun() ->
+ setup_test_config_env_var(),
+ meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
+ ?assertEqual(
+ {error, undefined},
+ rabbitmq_aws_config:credentials("bad-profile-name")
+ )
+ end},
+ {"from credentials file with default profile", fun() ->
+ setup_test_credentials_env_var(),
+
+ ?assertEqual(
+ {ok, "foo1", "bar1", undefined, undefined},
+ rabbitmq_aws_config:credentials()
+ )
+ end},
+ {"from credentials file with profile", fun() ->
+ setup_test_credentials_env_var(),
+ ?assertEqual(
+ {ok, "foo2", "bar2", undefined, undefined},
+ rabbitmq_aws_config:credentials("development")
+ )
+ end},
+ {"from credentials file with bad profile", fun() ->
+ setup_test_credentials_env_var(),
+ meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
+ ?assertEqual(
+ {error, undefined},
+ rabbitmq_aws_config:credentials("bad-profile-name")
+ )
+ end},
+ {"from credentials file with only the key in profile", fun() ->
+ setup_test_credentials_env_var(),
+ meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
+ ?assertEqual(
+ {error, undefined},
+ rabbitmq_aws_config:credentials("only-key")
+ )
+ end},
+ {"from credentials file with only the value in profile", fun() ->
+ setup_test_credentials_env_var(),
+ meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
+ ?assertEqual(
+ {error, undefined},
+ rabbitmq_aws_config:credentials("only-value")
+ )
+ end},
+ {"from credentials file with missing keys in profile", fun() ->
+ setup_test_credentials_env_var(),
+ meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
+ ?assertEqual(
+ {error, undefined},
+ rabbitmq_aws_config:credentials("bad-entry")
+ )
+ end},
+ {"from instance metadata service", fun() ->
+ CredsBody =
+ "{\n \"Code\" : \"Success\",\n \"LastUpdated\" : \"2016-03-31T21:51:49Z\",\n \"Type\" : \"AWS-HMAC\",\n \"AccessKeyId\" : \"ASIAIMAFAKEACCESSKEY\",\n \"SecretAccessKey\" : \"2+t64tZZVaz0yp0x1G23ZRYn+FAKEyVALUEs/4qh\",\n \"Token\" : \"FAKE//////////wEAK/TOKEN/VALUE=\",\n \"Expiration\" : \"2016-04-01T04:13:28Z\"\n}",
+ meck:sequence(
+ httpc,
+ request,
+ 4,
+ [
+ {ok, {{protocol, 200, message}, headers, "Bob"}},
+ {ok, {{protocol, 200, message}, headers, CredsBody}}
+ ]
+ ),
+ meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
+ Expectation =
+ {ok, "ASIAIMAFAKEACCESSKEY", "2+t64tZZVaz0yp0x1G23ZRYn+FAKEyVALUEs/4qh",
+ {{2016, 4, 1}, {4, 13, 28}}, "FAKE//////////wEAK/TOKEN/VALUE="},
+ ?assertEqual(Expectation, rabbitmq_aws_config:credentials())
+ end},
+ {"with instance metadata service role error", fun() ->
+ meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
+ meck:expect(httpc, request, 4, {error, timeout}),
+ ?assertEqual({error, undefined}, rabbitmq_aws_config:credentials())
+ end},
+ {"with instance metadata service role http error", fun() ->
+ meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
+ meck:expect(
+ httpc,
+ request,
+ 4,
+ {ok, {{protocol, 500, message}, headers, "Internal Server Error"}}
+ ),
+ ?assertEqual({error, undefined}, rabbitmq_aws_config:credentials())
+ end},
+ {"with instance metadata service credentials error", fun() ->
+ meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
+ meck:sequence(
+ httpc,
+ request,
+ 4,
+ [
+ {ok, {{protocol, 200, message}, headers, "Bob"}},
+ {error, timeout}
+ ]
+ ),
+ ?assertEqual({error, undefined}, rabbitmq_aws_config:credentials())
+ end},
+ {"with instance metadata service credentials not found", fun() ->
+ meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
+ meck:sequence(
+ httpc,
+ request,
+ 4,
+ [
+ {ok, {{protocol, 200, message}, headers, "Bob"}},
+ {ok, {{protocol, 404, message}, headers, "File Not Found"}}
+ ]
+ ),
+ ?assertEqual({error, undefined}, rabbitmq_aws_config:credentials())
+ end}
+ ]
+ }.
home_path_test_() ->
- [
- {"with HOME", fun() ->
- os:putenv("HOME", "/home/rrabbit"),
- ?assertEqual("/home/rrabbit",
- rabbitmq_aws_config:home_path())
- end},
- {"without HOME", fun() ->
- os:unsetenv("HOME"),
- ?assertEqual(filename:absname("."),
- rabbitmq_aws_config:home_path())
- end}
- ].
-
+ [
+ {"with HOME", fun() ->
+ os:putenv("HOME", "/home/rrabbit"),
+ ?assertEqual(
+ "/home/rrabbit",
+ rabbitmq_aws_config:home_path()
+ )
+ end},
+ {"without HOME", fun() ->
+ os:unsetenv("HOME"),
+ ?assertEqual(
+ filename:absname("."),
+ rabbitmq_aws_config:home_path()
+ )
+ end}
+ ].
ini_format_key_test_() ->
- [
- {"when value is list", fun() ->
- ?assertEqual(test_key, rabbitmq_aws_config:ini_format_key("test_key"))
- end},
- {"when value is binary", fun() ->
- ?assertEqual({error, type}, rabbitmq_aws_config:ini_format_key(<<"test_key">>))
- end}
- ].
-
+ [
+ {"when value is list", fun() ->
+ ?assertEqual(test_key, rabbitmq_aws_config:ini_format_key("test_key"))
+ end},
+ {"when value is binary", fun() ->
+ ?assertEqual({error, type}, rabbitmq_aws_config:ini_format_key(<<"test_key">>))
+ end}
+ ].
maybe_convert_number_test_() ->
- [
- {"when string contains an integer", fun() ->
- ?assertEqual(123, rabbitmq_aws_config:maybe_convert_number("123"))
- end},
- {"when string contains a float", fun() ->
- ?assertEqual(123.456, rabbitmq_aws_config:maybe_convert_number("123.456"))
- end},
- {"when string does not contain a number", fun() ->
- ?assertEqual("hello, world", rabbitmq_aws_config:maybe_convert_number("hello, world"))
- end}
- ].
-
+ [
+ {"when string contains an integer", fun() ->
+ ?assertEqual(123, rabbitmq_aws_config:maybe_convert_number("123"))
+ end},
+ {"when string contains a float", fun() ->
+ ?assertEqual(123.456, rabbitmq_aws_config:maybe_convert_number("123.456"))
+ end},
+ {"when string does not contain a number", fun() ->
+ ?assertEqual("hello, world", rabbitmq_aws_config:maybe_convert_number("hello, world"))
+ end}
+ ].
parse_iso8601_test_() ->
- [
- {"parse test", fun() ->
- Value = "2016-05-19T18:25:23Z",
- Expectation = {{2016,5,19},{18,25,23}},
- ?assertEqual(Expectation, rabbitmq_aws_config:parse_iso8601_timestamp(Value))
- end}
- ].
-
+ [
+ {"parse test", fun() ->
+ Value = "2016-05-19T18:25:23Z",
+ Expectation = {{2016, 5, 19}, {18, 25, 23}},
+ ?assertEqual(Expectation, rabbitmq_aws_config:parse_iso8601_timestamp(Value))
+ end}
+ ].
profile_test_() ->
- [
- {"from environment variable", fun() ->
- os:putenv("AWS_DEFAULT_PROFILE", "httpc-aws test"),
- ?assertEqual("httpc-aws test", rabbitmq_aws_config:profile())
- end},
- {"default without environment variable", fun() ->
- os:unsetenv("AWS_DEFAULT_PROFILE"),
- ?assertEqual("default", rabbitmq_aws_config:profile())
- end}
- ].
-
+ [
+ {"from environment variable", fun() ->
+ os:putenv("AWS_DEFAULT_PROFILE", "httpc-aws test"),
+ ?assertEqual("httpc-aws test", rabbitmq_aws_config:profile())
+ end},
+ {"default without environment variable", fun() ->
+ os:unsetenv("AWS_DEFAULT_PROFILE"),
+ ?assertEqual("default", rabbitmq_aws_config:profile())
+ end}
+ ].
read_file_test_() ->
- [
- {"file does not exist", fun() ->
- ?assertEqual({error, enoent}, rabbitmq_aws_config:read_file(filename:join([filename:absname("."), "bad_path"])))
- end}
- ].
-
-
-region_test_() ->
- {
- foreach,
- fun () ->
- meck:new(httpc),
- meck:new(rabbitmq_aws),
- reset_environment(),
- [httpc, rabbitmq_aws]
- end,
- fun meck:unload/1,
[
- {"with environment variable", fun() ->
- os:putenv("AWS_DEFAULT_REGION", "us-west-1"),
- ?assertEqual({ok, "us-west-1"}, rabbitmq_aws_config:region())
- end},
- {"with config file and specified profile", fun() ->
- setup_test_config_env_var(),
- ?assertEqual({ok, "us-west-5"}, rabbitmq_aws_config:region("testing"))
- end},
- {"with config file using default profile", fun() ->
- setup_test_config_env_var(),
- ?assertEqual({ok, "us-east-4"}, rabbitmq_aws_config:region())
- end},
- {"missing profile in config", fun() ->
- setup_test_config_env_var(),
- meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
- ?assertEqual({ok, ?DEFAULT_REGION}, rabbitmq_aws_config:region("no-region"))
- end},
- {"from instance metadata service", fun() ->
- meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
- meck:expect(httpc, request, 4,
- {ok, {{protocol, 200, message}, headers, "us-west-1a"}}),
- ?assertEqual({ok, "us-west-1"}, rabbitmq_aws_config:region())
- end},
- {"full lookup failure", fun() ->
- meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
- ?assertEqual({ok, ?DEFAULT_REGION}, rabbitmq_aws_config:region())
- end},
- {"http error failure", fun() ->
- meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
- meck:expect(httpc, request, 4,
- {ok, {{protocol, 500, message}, headers, "Internal Server Error"}}),
- ?assertEqual({ok, ?DEFAULT_REGION}, rabbitmq_aws_config:region())
- end}
- ]}.
+ {"file does not exist", fun() ->
+ ?assertEqual(
+ {error, enoent},
+ rabbitmq_aws_config:read_file(filename:join([filename:absname("."), "bad_path"]))
+ )
+ end}
+ ].
+region_test_() ->
+ {
+ foreach,
+ fun() ->
+ meck:new(httpc),
+ meck:new(rabbitmq_aws),
+ reset_environment(),
+ [httpc, rabbitmq_aws]
+ end,
+ fun meck:unload/1,
+ [
+ {"with environment variable", fun() ->
+ os:putenv("AWS_DEFAULT_REGION", "us-west-1"),
+ ?assertEqual({ok, "us-west-1"}, rabbitmq_aws_config:region())
+ end},
+ {"with config file and specified profile", fun() ->
+ setup_test_config_env_var(),
+ ?assertEqual({ok, "us-west-5"}, rabbitmq_aws_config:region("testing"))
+ end},
+ {"with config file using default profile", fun() ->
+ setup_test_config_env_var(),
+ ?assertEqual({ok, "us-east-4"}, rabbitmq_aws_config:region())
+ end},
+ {"missing profile in config", fun() ->
+ setup_test_config_env_var(),
+ meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
+ ?assertEqual({ok, ?DEFAULT_REGION}, rabbitmq_aws_config:region("no-region"))
+ end},
+ {"from instance metadata service", fun() ->
+ meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
+ meck:expect(
+ httpc,
+ request,
+ 4,
+ {ok, {{protocol, 200, message}, headers, "us-west-1a"}}
+ ),
+ ?assertEqual({ok, "us-west-1"}, rabbitmq_aws_config:region())
+ end},
+ {"full lookup failure", fun() ->
+ meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
+ ?assertEqual({ok, ?DEFAULT_REGION}, rabbitmq_aws_config:region())
+ end},
+ {"http error failure", fun() ->
+ meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
+ meck:expect(
+ httpc,
+ request,
+ 4,
+ {ok, {{protocol, 500, message}, headers, "Internal Server Error"}}
+ ),
+ ?assertEqual({ok, ?DEFAULT_REGION}, rabbitmq_aws_config:region())
+ end}
+ ]
+ }.
instance_id_test_() ->
- {
- foreach,
- fun () ->
- meck:new(httpc),
- meck:new(rabbitmq_aws),
- reset_environment(),
- [httpc, rabbitmq_aws]
- end,
- fun meck:unload/1,
- [
- {"get instance id successfully",
+ {
+ foreach,
fun() ->
- meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
- meck:expect(httpc, request, 4, {ok, {{protocol, 200, message}, headers, "instance-id"}}),
- ?assertEqual({ok, "instance-id"}, rabbitmq_aws_config:instance_id())
- end
- },
- {"getting instance id is rejected with invalid token error",
- fun() ->
- meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, "invalid"),
- meck:expect(httpc, request, 4, {error, {{protocol, 401, message}, headers, "Invalid token"}}),
- ?assertEqual({error, undefined}, rabbitmq_aws_config:instance_id())
- end
- },
- {"getting instance id is rejected with access denied error",
- fun() ->
- meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, "expired token"),
- meck:expect(httpc, request, 4, {error, {{protocol, 403, message}, headers, "access denied"}}),
- ?assertEqual({error, undefined}, rabbitmq_aws_config:instance_id())
- end
- }
- ]
- }.
+ meck:new(httpc),
+ meck:new(rabbitmq_aws),
+ reset_environment(),
+ [httpc, rabbitmq_aws]
+ end,
+ fun meck:unload/1,
+ [
+ {"get instance id successfully", fun() ->
+ meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
+ meck:expect(
+ httpc, request, 4, {ok, {{protocol, 200, message}, headers, "instance-id"}}
+ ),
+ ?assertEqual({ok, "instance-id"}, rabbitmq_aws_config:instance_id())
+ end},
+ {"getting instance id is rejected with invalid token error", fun() ->
+ meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, "invalid"),
+ meck:expect(
+ httpc, request, 4, {error, {{protocol, 401, message}, headers, "Invalid token"}}
+ ),
+ ?assertEqual({error, undefined}, rabbitmq_aws_config:instance_id())
+ end},
+ {"getting instance id is rejected with access denied error", fun() ->
+ meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, "expired token"),
+ meck:expect(
+ httpc, request, 4, {error, {{protocol, 403, message}, headers, "access denied"}}
+ ),
+ ?assertEqual({error, undefined}, rabbitmq_aws_config:instance_id())
+ end}
+ ]
+ }.
load_imdsv2_token_test_() ->
- {
- foreach,
- fun () ->
- meck:new(httpc),
- [httpc]
- end,
- fun meck:unload/1,
- [
- {"fail to get imdsv2 token - timeout",
+ {
+ foreach,
fun() ->
- meck:expect(httpc, request, 4, {error, timeout}),
- ?assertEqual(undefined, rabbitmq_aws_config:load_imdsv2_token())
- end},
- {"fail to get imdsv2 token - PUT request is not valid",
- fun() ->
- meck:expect(httpc, request, 4, {error, {{protocol, 400, messge}, headers, "Missing or Invalid Parameters – The PUT request is not valid."}}),
- ?assertEqual(undefined, rabbitmq_aws_config:load_imdsv2_token())
- end},
- {"successfully get imdsv2 token from instance metadata service",
- fun() ->
- IMDSv2Token = "super_secret_token_value",
- meck:sequence(httpc, request, 4,
- [{ok, {{protocol, 200, message}, headers, IMDSv2Token}}]),
- ?assertEqual(IMDSv2Token, rabbitmq_aws_config:load_imdsv2_token())
- end}
- ]
- }.
-
+ meck:new(httpc),
+ [httpc]
+ end,
+ fun meck:unload/1,
+ [
+ {"fail to get imdsv2 token - timeout", fun() ->
+ meck:expect(httpc, request, 4, {error, timeout}),
+ ?assertEqual(undefined, rabbitmq_aws_config:load_imdsv2_token())
+ end},
+ {"fail to get imdsv2 token - PUT request is not valid", fun() ->
+ meck:expect(
+ httpc,
+ request,
+ 4,
+ {error, {
+ {protocol, 400, messge},
+ headers,
+ "Missing or Invalid Parameters – The PUT request is not valid."
+ }}
+ ),
+ ?assertEqual(undefined, rabbitmq_aws_config:load_imdsv2_token())
+ end},
+ {"successfully get imdsv2 token from instance metadata service", fun() ->
+ IMDSv2Token = "super_secret_token_value",
+ meck:sequence(
+ httpc,
+ request,
+ 4,
+ [{ok, {{protocol, 200, message}, headers, IMDSv2Token}}]
+ ),
+ ?assertEqual(IMDSv2Token, rabbitmq_aws_config:load_imdsv2_token())
+ end}
+ ]
+ }.
maybe_imdsv2_token_headers_test_() ->
- {
- foreach,
- fun () ->
- meck:new(rabbitmq_aws),
- [rabbitmq_aws]
- end,
- fun meck:unload/1,
- [
- {"imdsv2 token is not available", fun() ->
- meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
- ?assertEqual([], rabbitmq_aws_config:maybe_imdsv2_token_headers())
- end}
- ,
- {"imdsv2 is available", fun() ->
- IMDSv2Token = "super_secret_token_value ;)",
- meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, IMDSv2Token),
- ?assertEqual([{"X-aws-ec2-metadata-token", IMDSv2Token}], rabbitmq_aws_config:maybe_imdsv2_token_headers())
- end}
- ]
- }.
+ {
+ foreach,
+ fun() ->
+ meck:new(rabbitmq_aws),
+ [rabbitmq_aws]
+ end,
+ fun meck:unload/1,
+ [
+ {"imdsv2 token is not available", fun() ->
+ meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, undefined),
+ ?assertEqual([], rabbitmq_aws_config:maybe_imdsv2_token_headers())
+ end},
+
+ {"imdsv2 is available", fun() ->
+ IMDSv2Token = "super_secret_token_value ;)",
+ meck:expect(rabbitmq_aws, ensure_imdsv2_token_valid, 0, IMDSv2Token),
+ ?assertEqual(
+ [{"X-aws-ec2-metadata-token", IMDSv2Token}],
+ rabbitmq_aws_config:maybe_imdsv2_token_headers()
+ )
+ end}
+ ]
+ }.
reset_environment() ->
- os:unsetenv("AWS_ACCESS_KEY_ID"),
- os:unsetenv("AWS_DEFAULT_REGION"),
- os:unsetenv("AWS_SECRET_ACCESS_KEY"),
- setup_test_file_with_env_var("AWS_CONFIG_FILE", "bad_config.ini"),
- setup_test_file_with_env_var("AWS_SHARED_CREDENTIALS_FILE",
- "bad_credentials.ini"),
- meck:expect(httpc, request, 4, {error, timeout}).
+ os:unsetenv("AWS_ACCESS_KEY_ID"),
+ os:unsetenv("AWS_DEFAULT_REGION"),
+ os:unsetenv("AWS_SECRET_ACCESS_KEY"),
+ setup_test_file_with_env_var("AWS_CONFIG_FILE", "bad_config.ini"),
+ setup_test_file_with_env_var(
+ "AWS_SHARED_CREDENTIALS_FILE",
+ "bad_credentials.ini"
+ ),
+ meck:expect(httpc, request, 4, {error, timeout}).
setup_test_config_env_var() ->
- setup_test_file_with_env_var("AWS_CONFIG_FILE", "test_aws_config.ini").
+ setup_test_file_with_env_var("AWS_CONFIG_FILE", "test_aws_config.ini").
setup_test_file_with_env_var(EnvVar, Filename) ->
- os:putenv(EnvVar,
- filename:join([filename:absname("."), "test",
- Filename])).
+ os:putenv(
+ EnvVar,
+ filename:join([
+ filename:absname("."),
+ "test",
+ Filename
+ ])
+ ).
setup_test_credentials_env_var() ->
- setup_test_file_with_env_var("AWS_SHARED_CREDENTIALS_FILE",
- "test_aws_credentials.ini").
+ setup_test_file_with_env_var(
+ "AWS_SHARED_CREDENTIALS_FILE",
+ "test_aws_credentials.ini"
+ ).
diff --git a/deps/rabbitmq_aws/test/rabbitmq_aws_json_tests.erl b/deps/rabbitmq_aws/test/rabbitmq_aws_json_tests.erl
index c69049e81efd..10d65ee2fd33 100644
--- a/deps/rabbitmq_aws/test/rabbitmq_aws_json_tests.erl
+++ b/deps/rabbitmq_aws/test/rabbitmq_aws_json_tests.erl
@@ -3,69 +3,93 @@
-include_lib("eunit/include/eunit.hrl").
parse_test_() ->
- [
- {"string decoding", fun() ->
- Value = "{\"requestId\":\"bda7fbdb-eddb-41fa-8626-7ba87923d690\",\"number\":128,\"enabled\":true,\"tagSet\":[{\"resourceId\":\"i-13a4abea\",\"resourceType\":\"instance\",\"key\":\"Environment\",\"value\":\"prod-us-east-1\"},{\"resourceId\":\"i-13a4abea\",\"resourceType\":\"instance\",\"key\":\"aws:cloudformation:logical-id\",\"value\":\"AutoScalingGroup\"},{\"resourceId\":\"i-13a4abea\",\"resourceType\":\"instance\",\"key\":\"aws:cloudformation:stack-name\",\"value\":\"prod-us-east-1-ecs-1\"}]}",
- Expectation = [
- {"requestId","bda7fbdb-eddb-41fa-8626-7ba87923d690"},
- {"number", 128},
- {"enabled", true},
- {"tagSet",
- [{"resourceId","i-13a4abea"},
- {"resourceType","instance"},
- {"key","Environment"},
- {"value","prod-us-east-1"},
- {"resourceId","i-13a4abea"},
- {"resourceType","instance"},
- {"key","aws:cloudformation:logical-id"},
- {"value","AutoScalingGroup"},
- {"resourceId","i-13a4abea"},
- {"resourceType","instance"},
- {"key","aws:cloudformation:stack-name"},
- {"value","prod-us-east-1-ecs-1"}]}
- ],
- Proplist = rabbitmq_aws_json:decode(Value),
- ?assertEqual(proplists:get_value("requestId", Expectation), proplists:get_value("requestId", Proplist)),
- ?assertEqual(proplists:get_value("number", Expectation), proplists:get_value("number", Proplist)),
- ?assertEqual(proplists:get_value("enabled", Expectation), proplists:get_value("enabled", Proplist)),
- ?assertEqual(lists:usort(proplists:get_value("tagSet", Expectation)),
- lists:usort(proplists:get_value("tagSet", Proplist)))
- end},
- {"binary decoding", fun() ->
- Value = <<"{\"requestId\":\"bda7fbdb-eddb-41fa-8626-7ba87923d690\",\"number\":128,\"enabled\":true,\"tagSet\":[{\"resourceId\":\"i-13a4abea\",\"resourceType\":\"instance\",\"key\":\"Environment\",\"value\":\"prod-us-east-1\"},{\"resourceId\":\"i-13a4abea\",\"resourceType\":\"instance\",\"key\":\"aws:cloudformation:logical-id\",\"value\":\"AutoScalingGroup\"},{\"resourceId\":\"i-13a4abea\",\"resourceType\":\"instance\",\"key\":\"aws:cloudformation:stack-name\",\"value\":\"prod-us-east-1-ecs-1\"}]}">>,
- Expectation = [
- {"requestId","bda7fbdb-eddb-41fa-8626-7ba87923d690"},
- {"number", 128},
- {"enabled", true},
- {"tagSet",
- [{"resourceId","i-13a4abea"},
- {"resourceType","instance"},
- {"key","Environment"},
- {"value","prod-us-east-1"},
- {"resourceId","i-13a4abea"},
- {"resourceType","instance"},
- {"key","aws:cloudformation:logical-id"},
- {"value","AutoScalingGroup"},
- {"resourceId","i-13a4abea"},
- {"resourceType","instance"},
- {"key","aws:cloudformation:stack-name"},
- {"value","prod-us-east-1-ecs-1"}]}
- ],
- Proplist = rabbitmq_aws_json:decode(Value),
- ?assertEqual(proplists:get_value("requestId", Expectation), proplists:get_value("requestId", Proplist)),
- ?assertEqual(proplists:get_value("number", Expectation), proplists:get_value("number", Proplist)),
- ?assertEqual(proplists:get_value("enabled", Expectation), proplists:get_value("enabled", Proplist)),
- ?assertEqual(lists:usort(proplists:get_value("tagSet", Expectation)),
- lists:usort(proplists:get_value("tagSet", Proplist)))
- end},
- {"list values", fun() ->
- Value = "{\"misc\": [\"foo\", true, 123]\}",
- Expectation = [{"misc", ["foo", true, 123]}],
- ?assertEqual(Expectation, rabbitmq_aws_json:decode(Value))
- end},
- {"empty objects", fun() ->
- Value = "{\"tags\": [{}]}",
- Expectation = [{"tags", [{}]}],
- ?assertEqual(Expectation, rabbitmq_aws_json:decode(Value))
- end}
- ].
+ [
+ {"string decoding", fun() ->
+ Value =
+ "{\"requestId\":\"bda7fbdb-eddb-41fa-8626-7ba87923d690\",\"number\":128,\"enabled\":true,\"tagSet\":[{\"resourceId\":\"i-13a4abea\",\"resourceType\":\"instance\",\"key\":\"Environment\",\"value\":\"prod-us-east-1\"},{\"resourceId\":\"i-13a4abea\",\"resourceType\":\"instance\",\"key\":\"aws:cloudformation:logical-id\",\"value\":\"AutoScalingGroup\"},{\"resourceId\":\"i-13a4abea\",\"resourceType\":\"instance\",\"key\":\"aws:cloudformation:stack-name\",\"value\":\"prod-us-east-1-ecs-1\"}]}",
+ Expectation = [
+ {"requestId", "bda7fbdb-eddb-41fa-8626-7ba87923d690"},
+ {"number", 128},
+ {"enabled", true},
+ {"tagSet", [
+ {"resourceId", "i-13a4abea"},
+ {"resourceType", "instance"},
+ {"key", "Environment"},
+ {"value", "prod-us-east-1"},
+ {"resourceId", "i-13a4abea"},
+ {"resourceType", "instance"},
+ {"key", "aws:cloudformation:logical-id"},
+ {"value", "AutoScalingGroup"},
+ {"resourceId", "i-13a4abea"},
+ {"resourceType", "instance"},
+ {"key", "aws:cloudformation:stack-name"},
+ {"value", "prod-us-east-1-ecs-1"}
+ ]}
+ ],
+ Proplist = rabbitmq_aws_json:decode(Value),
+ ?assertEqual(
+ proplists:get_value("requestId", Expectation),
+ proplists:get_value("requestId", Proplist)
+ ),
+ ?assertEqual(
+ proplists:get_value("number", Expectation), proplists:get_value("number", Proplist)
+ ),
+ ?assertEqual(
+ proplists:get_value("enabled", Expectation),
+ proplists:get_value("enabled", Proplist)
+ ),
+ ?assertEqual(
+ lists:usort(proplists:get_value("tagSet", Expectation)),
+ lists:usort(proplists:get_value("tagSet", Proplist))
+ )
+ end},
+ {"binary decoding", fun() ->
+ Value =
+ <<"{\"requestId\":\"bda7fbdb-eddb-41fa-8626-7ba87923d690\",\"number\":128,\"enabled\":true,\"tagSet\":[{\"resourceId\":\"i-13a4abea\",\"resourceType\":\"instance\",\"key\":\"Environment\",\"value\":\"prod-us-east-1\"},{\"resourceId\":\"i-13a4abea\",\"resourceType\":\"instance\",\"key\":\"aws:cloudformation:logical-id\",\"value\":\"AutoScalingGroup\"},{\"resourceId\":\"i-13a4abea\",\"resourceType\":\"instance\",\"key\":\"aws:cloudformation:stack-name\",\"value\":\"prod-us-east-1-ecs-1\"}]}">>,
+ Expectation = [
+ {"requestId", "bda7fbdb-eddb-41fa-8626-7ba87923d690"},
+ {"number", 128},
+ {"enabled", true},
+ {"tagSet", [
+ {"resourceId", "i-13a4abea"},
+ {"resourceType", "instance"},
+ {"key", "Environment"},
+ {"value", "prod-us-east-1"},
+ {"resourceId", "i-13a4abea"},
+ {"resourceType", "instance"},
+ {"key", "aws:cloudformation:logical-id"},
+ {"value", "AutoScalingGroup"},
+ {"resourceId", "i-13a4abea"},
+ {"resourceType", "instance"},
+ {"key", "aws:cloudformation:stack-name"},
+ {"value", "prod-us-east-1-ecs-1"}
+ ]}
+ ],
+ Proplist = rabbitmq_aws_json:decode(Value),
+ ?assertEqual(
+ proplists:get_value("requestId", Expectation),
+ proplists:get_value("requestId", Proplist)
+ ),
+ ?assertEqual(
+ proplists:get_value("number", Expectation), proplists:get_value("number", Proplist)
+ ),
+ ?assertEqual(
+ proplists:get_value("enabled", Expectation),
+ proplists:get_value("enabled", Proplist)
+ ),
+ ?assertEqual(
+ lists:usort(proplists:get_value("tagSet", Expectation)),
+ lists:usort(proplists:get_value("tagSet", Proplist))
+ )
+ end},
+ {"list values", fun() ->
+ Value = "{\"misc\": [\"foo\", true, 123]\}",
+ Expectation = [{"misc", ["foo", true, 123]}],
+ ?assertEqual(Expectation, rabbitmq_aws_json:decode(Value))
+ end},
+ {"empty objects", fun() ->
+ Value = "{\"tags\": [{}]}",
+ Expectation = [{"tags", [{}]}],
+ ?assertEqual(Expectation, rabbitmq_aws_json:decode(Value))
+ end}
+ ].
diff --git a/deps/rabbitmq_aws/test/rabbitmq_aws_sign_tests.erl b/deps/rabbitmq_aws/test/rabbitmq_aws_sign_tests.erl
index 071c4c3ef022..fbdd0a877344 100644
--- a/deps/rabbitmq_aws/test/rabbitmq_aws_sign_tests.erl
+++ b/deps/rabbitmq_aws/test/rabbitmq_aws_sign_tests.erl
@@ -3,289 +3,457 @@
-include_lib("eunit/include/eunit.hrl").
-include("rabbitmq_aws.hrl").
-
amz_date_test_() ->
- [
- {"value", fun() ->
- ?assertEqual("20160220",
- rabbitmq_aws_sign:amz_date("20160220T120000Z"))
- end}
- ].
-
+ [
+ {"value", fun() ->
+ ?assertEqual(
+ "20160220",
+ rabbitmq_aws_sign:amz_date("20160220T120000Z")
+ )
+ end}
+ ].
append_headers_test_() ->
- [
- {"with security token", fun() ->
-
- Headers = [{"Content-Type", "application/x-amz-json-1.0"},
- {"X-Amz-Target", "DynamoDB_20120810.DescribeTable"}],
-
- AMZDate = "20160220T120000Z",
- ContentLength = 128,
- PayloadHash = "c888ac0919d062cee1d7b97f44f2a765e4dc9270bc720ba32b8d9f8720626213",
- Hostname = "ec2.amazonaws.com",
- SecurityToken = "AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/L",
- Expectation = [{"content-length", integer_to_list(ContentLength)},
- {"content-type", "application/x-amz-json-1.0"},
- {"date", AMZDate},
- {"host", Hostname},
- {"x-amz-content-sha256", PayloadHash},
- {"x-amz-security-token", SecurityToken},
- {"x-amz-target", "DynamoDB_20120810.DescribeTable"}],
- ?assertEqual(Expectation,
- rabbitmq_aws_sign:append_headers(AMZDate, ContentLength,
- PayloadHash, Hostname,
- SecurityToken, Headers))
- end},
- {"without security token", fun() ->
-
- Headers = [{"Content-Type", "application/x-amz-json-1.0"},
- {"X-Amz-Target", "DynamoDB_20120810.DescribeTable"}],
+ [
+ {"with security token", fun() ->
+ Headers = [
+ {"Content-Type", "application/x-amz-json-1.0"},
+ {"X-Amz-Target", "DynamoDB_20120810.DescribeTable"}
+ ],
- AMZDate = "20160220T120000Z",
- ContentLength = 128,
- PayloadHash = "c888ac0919d062cee1d7b97f44f2a765e4dc9270bc720ba32b8d9f8720626213",
- Hostname = "ec2.amazonaws.com",
- Expectation = [{"content-length", integer_to_list(ContentLength)},
- {"content-type", "application/x-amz-json-1.0"},
- {"date", AMZDate},
- {"host", Hostname},
- {"x-amz-content-sha256", PayloadHash},
- {"x-amz-target", "DynamoDB_20120810.DescribeTable"}],
- ?assertEqual(Expectation,
- rabbitmq_aws_sign:append_headers(AMZDate, ContentLength,
- PayloadHash, Hostname,
- undefined, Headers))
- end}
- ].
+ AMZDate = "20160220T120000Z",
+ ContentLength = 128,
+ PayloadHash = "c888ac0919d062cee1d7b97f44f2a765e4dc9270bc720ba32b8d9f8720626213",
+ Hostname = "ec2.amazonaws.com",
+ SecurityToken = "AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/L",
+ Expectation = [
+ {"content-length", integer_to_list(ContentLength)},
+ {"content-type", "application/x-amz-json-1.0"},
+ {"date", AMZDate},
+ {"host", Hostname},
+ {"x-amz-content-sha256", PayloadHash},
+ {"x-amz-security-token", SecurityToken},
+ {"x-amz-target", "DynamoDB_20120810.DescribeTable"}
+ ],
+ ?assertEqual(
+ Expectation,
+ rabbitmq_aws_sign:append_headers(
+ AMZDate,
+ ContentLength,
+ PayloadHash,
+ Hostname,
+ SecurityToken,
+ Headers
+ )
+ )
+ end},
+ {"without security token", fun() ->
+ Headers = [
+ {"Content-Type", "application/x-amz-json-1.0"},
+ {"X-Amz-Target", "DynamoDB_20120810.DescribeTable"}
+ ],
+ AMZDate = "20160220T120000Z",
+ ContentLength = 128,
+ PayloadHash = "c888ac0919d062cee1d7b97f44f2a765e4dc9270bc720ba32b8d9f8720626213",
+ Hostname = "ec2.amazonaws.com",
+ Expectation = [
+ {"content-length", integer_to_list(ContentLength)},
+ {"content-type", "application/x-amz-json-1.0"},
+ {"date", AMZDate},
+ {"host", Hostname},
+ {"x-amz-content-sha256", PayloadHash},
+ {"x-amz-target", "DynamoDB_20120810.DescribeTable"}
+ ],
+ ?assertEqual(
+ Expectation,
+ rabbitmq_aws_sign:append_headers(
+ AMZDate,
+ ContentLength,
+ PayloadHash,
+ Hostname,
+ undefined,
+ Headers
+ )
+ )
+ end}
+ ].
authorization_header_test_() ->
- [
- {"value", fun() ->
- AccessKey = "AKIDEXAMPLE",
- SecretKey = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
- RequestTimestamp = "20150830T123600Z",
- Region = "us-east-1",
- Service = "iam",
- Headers = [{"Content-Type", "application/x-www-form-urlencoded; charset=utf-8"},
- {"Host", "iam.amazonaws.com"},
- {"Date", "20150830T123600Z"}],
- RequestHash = "f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59",
- Expectation = "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request, SignedHeaders=content-type;date;host, Signature=5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7",
- ?assertEqual(Expectation,
- rabbitmq_aws_sign:authorization(AccessKey, SecretKey, RequestTimestamp,
- Region, Service, Headers, RequestHash))
- end}
- ].
-
+ [
+ {"value", fun() ->
+ AccessKey = "AKIDEXAMPLE",
+ SecretKey = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
+ RequestTimestamp = "20150830T123600Z",
+ Region = "us-east-1",
+ Service = "iam",
+ Headers = [
+ {"Content-Type", "application/x-www-form-urlencoded; charset=utf-8"},
+ {"Host", "iam.amazonaws.com"},
+ {"Date", "20150830T123600Z"}
+ ],
+ RequestHash = "f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59",
+ Expectation =
+ "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request, SignedHeaders=content-type;date;host, Signature=5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7",
+ ?assertEqual(
+ Expectation,
+ rabbitmq_aws_sign:authorization(
+ AccessKey,
+ SecretKey,
+ RequestTimestamp,
+ Region,
+ Service,
+ Headers,
+ RequestHash
+ )
+ )
+ end}
+ ].
canonical_headers_test_() ->
- [
- {"with security token", fun() ->
- Value = [{"Host", "iam.amazonaws.com"},
- {"Content-Type", "content-type:application/x-www-form-urlencoded; charset=utf-8"},
- {"My-Header2", "\"a b c \""},
- {"My-Header1", "a b c"},
- {"Date", "20150830T123600Z"}],
- Expectation = lists:flatten([
- "content-type:content-type:application/x-www-form-urlencoded; charset=utf-8\n",
- "date:20150830T123600Z\n",
- "host:iam.amazonaws.com\n",
- "my-header1:a b c\n",
- "my-header2:\"a b c \"\n"]),
- ?assertEqual(Expectation, rabbitmq_aws_sign:canonical_headers(Value))
- end}
- ].
+ [
+ {"with security token", fun() ->
+ Value = [
+ {"Host", "iam.amazonaws.com"},
+ {"Content-Type", "content-type:application/x-www-form-urlencoded; charset=utf-8"},
+ {"My-Header2", "\"a b c \""},
+ {"My-Header1", "a b c"},
+ {"Date", "20150830T123600Z"}
+ ],
+ Expectation = lists:flatten([
+ "content-type:content-type:application/x-www-form-urlencoded; charset=utf-8\n",
+ "date:20150830T123600Z\n",
+ "host:iam.amazonaws.com\n",
+ "my-header1:a b c\n",
+ "my-header2:\"a b c \"\n"
+ ]),
+ ?assertEqual(Expectation, rabbitmq_aws_sign:canonical_headers(Value))
+ end}
+ ].
credential_scope_test_() ->
- [
- {"string value", fun() ->
- RequestDate = "20150830",
- Region = "us-east-1",
- Service = "iam",
- Expectation = "20150830/us-east-1/iam/aws4_request",
- ?assertEqual(Expectation,
- rabbitmq_aws_sign:credential_scope(RequestDate, Region, Service))
- end}
- ].
+ [
+ {"string value", fun() ->
+ RequestDate = "20150830",
+ Region = "us-east-1",
+ Service = "iam",
+ Expectation = "20150830/us-east-1/iam/aws4_request",
+ ?assertEqual(
+ Expectation,
+ rabbitmq_aws_sign:credential_scope(RequestDate, Region, Service)
+ )
+ end}
+ ].
hmac_sign_test_() ->
- [
- {"signed value", fun() ->
- ?assertEqual([84, 114, 243, 48, 184, 73, 81, 138, 195, 123, 62, 27, 222, 141, 188, 149, 178, 82, 252, 75, 29, 34, 102, 186, 98, 232, 224, 105, 64, 6, 119, 33],
- rabbitmq_aws_sign:hmac_sign("sixpence", "burn the witch"))
- end}
- ].
+ [
+ {"signed value", fun() ->
+ ?assertEqual(
+ [
+ 84,
+ 114,
+ 243,
+ 48,
+ 184,
+ 73,
+ 81,
+ 138,
+ 195,
+ 123,
+ 62,
+ 27,
+ 222,
+ 141,
+ 188,
+ 149,
+ 178,
+ 82,
+ 252,
+ 75,
+ 29,
+ 34,
+ 102,
+ 186,
+ 98,
+ 232,
+ 224,
+ 105,
+ 64,
+ 6,
+ 119,
+ 33
+ ],
+ rabbitmq_aws_sign:hmac_sign("sixpence", "burn the witch")
+ )
+ end}
+ ].
query_string_test_() ->
- [
- {"properly sorted", fun() ->
- QArgs = [{"Version", "2015-10-01"},
- {"Action", "RunInstances"},
- {"x-amz-algorithm", "AWS4-HMAC-SHA256"},
- {"Date", "20160220T120000Z"},
- {"x-amz-credential", "AKIDEXAMPLE/20140707/us-east-1/ec2/aws4_request"}],
- Expectation = "Action=RunInstances&Date=20160220T120000Z&Version=2015-10-01&x-amz-algorithm=AWS4-HMAC-SHA256&x-amz-credential=AKIDEXAMPLE%2F20140707%2Fus-east-1%2Fec2%2Faws4_request",
- ?assertEqual(Expectation,
- rabbitmq_aws_sign:query_string(QArgs))
- end},
- {"undefined", fun() ->
- ?assertEqual([], rabbitmq_aws_sign:query_string(undefined))
- end}
- ].
+ [
+ {"properly sorted", fun() ->
+ QArgs = [
+ {"Version", "2015-10-01"},
+ {"Action", "RunInstances"},
+ {"x-amz-algorithm", "AWS4-HMAC-SHA256"},
+ {"Date", "20160220T120000Z"},
+ {"x-amz-credential", "AKIDEXAMPLE/20140707/us-east-1/ec2/aws4_request"}
+ ],
+ Expectation =
+ "Action=RunInstances&Date=20160220T120000Z&Version=2015-10-01&x-amz-algorithm=AWS4-HMAC-SHA256&x-amz-credential=AKIDEXAMPLE%2F20140707%2Fus-east-1%2Fec2%2Faws4_request",
+ ?assertEqual(
+ Expectation,
+ rabbitmq_aws_sign:query_string(QArgs)
+ )
+ end},
+ {"undefined", fun() ->
+ ?assertEqual([], rabbitmq_aws_sign:query_string(undefined))
+ end}
+ ].
request_hash_test_() ->
- [
- {"hash value", fun() ->
- Method = get,
- Path = "/",
- QArgs = [{"Action", "ListUsers"}, {"Version", "2010-05-08"}],
- Headers = [{"Content-Type", "application/x-www-form-urlencoded; charset=utf-8"},
- {"Host", "iam.amazonaws.com"},
- {"Date", "20150830T123600Z"}],
- Payload = "",
- Expectation = "49b454e0f20fe17f437eaa570846fc5d687efc1752c8b5a1eeee5597a7eb92a5",
- ?assertEqual(Expectation,
- rabbitmq_aws_sign:request_hash(Method, Path, QArgs, Headers, Payload))
- end}
- ].
+ [
+ {"hash value", fun() ->
+ Method = get,
+ Path = "/",
+ QArgs = [{"Action", "ListUsers"}, {"Version", "2010-05-08"}],
+ Headers = [
+ {"Content-Type", "application/x-www-form-urlencoded; charset=utf-8"},
+ {"Host", "iam.amazonaws.com"},
+ {"Date", "20150830T123600Z"}
+ ],
+ Payload = "",
+ Expectation = "49b454e0f20fe17f437eaa570846fc5d687efc1752c8b5a1eeee5597a7eb92a5",
+ ?assertEqual(
+ Expectation,
+ rabbitmq_aws_sign:request_hash(Method, Path, QArgs, Headers, Payload)
+ )
+ end}
+ ].
signature_test_() ->
- [
- {"value", fun() ->
- StringToSign = "AWS4-HMAC-SHA256\n20150830T123600Z\n20150830/us-east-1/iam/aws4_request\nf536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59",
- SigningKey = [196, 175, 177, 204, 87, 113, 216, 113, 118, 58, 57, 62, 68, 183, 3, 87, 27, 85, 204, 40, 66, 77, 26, 94, 134, 218, 110, 211, 193, 84, 164, 185],
- Expectation = "5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7",
- ?assertEqual(Expectation, rabbitmq_aws_sign:signature(StringToSign, SigningKey))
- end}
- ].
-
+ [
+ {"value", fun() ->
+ StringToSign =
+ "AWS4-HMAC-SHA256\n20150830T123600Z\n20150830/us-east-1/iam/aws4_request\nf536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59",
+ SigningKey = [
+ 196,
+ 175,
+ 177,
+ 204,
+ 87,
+ 113,
+ 216,
+ 113,
+ 118,
+ 58,
+ 57,
+ 62,
+ 68,
+ 183,
+ 3,
+ 87,
+ 27,
+ 85,
+ 204,
+ 40,
+ 66,
+ 77,
+ 26,
+ 94,
+ 134,
+ 218,
+ 110,
+ 211,
+ 193,
+ 84,
+ 164,
+ 185
+ ],
+ Expectation = "5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7",
+ ?assertEqual(Expectation, rabbitmq_aws_sign:signature(StringToSign, SigningKey))
+ end}
+ ].
signed_headers_test_() ->
- [
- {"with security token", fun() ->
- Value = [{"X-Amz-Security-Token", "AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/L"},
- {"Date", "20160220T120000Z"},
- {"Content-Type", "application/x-amz-json-1.0"},
- {"Host", "ec2.amazonaws.com"},
- {"Content-Length", 128},
- {"X-Amz-Content-sha256", "c888ac0919d062cee1d7b97f44f2a765e4dc9270bc720ba32b8d9f8720626213"},
- {"X-Amz-Target", "DynamoDB_20120810.DescribeTable"}],
- Expectation = "content-length;content-type;date;host;x-amz-content-sha256;x-amz-security-token;x-amz-target",
- ?assertEqual(Expectation, rabbitmq_aws_sign:signed_headers(Value))
- end}
- ].
+ [
+ {"with security token", fun() ->
+ Value = [
+ {"X-Amz-Security-Token",
+ "AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/L"},
+ {"Date", "20160220T120000Z"},
+ {"Content-Type", "application/x-amz-json-1.0"},
+ {"Host", "ec2.amazonaws.com"},
+ {"Content-Length", 128},
+ {"X-Amz-Content-sha256",
+ "c888ac0919d062cee1d7b97f44f2a765e4dc9270bc720ba32b8d9f8720626213"},
+ {"X-Amz-Target", "DynamoDB_20120810.DescribeTable"}
+ ],
+ Expectation =
+ "content-length;content-type;date;host;x-amz-content-sha256;x-amz-security-token;x-amz-target",
+ ?assertEqual(Expectation, rabbitmq_aws_sign:signed_headers(Value))
+ end}
+ ].
signing_key_test_() ->
- [
- {"signing key value", fun() ->
- SecretKey = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
- AMZDate = "20150830",
- Region = "us-east-1",
- Service = "iam",
- Expectation = [196, 175, 177, 204, 87, 113, 216, 113, 118, 58, 57, 62, 68, 183, 3, 87, 27, 85, 204, 40, 66, 77, 26, 94, 134, 218, 110, 211, 193, 84, 164, 185],
- ?assertEqual(Expectation,
- rabbitmq_aws_sign:signing_key(SecretKey, AMZDate, Region, Service))
- end}
- ].
+ [
+ {"signing key value", fun() ->
+ SecretKey = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
+ AMZDate = "20150830",
+ Region = "us-east-1",
+ Service = "iam",
+ Expectation = [
+ 196,
+ 175,
+ 177,
+ 204,
+ 87,
+ 113,
+ 216,
+ 113,
+ 118,
+ 58,
+ 57,
+ 62,
+ 68,
+ 183,
+ 3,
+ 87,
+ 27,
+ 85,
+ 204,
+ 40,
+ 66,
+ 77,
+ 26,
+ 94,
+ 134,
+ 218,
+ 110,
+ 211,
+ 193,
+ 84,
+ 164,
+ 185
+ ],
+ ?assertEqual(
+ Expectation,
+ rabbitmq_aws_sign:signing_key(SecretKey, AMZDate, Region, Service)
+ )
+ end}
+ ].
string_to_sign_test_() ->
- [
- {"string value", fun() ->
- RequestTimestamp = "20150830T123600Z",
- RequestDate = "20150830",
- Region = "us-east-1",
- Service = "iam",
- RequestHash = "f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59",
- Expectation = "AWS4-HMAC-SHA256\n20150830T123600Z\n20150830/us-east-1/iam/aws4_request\nf536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59",
- ?assertEqual(Expectation,
- rabbitmq_aws_sign:string_to_sign(RequestTimestamp, RequestDate, Region, Service, RequestHash))
- end}
- ].
+ [
+ {"string value", fun() ->
+ RequestTimestamp = "20150830T123600Z",
+ RequestDate = "20150830",
+ Region = "us-east-1",
+ Service = "iam",
+ RequestHash = "f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59",
+ Expectation =
+ "AWS4-HMAC-SHA256\n20150830T123600Z\n20150830/us-east-1/iam/aws4_request\nf536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59",
+ ?assertEqual(
+ Expectation,
+ rabbitmq_aws_sign:string_to_sign(
+ RequestTimestamp, RequestDate, Region, Service, RequestHash
+ )
+ )
+ end}
+ ].
local_time_0_test_() ->
- {foreach,
- fun() ->
- meck:new(calendar, [passthrough, unstick])
- end,
- fun(_) ->
- meck:unload(calendar)
- end,
- [
- {"variation1", fun() ->
- meck:expect(calendar, local_time_to_universal_time_dst, fun(_) -> [{{2015, 05, 08}, {12, 36, 00}}] end),
- Expectation = "20150508T123600Z",
- ?assertEqual(Expectation, rabbitmq_aws_sign:local_time()),
- meck:validate(calendar)
- end}
- ]}.
+ {foreach,
+ fun() ->
+ meck:new(calendar, [passthrough, unstick])
+ end,
+ fun(_) ->
+ meck:unload(calendar)
+ end,
+ [
+ {"variation1", fun() ->
+ meck:expect(calendar, local_time_to_universal_time_dst, fun(_) ->
+ [{{2015, 05, 08}, {12, 36, 00}}]
+ end),
+ Expectation = "20150508T123600Z",
+ ?assertEqual(Expectation, rabbitmq_aws_sign:local_time()),
+ meck:validate(calendar)
+ end}
+ ]}.
local_time_1_test_() ->
- [
- {"variation1", fun() ->
- Value = {{2015, 05, 08}, {13, 15, 20}},
- Expectation = "20150508T131520Z",
- ?assertEqual(Expectation, rabbitmq_aws_sign:local_time(Value))
- end},
- {"variation2", fun() ->
- Value = {{2015, 05, 08}, {06, 07, 08}},
- Expectation = "20150508T060708Z",
- ?assertEqual(Expectation, rabbitmq_aws_sign:local_time(Value))
- end}
- ].
+ [
+ {"variation1", fun() ->
+ Value = {{2015, 05, 08}, {13, 15, 20}},
+ Expectation = "20150508T131520Z",
+ ?assertEqual(Expectation, rabbitmq_aws_sign:local_time(Value))
+ end},
+ {"variation2", fun() ->
+ Value = {{2015, 05, 08}, {06, 07, 08}},
+ Expectation = "20150508T060708Z",
+ ?assertEqual(Expectation, rabbitmq_aws_sign:local_time(Value))
+ end}
+ ].
headers_test_() ->
- {foreach,
- fun() ->
- meck:new(calendar, [passthrough, unstick])
- end,
- fun(_) ->
- meck:unload(calendar)
- end,
- [
- {"without signing key", fun() ->
- meck:expect(calendar, local_time_to_universal_time_dst, fun(_) -> [{{2015, 08, 30}, {12, 36, 00}}] end),
- Request = #request{
- access_key = "AKIDEXAMPLE",
- secret_access_key = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
- service = "iam",
- method = get,
- region = "us-east-1",
- uri = "https://iam.amazonaws.com/?Action=ListUsers&Version=2015-05-08",
- body = "",
- headers = [{"Content-Type", "application/x-www-form-urlencoded; charset=utf-8"}]},
- Expectation = [
- {"authorization", "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request, SignedHeaders=content-length;content-type;date;host;x-amz-content-sha256, Signature=81cb49e1e232a0a5f7f594ad6b2ad2b8b7adbafddb3604d00491fe8f3cc5a442"},
- {"content-length", "0"},
- {"content-type", "application/x-www-form-urlencoded; charset=utf-8"},
- {"date", "20150830T123600Z"},
- {"host", "iam.amazonaws.com"},
- {"x-amz-content-sha256", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}
- ],
- ?assertEqual(Expectation, rabbitmq_aws_sign:headers(Request)),
- meck:validate(calendar)
- end},
- {"with host header", fun() ->
- meck:expect(calendar, local_time_to_universal_time_dst, fun(_) -> [{{2015, 08, 30}, {12, 36, 00}}] end),
- Request = #request{
- access_key = "AKIDEXAMPLE",
- secret_access_key = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
- service = "iam",
- method = get,
- region = "us-east-1",
- uri = "https://s3.us-east-1.amazonaws.com/?list-type=2",
- body = "",
- headers = [{"host", "gavinroy.com.s3.amazonaws.com"}]},
- Expectation = [
- {"authorization", "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request, SignedHeaders=content-length;date;host;x-amz-content-sha256, Signature=64e549daad14fc1ba9fc4aca6b7df4b2c60e352e3313090d84a2941c1e653d36"},
- {"content-length","0"},
- {"date","20150830T123600Z"},
- {"host","gavinroy.com.s3.amazonaws.com"},
- {"x-amz-content-sha256", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}
- ],
- ?assertEqual(Expectation, rabbitmq_aws_sign:headers(Request)),
- meck:validate(calendar)
- end}
- ]
- }.
+ {foreach,
+ fun() ->
+ meck:new(calendar, [passthrough, unstick])
+ end,
+ fun(_) ->
+ meck:unload(calendar)
+ end,
+ [
+ {"without signing key", fun() ->
+ meck:expect(calendar, local_time_to_universal_time_dst, fun(_) ->
+ [{{2015, 08, 30}, {12, 36, 00}}]
+ end),
+ Request = #request{
+ access_key = "AKIDEXAMPLE",
+ secret_access_key = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
+ service = "iam",
+ method = get,
+ region = "us-east-1",
+ uri = "https://iam.amazonaws.com/?Action=ListUsers&Version=2015-05-08",
+ body = "",
+ headers = [{"Content-Type", "application/x-www-form-urlencoded; charset=utf-8"}]
+ },
+ Expectation = [
+ {"authorization",
+ "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request, SignedHeaders=content-length;content-type;date;host;x-amz-content-sha256, Signature=81cb49e1e232a0a5f7f594ad6b2ad2b8b7adbafddb3604d00491fe8f3cc5a442"},
+ {"content-length", "0"},
+ {"content-type", "application/x-www-form-urlencoded; charset=utf-8"},
+ {"date", "20150830T123600Z"},
+ {"host", "iam.amazonaws.com"},
+ {"x-amz-content-sha256",
+ "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}
+ ],
+ ?assertEqual(Expectation, rabbitmq_aws_sign:headers(Request)),
+ meck:validate(calendar)
+ end},
+ {"with host header", fun() ->
+ meck:expect(calendar, local_time_to_universal_time_dst, fun(_) ->
+ [{{2015, 08, 30}, {12, 36, 00}}]
+ end),
+ Request = #request{
+ access_key = "AKIDEXAMPLE",
+ secret_access_key = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
+ service = "iam",
+ method = get,
+ region = "us-east-1",
+ uri = "https://s3.us-east-1.amazonaws.com/?list-type=2",
+ body = "",
+ headers = [{"host", "gavinroy.com.s3.amazonaws.com"}]
+ },
+ Expectation = [
+ {"authorization",
+ "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request, SignedHeaders=content-length;date;host;x-amz-content-sha256, Signature=64e549daad14fc1ba9fc4aca6b7df4b2c60e352e3313090d84a2941c1e653d36"},
+ {"content-length", "0"},
+ {"date", "20150830T123600Z"},
+ {"host", "gavinroy.com.s3.amazonaws.com"},
+ {"x-amz-content-sha256",
+ "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}
+ ],
+ ?assertEqual(Expectation, rabbitmq_aws_sign:headers(Request)),
+ meck:validate(calendar)
+ end}
+ ]}.
diff --git a/deps/rabbitmq_aws/test/rabbitmq_aws_sup_tests.erl b/deps/rabbitmq_aws/test/rabbitmq_aws_sup_tests.erl
index c26af15b381e..fdb54facb75a 100644
--- a/deps/rabbitmq_aws/test/rabbitmq_aws_sup_tests.erl
+++ b/deps/rabbitmq_aws/test/rabbitmq_aws_sup_tests.erl
@@ -3,25 +3,29 @@
-include_lib("eunit/include/eunit.hrl").
start_link_test_() ->
- {foreach,
- fun() ->
- meck:new(supervisor, [passthrough, unstick])
- end,
- fun(_) ->
- meck:unload(supervisor)
- end,
- [
- {"supervisor start_link", fun() ->
- meck:expect(supervisor, start_link, fun(_, _, _) -> {ok, test_result} end),
- ?assertEqual({ok, test_result},
- rabbitmq_aws_sup:start_link()),
- meck:validate(supervisor)
- end}
- ]
- }.
+ {foreach,
+ fun() ->
+ meck:new(supervisor, [passthrough, unstick])
+ end,
+ fun(_) ->
+ meck:unload(supervisor)
+ end,
+ [
+ {"supervisor start_link", fun() ->
+ meck:expect(supervisor, start_link, fun(_, _, _) -> {ok, test_result} end),
+ ?assertEqual(
+ {ok, test_result},
+ rabbitmq_aws_sup:start_link()
+ ),
+ meck:validate(supervisor)
+ end}
+ ]}.
init_test() ->
- ?assertEqual({ok, {{one_for_one, 5, 10},
- [{rabbitmq_aws, {rabbitmq_aws, start_link, []},
- permanent, 5, worker, [rabbitmq_aws]}]}},
- rabbitmq_aws_sup:init([])).
+ ?assertEqual(
+ {ok,
+ {{one_for_one, 5, 10}, [
+ {rabbitmq_aws, {rabbitmq_aws, start_link, []}, permanent, 5, worker, [rabbitmq_aws]}
+ ]}},
+ rabbitmq_aws_sup:init([])
+ ).
diff --git a/deps/rabbitmq_aws/test/rabbitmq_aws_tests.erl b/deps/rabbitmq_aws/test/rabbitmq_aws_tests.erl
index d622d1359731..7f5eaa906e44 100644
--- a/deps/rabbitmq_aws/test/rabbitmq_aws_tests.erl
+++ b/deps/rabbitmq_aws/test/rabbitmq_aws_tests.erl
@@ -5,626 +5,750 @@
-include("rabbitmq_aws.hrl").
init_test_() ->
- {foreach,
- fun() ->
- os:putenv("AWS_DEFAULT_REGION", "us-west-3"),
- meck:new(rabbitmq_aws_config, [passthrough])
- end,
- fun(_) ->
- os:unsetenv("AWS_DEFAULT_REGION"),
- meck:unload(rabbitmq_aws_config)
- end,
- [
- {"ok", fun() ->
- os:putenv("AWS_ACCESS_KEY_ID", "Sésame"),
- os:putenv("AWS_SECRET_ACCESS_KEY", "ouvre-toi"),
- {ok, Pid} = rabbitmq_aws:start_link(),
- rabbitmq_aws:set_region("us-west-3"),
- rabbitmq_aws:refresh_credentials(),
- {ok, State} = gen_server:call(Pid, get_state),
- ok = gen_server:stop(Pid),
- os:unsetenv("AWS_ACCESS_KEY_ID"),
- os:unsetenv("AWS_SECRET_ACCESS_KEY"),
- Expectation = {state,"Sésame","ouvre-toi",undefined,undefined,"us-west-3", undefined,undefined},
- ?assertEqual(Expectation, State)
- end},
- {"error", fun() ->
- meck:expect(rabbitmq_aws_config, credentials, fun() -> {error, test_result} end),
- {ok, Pid} = rabbitmq_aws:start_link(),
- rabbitmq_aws:set_region("us-west-3"),
- rabbitmq_aws:refresh_credentials(),
- {ok, State} = gen_server:call(Pid, get_state),
- ok = gen_server:stop(Pid),
- Expectation = {state,undefined,undefined,undefined,undefined,"us-west-3",undefined,test_result},
- ?assertEqual(Expectation, State),
- meck:validate(rabbitmq_aws_config)
- end}
- ]
- }.
+ {foreach,
+ fun() ->
+ os:putenv("AWS_DEFAULT_REGION", "us-west-3"),
+ meck:new(rabbitmq_aws_config, [passthrough])
+ end,
+ fun(_) ->
+ os:unsetenv("AWS_DEFAULT_REGION"),
+ meck:unload(rabbitmq_aws_config)
+ end,
+ [
+ {"ok", fun() ->
+ os:putenv("AWS_ACCESS_KEY_ID", "Sésame"),
+ os:putenv("AWS_SECRET_ACCESS_KEY", "ouvre-toi"),
+ {ok, Pid} = rabbitmq_aws:start_link(),
+ rabbitmq_aws:set_region("us-west-3"),
+ rabbitmq_aws:refresh_credentials(),
+ {ok, State} = gen_server:call(Pid, get_state),
+ ok = gen_server:stop(Pid),
+ os:unsetenv("AWS_ACCESS_KEY_ID"),
+ os:unsetenv("AWS_SECRET_ACCESS_KEY"),
+ Expectation =
+ {state, "Sésame", "ouvre-toi", undefined, undefined, "us-west-3", undefined,
+ undefined},
+ ?assertEqual(Expectation, State)
+ end},
+ {"error", fun() ->
+ meck:expect(rabbitmq_aws_config, credentials, fun() -> {error, test_result} end),
+ {ok, Pid} = rabbitmq_aws:start_link(),
+ rabbitmq_aws:set_region("us-west-3"),
+ rabbitmq_aws:refresh_credentials(),
+ {ok, State} = gen_server:call(Pid, get_state),
+ ok = gen_server:stop(Pid),
+ Expectation =
+ {state, undefined, undefined, undefined, undefined, "us-west-3", undefined,
+ test_result},
+ ?assertEqual(Expectation, State),
+ meck:validate(rabbitmq_aws_config)
+ end}
+ ]}.
terminate_test() ->
- ?assertEqual(ok, rabbitmq_aws:terminate(foo, bar)).
+ ?assertEqual(ok, rabbitmq_aws:terminate(foo, bar)).
code_change_test() ->
- ?assertEqual({ok, {state, denial}}, rabbitmq_aws:code_change(foo, bar, {state, denial})).
+ ?assertEqual({ok, {state, denial}}, rabbitmq_aws:code_change(foo, bar, {state, denial})).
endpoint_test_() ->
- [
- {"specified", fun() ->
- Region = "us-east-3",
- Service = "dynamodb",
- Path = "/",
- Host = "localhost:32767",
- Expectation = "https://localhost:32767/",
- ?assertEqual(Expectation, rabbitmq_aws:endpoint(#state{region = Region}, Host, Service, Path))
- end},
- {"unspecified", fun() ->
- Region = "us-east-3",
- Service = "dynamodb",
- Path = "/",
- Host = undefined,
- Expectation = "https://dynamodb.us-east-3.amazonaws.com/",
- ?assertEqual(Expectation, rabbitmq_aws:endpoint(#state{region = Region}, Host, Service, Path))
- end}
- ].
+ [
+ {"specified", fun() ->
+ Region = "us-east-3",
+ Service = "dynamodb",
+ Path = "/",
+ Host = "localhost:32767",
+ Expectation = "https://localhost:32767/",
+ ?assertEqual(
+ Expectation, rabbitmq_aws:endpoint(#state{region = Region}, Host, Service, Path)
+ )
+ end},
+ {"unspecified", fun() ->
+ Region = "us-east-3",
+ Service = "dynamodb",
+ Path = "/",
+ Host = undefined,
+ Expectation = "https://dynamodb.us-east-3.amazonaws.com/",
+ ?assertEqual(
+ Expectation, rabbitmq_aws:endpoint(#state{region = Region}, Host, Service, Path)
+ )
+ end}
+ ].
endpoint_host_test_() ->
- [
- {"dynamodb service", fun() ->
- Expectation = "dynamodb.us-west-2.amazonaws.com",
- ?assertEqual(Expectation, rabbitmq_aws:endpoint_host("us-west-2", "dynamodb"))
- end}
- ].
+ [
+ {"dynamodb service", fun() ->
+ Expectation = "dynamodb.us-west-2.amazonaws.com",
+ ?assertEqual(Expectation, rabbitmq_aws:endpoint_host("us-west-2", "dynamodb"))
+ end}
+ ].
cn_endpoint_host_test_() ->
- [
- {"s3", fun() ->
- Expectation = "s3.cn-north-1.amazonaws.com.cn",
- ?assertEqual(Expectation, rabbitmq_aws:endpoint_host("cn-north-1", "s3"))
- end},
- {"s3", fun() ->
- Expectation = "s3.cn-northwest-1.amazonaws.com.cn",
- ?assertEqual(Expectation, rabbitmq_aws:endpoint_host("cn-northwest-1", "s3"))
- end}
- ].
+ [
+ {"s3", fun() ->
+ Expectation = "s3.cn-north-1.amazonaws.com.cn",
+ ?assertEqual(Expectation, rabbitmq_aws:endpoint_host("cn-north-1", "s3"))
+ end},
+ {"s3", fun() ->
+ Expectation = "s3.cn-northwest-1.amazonaws.com.cn",
+ ?assertEqual(Expectation, rabbitmq_aws:endpoint_host("cn-northwest-1", "s3"))
+ end}
+ ].
expired_credentials_test_() ->
- {
- foreach,
- fun () ->
- meck:new(calendar, [passthrough, unstick]),
- [calendar]
- end,
- fun meck:unload/1,
- [
- {"true", fun() ->
- Value = {{2016, 4, 1}, {12, 0, 0}},
- Expectation = true,
- meck:expect(calendar, local_time_to_universal_time_dst, fun(_) -> [{{2016, 4, 1}, {12, 0, 0}}] end),
- ?assertEqual(Expectation, rabbitmq_aws:expired_credentials(Value)),
- meck:validate(calendar)
- end},
- {"false", fun() ->
- Value = {{2016,5, 1}, {16, 30, 0}},
- Expectation = false,
- meck:expect(calendar, local_time_to_universal_time_dst, fun(_) -> [{{2016, 4, 1}, {12, 0, 0}}] end),
- ?assertEqual(Expectation, rabbitmq_aws:expired_credentials(Value)),
- meck:validate(calendar)
- end},
- {"undefined", fun() ->
- ?assertEqual(false, rabbitmq_aws:expired_credentials(undefined))
- end}
- ]
- }.
+ {
+ foreach,
+ fun() ->
+ meck:new(calendar, [passthrough, unstick]),
+ [calendar]
+ end,
+ fun meck:unload/1,
+ [
+ {"true", fun() ->
+ Value = {{2016, 4, 1}, {12, 0, 0}},
+ Expectation = true,
+ meck:expect(calendar, local_time_to_universal_time_dst, fun(_) ->
+ [{{2016, 4, 1}, {12, 0, 0}}]
+ end),
+ ?assertEqual(Expectation, rabbitmq_aws:expired_credentials(Value)),
+ meck:validate(calendar)
+ end},
+ {"false", fun() ->
+ Value = {{2016, 5, 1}, {16, 30, 0}},
+ Expectation = false,
+ meck:expect(calendar, local_time_to_universal_time_dst, fun(_) ->
+ [{{2016, 4, 1}, {12, 0, 0}}]
+ end),
+ ?assertEqual(Expectation, rabbitmq_aws:expired_credentials(Value)),
+ meck:validate(calendar)
+ end},
+ {"undefined", fun() ->
+ ?assertEqual(false, rabbitmq_aws:expired_credentials(undefined))
+ end}
+ ]
+ }.
format_response_test_() ->
- [
- {"ok", fun() ->
- Response = {ok, {{"HTTP/1.1", 200, "Ok"}, [{"Content-Type", "text/xml"}], "
SignatureDoesNotMatch
SignatureDoesNotMatch