diff --git a/config/config.go b/config/config.go index fa2df2c822d..438a996743f 100644 --- a/config/config.go +++ b/config/config.go @@ -34,8 +34,10 @@ var defaultAWSConfigResolvers = []awsConfigResolver{ // Sets the endpoint resolving behavior the API Clients will use for making // requests to. Clients default to their own clients this allows overrides - // to be specified. + // to be specified. This value is deprecated, but we still need to set it for + // backwards compatability on config construction. resolveEndpointResolver, + resolveEndpointResolverWithOptions, // Sets the retry behavior API clients will use within their retry attempt // middleware. Defaults to unset, allowing API clients to define their own diff --git a/config/example_test.go b/config/example_test.go index a81d29a6b93..267bd6944f0 100644 --- a/config/example_test.go +++ b/config/example_test.go @@ -91,6 +91,20 @@ func ExampleWithEndpointResolver() { _ = cfg } +func ExampleWithEndpointResolverWithOptions() { + cfg, err := config.LoadDefaultConfig(context.TODO(), + config.WithEndpointResolverWithOptions(aws.EndpointResolverWithOptionsFunc( + func(service, region string, options ...interface{}) (aws.Endpoint, error) { + return aws.Endpoint{URL: "https://mock.amazonaws.com"}, nil + })), + ) + + if err != nil { + log.Fatal(err) + } + _ = cfg +} + func ExampleWithHTTPClient() { cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithHTTPClient(awshttp.NewBuildableClient(). diff --git a/config/load_options.go b/config/load_options.go index 15197dfb1b2..a02c6b08b87 100644 --- a/config/load_options.go +++ b/config/load_options.go @@ -31,9 +31,19 @@ type LoadOptions struct { HTTPClient HTTPClient // EndpointResolver that can be used to provide or override an endpoint for the given - // service and region Please see the `aws.EndpointResolver` documentation on usage. + // service and region. + // + // See the `aws.EndpointResolver` documentation on usage. + // + // Deprecated: See EndpointResolverWithOptions EndpointResolver aws.EndpointResolver + // EndpointResolverWithOptions that can be used to provide or override an endpoint for the given + // service and region. + // + // See the `aws.EndpointResolverWithOptions` documentation on usage. + EndpointResolverWithOptions aws.EndpointResolverWithOptions + // Retryer is a function that provides a Retryer implementation. A Retryer guides how HTTP requests should be // retried in case of recoverable failures. Retryer func() aws.Retryer @@ -533,9 +543,11 @@ func (o LoadOptions) getEndpointResolver(ctx context.Context) (aws.EndpointResol } // WithEndpointResolver is a helper function to construct functional options -// that sets endpoint resolver on LoadOptions. The EndpointResolver is set to nil, +// that sets the EndpointResolver on LoadOptions. If the EndpointResolver is set to nil, // the EndpointResolver value is ignored. If multiple WithEndpointResolver calls // are made, the last call overrides the previous call values. +// +// Deprecated: See WithEndpointResolverWithOptions func WithEndpointResolver(v aws.EndpointResolver) LoadOptionsFunc { return func(o *LoadOptions) error { o.EndpointResolver = v @@ -543,6 +555,25 @@ func WithEndpointResolver(v aws.EndpointResolver) LoadOptionsFunc { } } +func (o LoadOptions) getEndpointResolverWithOptions(ctx context.Context) (aws.EndpointResolverWithOptions, bool, error) { + if o.EndpointResolverWithOptions == nil { + return nil, false, nil + } + + return o.EndpointResolverWithOptions, true, nil +} + +// WithEndpointResolverWithOptions is a helper function to construct functional options +// that sets the EndpointResolverWithOptions on LoadOptions. If the EndpointResolverWithOptions is set to nil, +// the EndpointResolver value is ignored. If multiple WithEndpointResolver calls +// are made, the last call overrides the previous call values. +func WithEndpointResolverWithOptions(v aws.EndpointResolverWithOptions) LoadOptionsFunc { + return func(o *LoadOptions) error { + o.EndpointResolverWithOptions = v + return nil + } +} + func (o LoadOptions) getLogger(ctx context.Context) (logging.Logger, bool, error) { if o.Logger == nil { return nil, false, nil diff --git a/config/provider.go b/config/provider.go index a4308368d03..557db2c264a 100644 --- a/config/provider.go +++ b/config/provider.go @@ -336,6 +336,25 @@ func getEndpointResolver(ctx context.Context, configs configs) (f aws.EndpointRe return } +// endpointResolverWithOptionsProvider is an interface for retrieving an aws.EndpointResolverWithOptions from a configuration source +type endpointResolverWithOptionsProvider interface { + getEndpointResolverWithOptions(ctx context.Context) (aws.EndpointResolverWithOptions, bool, error) +} + +// getEndpointResolver searches the provided config sources for a EndpointResolverFunc that can be used +// to configure the aws.Config.EndpointResolver value. +func getEndpointResolverWithOptions(ctx context.Context, configs configs) (f aws.EndpointResolverWithOptions, found bool, err error) { + for _, c := range configs { + if p, ok := c.(endpointResolverWithOptionsProvider); ok { + f, found, err = p.getEndpointResolverWithOptions(ctx) + if err != nil || found { + break + } + } + } + return +} + // loggerProvider is an interface for retrieving a logging.Logger from a configuration source. type loggerProvider interface { getLogger(ctx context.Context) (logging.Logger, bool, error) diff --git a/config/resolve.go b/config/resolve.go index 550ca4e7178..305a2a16a3b 100644 --- a/config/resolve.go +++ b/config/resolve.go @@ -166,6 +166,22 @@ func resolveEndpointResolver(ctx context.Context, cfg *aws.Config, configs confi return nil } +// resolveEndpointResolver extracts the first instance of a EndpointResolverFunc from the config slice +// and sets the functions result on the aws.Config.EndpointResolver +func resolveEndpointResolverWithOptions(ctx context.Context, cfg *aws.Config, configs configs) error { + endpointResolver, found, err := getEndpointResolverWithOptions(ctx, configs) + if err != nil { + return err + } + if !found { + return nil + } + + cfg.EndpointResolverWithOptions = endpointResolver + + return nil +} + func resolveLogger(ctx context.Context, cfg *aws.Config, configs configs) error { logger, found, err := getLogger(ctx, configs) if err != nil { diff --git a/config/resolve_credentials_test.go b/config/resolve_credentials_test.go index a3888bbfdf7..d6663a0b77a 100644 --- a/config/resolve_credentials_test.go +++ b/config/resolve_credentials_test.go @@ -30,7 +30,7 @@ func swapECSContainerURI(path string) func() { } } -func setupCredentialsEndpoints(t *testing.T) (aws.EndpointResolver, func()) { +func setupCredentialsEndpoints(t *testing.T) (aws.EndpointResolverWithOptions, func()) { ecsMetadataServer := httptest.NewServer(http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/ECS" { @@ -95,8 +95,8 @@ func setupCredentialsEndpoints(t *testing.T) (aws.EndpointResolver, func()) { UnixNano()/int64(time.Millisecond)))) })) - resolver := aws.EndpointResolverFunc( - func(service, region string) (aws.Endpoint, error) { + resolver := aws.EndpointResolverWithOptionsFunc( + func(service, region string, options ...interface{}) (aws.Endpoint, error) { switch service { case sts.ServiceID: return aws.Endpoint{ @@ -394,7 +394,7 @@ func TestSharedConfigCredentialSource(t *testing.T) { var credChain []string loadOptions := []func(*LoadOptions) error{ - WithEndpointResolver(endpointResolver), + WithEndpointResolverWithOptions(endpointResolver), WithAPIOptions([]func(*middleware.Stack) error{ func(stack *middleware.Stack) error { return stack.Initialize.Add(middleware.InitializeMiddlewareFunc("GetRoleArns", func(ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler,