Switch to using the dep tool and update all the dependencies

This commit is contained in:
Nick Craig-Wood 2017-05-11 15:39:54 +01:00
parent 5135ff73cb
commit 98c2d2c41b
5321 changed files with 4483201 additions and 5922 deletions

View file

@ -0,0 +1,14 @@
Custom Endpoint Example
===
This example provides examples on how you can provide custom endpoints, and logic to how endpoints are resolved by the SDK.
The example creates multiple clients with different endpoint configuration. From a custom endpoint resolver that wraps the default resolver so that any Amazon S3 service client created uses the custom endpoint, to how you can provide your own logic to a single service's endpoint resolving.
Usage
---
```sh
go run -tags example customeEndpoint.go
```

View file

@ -0,0 +1,77 @@
// +build example
package main
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/endpoints"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/sqs"
)
func main() {
defaultResolver := endpoints.DefaultResolver()
s3CustResolverFn := func(service, region string, optFns ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) {
if service == "s3" {
return endpoints.ResolvedEndpoint{
URL: "s3.custom.endpoint.com",
SigningRegion: "custom-signing-region",
}, nil
}
return defaultResolver.EndpointFor(service, region, optFns...)
}
sess := session.Must(session.NewSessionWithOptions(session.Options{
Config: aws.Config{
Region: aws.String("us-west-2"),
EndpointResolver: endpoints.ResolverFunc(s3CustResolverFn),
},
}))
// Create the S3 service client with the shared session. This will
// automatically use the S3 custom endpoint configured in the custom
// endpoint resolver wrapping the default endpoint resolver.
s3Svc := s3.New(sess)
// Operation calls will be made to the custom endpoint.
s3Svc.GetObject(&s3.GetObjectInput{
Bucket: aws.String("myBucket"),
Key: aws.String("myObjectKey"),
})
// Create the SQS service client with the shared session. This will
// fallback to the default endpoint resolver because the customization
// passes any non S3 service endpoint resolve to the default resolver.
sqsSvc := sqs.New(sess)
// Operation calls will be made to the default endpoint for SQS for the
// region configured.
sqsSvc.ReceiveMessage(&sqs.ReceiveMessageInput{
QueueUrl: aws.String("my-queue-url"),
})
// Create a DynamoDB service client that will use a custom endpoint
// resolver that overrides the shared session's. This is useful when
// custom endpoints are generated, or multiple endpoints are switched on
// by a region value.
ddbCustResolverFn := func(service, region string, optFns ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) {
return endpoints.ResolvedEndpoint{
URL: "dynamodb.custom.endpoint",
SigningRegion: "custom-signing-region",
}, nil
}
ddbSvc := dynamodb.New(sess, &aws.Config{
EndpointResolver: endpoints.ResolverFunc(ddbCustResolverFn),
})
// Operation calls will be made to the custom endpoint set in the
// ddCustResolverFn.
ddbSvc.ListTables(&dynamodb.ListTablesInput{})
// Setting Config's Endpoint will override the EndpointResolver. Forcing
// the service clien to make all operation to the endpoint specified
// the in the config.
ddbSvcLocal := dynamodb.New(sess, &aws.Config{
Endpoint: aws.String("http://localhost:8088"),
})
ddbSvcLocal.ListTables(&dynamodb.ListTablesInput{})
}

View file

@ -0,0 +1,37 @@
Enumerate Regions and Endpoints Example
===
Demonstrates how the SDK's endpoints can be enumerated over to discover regions, services, and endpoints defined by the SDK's Regions and Endpoints metadata.
Usage
---
The following parameters can be used to enumerate the SDK's partition metadata.
Example:
go run -tags example enumEndpoints.go -p aws -services -r us-west-2
Output:
Services with endpoint us-west-2 in aws:
ec2
dynamodb
s3
...
CLI parameters
---
```
-p=id partition id, e.g: aws
-r=id region id, e.g: us-west-2
-s=id service id, e.g: s3
-partitions Lists all partitions.
-regions Lists all regions in a partition. Requires partition ID.
If service ID is also provided will show endpoints for a service.
-services Lists all services in a partition. Requires partition ID.
If region ID is also provided, will show services available in that region.
```

View file

@ -0,0 +1,126 @@
// +build example
package main
import (
"flag"
"fmt"
"os"
"github.com/aws/aws-sdk-go/aws/endpoints"
)
// Demostrates how the SDK's endpoints can be enumerated over to discover
// regions, services, and endpoints defined by the SDK's Regions and Endpoints
// metadata.
//
// Usage:
// -p=id partition id, e.g: aws
// -r=id region id, e.g: us-west-2
// -s=id service id, e.g: s3
//
// -partitions Lists all partitions.
// -regions Lists all regions in a partition. Requires partition ID.
// If service ID is also provided will show endpoints for a service.
// -services Lists all services in a partition. Requires partition ID.
// If region ID is also provided, will show services available in that region.
//
// Example:
// go run enumEndpoints.go -p aws -services -r us-west-2
//
// Output:
// Services with endpoint us-west-2 in aws:
// ...
func main() {
var partitionID, regionID, serviceID string
flag.StringVar(&partitionID, "p", "", "Partition ID")
flag.StringVar(&regionID, "r", "", "Region ID")
flag.StringVar(&serviceID, "s", "", "Service ID")
var cmdPartitions, cmdRegions, cmdServices bool
flag.BoolVar(&cmdPartitions, "partitions", false, "Lists partitions.")
flag.BoolVar(&cmdRegions, "regions", false, "Lists regions of a partition. Requires partition ID to be provided. Will filter by a service if '-s' is set.")
flag.BoolVar(&cmdServices, "services", false, "Lists services for a partition. Requires partition ID to be provided. Will filter by a region if '-r' is set.")
flag.Parse()
partitions := endpoints.DefaultResolver().(endpoints.EnumPartitions).Partitions()
if cmdPartitions {
printPartitions(partitions)
}
if !(cmdRegions || cmdServices) {
return
}
p, ok := findPartition(partitions, partitionID)
if !ok {
fmt.Fprintf(os.Stderr, "Partition %q not found", partitionID)
os.Exit(1)
}
if cmdRegions {
printRegions(p, serviceID)
}
if cmdServices {
printServices(p, regionID)
}
}
func printPartitions(ps []endpoints.Partition) {
fmt.Println("Partitions:")
for _, p := range ps {
fmt.Println(p.ID())
}
}
func printRegions(p endpoints.Partition, serviceID string) {
if len(serviceID) != 0 {
s, ok := p.Services()[serviceID]
if !ok {
fmt.Fprintf(os.Stderr, "service %q does not exist in partition %q", serviceID, p.ID())
os.Exit(1)
}
es := s.Endpoints()
fmt.Printf("Endpoints for %s in %s:\n", serviceID, p.ID())
for _, e := range es {
r, _ := e.ResolveEndpoint()
fmt.Printf("%s: %s\n", e.ID(), r.URL)
}
} else {
rs := p.Regions()
fmt.Printf("Regions in %s:\n", p.ID())
for _, r := range rs {
fmt.Println(r.ID())
}
}
}
func printServices(p endpoints.Partition, endpointID string) {
ss := p.Services()
if len(endpointID) > 0 {
fmt.Printf("Services with endpoint %s in %s:\n", endpointID, p.ID())
} else {
fmt.Printf("Services in %s:\n", p.ID())
}
for id, s := range ss {
if _, ok := s.Endpoints()[endpointID]; !ok && len(endpointID) > 0 {
continue
}
fmt.Println(id)
}
}
func findPartition(ps []endpoints.Partition, partitionID string) (endpoints.Partition, bool) {
for _, p := range ps {
if p.ID() == partitionID {
return p, true
}
}
return endpoints.Partition{}, false
}

View file

@ -0,0 +1,17 @@
# Handling Specific Service Error Codes
This examples highlights how you can use the `awserr.Error` type to perform logic based on specific error codes returned by service API operations.
In this example the `S3` `GetObject` API operation is used to request the contents of a object in S3. The example handles the `NoSuchBucket` and `NoSuchKey` error codes printing custom messages to stderr. If Any other error is received a generic message is printed.
## Usage
Will make a request to S3 for the contents of an object. If the request was successful, and the object was found the object's path and size will be printed to stdout.
If the object's bucket or key does not exist a specific error message will be printed to stderr for the error.
Any other error will be printed as an unknown error.
```sh
go run -tags example handleServiceErrorCodes.go mybucket mykey
```

View file

@ -0,0 +1,66 @@
// +build example
package main
import (
"fmt"
"os"
"path/filepath"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
func exitErrorf(msg string, args ...interface{}) {
fmt.Fprintf(os.Stderr, msg+"\n", args...)
os.Exit(1)
}
// Will make a request to S3 for the contents of an object. If the request
// was successful, and the object was found the object's path and size will be
// printed to stdout.
//
// If the object's bucket or key does not exist a specific error message will
// be printed to stderr for the error.
//
// Any other error will be printed as an unknown error.
//
// Usage: handleServiceErrorCodes <bucket> <key>
func main() {
if len(os.Args) < 3 {
exitErrorf("Usage: %s <bucket> <key>", filepath.Base(os.Args[0]))
}
sess := session.Must(session.NewSession())
svc := s3.New(sess)
resp, err := svc.GetObject(&s3.GetObjectInput{
Bucket: aws.String(os.Args[1]),
Key: aws.String(os.Args[2]),
})
if err != nil {
// Casting to the awserr.Error type will allow you to inspect the error
// code returned by the service in code. The error code can be used
// to switch on context specific functionality. In this case a context
// specific error message is printed to the user based on the bucket
// and key existing.
//
// For information on other S3 API error codes see:
// http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
case s3.ErrCodeNoSuchBucket:
exitErrorf("bucket %s does not exist", os.Args[1])
case s3.ErrCodeNoSuchKey:
exitErrorf("object with key %s does not exist in bucket %s", os.Args[2], os.Args[1])
}
}
exitErrorf("unknown error occurred, %v", err)
}
defer resp.Body.Close()
fmt.Printf("s3://%s/%s exists. size: %d\n", os.Args[1], os.Args[2],
aws.Int64Value(resp.ContentLength))
}

View file

@ -0,0 +1,13 @@
# Example
Uploads a file to S3 given a bucket and object key. Also takes a duration
value to terminate the update if it doesn't complete within that time.
The AWS Region needs to be provided in the AWS shared config or on the
environment variable as `AWS_REGION`. Credentials also must be provided
Will default to shared config file, but can load from environment if provided.
## Usage:
# Upload myfile.txt to myBucket/myKey. Must complete within 10 minutes or will fail
go run -tags example withContext.go -b mybucket -k myKey -d 10m < myfile.txt

View file

@ -0,0 +1,71 @@
// +build example,go1.7
package main
import (
"context"
"flag"
"fmt"
"os"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
// Uploads a file to S3 given a bucket and object key. Also takes a duration
// value to terminate the update if it doesn't complete within that time.
//
// The AWS Region needs to be provided in the AWS shared config or on the
// environment variable as `AWS_REGION`. Credentials also must be provided
// Will default to shared config file, but can load from environment if provided.
//
// Usage:
// # Upload myfile.txt to myBucket/myKey. Must complete within 10 minutes or will fail
// go run withContext.go -b mybucket -k myKey -d 10m < myfile.txt
func main() {
var bucket, key string
var timeout time.Duration
flag.StringVar(&bucket, "b", "", "Bucket name.")
flag.StringVar(&key, "k", "", "Object key name.")
flag.DurationVar(&timeout, "d", 0, "Upload timeout.")
flag.Parse()
sess := session.Must(session.NewSession())
svc := s3.New(sess)
// Create a context with a timeout that will abort the upload if it takes
// more than the passed in timeout.
ctx := context.Background()
var cancelFn func()
if timeout > 0 {
ctx, cancelFn = context.WithTimeout(ctx, timeout)
}
// Ensure the context is canceled to prevent leaking.
// See context package for more information, https://golang.org/pkg/context/
defer cancelFn()
// Uploads the object to S3. The Context will interrupt the request if the
// timeout expires.
_, err := svc.PutObjectWithContext(ctx, &s3.PutObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
Body: os.Stdin,
})
if err != nil {
if aerr, ok := err.(awserr.Error); ok && aerr.Code() == request.CanceledErrorCode {
// If the SDK can determine the request or retry delay was canceled
// by a context the CanceledErrorCode error code will be returned.
fmt.Fprintf(os.Stderr, "upload canceled due to timeout, %v\n", err)
} else {
fmt.Fprintf(os.Stderr, "failed to upload object, %v\n", err)
}
os.Exit(1)
}
fmt.Printf("successfully uploaded file to %s/%s\n", bucket, key)
}

View file

@ -0,0 +1,12 @@
# Example
This example shows how the CloudFront CookieSigner can be used to generate signed cookies to provided short term access to restricted resourced fronted by CloudFront.
# Usage
Makes a request for object using CloudFront cookie signing, and outputs the contents of the object to stdout.
```sh
go run -tags example signCookies.go -file <privkey file> -id <keyId> -r <resource pattern> -g <object to get>
```

View file

@ -0,0 +1,79 @@
// +build example
package main
import (
"flag"
"fmt"
"io/ioutil"
"net/http"
"time"
"github.com/aws/aws-sdk-go/service/cloudfront/sign"
)
// Makes a request for object using CloudFront cookie signing, and outputs
// the contents of the object to stdout.
//
// Usage example:
// signCookies -file <privkey file> -id <keyId> -r <resource pattern> -g <object to get>
func main() {
var keyFile string // Private key PEM file
var keyID string // Key pair ID of CloudFront key pair
var resource string // CloudFront resource pattern
var object string // S3 object frontented by CloudFront
flag.StringVar(&keyFile, "file", "", "private key file")
flag.StringVar(&keyID, "id", "", "key pair id")
flag.StringVar(&resource, "r", "", "resource to request")
flag.StringVar(&object, "g", "", "object to get")
flag.Parse()
// Load the PEM file into memory so it can be used by the signer
privKey, err := sign.LoadPEMPrivKeyFile(keyFile)
if err != nil {
fmt.Println("failed to load key,", err)
return
}
// Create the new CookieSigner to get signed cookies for CloudFront
// resource requests
signer := sign.NewCookieSigner(keyID, privKey)
// Get the cookies for the resource. These will be used
// to make the requests with
cookies, err := signer.Sign(resource, time.Now().Add(1*time.Hour))
if err != nil {
fmt.Println("failed to sign cookies", err)
return
}
// Use the cookies in a http.Client to show how they allow the client
// to request resources from CloudFront.
req, err := http.NewRequest("GET", object, nil)
fmt.Println("Cookies:")
for _, c := range cookies {
fmt.Printf("%s=%s;\n", c.Name, c.Value)
req.AddCookie(c)
}
// Send and handle the response. For a successful response the object's
// content will be written to stdout. The same process could be applied
// to a http service written cookies to the response but using
// http.SetCookie(w, c,) on the ResponseWriter.
resp, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Println("failed to send request", err)
return
}
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("failed to read requested body", err)
return
}
fmt.Println("Response:", resp.Status)
fmt.Println(string(b))
}

View file

@ -0,0 +1,47 @@
# Example
`scanItems` is an example how to use Amazon DynamoDB's Scan API operation with the SDK's `dynamodbattributes.UnmarshalListOfMaps` to unmarshal the Scan response's `Items` `[]map[string]*dynamodb.AttributeValue` field. This unmarshaler can be used with all `[]map[string]*dynamodb.AttributeValue` type fields.
## Go Type
The `Item` time will be used by the example to unmarshal the DynamoDB table's items to.
```go
type Item struct {
Key int
Desc string
Data map[string]interface{}
}
```
Use Go tags to define what the name is of the attribute in your DynamoDB table. See [AWS SDK for Go API Reference: Marshal](https://docs.aws.amazon.com/sdk-for-go/api/service/dynamodb/dynamodbattribute/#Marshal) for more information.
In DynamoDB the structure of the item to be returned will be:
```json
{
"Data": {
"Value 1": "abc",
"Value 2": 1234567890
},
"Desc": "First ddb item",
"Key": 1
}
```
## Usage
`go run -tags example scanItems.go -table "<table_name>" -region "<optional_region>"`
## Output
```
0: Key: 123, Desc: An item in the DynamoDB table
Num Data Values: 0
1: Key: 2, Desc: Second ddb item
Num Data Values: 2
- "A Field": 123
- "Another Field": abc
2: Key: 1, Desc: First ddb item
Num Data Values: 2
- "Value 1": abc
- "Value 2": 1234567890
```

View file

@ -0,0 +1,98 @@
// +build example
package main
import (
"flag"
"fmt"
"os"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
)
func exitWithError(err error) {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
func main() {
cfg := Config{}
if err := cfg.Load(); err != nil {
exitWithError(fmt.Errorf("failed to load config, %v", err))
}
// Create the config specifying the Region for the DynamoDB table.
// If Config.Region is not set the region must come from the shared
// config or AWS_REGION environment variable.
awscfg := &aws.Config{}
if len(cfg.Region) > 0 {
awscfg.WithRegion(cfg.Region)
}
// Create the session that the DynamoDB service will use.
sess := session.Must(session.NewSession(awscfg))
// Create the DynamoDB service client to make the query request with.
svc := dynamodb.New(sess)
// Build the query input parameters
params := &dynamodb.ScanInput{
TableName: aws.String(cfg.Table),
}
if cfg.Limit > 0 {
params.Limit = aws.Int64(cfg.Limit)
}
// Make the DynamoDB Query API call
result, err := svc.Scan(params)
if err != nil {
exitWithError(fmt.Errorf("failed to make Query API call, %v", err))
}
items := []Item{}
// Unmarshal the Items field in the result value to the Item Go type.
err = dynamodbattribute.UnmarshalListOfMaps(result.Items, &items)
if err != nil {
exitWithError(fmt.Errorf("failed to unmarshal Query result items, %v", err))
}
// Print out the items returned
for i, item := range items {
fmt.Printf("%d: Key: %d, Desc: %s\n", i, item.Key, item.Desc)
fmt.Printf("\tNum Data Values: %d\n", len(item.Data))
for k, v := range item.Data {
fmt.Printf("\t- %q: %v\n", k, v)
}
}
}
type Item struct {
Key int
Desc string
Data map[string]interface{}
}
type Config struct {
Table string // required
Region string // optional
Limit int64 // optional
}
func (c *Config) Load() error {
flag.Int64Var(&c.Limit, "limit", 0, "Limit is the max items to be returned, 0 is no limit")
flag.StringVar(&c.Table, "table", "", "Table to Query on")
flag.StringVar(&c.Region, "region", "", "AWS Region the table is in")
flag.Parse()
if len(c.Table) == 0 {
flag.PrintDefaults()
return fmt.Errorf("table name is required.")
}
return nil
}

View file

@ -0,0 +1,52 @@
# Example
You can instantiate `*dynamodb.DynamoDB` and pass that as a parameter to all
methods connecting to DynamoDB, or as `unitTest` demonstrates, create your own
`type` and pass it along as a field.
## Test-compatible DynamoDB field
If you use `*dynamodb.DynamoDB` as a field, you will be unable to unit test it,
as documented in #88. Cast it instead as `dynamodbiface.DynamoDBAPI`:
```go
type ItemGetter struct {
DynamoDB dynamodbiface.DynamoDBAPI
}
```
## Querying actual DynamoDB
You'll need an `*aws.Config` and `*session.Session` for these to work correctly:
```go
// Setup
var getter = new(ItemGetter)
var config *aws.Config = &aws.Config{Region: aws.String("us-west-2"),}
var sess *session.Session = session.NewSession(config)
var svc *dynamodb.DynamoDB = dynamodb.New()
getter.DynamoDB = dynamodbiface.DynamoDBAPI(svc)
// Finally
getter.DynamoDB.GetItem(/* ... */)
```
## Querying in tests
Construct a `fakeDynamoDB` and add the necessary methods for each of those
structs (custom ones for `ItemGetter` and [whatever methods you're using for
DynamoDB](https://github.com/aws/aws-sdk-go/blob/master/service/dynamodb/dynamodbiface/interface.go)),
and you're good to go!
```go
type fakeDynamoDB struct {
dynamodbiface.DynamoDBAPI
}
var getter = new(ItemGetter)
getter.DynamoDB = &fakeDynamoDB{}
// And to run it (assuming you've mocked fakeDynamoDB.GetItem)
getter.DynamoDB.GetItem(/* ... */)
```
## Output
```
$ go test -tags example -cover
PASS
coverage: 100.0% of statements
ok _/Users/shatil/workspace/aws-sdk-go/example/service/dynamodb/unitTest 0.008s
```

View file

@ -0,0 +1,41 @@
// +build example
// Package unitTest demonstrates how to unit test, without needing to pass a
// connector to every function, code that uses DynamoDB.
package unitTest
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface"
)
// ItemGetter can be assigned a DynamoDB connector like:
// svc := dynamodb.DynamoDB(sess)
// getter.DynamoDB = dynamodbiface.DynamoDBAPI(svc)
type ItemGetter struct {
DynamoDB dynamodbiface.DynamoDBAPI
}
// Get a value from a DynamoDB table containing entries like:
// {"id": "my primary key", "value": "valuable value"}
func (ig *ItemGetter) Get(id string) (value string) {
var input = &dynamodb.GetItemInput{
Key: map[string]*dynamodb.AttributeValue{
"id": {
S: aws.String(id),
},
},
TableName: aws.String("my_table"),
AttributesToGet: []*string{
aws.String("value"),
},
}
if output, err := ig.DynamoDB.GetItem(input); err == nil {
if _, ok := output.Item["value"]; ok {
dynamodbattribute.Unmarshal(output.Item["value"], &value)
}
}
return
}

View file

@ -0,0 +1,59 @@
// +build example
// Unit tests for package unitTest.
package unitTest
import (
"errors"
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface"
)
// A fakeDynamoDB instance. During testing, instatiate ItemGetter, then simply
// assign an instance of fakeDynamoDB to it.
type fakeDynamoDB struct {
dynamodbiface.DynamoDBAPI
payload map[string]string // Store expected return values
err error
}
// Mock GetItem such that the output returned carries values identical to input.
func (fd *fakeDynamoDB) GetItem(input *dynamodb.GetItemInput) (*dynamodb.GetItemOutput, error) {
output := new(dynamodb.GetItemOutput)
output.Item = make(map[string]*dynamodb.AttributeValue)
for key, value := range fd.payload {
output.Item[key] = &dynamodb.AttributeValue{
S: aws.String(value),
}
}
return output, fd.err
}
func TestItemGetterGet(t *testing.T) {
expectedKey := "expected key"
expectedValue := "expected value"
getter := new(ItemGetter)
getter.DynamoDB = &fakeDynamoDB{
payload: map[string]string{"id": expectedKey, "value": expectedValue},
}
if actualValue := getter.Get(expectedKey); actualValue != expectedValue {
t.Errorf("Expected %q but got %q", expectedValue, actualValue)
}
}
// When DynamoDB.GetItem returns a non-nil error, expect an empty string.
func TestItemGetterGetFail(t *testing.T) {
expectedKey := "expected key"
expectedValue := "expected value"
getter := new(ItemGetter)
getter.DynamoDB = &fakeDynamoDB{
payload: map[string]string{"id": expectedKey, "value": expectedValue},
err: errors.New("any error"),
}
if actualValue := getter.Get(expectedKey); len(actualValue) > 0 {
t.Errorf("Expected %q but got %q", expectedValue, actualValue)
}
}

View file

@ -0,0 +1,31 @@
# Example
This is an example using the AWS SDK for Go to list ec2 instances that match provided tag name filter.
# Usage
The example uses the bucket name provided, and lists all object keys in a bucket.
```sh
go run -tags example filter_ec2_by_tag.go <name_filter>
```
Output:
```
listing instances with tag vpn in: us-east-1
[{
Instances: [{
AmiLaunchIndex: 0,
Architecture: "x86_64",
BlockDeviceMappings: [{
DeviceName: "/dev/xvda",
Ebs: {
AttachTime: 2016-07-06 18:04:53 +0000 UTC,
DeleteOnTermination: true,
Status: "attached",
VolumeId: "vol-xxxx"
}
}],
...
```

View file

@ -0,0 +1,43 @@
// +build example
package main
import (
"fmt"
"log"
"os"
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
)
// This example will list instances with a filter
//
// Usage:
// filter_ec2_by_tag <name_filter>
func main() {
sess := session.Must(session.NewSession())
nameFilter := os.Args[1]
awsRegion := "us-east-1"
svc := ec2.New(sess, &aws.Config{Region: aws.String(awsRegion)})
fmt.Printf("listing instances with tag %v in: %v\n", nameFilter, awsRegion)
params := &ec2.DescribeInstancesInput{
Filters: []*ec2.Filter{
{
Name: aws.String("tag:Name"),
Values: []*string{
aws.String(strings.Join([]string{"*", nameFilter, "*"}, "")),
},
},
},
}
resp, err := svc.DescribeInstances(params)
if err != nil {
fmt.Println("there was an error listing instances in", awsRegion, err.Error())
log.Fatal(err.Error())
}
fmt.Printf("%+v\n", *resp)
}

View file

@ -0,0 +1,14 @@
# Example
This is an example using the AWS SDK for Go to concatenate two objects together.
We use `UploadPartCopy` which uses an object for a part. Here in this example we have two parts, or in other words
two objects that we want to concatenate together.
# Usage
The example uses the bucket name provided, two keys for each object, and lastly the output key.
```sh
AWS_REGION=<region> go run -tags example concatenateObjects.go <bucket> <key for object 1> <key for object 2> <key for output>
```

View file

@ -0,0 +1,104 @@
// +build example
package main
import (
"log"
"net/url"
"os"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
type client struct {
s3Client *s3.S3
bucket *string
}
// concatenate will contenate key1's object to key2's object under the key testKey
func (c *client) concatenate(key1, key2, key3 string, uploadID *string) (*string, *string, error) {
// The first part to be uploaded which is represented as part number 1
foo, err := c.s3Client.UploadPartCopy(&s3.UploadPartCopyInput{
Bucket: c.bucket,
CopySource: aws.String(url.QueryEscape(*c.bucket + "/" + key1)),
PartNumber: aws.Int64(1),
Key: &key3,
UploadId: uploadID,
})
if err != nil {
return nil, nil, err
}
// The second part that is going to be appended to the newly created testKey
// object.
bar, err := c.s3Client.UploadPartCopy(&s3.UploadPartCopyInput{
Bucket: c.bucket,
CopySource: aws.String(url.QueryEscape(*c.bucket + "/" + key2)),
PartNumber: aws.Int64(2),
Key: &key3,
UploadId: uploadID,
})
if err != nil {
return nil, nil, err
}
// The ETags are needed to complete the process
return foo.CopyPartResult.ETag, bar.CopyPartResult.ETag, nil
}
func main() {
if len(os.Args) < 4 {
log.Println("USAGE ERROR: AWS_REGION=us-east-1 go run concatenateObjects.go <bucket> <key for object 1> <key for object 2> <key for output>")
return
}
bucket := os.Args[1]
key1 := os.Args[2]
key2 := os.Args[3]
key3 := os.Args[4]
sess := session.New(&aws.Config{})
svc := s3.New(sess)
c := client{svc, &bucket}
// We let the service know that we want to do a multipart upload
output, err := c.s3Client.CreateMultipartUpload(&s3.CreateMultipartUploadInput{
Bucket: &bucket,
Key: &key3,
})
if err != nil {
log.Println("ERROR:", err)
return
}
foo, bar, err := c.concatenate(key1, key2, key3, output.UploadId)
if err != nil {
log.Println("ERROR:", err)
return
}
// We finally complete the multipart upload.
_, err = c.s3Client.CompleteMultipartUpload(&s3.CompleteMultipartUploadInput{
Bucket: &bucket,
Key: &key3,
UploadId: output.UploadId,
MultipartUpload: &s3.CompletedMultipartUpload{
Parts: []*s3.CompletedPart{
{
ETag: foo,
PartNumber: aws.Int64(1),
},
{
ETag: bar,
PartNumber: aws.Int64(2),
},
},
},
})
if err != nil {
log.Println("ERROR:", err)
return
}
}

View file

@ -0,0 +1,27 @@
# Example
This is an example using the AWS SDK for Go to list objects' key in a S3 bucket.
# Usage
The example uses the bucket name provided, and lists all object keys in a bucket.
```sh
go run -tags example listObjects.go <bucket>
```
Output:
```
Page, 0
Object: myKey
Object: mykey.txt
Object: resources/0001/item-01
Object: resources/0001/item-02
Object: resources/0001/item-03
Object: resources/0002/item-01
Object: resources/0002/item-02
Object: resources/0002/item-03
Object: resources/0002/item-04
Object: resources/0002/item-05
```

View file

@ -0,0 +1,43 @@
// +build example
package main
import (
"fmt"
"os"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
// Lists all objects in a bucket using pagination
//
// Usage:
// listObjects <bucket>
func main() {
if len(os.Args) < 2 {
fmt.Println("you must specify a bucket")
return
}
sess := session.Must(session.NewSession())
svc := s3.New(sess)
i := 0
err := svc.ListObjectsPages(&s3.ListObjectsInput{
Bucket: &os.Args[1],
}, func(p *s3.ListObjectsOutput, last bool) (shouldContinue bool) {
fmt.Println("Page,", i)
i++
for _, obj := range p.Contents {
fmt.Println("Object:", *obj.Key)
}
return true
})
if err != nil {
fmt.Println("failed to list objects", err)
return
}
}

View file

@ -0,0 +1,13 @@
## Example
This is an example using the AWS SDK for Go concurrently to list the encrypted objects in the S3 buckets owned by an account.
## Usage
The example's `accounts` string slice contains a list of the SharedCredentials profiles which will be used to look up the buckets owned by each profile. Each bucket's objects will be queried.
```
AWS_REGION=us-east-1 go run -tags example listObjectsConcurrentlv.go
```

View file

@ -0,0 +1,236 @@
// +build example
package main
import (
"fmt"
"os"
"sort"
"sync"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
func exit(msg ...interface{}) {
fmt.Fprintln(os.Stderr, msg...)
os.Exit(1)
}
// Lists all encrypted objects owned by an account. The `accounts` string
// contains a list of profiles to use.
//
// Usage:
// listObjectsConcurrentlv
func main() {
accounts := []string{"default", "default2", "otherprofile"}
// Spin off a worker for each account to retrieve that account's
bucketCh := make(chan *Bucket, 5)
var wg sync.WaitGroup
for _, acc := range accounts {
wg.Add(1)
go func(acc string) {
defer wg.Done()
sess, err := session.NewSessionWithOptions(session.Options{
Profile: acc,
})
if err != nil {
fmt.Fprintf(os.Stderr, "failed to create session for account, %s, %v\n", acc, err)
return
}
if err = getAccountBuckets(sess, bucketCh, acc); err != nil {
fmt.Fprintf(os.Stderr, "failed to get account %s's bucket info, %v\n", acc, err)
}
}(acc)
}
// Spin off a goroutine which will wait until all account buckets have been collected and
// added to the bucketCh. Close the bucketCh so the for range below will exit once all
// bucket info is printed.
go func() {
wg.Wait()
close(bucketCh)
}()
// Receive from the bucket channel printing the information for each bucket to the console
// when the bucketCh channel is drained.
buckets := []*Bucket{}
for b := range bucketCh {
buckets = append(buckets, b)
}
sortBuckets(buckets)
for _, b := range buckets {
if b.Error != nil {
fmt.Printf("Bucket %s, owned by: %s, failed: %v\n", b.Name, b.Owner, b.Error)
continue
}
encObjs := b.encryptedObjects()
fmt.Printf("Bucket: %s, owned by: %s, total objects: %d, failed objects: %d, encrypted objects: %d\n",
b.Name, b.Owner, len(b.Objects), len(b.ErrObjects), len(encObjs))
if len(encObjs) > 0 {
for _, encObj := range encObjs {
fmt.Printf("\t%s %s:%s/%s\n", encObj.EncryptionType, b.Region, b.Name, encObj.Key)
}
}
}
}
func sortBuckets(buckets []*Bucket) {
s := sortalbeBuckets(buckets)
sort.Sort(s)
}
type sortalbeBuckets []*Bucket
func (s sortalbeBuckets) Len() int { return len(s) }
func (s sortalbeBuckets) Swap(a, b int) { s[a], s[b] = s[b], s[a] }
func (s sortalbeBuckets) Less(a, b int) bool {
if s[a].Owner == s[b].Owner && s[a].Name < s[b].Name {
return true
}
if s[a].Owner < s[b].Owner {
return true
}
return false
}
func getAccountBuckets(sess *session.Session, bucketCh chan<- *Bucket, owner string) error {
svc := s3.New(sess)
buckets, err := listBuckets(svc)
if err != nil {
return fmt.Errorf("failed to list buckets, %v", err)
}
for _, bucket := range buckets {
bucket.Owner = owner
if bucket.Error != nil {
continue
}
bckSvc := s3.New(sess, &aws.Config{
Region: aws.String(bucket.Region),
Credentials: svc.Config.Credentials,
})
bucketDetails(bckSvc, bucket)
bucketCh <- bucket
}
return nil
}
func bucketDetails(svc *s3.S3, bucket *Bucket) {
objs, errObjs, err := listBucketObjects(svc, bucket.Name)
if err != nil {
bucket.Error = err
} else {
bucket.Objects = objs
bucket.ErrObjects = errObjs
}
}
// A Object provides details of an S3 object
type Object struct {
Bucket string
Key string
Encrypted bool
EncryptionType string
}
// An ErrObject provides details of the error occurred retrieving
// an object's status.
type ErrObject struct {
Bucket string
Key string
Error error
}
// A Bucket provides details about a bucket and its objects
type Bucket struct {
Owner string
Name string
CreationDate time.Time
Region string
Objects []Object
Error error
ErrObjects []ErrObject
}
func (b *Bucket) encryptedObjects() []Object {
encObjs := []Object{}
for _, obj := range b.Objects {
if obj.Encrypted {
encObjs = append(encObjs, obj)
}
}
return encObjs
}
func listBuckets(svc *s3.S3) ([]*Bucket, error) {
res, err := svc.ListBuckets(&s3.ListBucketsInput{})
if err != nil {
return nil, err
}
buckets := make([]*Bucket, len(res.Buckets))
for i, b := range res.Buckets {
buckets[i] = &Bucket{
Name: *b.Name,
CreationDate: *b.CreationDate,
}
locRes, err := svc.GetBucketLocation(&s3.GetBucketLocationInput{
Bucket: b.Name,
})
if err != nil {
buckets[i].Error = err
continue
}
if locRes.LocationConstraint == nil {
buckets[i].Region = "us-east-1"
} else {
buckets[i].Region = *locRes.LocationConstraint
}
}
return buckets, nil
}
func listBucketObjects(svc *s3.S3, bucket string) ([]Object, []ErrObject, error) {
listRes, err := svc.ListObjects(&s3.ListObjectsInput{
Bucket: &bucket,
})
if err != nil {
return nil, nil, err
}
objs := make([]Object, 0, len(listRes.Contents))
errObjs := []ErrObject{}
for _, listObj := range listRes.Contents {
objData, err := svc.HeadObject(&s3.HeadObjectInput{
Bucket: &bucket,
Key: listObj.Key,
})
if err != nil {
errObjs = append(errObjs, ErrObject{Bucket: bucket, Key: *listObj.Key, Error: err})
continue
}
obj := Object{Bucket: bucket, Key: *listObj.Key}
if objData.ServerSideEncryption != nil {
obj.Encrypted = true
obj.EncryptionType = *objData.ServerSideEncryption
}
objs = append(objs, obj)
}
return objs, errObjs, nil
}

View file

@ -0,0 +1,40 @@
# Example
putObjectAcl is an example using the AWS SDK for Go to put an ACL on an S3 object.
# Usage
```sh
putBucketAcl <params>
-region <region> // required
-bucket <bucket> // required
-key <key> // required
-owner-name <owner-name>
-owner-id <owner-id>
-grantee-type <some type> // required
-uri <uri to group>
-email <email address>
-user-id <user-id>
-display-name <display name>
```
```sh
go run -tags example putObjectAcl.go
-bucket <bucket>
-key <key>
-owner-name <name>
-owner-id <id>
-grantee-type <some type>
-user-id <user-id>
```
Depending on the type is used depends on which of the three, `uri`, `email`, or `user-id`, needs to be used.
* `s3.TypeCanonicalUser`: `user-id` or `display-name` must be used
* `s3.TypeAmazonCustomerByEmail`: `email` must be used
* `s3.TypeGroup`: `uri` must be used
Output:
```
success {
} nil
```

View file

@ -0,0 +1,91 @@
// +build example
package main
import (
"flag"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
// Put an ACL on an S3 object
//
// Usage:
// putBucketAcl <params>
// -region <region> // required
// -bucket <bucket> // required
// -key <key> // required
// -owner-name <owner-name>
// -owner-id <owner-id>
// -grantee-type <some type> // required
// -uri <uri to group>
// -email <email address>
// -user-id <user-id>
func main() {
regionPtr := flag.String("region", "", "region of your request")
bucketPtr := flag.String("bucket", "", "name of your bucket")
keyPtr := flag.String("key", "", "of your object")
ownerNamePtr := flag.String("owner-name", "", "of your request")
ownerIDPtr := flag.String("owner-id", "", "of your request")
granteeTypePtr := flag.String("grantee-type", "", "of your request")
uriPtr := flag.String("uri", "", "of your grantee type")
emailPtr := flag.String("email", "", "of your grantee type")
userPtr := flag.String("user-id", "", "of your grantee type")
displayNamePtr := flag.String("display-name", "", "of your grantee type")
flag.Parse()
// Based off the type, fields must be excluded.
switch *granteeTypePtr {
case s3.TypeCanonicalUser:
emailPtr, uriPtr = nil, nil
if *displayNamePtr == "" {
displayNamePtr = nil
}
if *userPtr == "" {
userPtr = nil
}
case s3.TypeAmazonCustomerByEmail:
uriPtr, userPtr = nil, nil
case s3.TypeGroup:
emailPtr, userPtr = nil, nil
}
sess := session.Must(session.NewSession(&aws.Config{
Region: regionPtr,
}))
svc := s3.New(sess)
resp, err := svc.PutObjectAcl(&s3.PutObjectAclInput{
Bucket: bucketPtr,
Key: keyPtr,
AccessControlPolicy: &s3.AccessControlPolicy{
Owner: &s3.Owner{
DisplayName: ownerNamePtr,
ID: ownerIDPtr,
},
Grants: []*s3.Grant{
{
Grantee: &s3.Grantee{
Type: granteeTypePtr,
DisplayName: displayNamePtr,
URI: uriPtr,
EmailAddress: emailPtr,
ID: userPtr,
},
Permission: aws.String(s3.BucketLogsPermissionFullControl),
},
},
},
})
if err != nil {
fmt.Println("failed", err)
} else {
fmt.Println("success", resp)
}
}

View file

@ -0,0 +1,9 @@
# Example
This example shows how the SDK's API interfaces can be used by your code instead of the concrete service client type directly. Using this pattern allows you to mock out your code's usage of the SDK's service client for testing.
# Usage
Use the `go test` tool to verify the `Queue` type's `GetMessages` function correctly unmarshals the SQS message responses.
`go test -tags example ifaceExample.go`

View file

@ -0,0 +1,79 @@
// +build example
package main
import (
"encoding/json"
"fmt"
"os"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sqs"
"github.com/aws/aws-sdk-go/service/sqs/sqsiface"
)
func main() {
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "Queue URL required.")
os.Exit(1)
}
sess := session.Must(session.NewSession())
q := Queue{
Client: sqs.New(sess),
URL: os.Args[1],
}
msgs, err := q.GetMessages(20)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
fmt.Println("Messages:")
for _, msg := range msgs {
fmt.Printf("%s>%s: %s\n", msg.From, msg.To, msg.Msg)
}
}
// Queue provides the ability to handle SQS messages.
type Queue struct {
Client sqsiface.SQSAPI
URL string
}
// Message is a concrete representation of the SQS message
type Message struct {
From string `json:"from"`
To string `json:"to"`
Msg string `json:"msg"`
}
// GetMessages returns the parsed messages from SQS if any. If an error
// occurs that error will be returned.
func (q *Queue) GetMessages(waitTimeout int64) ([]Message, error) {
params := sqs.ReceiveMessageInput{
QueueUrl: aws.String(q.URL),
}
if waitTimeout > 0 {
params.WaitTimeSeconds = aws.Int64(waitTimeout)
}
resp, err := q.Client.ReceiveMessage(&params)
if err != nil {
return nil, fmt.Errorf("failed to get messages, %v", err)
}
msgs := make([]Message, len(resp.Messages))
for i, msg := range resp.Messages {
parsedMsg := Message{}
if err := json.Unmarshal([]byte(aws.StringValue(msg.Body)), &parsedMsg); err != nil {
return nil, fmt.Errorf("failed to unmarshal message, %v", err)
}
msgs[i] = parsedMsg
}
return msgs, nil
}

View file

@ -0,0 +1,65 @@
// +build example
package main
import (
"fmt"
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/sqs"
"github.com/aws/aws-sdk-go/service/sqs/sqsiface"
)
type mockedReceiveMsgs struct {
sqsiface.SQSAPI
Resp sqs.ReceiveMessageOutput
}
func (m mockedReceiveMsgs) ReceiveMessage(in *sqs.ReceiveMessageInput) (*sqs.ReceiveMessageOutput, error) {
// Only need to return mocked response output
return &m.Resp, nil
}
func TestQueueGetMessage(t *testing.T) {
cases := []struct {
Resp sqs.ReceiveMessageOutput
Expected []Message
}{
{ // Case 1, expect parsed responses
Resp: sqs.ReceiveMessageOutput{
Messages: []*sqs.Message{
{Body: aws.String(`{"from":"user_1","to":"room_1","msg":"Hello!"}`)},
{Body: aws.String(`{"from":"user_2","to":"room_1","msg":"Hi user_1 :)"}`)},
},
},
Expected: []Message{
{From: "user_1", To: "room_1", Msg: "Hello!"},
{From: "user_2", To: "room_1", Msg: "Hi user_1 :)"},
},
},
{ // Case 2, not messages returned
Resp: sqs.ReceiveMessageOutput{},
Expected: []Message{},
},
}
for i, c := range cases {
q := Queue{
Client: mockedReceiveMsgs{Resp: c.Resp},
URL: fmt.Sprintf("mockURL_%d", i),
}
msgs, err := q.GetMessages(20)
if err != nil {
t.Fatalf("%d, unexpected error, %v", i, err)
}
if a, e := len(msgs), len(c.Expected); a != e {
t.Fatalf("%d, expected %d messages, got %d", i, e, a)
}
for j, msg := range msgs {
if a, e := msg, c.Expected[j]; a != e {
t.Errorf("%d, expected %v message, got %v", i, e, a)
}
}
}
}