diff --git a/src/aws_credentials_ec2.erl b/src/aws_credentials_ec2.erl index 5796c85..5601752 100644 --- a/src/aws_credentials_ec2.erl +++ b/src/aws_credentials_ec2.erl @@ -31,7 +31,7 @@ -export([fetch/1]). --spec fetch(aws_credentials_provider:options()) -> +-spec fetch(any()) -> {error, _} | {ok, aws_credentials:credentials(), aws_credentials_provider:expiration()}. fetch(_Options) -> diff --git a/src/aws_credentials_file.erl b/src/aws_credentials_file.erl index dfc47d5..51a83c2 100644 --- a/src/aws_credentials_file.erl +++ b/src/aws_credentials_file.erl @@ -21,10 +21,11 @@ %% %% Environment parameters: %% %% @end @@ -33,7 +34,12 @@ -export([fetch/1]). --spec fetch(aws_credentials_provider:options()) -> +-type options() :: #{ credential_path => string() + , profile => binary() + }. +-export_type([options/0]). + +-spec fetch(options()) -> {error, any()} | {ok, aws_credentials:credentials(), 'infinity'}. fetch(Options) -> FilePath = get_file_path(Options), @@ -62,7 +68,7 @@ maybe_path_from_env(EnvVar, FilePath) -> {_, Path} -> Path end. --spec get_file_path(aws_credentials_provider:options()) -> {error, any()} | string(). +-spec get_file_path(options()) -> {error, any()} | string(). get_file_path(Options) -> case maps:get(credential_path, Options, undefined) of undefined -> maybe_add_home("/.aws/"); @@ -79,7 +85,7 @@ maybe_add_home(Path) -> -spec maybe_add_region( {error, any()} | {ok, aws_credentials:credentials(), 'infinity'}, {error, any()} | string(), - aws_credentials_provider:options() + options() ) -> {ok, aws_credentials:credentials(), 'infinity'}. maybe_add_region({error, _} = Error, _Config, _Options) -> Error; maybe_add_region(Result, {error, _Error}, _Options) -> Result; @@ -98,7 +104,7 @@ check_path_exists(Path) -> true -> Path end. --spec parse_credentials_file(string(), aws_credentials_provider:options()) -> +-spec parse_credentials_file(string(), options()) -> {error, any()} | {ok, aws_credentials:credentials(), 'infinity'}. parse_credentials_file(Path, Options) -> {ok, F} = file:read_file(Path), @@ -123,7 +129,7 @@ parse_credentials_file(Path, Options) -> end end. --spec parse_config_file(string(), aws_credentials_provider:options()) -> +-spec parse_config_file(string(), options()) -> {error, any()} | {ok, map()}. parse_config_file(Path, Options) -> {ok, F} = file:read_file(Path), @@ -138,7 +144,7 @@ read_from_profile(File, Profile) -> Map -> {ok, Map} end. --spec desired_profile(aws_credentials_provider:options()) -> binary(). +-spec desired_profile(options()) -> binary(). desired_profile(Options) -> case {os:getenv("AWS_PROFILE"), maps:get(profile, Options, undefined)} of {false, undefined} -> <<"default">>; diff --git a/src/aws_credentials_provider.erl b/src/aws_credentials_provider.erl index 9ea7430..37867dc 100644 --- a/src/aws_credentials_provider.erl +++ b/src/aws_credentials_provider.erl @@ -30,7 +30,19 @@ -export([fetch/0, fetch/1]). --type options() :: #{provider() => map()}. +%% `credential_path' and `profile' are treated as common options, +%% and their values are inherited by `provider_specific_options()' +%% unless the same options exist in `provider_specific_options()'. +%% Note: This behaviour is for compatibility reason only, and +%% do not add any further common options. +-type options() :: #{ credential_path => string() + , profile => binary() + , provider() => provider_specific_options() + }. +-type provider_specific_options() :: #{ credential_path => string() + , profile => binary() + , any() => any() + }. -type expiration() :: binary() | pos_integer() | infinity. -type provider() :: aws_credentials_env | aws_credentials_file @@ -40,7 +52,7 @@ -type error_log() :: [{provider(), term()}]. -export_type([ options/0, expiration/0, provider/0 ]). --callback fetch(options()) -> +-callback fetch(provider_specific_options()) -> {ok, aws_credentials:credentials(), expiration()} | {error, any()}. -include_lib("kernel/include/logger.hrl"). @@ -74,7 +86,8 @@ evaluate_providers([], _Options, []) -> evaluate_providers([], _Options, Errors) when is_list(Errors) -> {error, lists:reverse(Errors)}; evaluate_providers([ Provider | Providers ], Options, Errors) -> - case Provider:fetch(Options) of + ProviderOptions = get_provider_specific_options(Provider, Options), + case Provider:fetch(ProviderOptions) of {error, _} = Error -> evaluate_providers(Providers, Options, [{Provider, Error} | Errors]); {ok, Credentials, Expiration} -> @@ -87,3 +100,12 @@ get_env(Key, Default) -> undefined -> Default; {ok, Value} -> Value end. + +-spec get_provider_specific_options(provider(), options()) -> provider_specific_options(). +get_provider_specific_options(Provider, Options) -> + ProviderSpecificOptions = maps:get(Provider, Options, #{}), + IsCommonOptions = fun(profile, _) -> true; (credential_path, _) -> true; (_, _) -> false end, + CommonOptions = maps:filter(IsCommonOptions, Options), + %% If an option exists in both ProviderSpecificOptions and CommonOptions, + %% the value in ProviderSpecificOptions should be adopted. + maps:merge(CommonOptions, ProviderSpecificOptions).