Skip to content

Commit

Permalink
Refactor Config Module, Add Config Package Documentation and Examples…
Browse files Browse the repository at this point in the history
…, Improve Overall SDK Readme (#822)
  • Loading branch information
skmcgrail authored Oct 15, 2020
1 parent d6986a7 commit e0dda86
Show file tree
Hide file tree
Showing 25 changed files with 547 additions and 418 deletions.
95 changes: 52 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# AWS SDK for Go v2

![Build Status](https://codebuild.us-west-2.amazonaws.com/badges?uuid=eyJlbmNyeXB0ZWREYXRhIjoib1lGQ3N6RFJsalI5a3BPcXB3Rytaak9kYVh1ZW1lZExPNjgzaU9Udng3VE5OL1I3czIwcVhkMUlUeG91ajBVaWRYcVVJSEVQcmZwTWVyT1p5MGszbnA4PSIsIml2UGFyYW1ldGVyU3BlYyI6IkhrZ1VMN20zRmtYY1BrR0wiLCJtYXRlcmlhbFNldFNlcmlhbCI6MX0%3D&branch=master) [![API Reference](https://img.shields.io/badge/api-reference-blue.svg)](https://docs.aws.amazon.com/sdk-for-go/v2/api) [![Join the chat at https://gitter.im/aws/aws-sdk-go](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/aws/aws-sdk-go-v2?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Apache V2 License](https://img.shields.io/badge/license-Apache%20V2-blue.svg)](https://github.com/aws/aws-sdk-go/blob/master/LICENSE.txt)
![Build Status](https://codebuild.us-west-2.amazonaws.com/badges?uuid=eyJlbmNyeXB0ZWREYXRhIjoib1lGQ3N6RFJsalI5a3BPcXB3Rytaak9kYVh1ZW1lZExPNjgzaU9Udng3VE5OL1I3czIwcVhkMUlUeG91ajBVaWRYcVVJSEVQcmZwTWVyT1p5MGszbnA4PSIsIml2UGFyYW1ldGVyU3BlYyI6IkhrZ1VMN20zRmtYY1BrR0wiLCJtYXRlcmlhbFNldFNlcmlhbCI6MX0%3D&branch=master) [![API Reference](https://img.shields.io/badge/api-reference-blue.svg)](https://pkg.go.dev/mod/github.com/aws/aws-sdk-go-v2) [![Apache V2 License](https://img.shields.io/badge/license-Apache%20V2-blue.svg)](https://github.com/aws/aws-sdk-go/blob/master/LICENSE.txt)


`aws-sdk-go-v2` is the **Developer Preview** (aka **beta**) for the v2 AWS SDK for the Go programming language. This Developer Preview is provided to receive feedback from the language community on SDK changes prior to the final release. As such users should expect the SDK to release minor version releases that break backwards compatability. The release notes for the breaking change will include information about the breaking change, and how you can migrate to the latest version.
Expand All @@ -12,7 +12,6 @@ We'll be expanding out the [Issues] and [Projects] sections with additional chan
Jump To:
* [Project Status](_#Project-Status_)
* [Getting Started](_#Getting-Started_)
* [Quick Examples](_#Quick-Examples_)
* [Getting Help](_#Getting-Help_)
* [Contributing](_#Feedback-and-contributing_)
* [More Resources](_#Resources_)
Expand All @@ -33,63 +32,73 @@ Users should expect significant changes that could affect the following (non-exh
* Minimum Supported Go Release following the [Language Release Policy](https://golang.org/doc/devel/release.html#policy)

## Getting started
To get started working with the SDK setup your project for Go modules, and retrieve the SDK dependencies with `go get`.
This example shows how you can use the v2 SDK to make an API request using the SDK's [Amazon DynamoDB] client.

To get started working with the SDK is to use `go get` to add the SDK to your application dependencies using Go modules.

###### Initialize Project
```sh
go get github.com/aws/aws-sdk-go-v2
go get github.com/aws/aws-sdk-go-v2/service/dynamodb
$ mkdir ~/helloaws
$ cd ~/helloaws
$ go mod init helloaws
```
###### Add SDK Dependencies
```sh
$ go get github.com/aws/aws-sdk-go-v2/aws
$ go get github.com/aws/aws-sdk-go-v2/aws/config
$ go get github.com/aws/aws-sdk-go-v2/service/dynamodb
```

## Quick Examples

### Hello AWS

This example shows how you can use the v2 SDK to make an API request using the SDK's [Amazon DynamoDB] client.
###### Write Code
In your preferred editor add the following content to `main.go`

```go
package main

import (
"context"
"fmt"
"context"
"fmt"
"log"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
)

func main() {
// Using the SDK's default configuration, loading additional config
// and credentials values from the environment variables, shared
// credentials, and shared configuration files
cfg, err := config.LoadDefaultConfig()
if err != nil {
panic("unable to load SDK config, " + err.Error())
}

// Set the AWS Region that the service clients should use
cfg.Region = "us-west-2"

// Using the Config value, create the DynamoDB client
svc := dynamodb.NewFromConfig(cfg)

// Build the request with its input parameters
resp, err := svc.DescribeTable(context.Background(), &dynamodb.DescribeTableInput{
TableName: aws.String("myTable"),
})
if err != nil {
panic("failed to describe table, " + err.Error())
}

if err != nil {
panic("failed to describe table, " + err.Error())
}

fmt.Println("Response", resp)
// Using the SDK's default configuration, loading additional config
// and credentials values from the environment variables, shared
// credentials, and shared configuration files
cfg, err := config.LoadDefaultConfig(config.WithRegion("us-west-2"))
if err != nil {
log.Fatalf("unable to load SDK config, %v", err)
}

// Using the Config value, create the DynamoDB client
svc := dynamodb.NewFromConfig(cfg)

// Build the request with its input parameters
resp, err := svc.ListTables(context.Background(), &dynamodb.ListTablesInput{
Limit: aws.Int32(5),
})
if err != nil {
log.Fatalf("failed to list tables, %v", err)
}

fmt.Println("Tables:")
for _, tableName := range resp.TableNames {
fmt.Println(aws.ToString(tableName))
}
}
```

###### Compile and Execute
```sh
$ go run .
Table:
tableOne
tableTwo
```

## Getting Help

Please use these community resources for getting help. We use the GitHub issues
Expand Down
24 changes: 13 additions & 11 deletions config/codegen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,19 @@ const (
)

var implAsserts = map[string][]string{
"SharedConfigProfileProvider": {envConfigType, `WithSharedConfigProfile("")`},
"SharedConfigFilesProvider": {envConfigType, "WithSharedConfigFiles([]string{})"},
"CustomCABundleProvider": {envConfigType, "WithCustomCABundle([]byte{})"},
"RegionProvider": {envConfigType, sharedConfigType, `WithRegion("")` /*"&WithEC2MetadataRegion{}"*/},
"MFATokenFuncProvider": {`WithMFATokenFunc(func() (string, error) { return "", nil })`},
"CredentialsProviderProvider": {`WithCredentialsProvider{credentials.NewStaticCredentialsProvider("", "", "")}`},
"DefaultRegionProvider": {`WithDefaultRegion("")`},
"SharedConfigProfileProvider": {envConfigType, `WithSharedConfigProfile("")`},
"SharedConfigFilesProvider": {envConfigType, `WithSharedConfigFiles(nil)`},
"CustomCABundleProvider": {envConfigType, `WithCustomCABundle(nil)`},
"RegionProvider": {envConfigType, sharedConfigType, `WithRegion("")`, `WithEC2IMDSRegion{}`},
"CredentialsProviderProvider": {`WithCredentialsProvider(nil)`},
"DefaultRegionProvider": {`WithDefaultRegion("")`},
"EC2RoleCredentialOptionsProvider": {`WithEC2RoleCredentialOptions(nil)`},
"EndpointCredentialOptionsProvider": {`WithEndpointCredentialOptions(nil)`},
"EndpointResolverProvider": {`WithEndpointResolver(nil)`},
"APIOptionsProvider": {`WithAPIOptions(nil)`},
"HTTPClientProvider": {`WithHTTPClient(nil)`},
"AssumeRoleCredentialOptionsProvider": {`WithAssumeRoleCredentialOptions(nil)`},
"WebIdentityRoleCredentialOptionsProvider": {`WithWebIdentityRoleCredentialOptions(nil)`},
}

var tplProviderTests = template.Must(template.New("tplProviderTests").Funcs(map[string]interface{}{
Expand All @@ -41,10 +47,6 @@ var tplProviderTests = template.Must(template.New("tplProviderTests").Funcs(map[
package config
import (
"github.com/aws/aws-sdk-go-v2/credentials"
)
{{ $sortedKeys := SortKeys . }}
{{- range $_, $provider := $sortedKeys }}
{{- $implementors := index $ $provider -}}
Expand Down
62 changes: 31 additions & 31 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,30 @@ import (
"github.com/aws/aws-sdk-go-v2/aws"
)

// DefaultLoaders are a slice of functions that will read external configuration
// defaultLoaders are a slice of functions that will read external configuration
// sources for configuration values. These values are read by the AWSConfigResolvers
// using interfaces to extract specific information from the external configuration.
var DefaultLoaders = []Loader{
LoadEnvConfig,
LoadSharedConfigIgnoreNotExist,
var defaultLoaders = []loader{
loadEnvConfig,
loadSharedConfigIgnoreNotExist,
}

// DefaultAWSConfigResolvers are a slice of functions that will resolve external
// defaultAWSConfigResolvers are a slice of functions that will resolve external
// configuration values into AWS configuration values.
//
// This will setup the AWS configuration's Region,
var DefaultAWSConfigResolvers = []AWSConfigResolver{
ResolveDefaultAWSConfig,
ResolveCustomCABundle,
ResolveHTTPClient,
ResolveEndpointResolver,
ResolveAPIOptions,

ResolveRegion,
var defaultAWSConfigResolvers = []awsConfigResolver{
resolveDefaultAWSConfig,
resolveCustomCABundle,
resolveHTTPClient,
resolveEndpointResolver,
resolveAPIOptions,

resolveRegion,
// TODO: Add back EC2 Region Resolver Support
ResolveDefaultRegion,
resolveDefaultRegion,

ResolveCredentials,
resolveCredentials,
}

// A Config represents a generic configuration value or set of values. This type
Expand All @@ -37,22 +37,22 @@ var DefaultAWSConfigResolvers = []AWSConfigResolver{
// to extract specific data from the Config.
type Config interface{}

// A Loader is used to load external configuration data and returns it as
// A loader is used to load external configuration data and returns it as
// a generic Config type.
//
// The loader should return an error if it fails to load the external configuration
// or the configuration data is malformed, or required components missing.
type Loader func(Configs) (Config, error)
type loader func(configs) (Config, error)

// An AWSConfigResolver will extract configuration data from the Configs slice
// An awsConfigResolver will extract configuration data from the configs slice
// using the provider interfaces to extract specific functionality. The extracted
// configuration values will be written to the AWS Config value.
//
// The resolver should return an error if it it fails to extract the data, the
// data is malformed, or incomplete.
type AWSConfigResolver func(cfg *aws.Config, configs Configs) error
type awsConfigResolver func(cfg *aws.Config, configs configs) error

// Configs is a slice of Config values. These values will be used by the
// configs is a slice of Config values. These values will be used by the
// AWSConfigResolvers to extract external configuration values to populate the
// AWS Config type.
//
Expand All @@ -61,15 +61,15 @@ type AWSConfigResolver func(cfg *aws.Config, configs Configs) error
//
// Use ResolveAWSConfig after external Config values have been added or loaded
// to extract the loaded configuration values into the AWS Config.
type Configs []Config
type configs []Config

// AppendFromLoaders iterates over the slice of loaders passed in calling each
// loader function in order. The external config value returned by the loader
// will be added to the returned Configs slice.
// will be added to the returned configs slice.
//
// If a loader returns an error this method will stop iterating and return
// that error.
func (cs Configs) AppendFromLoaders(loaders []Loader) (Configs, error) {
func (cs configs) AppendFromLoaders(loaders []loader) (configs, error) {
for _, fn := range loaders {
cfg, err := fn(cs)
if err != nil {
Expand All @@ -88,7 +88,7 @@ func (cs Configs) AppendFromLoaders(loaders []Loader) (Configs, error) {
//
// If an resolver returns an error this method will return that error, and stop
// iterating over the resolvers.
func (cs Configs) ResolveAWSConfig(resolvers []AWSConfigResolver) (aws.Config, error) {
func (cs configs) ResolveAWSConfig(resolvers []awsConfigResolver) (aws.Config, error) {
var cfg aws.Config

for _, fn := range resolvers {
Expand All @@ -109,7 +109,7 @@ func (cs Configs) ResolveAWSConfig(resolvers []AWSConfigResolver) (aws.Config, e

// ResolveConfig calls the provide function passing slice of configuration sources.
// This implements the aws.ConfigResolver interface.
func (cs Configs) ResolveConfig(f func(configs []interface{}) error) error {
func (cs configs) ResolveConfig(f func(configs []interface{}) error) error {
var cfgs []interface{}
for i := range cs {
cfgs = append(cfgs, cs[i])
Expand All @@ -121,7 +121,7 @@ func (cs Configs) ResolveConfig(f func(configs []interface{}) error) error {
// populates an AWS Config with the values from the external configurations.
//
// An optional variadic set of additional Config values can be provided as input
// that will be prepended to the Configs slice. Use this to add custom configuration.
// that will be prepended to the configs slice. Use this to add custom configuration.
// The custom configurations must satisfy the respective providers for their data
// or the custom data will be ignored by the resolvers and config loaders.
//
Expand All @@ -136,14 +136,14 @@ func (cs Configs) ResolveConfig(f func(configs []interface{}) error) error {
// The default configuration sources are:
// * Environment Variables
// * Shared Configuration and Shared Credentials files.
func LoadDefaultConfig(configs ...Config) (aws.Config, error) {
var cfgs Configs
cfgs = append(cfgs, configs...)
func LoadDefaultConfig(cfgs ...Config) (aws.Config, error) {
var cfgCpy configs
cfgCpy = append(cfgCpy, cfgs...)

cfgs, err := cfgs.AppendFromLoaders(DefaultLoaders)
cfgCpy, err := cfgCpy.AppendFromLoaders(defaultLoaders)
if err != nil {
return aws.Config{}, err
}

return cfgs.ResolveAWSConfig(DefaultAWSConfigResolvers)
return cfgCpy.ResolveAWSConfig(defaultAWSConfigResolvers)
}
22 changes: 11 additions & 11 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import (
)

func TestConfigs_SharedConfigOptions(t *testing.T) {
_, err := Configs{
_, err := configs{
WithSharedConfigProfile("profile-name"),
WithSharedConfigFiles([]string{"creds-file"}),
}.AppendFromLoaders([]Loader{
func(configs Configs) (Config, error) {
}.AppendFromLoaders([]loader{
func(configs configs) (Config, error) {
var profile string
var files []string
var err error
Expand Down Expand Up @@ -54,8 +54,8 @@ func TestConfigs_SharedConfigOptions(t *testing.T) {
func TestConfigs_AppendFromLoaders(t *testing.T) {
expectCfg := WithRegion("mock-region")

cfgs, err := Configs{}.AppendFromLoaders([]Loader{
func(configs Configs) (Config, error) {
cfgs, err := configs{}.AppendFromLoaders([]loader{
func(configs configs) (Config, error) {
if e, a := 0, len(configs); e != a {
t.Errorf("expect %v configs, got %v", e, a)
}
Expand All @@ -77,19 +77,19 @@ func TestConfigs_AppendFromLoaders(t *testing.T) {
}

func TestConfigs_ResolveAWSConfig(t *testing.T) {
configSources := Configs{
configSources := configs{
WithRegion("mock-region"),
WithCredentialsProvider{credentials.StaticCredentialsProvider{
WithCredentialsProvider(credentials.StaticCredentialsProvider{
Value: aws.Credentials{
AccessKeyID: "AKID", SecretAccessKey: "SECRET",
Source: "provider",
},
}},
}),
}

cfg, err := configSources.ResolveAWSConfig([]AWSConfigResolver{
ResolveRegion,
ResolveCredentials,
cfg, err := configSources.ResolveAWSConfig([]awsConfigResolver{
resolveRegion,
resolveCredentials,
})
if err != nil {
t.Fatalf("expect no error, got %v", err)
Expand Down
10 changes: 9 additions & 1 deletion config/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,13 @@
// Use the LoadDefaultConfig to load configuration from all the SDK's supported
// sources, and resolve credentials using the SDK's default credential chain.
//
// * TODO Additional documentation needed.
// LoadDefaultConfig allows for a variadic list of additional Config sources that can
// provide one or more configuration values which can be used to programmatically control the resolution
// of a specific value, or allow for broader range of additional configuration sources not supported by the SDK.
// A Config source implements one or more provider interfaces defined in this package. Config sources passed in will
// take precedence over the default environment and shared config sources used by the SDK. If one or more Config sources
// implement the same provider interface, priority will be handled by the order in which the sources were passed in.
//
// A number of helpers (prefixed by ``With``) are provided in this package that implement their respective provider
// interface. These helpers should be used for overriding configuration programatically at runtime.
package config
Loading

0 comments on commit e0dda86

Please sign in to comment.