Skip to content

Commit

Permalink
Feature/config refactor (#14)
Browse files Browse the repository at this point in the history
Update the v2 SDK removing the `Session` and `ConfigProvider` types. In their place a new package `external` was created to provide external configuration loading. Such as Environment and Shared config.

This change also flattens the SDK's `request`, `client`, `metadata`, and `credentials` packages into `aws.

* Add external config loading, Remove Session, flatten packages. (#8)

Updates the SDK adding an external package. This package is responsible
for loading external configuration data such as environment and shared
config files. In addition this would be the customers initial interface
into the SDK loading the SDKs config.

Removes session package from the SDK. This update removes the Session
type and all of its loading logic. This is all replaced with the
external package. The aws.Config type is updated to satisfy the
ConfigProvider interface.

Flattens the client, metadata, request, and credentials packages into
aws.

* Renames additional parameters of Credentials (#9)

Renames Credentials:

* Valid -> HasKeys
* ProviderName -> Source
* StaticProvider -> StaticCredentialsProvider
* Add CA Bundle injection
* Add EC2 Metadata region provider util
* Add shared config loading tests.

* Correct the load order of ec2 role creds config resolver (#12)

Corrects the external config loading of credentials so that the EC2 role provider is set first as a fallback. Any other credentials set will override it.

* Remove ConfigProvider switching to aws.Config  (#13)

Removing the ConfigProvider interface replacing all usage with `aws.Config`
  • Loading branch information
jasdel authored Oct 25, 2017
1 parent 9d7ef9b commit 582ad60
Show file tree
Hide file tree
Showing 692 changed files with 54,073 additions and 49,769 deletions.
62 changes: 22 additions & 40 deletions aws/credentials/chain_provider.go → aws/chain_provider.go
Original file line number Diff line number Diff line change
@@ -1,77 +1,63 @@
package credentials
package aws

import (
"github.com/aws/aws-sdk-go-v2/aws/awserr"
)

var (
// ErrNoValidProvidersFoundInChain Is returned when there are no valid
// providers in the ChainProvider.
//
// This has been deprecated. For verbose error messaging set
// aws.Config.CredentialsChainVerboseErrors to true
//
// @readonly
ErrNoValidProvidersFoundInChain = awserr.New("NoCredentialProviders",
`no valid providers in chain. Deprecated.
For verbose messaging see aws.Config.CredentialsChainVerboseErrors`,
nil)
)

// A ChainProvider will search for a provider which returns credentials
// and cache that provider until Retrieve is called again.
//
// The ChainProvider provides a way of chaining multiple providers together
// which will pick the first available using priority order of the Providers
// in the list.
//
// If none of the Providers retrieve valid credentials Value, ChainProvider's
// If none of the Providers retrieve valid credentials Credentials, ChainProvider's
// Retrieve() will return the error ErrNoValidProvidersFoundInChain.
//
// If a Provider is found which returns valid credentials Value ChainProvider
// will cache that Provider for all calls to IsExpired(), until Retrieve is
// If a CredentialsProvider is found which returns valid credentials Credentials ChainProvider
// will cache that CredentialsProvider for all calls to IsExpired(), until Retrieve is
// called again.
//
// Example of ChainProvider to be used with an EnvProvider and EC2RoleProvider.
// In this example EnvProvider will first check if any credentials are available
// via the environment variables. If there are none ChainProvider will check
// the next Provider in the list, EC2RoleProvider in this case. If EC2RoleProvider
// the next CredentialsProvider in the list, EC2RoleProvider in this case. If EC2RoleProvider
// does not return any credentials ChainProvider will return the error
// ErrNoValidProvidersFoundInChain
//
// creds := credentials.NewChainCredentials(
// []credentials.Provider{
// creds := aws.NewChainCredentials(
// []aws.CredentialsProvider{
// &credentials.EnvProvider{},
// &ec2rolecreds.EC2RoleProvider{
// Client: ec2metadata.New(sess),
// Client: ec2metadata.New(cfg),
// },
// })
//
// // Usage of ChainCredentials with aws.Config
// svc := ec2.New(session.Must(session.NewSession(&aws.Config{
// Credentials: creds,
// })))
// cfg := cfg.Copy()
// cfg.Credentials = creds
// svc := ec2.New(cfg)
//
type ChainProvider struct {
Providers []Provider
curr Provider
Providers []CredentialsProvider
curr CredentialsProvider
VerboseErrors bool
}

// NewChainCredentials returns a pointer to a new Credentials object
// wrapping a chain of providers.
func NewChainCredentials(providers []Provider) *Credentials {
return NewCredentials(&ChainProvider{
Providers: append([]Provider{}, providers...),
})
// NewChainProvider returns a pointer to a new ChainProvider value wrapping
// a chain of credentials providers.
func NewChainProvider(providers []CredentialsProvider) *ChainProvider {
return &ChainProvider{
Providers: append([]CredentialsProvider{}, providers...),
}
}

// Retrieve returns the credentials value or error if no provider returned
// without error.
//
// If a provider is found it will be cached and any calls to IsExpired()
// will return the expired state of the cached provider.
func (c *ChainProvider) Retrieve() (Value, error) {
func (c *ChainProvider) Retrieve() (Credentials, error) {
var errs []error
for _, p := range c.Providers {
creds, err := p.Retrieve()
Expand All @@ -83,12 +69,8 @@ func (c *ChainProvider) Retrieve() (Value, error) {
}
c.curr = nil

var err error
err = ErrNoValidProvidersFoundInChain
if c.VerboseErrors {
err = awserr.NewBatchError("NoCredentialProviders", "no valid providers in chain", errs)
}
return Value{}, err
return Credentials{},
awserr.NewBatchError("NoCredentialProviders", "no valid providers in chain", errs)
}

// IsExpired will returned the expired state of the currently cached provider
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
package credentials
package aws

import (
"strings"
"testing"

"github.com/aws/aws-sdk-go-v2/aws/awserr"
"github.com/stretchr/testify/assert"
)

type secondStubProvider struct {
creds Value
creds Credentials
expired bool
err error
}

func (s *secondStubProvider) Retrieve() (Value, error) {
func (s *secondStubProvider) Retrieve() (Credentials, error) {
s.expired = false
s.creds.ProviderName = "secondStubProvider"
s.creds.Source = "secondStubProvider"
return s.creds, s.err
}
func (s *secondStubProvider) IsExpired() bool {
Expand All @@ -24,18 +25,18 @@ func (s *secondStubProvider) IsExpired() bool {

func TestChainProviderWithNames(t *testing.T) {
p := &ChainProvider{
Providers: []Provider{
Providers: []CredentialsProvider{
&stubProvider{err: awserr.New("FirstError", "first provider error", nil)},
&stubProvider{err: awserr.New("SecondError", "second provider error", nil)},
&secondStubProvider{
creds: Value{
creds: Credentials{
AccessKeyID: "AKIF",
SecretAccessKey: "NOSECRET",
SessionToken: "",
},
},
&stubProvider{
creds: Value{
creds: Credentials{
AccessKeyID: "AKID",
SecretAccessKey: "SECRET",
SessionToken: "",
Expand All @@ -46,7 +47,7 @@ func TestChainProviderWithNames(t *testing.T) {

creds, err := p.Retrieve()
assert.Nil(t, err, "Expect no error")
assert.Equal(t, "secondStubProvider", creds.ProviderName, "Expect provider name to match")
assert.Equal(t, "secondStubProvider", creds.Source, "Expect provider name to match")

// Also check credentials
assert.Equal(t, "AKIF", creds.AccessKeyID, "Expect access key ID to match")
Expand All @@ -57,11 +58,11 @@ func TestChainProviderWithNames(t *testing.T) {

func TestChainProviderGet(t *testing.T) {
p := &ChainProvider{
Providers: []Provider{
Providers: []CredentialsProvider{
&stubProvider{err: awserr.New("FirstError", "first provider error", nil)},
&stubProvider{err: awserr.New("SecondError", "second provider error", nil)},
&stubProvider{
creds: Value{
creds: Credentials{
AccessKeyID: "AKID",
SecretAccessKey: "SECRET",
SessionToken: "",
Expand All @@ -80,7 +81,7 @@ func TestChainProviderGet(t *testing.T) {
func TestChainProviderIsExpired(t *testing.T) {
stubProvider := &stubProvider{expired: true}
p := &ChainProvider{
Providers: []Provider{
Providers: []CredentialsProvider{
stubProvider,
},
}
Expand All @@ -99,15 +100,14 @@ func TestChainProviderIsExpired(t *testing.T) {

func TestChainProviderWithNoProvider(t *testing.T) {
p := &ChainProvider{
Providers: []Provider{},
Providers: []CredentialsProvider{},
}

assert.True(t, p.IsExpired(), "Expect expired with no providers")
_, err := p.Retrieve()
assert.Equal(t,
ErrNoValidProvidersFoundInChain,
err,
"Expect no providers error returned")
if e, a := "no valid providers", err.Error(); !strings.Contains(a, e) {
t.Errorf("expect %q error in %q", e, a)
}
}

func TestChainProviderWithNoValidProvider(t *testing.T) {
Expand All @@ -116,39 +116,15 @@ func TestChainProviderWithNoValidProvider(t *testing.T) {
awserr.New("SecondError", "second provider error", nil),
}
p := &ChainProvider{
Providers: []Provider{
Providers: []CredentialsProvider{
&stubProvider{err: errs[0]},
&stubProvider{err: errs[1]},
},
}

assert.True(t, p.IsExpired(), "Expect expired with no providers")
_, err := p.Retrieve()

assert.Equal(t,
ErrNoValidProvidersFoundInChain,
err,
"Expect no providers error returned")
}

func TestChainProviderWithNoValidProviderWithVerboseEnabled(t *testing.T) {
errs := []error{
awserr.New("FirstError", "first provider error", nil),
awserr.New("SecondError", "second provider error", nil),
}
p := &ChainProvider{
VerboseErrors: true,
Providers: []Provider{
&stubProvider{err: errs[0]},
&stubProvider{err: errs[1]},
},
if e, a := "no valid providers", err.Error(); !strings.Contains(a, e) {
t.Errorf("expect %q error in %q", e, a)
}

assert.True(t, p.IsExpired(), "Expect expired with no providers")
_, err := p.Retrieve()

assert.Equal(t,
awserr.NewBatchError("NoCredentialProviders", "no valid providers in chain", errs),
err,
"Expect no providers error returned")
}
85 changes: 85 additions & 0 deletions aws/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package aws

import (
"net/http"
)

// Metadata wraps immutable data from the Client structure.
type Metadata struct {
ServiceName string
APIVersion string

Endpoint string
SigningName string
SigningRegion string

JSONVersion string
TargetPrefix string
}

// A Client implements the base client request and response handling
// used by all service clients.
type Client struct {
Metadata Metadata

Config Config

Region string
CredentialsLoader *CredentialsLoader
EndpointResolver EndpointResolver
Handlers Handlers
Retryer Retryer

// TODO replace with value not pointer
LogLevel *LogLevelType
Logger Logger

HTTPClient *http.Client
}

// NewClient will return a pointer to a new initialized service client.
func NewClient(cfg Config, metadata Metadata) *Client {
svc := &Client{
Metadata: metadata,

// TODO remove config when request reqfactored
Config: cfg,

Region: StringValue(cfg.Region),
CredentialsLoader: cfg.CredentialsLoader,
EndpointResolver: cfg.EndpointResolver,
Handlers: cfg.Handlers.Copy(),
Retryer: cfg.Retryer,

LogLevel: cfg.LogLevel,
Logger: cfg.Logger,
}

retryer := cfg.Retryer
if retryer == nil {
// TODO need better way of specifing default num retries
retryer = DefaultRetryer{NumMaxRetries: 3}
}
svc.Retryer = retryer

svc.AddDebugHandlers()

return svc
}

// NewRequest returns a new Request pointer for the service API
// operation and parameters.
func (c *Client) NewRequest(operation *Operation, params interface{}, data interface{}) *Request {
return New(c.Config, c.Metadata, c.Handlers, c.Retryer, operation, params, data)
}

// AddDebugHandlers injects debug logging handlers into the service to log request
// debug information.
func (c *Client) AddDebugHandlers() {
if !c.Config.LogLevel.AtLeast(LogDebug) {
return
}

c.Handlers.Send.PushFrontNamed(NamedHandler{Name: "awssdk.client.LogRequest", Fn: logRequest})
c.Handlers.Send.PushBackNamed(NamedHandler{Name: "awssdk.client.LogResponse", Fn: logResponse})
}
Loading

0 comments on commit 582ad60

Please sign in to comment.