ソースを参照

Merge pull request #16640 from samuelkarp/awslogs-logging-driver

[awslogs] Auto-detect region and set user-agent
Tibor Vass 9 年 前
コミット
c545dce004
35 ファイル変更1599 行追加582 行削除
  1. 64 14
      daemon/logger/awslogs/cloudwatchlogs.go
  2. 55 0
      daemon/logger/awslogs/cloudwatchlogs_test.go
  3. 20 0
      daemon/logger/awslogs/cwlogsiface_mock_test.go
  4. 4 3
      docs/reference/logging/awslogs.md
  5. 1 1
      hack/vendor.sh
  6. 1 1
      vendor/src/github.com/aws/aws-sdk-go/aws/awserr/types.go
  7. 15 30
      vendor/src/github.com/aws/aws-sdk-go/aws/config.go
  8. 0 0
      vendor/src/github.com/aws/aws-sdk-go/aws/convert_types.go
  9. 32 53
      vendor/src/github.com/aws/aws-sdk-go/aws/corehandlers/handlers.go
  10. 144 0
      vendor/src/github.com/aws/aws-sdk-go/aws/corehandlers/param_validator.go
  11. 49 43
      vendor/src/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go
  12. 10 2
      vendor/src/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider.go
  13. 39 0
      vendor/src/github.com/aws/aws-sdk-go/aws/defaults/defaults.go
  14. 43 0
      vendor/src/github.com/aws/aws-sdk-go/aws/ec2metadata/api.go
  15. 135 0
      vendor/src/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go
  16. 17 0
      vendor/src/github.com/aws/aws-sdk-go/aws/errors.go
  17. 9 0
      vendor/src/github.com/aws/aws-sdk-go/aws/logger.go
  18. 0 89
      vendor/src/github.com/aws/aws-sdk-go/aws/param_validator.go
  19. 40 13
      vendor/src/github.com/aws/aws-sdk-go/aws/request/handlers.go
  20. 46 10
      vendor/src/github.com/aws/aws-sdk-go/aws/request/request.go
  21. 71 0
      vendor/src/github.com/aws/aws-sdk-go/aws/request/retryer.go
  22. 0 194
      vendor/src/github.com/aws/aws-sdk-go/aws/service.go
  23. 51 0
      vendor/src/github.com/aws/aws-sdk-go/aws/service/default_retryer.go
  24. 133 0
      vendor/src/github.com/aws/aws-sdk-go/aws/service/service.go
  25. 15 0
      vendor/src/github.com/aws/aws-sdk-go/aws/service/serviceinfo/service_info.go
  26. 33 0
      vendor/src/github.com/aws/aws-sdk-go/aws/types.go
  27. 1 1
      vendor/src/github.com/aws/aws-sdk-go/aws/version.go
  28. 19 0
      vendor/src/github.com/aws/aws-sdk-go/internal/protocol/json/jsonutil/build.go
  29. 1 2
      vendor/src/github.com/aws/aws-sdk-go/internal/protocol/json/jsonutil/unmarshal.go
  30. 8 7
      vendor/src/github.com/aws/aws-sdk-go/internal/protocol/jsonrpc/jsonrpc.go
  31. 14 9
      vendor/src/github.com/aws/aws-sdk-go/internal/protocol/rest/build.go
  32. 12 3
      vendor/src/github.com/aws/aws-sdk-go/internal/protocol/rest/unmarshal.go
  33. 2 1
      vendor/src/github.com/aws/aws-sdk-go/internal/signer/v4/v4.go
  34. 498 95
      vendor/src/github.com/aws/aws-sdk-go/service/cloudwatchlogs/api.go
  35. 17 11
      vendor/src/github.com/aws/aws-sdk-go/service/cloudwatchlogs/service.go

+ 64 - 14
daemon/logger/awslogs/cloudwatchlogs.go

@@ -2,8 +2,10 @@
 package awslogs
 
 import (
+	"errors"
 	"fmt"
 	"os"
+	"runtime"
 	"sort"
 	"strings"
 	"sync"
@@ -12,8 +14,12 @@ import (
 	"github.com/Sirupsen/logrus"
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws/awserr"
+	"github.com/aws/aws-sdk-go/aws/defaults"
+	"github.com/aws/aws-sdk-go/aws/ec2metadata"
+	"github.com/aws/aws-sdk-go/aws/request"
 	"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
 	"github.com/docker/docker/daemon/logger"
+	"github.com/docker/docker/version"
 )
 
 const (
@@ -35,6 +41,8 @@ const (
 	resourceAlreadyExistsCode = "ResourceAlreadyExistsException"
 	dataAlreadyAcceptedCode   = "DataAlreadyAcceptedException"
 	invalidSequenceTokenCode  = "InvalidSequenceTokenException"
+
+	userAgentHeader = "User-Agent"
 )
 
 type logStream struct {
@@ -52,12 +60,16 @@ type api interface {
 	PutLogEvents(*cloudwatchlogs.PutLogEventsInput) (*cloudwatchlogs.PutLogEventsOutput, error)
 }
 
+type regionFinder interface {
+	Region() (string, error)
+}
+
 type byTimestamp []*cloudwatchlogs.InputLogEvent
 
 // init registers the awslogs driver and sets the default region, if provided
 func init() {
 	if os.Getenv(regionEnvKey) != "" {
-		aws.DefaultConfig.Region = aws.String(os.Getenv(regionEnvKey))
+		defaults.DefaultConfig.Region = aws.String(os.Getenv(regionEnvKey))
 	}
 	if err := logger.RegisterLogDriver(name, New); err != nil {
 		logrus.Fatal(err)
@@ -79,19 +91,17 @@ func New(ctx logger.Context) (logger.Logger, error) {
 	if ctx.Config[logStreamKey] != "" {
 		logStreamName = ctx.Config[logStreamKey]
 	}
-	config := aws.DefaultConfig
-	if ctx.Config[regionKey] != "" {
-		config = aws.DefaultConfig.Merge(&aws.Config{
-			Region: aws.String(ctx.Config[regionKey]),
-		})
+	client, err := newAWSLogsClient(ctx)
+	if err != nil {
+		return nil, err
 	}
 	containerStream := &logStream{
 		logStreamName: logStreamName,
 		logGroupName:  logGroupName,
-		client:        cloudwatchlogs.New(config),
+		client:        client,
 		messages:      make(chan *logger.Message, 4096),
 	}
-	err := containerStream.create()
+	err = containerStream.create()
 	if err != nil {
 		return nil, err
 	}
@@ -100,6 +110,52 @@ func New(ctx logger.Context) (logger.Logger, error) {
 	return containerStream, nil
 }
 
+// newRegionFinder is a variable such that the implementation
+// can be swapped out for unit tests.
+var newRegionFinder = func() regionFinder {
+	return ec2metadata.New(nil)
+}
+
+// newAWSLogsClient creates the service client for Amazon CloudWatch Logs.
+// Customizations to the default client from the SDK include a Docker-specific
+// User-Agent string and automatic region detection using the EC2 Instance
+// Metadata Service when region is otherwise unspecified.
+func newAWSLogsClient(ctx logger.Context) (api, error) {
+	config := defaults.DefaultConfig
+	if ctx.Config[regionKey] != "" {
+		config = defaults.DefaultConfig.Merge(&aws.Config{
+			Region: aws.String(ctx.Config[regionKey]),
+		})
+	}
+	if config.Region == nil || *config.Region == "" {
+		logrus.Info("Trying to get region from EC2 Metadata")
+		ec2MetadataClient := newRegionFinder()
+		region, err := ec2MetadataClient.Region()
+		if err != nil {
+			logrus.WithFields(logrus.Fields{
+				"error": err,
+			}).Error("Could not get region from EC2 metadata, environment, or log option")
+			return nil, errors.New("Cannot determine region for awslogs driver")
+		}
+		config.Region = &region
+	}
+	logrus.WithFields(logrus.Fields{
+		"region": *config.Region,
+	}).Debug("Created awslogs client")
+	client := cloudwatchlogs.New(config)
+
+	client.Handlers.Build.PushBackNamed(request.NamedHandler{
+		Name: "DockerUserAgentHandler",
+		Fn: func(r *request.Request) {
+			currentAgent := r.HTTPRequest.Header.Get(userAgentHeader)
+			r.HTTPRequest.Header.Set(userAgentHeader,
+				fmt.Sprintf("Docker %s (%s) %s",
+					version.VERSION, runtime.GOOS, currentAgent))
+		},
+	})
+	return client, nil
+}
+
 // Name returns the name of the awslogs logging driver
 func (l *logStream) Name() string {
 	return name
@@ -291,12 +347,6 @@ func ValidateLogOpt(cfg map[string]string) error {
 	if cfg[logGroupKey] == "" {
 		return fmt.Errorf("must specify a value for log opt '%s'", logGroupKey)
 	}
-	if cfg[regionKey] == "" && os.Getenv(regionEnvKey) == "" {
-		return fmt.Errorf(
-			"must specify a value for environment variable '%s' or log opt '%s'",
-			regionEnvKey,
-			regionKey)
-	}
 	return nil
 }
 

+ 55 - 0
daemon/logger/awslogs/cloudwatchlogs_test.go

@@ -2,14 +2,19 @@ package awslogs
 
 import (
 	"errors"
+	"fmt"
+	"net/http"
+	"runtime"
 	"strings"
 	"testing"
 	"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/service/cloudwatchlogs"
 	"github.com/docker/docker/daemon/logger"
+	"github.com/docker/docker/version"
 )
 
 const (
@@ -20,6 +25,56 @@ const (
 	logline           = "this is a log line"
 )
 
+func TestNewAWSLogsClientUserAgentHandler(t *testing.T) {
+	ctx := logger.Context{
+		Config: map[string]string{
+			regionKey: "us-east-1",
+		},
+	}
+
+	client, err := newAWSLogsClient(ctx)
+	if err != nil {
+		t.Fatal(err)
+	}
+	realClient, ok := client.(*cloudwatchlogs.CloudWatchLogs)
+	if !ok {
+		t.Fatal("Could not cast client to cloudwatchlogs.CloudWatchLogs")
+	}
+	buildHandlerList := realClient.Handlers.Build
+	request := &request.Request{
+		HTTPRequest: &http.Request{
+			Header: http.Header{},
+		},
+	}
+	buildHandlerList.Run(request)
+	expectedUserAgentString := fmt.Sprintf("Docker %s (%s) %s/%s",
+		version.VERSION, runtime.GOOS, aws.SDKName, aws.SDKVersion)
+	userAgent := request.HTTPRequest.Header.Get("User-Agent")
+	if userAgent != expectedUserAgentString {
+		t.Errorf("Wrong User-Agent string, expected \"%s\" but was \"%s\"",
+			expectedUserAgentString, userAgent)
+	}
+}
+
+func TestNewAWSLogsClientRegionDetect(t *testing.T) {
+	ctx := logger.Context{
+		Config: map[string]string{},
+	}
+
+	mockMetadata := newMockMetadataClient()
+	newRegionFinder = func() regionFinder {
+		return mockMetadata
+	}
+	mockMetadata.regionResult <- &regionResult{
+		successResult: "us-east-1",
+	}
+
+	_, err := newAWSLogsClient(ctx)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
 func TestCreateSuccess(t *testing.T) {
 	mockClient := newMockClient()
 	stream := &logStream{

+ 20 - 0
daemon/logger/awslogs/cwlogsiface_mock_test.go

@@ -49,6 +49,26 @@ func (m *mockcwlogsclient) PutLogEvents(input *cloudwatchlogs.PutLogEventsInput)
 	return output.successResult, output.errorResult
 }
 
+type mockmetadataclient struct {
+	regionResult chan *regionResult
+}
+
+type regionResult struct {
+	successResult string
+	errorResult   error
+}
+
+func newMockMetadataClient() *mockmetadataclient {
+	return &mockmetadataclient{
+		regionResult: make(chan *regionResult, 1),
+	}
+}
+
+func (m *mockmetadataclient) Region() (string, error) {
+	output := <-m.regionResult
+	return output.successResult, output.errorResult
+}
+
 func test() {
 	_ = &logStream{
 		client: newMockClient(),

+ 4 - 3
docs/reference/logging/awslogs.md

@@ -34,9 +34,10 @@ You can use the `--log-opt NAME=VALUE` flag to specify Amazon CloudWatch Logs lo
 
 ### awslogs-region
 
-You must specify a region for the `awslogs` logging driver. You can specify the
-region with either the `awslogs-region` log option or `AWS_REGION` environment
-variable:
+The `awslogs` logging driver sends your Docker logs to a specific region. Use
+the `awslogs-region` log option or the `AWS_REGION` environment variable to set
+the region.  By default, if your Docker daemon is running on an EC2 instance
+and no region is set, the driver uses the instance's region.
 
     docker run --log-driver=awslogs --log-opt awslogs-region=us-east-1 ...
 

+ 1 - 1
hack/vendor.sh

@@ -64,7 +64,7 @@ clone git github.com/tinylib/msgp 75ee40d2601edf122ef667e2a07d600d4c44490c
 clone git gopkg.in/fsnotify.v1 v1.2.0
 
 # awslogs deps
-clone git github.com/aws/aws-sdk-go v0.7.1
+clone git github.com/aws/aws-sdk-go v0.9.9
 clone git github.com/vaughan0/go-ini a98ad7ee00ec53921f08832bc06ecf7fd600e6a1
 
 clean

+ 1 - 1
vendor/src/github.com/aws/aws-sdk-go/aws/awserr/types.go

@@ -113,7 +113,7 @@ func newRequestError(err Error, statusCode int, requestID string) *requestError
 // Error returns the string representation of the error.
 // Satisfies the error interface.
 func (r requestError) Error() string {
-	extra := fmt.Sprintf("status code: %d, request id: [%s]",
+	extra := fmt.Sprintf("status code: %d, request id: %s",
 		r.statusCode, r.requestID)
 	return SprintError(r.Code(), r.Message(), extra, r.OrigErr())
 }

+ 15 - 30
vendor/src/github.com/aws/aws-sdk-go/aws/config.go

@@ -2,48 +2,20 @@ package aws
 
 import (
 	"net/http"
-	"os"
 	"time"
 
 	"github.com/aws/aws-sdk-go/aws/credentials"
 )
 
-// DefaultChainCredentials is a Credentials which will find the first available
-// credentials Value from the list of Providers.
-//
-// This should be used in the default case. Once the type of credentials are
-// known switching to the specific Credentials will be more efficient.
-var DefaultChainCredentials = credentials.NewChainCredentials(
-	[]credentials.Provider{
-		&credentials.EnvProvider{},
-		&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
-		&credentials.EC2RoleProvider{ExpiryWindow: 5 * time.Minute},
-	})
-
 // The default number of retries for a service. The value of -1 indicates that
 // the service specific retry default will be used.
 const DefaultRetries = -1
 
-// DefaultConfig is the default all service configuration will be based off of.
-// By default, all clients use this structure for initialization options unless
-// a custom configuration object is passed in.
-//
-// You may modify this global structure to change all default configuration
-// in the SDK. Note that configuration options are copied by value, so any
-// modifications must happen before constructing a client.
-var DefaultConfig = NewConfig().
-	WithCredentials(DefaultChainCredentials).
-	WithRegion(os.Getenv("AWS_REGION")).
-	WithHTTPClient(http.DefaultClient).
-	WithMaxRetries(DefaultRetries).
-	WithLogger(NewDefaultLogger()).
-	WithLogLevel(LogOff)
-
 // A Config provides service configuration for service clients. By default,
-// all clients will use the {DefaultConfig} structure.
+// all clients will use the {defaults.DefaultConfig} structure.
 type Config struct {
 	// The credentials object to use when signing requests. Defaults to
-	// {DefaultChainCredentials}.
+	// {defaults.DefaultChainCredentials}.
 	Credentials *credentials.Credentials
 
 	// An optional endpoint URL (hostname only or fully qualified URI)
@@ -102,6 +74,8 @@ type Config struct {
 	// @see http://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html
 	//   Amazon S3: Virtual Hosting of Buckets
 	S3ForcePathStyle *bool
+
+	SleepDelay func(time.Duration)
 }
 
 // NewConfig returns a new Config pointer that can be chained with builder methods to
@@ -190,6 +164,13 @@ func (c *Config) WithS3ForcePathStyle(force bool) *Config {
 	return c
 }
 
+// WithSleepDelay overrides the function used to sleep while waiting for the
+// next retry. Defaults to time.Sleep.
+func (c *Config) WithSleepDelay(fn func(time.Duration)) *Config {
+	c.SleepDelay = fn
+	return c
+}
+
 // Merge returns a new Config with the other Config's attribute values merged into
 // this Config. If the other Config's attribute is nil it will not be merged into
 // the new Config to be returned.
@@ -244,6 +225,10 @@ func (c Config) Merge(other *Config) *Config {
 		dst.S3ForcePathStyle = other.S3ForcePathStyle
 	}
 
+	if other.SleepDelay != nil {
+		dst.SleepDelay = other.SleepDelay
+	}
+
 	return &dst
 }
 

+ 0 - 0
vendor/src/github.com/aws/aws-sdk-go/aws/convutil.go → vendor/src/github.com/aws/aws-sdk-go/aws/convert_types.go


+ 32 - 53
vendor/src/github.com/aws/aws-sdk-go/aws/handler_functions.go → vendor/src/github.com/aws/aws-sdk-go/aws/corehandlers/handlers.go

@@ -1,4 +1,4 @@
-package aws
+package corehandlers
 
 import (
 	"bytes"
@@ -9,15 +9,12 @@ import (
 	"net/url"
 	"regexp"
 	"strconv"
-	"time"
 
+	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws/awserr"
+	"github.com/aws/aws-sdk-go/aws/request"
 )
 
-var sleepDelay = func(delay time.Duration) {
-	time.Sleep(delay)
-}
-
 // Interface for matching types which also have a Len method.
 type lener interface {
 	Len() int
@@ -26,7 +23,7 @@ type lener interface {
 // BuildContentLength builds the content length of a request based on the body,
 // or will use the HTTPRequest.Header's "Content-Length" if defined. If unable
 // to determine request body length and no "Content-Length" was specified it will panic.
-func BuildContentLength(r *Request) {
+var BuildContentLengthHandler = request.NamedHandler{"core.BuildContentLengthHandler", func(r *request.Request) {
 	if slength := r.HTTPRequest.Header.Get("Content-Length"); slength != "" {
 		length, _ := strconv.ParseInt(slength, 10, 64)
 		r.HTTPRequest.ContentLength = length
@@ -40,27 +37,27 @@ func BuildContentLength(r *Request) {
 	case lener:
 		length = int64(body.Len())
 	case io.Seeker:
-		r.bodyStart, _ = body.Seek(0, 1)
+		r.BodyStart, _ = body.Seek(0, 1)
 		end, _ := body.Seek(0, 2)
-		body.Seek(r.bodyStart, 0) // make sure to seek back to original location
-		length = end - r.bodyStart
+		body.Seek(r.BodyStart, 0) // make sure to seek back to original location
+		length = end - r.BodyStart
 	default:
 		panic("Cannot get length of body, must provide `ContentLength`")
 	}
 
 	r.HTTPRequest.ContentLength = length
 	r.HTTPRequest.Header.Set("Content-Length", fmt.Sprintf("%d", length))
-}
+}}
 
 // UserAgentHandler is a request handler for injecting User agent into requests.
-func UserAgentHandler(r *Request) {
-	r.HTTPRequest.Header.Set("User-Agent", SDKName+"/"+SDKVersion)
-}
+var UserAgentHandler = request.NamedHandler{"core.UserAgentHandler", func(r *request.Request) {
+	r.HTTPRequest.Header.Set("User-Agent", aws.SDKName+"/"+aws.SDKVersion)
+}}
 
-var reStatusCode = regexp.MustCompile(`^(\d+)`)
+var reStatusCode = regexp.MustCompile(`^(\d{3})`)
 
 // SendHandler is a request handler to send service request using HTTP client.
-func SendHandler(r *Request) {
+var SendHandler = request.NamedHandler{"core.SendHandler", func(r *request.Request) {
 	var err error
 	r.HTTPResponse, err = r.Service.Config.HTTPClient.Do(r.HTTPRequest)
 	if err != nil {
@@ -68,8 +65,8 @@ func SendHandler(r *Request) {
 		// response. e.g. 301 without location header comes back as string
 		// error and r.HTTPResponse is nil. Other url redirect errors will
 		// comeback in a similar method.
-		if e, ok := err.(*url.Error); ok {
-			if s := reStatusCode.FindStringSubmatch(e.Error()); s != nil {
+		if e, ok := err.(*url.Error); ok && e.Err != nil {
+			if s := reStatusCode.FindStringSubmatch(e.Err.Error()); s != nil {
 				code, _ := strconv.ParseInt(s[1], 10, 64)
 				r.HTTPResponse = &http.Response{
 					StatusCode: int(code),
@@ -79,7 +76,7 @@ func SendHandler(r *Request) {
 				return
 			}
 		}
-		if r.HTTPRequest == nil {
+		if r.HTTPResponse == nil {
 			// Add a dummy request response object to ensure the HTTPResponse
 			// value is consistent.
 			r.HTTPResponse = &http.Response{
@@ -90,68 +87,50 @@ func SendHandler(r *Request) {
 		}
 		// Catch all other request errors.
 		r.Error = awserr.New("RequestError", "send request failed", err)
-		r.Retryable = Bool(true) // network errors are retryable
+		r.Retryable = aws.Bool(true) // network errors are retryable
 	}
-}
+}}
 
 // ValidateResponseHandler is a request handler to validate service response.
-func ValidateResponseHandler(r *Request) {
+var ValidateResponseHandler = request.NamedHandler{"core.ValidateResponseHandler", func(r *request.Request) {
 	if r.HTTPResponse.StatusCode == 0 || r.HTTPResponse.StatusCode >= 300 {
 		// this may be replaced by an UnmarshalError handler
 		r.Error = awserr.New("UnknownError", "unknown error", nil)
 	}
-}
+}}
 
 // AfterRetryHandler performs final checks to determine if the request should
 // be retried and how long to delay.
-func AfterRetryHandler(r *Request) {
+var AfterRetryHandler = request.NamedHandler{"core.AfterRetryHandler", func(r *request.Request) {
 	// If one of the other handlers already set the retry state
 	// we don't want to override it based on the service's state
 	if r.Retryable == nil {
-		r.Retryable = Bool(r.Service.ShouldRetry(r))
+		r.Retryable = aws.Bool(r.ShouldRetry(r))
 	}
 
 	if r.WillRetry() {
-		r.RetryDelay = r.Service.RetryRules(r)
-		sleepDelay(r.RetryDelay)
+		r.RetryDelay = r.RetryRules(r)
+		r.Service.Config.SleepDelay(r.RetryDelay)
 
 		// when the expired token exception occurs the credentials
 		// need to be expired locally so that the next request to
 		// get credentials will trigger a credentials refresh.
-		if r.Error != nil {
-			if err, ok := r.Error.(awserr.Error); ok {
-				if isCodeExpiredCreds(err.Code()) {
-					r.Config.Credentials.Expire()
-				}
-			}
+		if r.IsErrorExpired() {
+			r.Service.Config.Credentials.Expire()
 		}
 
 		r.RetryCount++
 		r.Error = nil
 	}
-}
-
-var (
-	// ErrMissingRegion is an error that is returned if region configuration is
-	// not found.
-	//
-	// @readonly
-	ErrMissingRegion error = awserr.New("MissingRegion", "could not find region configuration", nil)
-
-	// ErrMissingEndpoint is an error that is returned if an endpoint cannot be
-	// resolved for a service.
-	//
-	// @readonly
-	ErrMissingEndpoint error = awserr.New("MissingEndpoint", "'Endpoint' configuration is required for this service", nil)
-)
+}}
 
 // ValidateEndpointHandler is a request handler to validate a request had the
 // appropriate Region and Endpoint set. Will set r.Error if the endpoint or
 // region is not valid.
-func ValidateEndpointHandler(r *Request) {
-	if r.Service.SigningRegion == "" && StringValue(r.Service.Config.Region) == "" {
-		r.Error = ErrMissingRegion
+var ValidateEndpointHandler = request.NamedHandler{"core.ValidateEndpointHandler", func(r *request.Request) {
+	if r.Service.SigningRegion == "" && aws.StringValue(r.Service.Config.Region) == "" {
+		r.Error = aws.ErrMissingRegion
 	} else if r.Service.Endpoint == "" {
-		r.Error = ErrMissingEndpoint
+		r.Error = aws.ErrMissingEndpoint
 	}
-}
+}}

+ 144 - 0
vendor/src/github.com/aws/aws-sdk-go/aws/corehandlers/param_validator.go

@@ -0,0 +1,144 @@
+package corehandlers
+
+import (
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+
+	"github.com/aws/aws-sdk-go/aws/awserr"
+	"github.com/aws/aws-sdk-go/aws/request"
+)
+
+// ValidateParameters is a request handler to validate the input parameters.
+// Validating parameters only has meaning if done prior to the request being sent.
+var ValidateParametersHandler = request.NamedHandler{"core.ValidateParametersHandler", func(r *request.Request) {
+	if r.ParamsFilled() {
+		v := validator{errors: []string{}}
+		v.validateAny(reflect.ValueOf(r.Params), "")
+
+		if count := len(v.errors); count > 0 {
+			format := "%d validation errors:\n- %s"
+			msg := fmt.Sprintf(format, count, strings.Join(v.errors, "\n- "))
+			r.Error = awserr.New("InvalidParameter", msg, nil)
+		}
+	}
+}}
+
+// A validator validates values. Collects validations errors which occurs.
+type validator struct {
+	errors []string
+}
+
+// validateAny will validate any struct, slice or map type. All validations
+// are also performed recursively for nested types.
+func (v *validator) validateAny(value reflect.Value, path string) {
+	value = reflect.Indirect(value)
+	if !value.IsValid() {
+		return
+	}
+
+	switch value.Kind() {
+	case reflect.Struct:
+		v.validateStruct(value, path)
+	case reflect.Slice:
+		for i := 0; i < value.Len(); i++ {
+			v.validateAny(value.Index(i), path+fmt.Sprintf("[%d]", i))
+		}
+	case reflect.Map:
+		for _, n := range value.MapKeys() {
+			v.validateAny(value.MapIndex(n), path+fmt.Sprintf("[%q]", n.String()))
+		}
+	}
+}
+
+// validateStruct will validate the struct value's fields. If the structure has
+// nested types those types will be validated also.
+func (v *validator) validateStruct(value reflect.Value, path string) {
+	prefix := "."
+	if path == "" {
+		prefix = ""
+	}
+
+	for i := 0; i < value.Type().NumField(); i++ {
+		f := value.Type().Field(i)
+		if strings.ToLower(f.Name[0:1]) == f.Name[0:1] {
+			continue
+		}
+		fvalue := value.FieldByName(f.Name)
+
+		err := validateField(f, fvalue, validateFieldRequired, validateFieldMin)
+		if err != nil {
+			v.errors = append(v.errors, fmt.Sprintf("%s: %s", err.Error(), path+prefix+f.Name))
+			continue
+		}
+
+		v.validateAny(fvalue, path+prefix+f.Name)
+	}
+}
+
+type validatorFunc func(f reflect.StructField, fvalue reflect.Value) error
+
+func validateField(f reflect.StructField, fvalue reflect.Value, funcs ...validatorFunc) error {
+	for _, fn := range funcs {
+		if err := fn(f, fvalue); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// Validates that a field has a valid value provided for required fields.
+func validateFieldRequired(f reflect.StructField, fvalue reflect.Value) error {
+	if f.Tag.Get("required") == "" {
+		return nil
+	}
+
+	switch fvalue.Kind() {
+	case reflect.Ptr, reflect.Slice, reflect.Map:
+		if fvalue.IsNil() {
+			return fmt.Errorf("missing required parameter")
+		}
+	default:
+		if !fvalue.IsValid() {
+			return fmt.Errorf("missing required parameter")
+		}
+	}
+	return nil
+}
+
+// Validates that if a value is provided for a field, that value must be at
+// least a minimum length.
+func validateFieldMin(f reflect.StructField, fvalue reflect.Value) error {
+	minStr := f.Tag.Get("min")
+	if minStr == "" {
+		return nil
+	}
+	min, _ := strconv.ParseInt(minStr, 10, 64)
+
+	kind := fvalue.Kind()
+	if kind == reflect.Ptr {
+		if fvalue.IsNil() {
+			return nil
+		}
+		fvalue = fvalue.Elem()
+	}
+
+	switch fvalue.Kind() {
+	case reflect.String:
+		if int64(fvalue.Len()) < min {
+			return fmt.Errorf("field too short, minimum length %d", min)
+		}
+	case reflect.Slice, reflect.Map:
+		if fvalue.IsNil() {
+			return nil
+		}
+		if int64(fvalue.Len()) < min {
+			return fmt.Errorf("field too short, minimum length %d", min)
+		}
+
+		// TODO min can also apply to number minimum value.
+
+	}
+	return nil
+}

+ 49 - 43
vendor/src/github.com/aws/aws-sdk-go/aws/credentials/ec2_role_provider.go → vendor/src/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go

@@ -1,24 +1,25 @@
-package credentials
+package ec2rolecreds
 
 import (
 	"bufio"
 	"encoding/json"
 	"fmt"
-	"net/http"
+	"path"
+	"strings"
 	"time"
 
 	"github.com/aws/aws-sdk-go/aws/awserr"
+	"github.com/aws/aws-sdk-go/aws/credentials"
+	"github.com/aws/aws-sdk-go/aws/ec2metadata"
 )
 
-const metadataCredentialsEndpoint = "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
-
 // A EC2RoleProvider retrieves credentials from the EC2 service, and keeps track if
 // those credentials are expired.
 //
 // Example how to configure the EC2RoleProvider with custom http Client, Endpoint
 // or ExpiryWindow
 //
-//     p := &credentials.EC2RoleProvider{
+//     p := &ec2rolecreds.EC2RoleProvider{
 //         // Pass in a custom timeout to be used when requesting
 //         // IAM EC2 Role credentials.
 //         Client: &http.Client{
@@ -32,13 +33,10 @@ const metadataCredentialsEndpoint = "http://169.254.169.254/latest/meta-data/iam
 //         ExpiryWindow: 0,
 //     }
 type EC2RoleProvider struct {
-	Expiry
-
-	// Endpoint must be fully quantified URL
-	Endpoint string
+	credentials.Expiry
 
-	// HTTP client to use when connecting to EC2 service
-	Client *http.Client
+	// EC2Metadata client to use when connecting to EC2 metadata service
+	Client *ec2metadata.Client
 
 	// ExpiryWindow will allow the credentials to trigger refreshing prior to
 	// the credentials actually expiring. This is beneficial so race conditions
@@ -52,7 +50,7 @@ type EC2RoleProvider struct {
 	ExpiryWindow time.Duration
 }
 
-// NewEC2RoleCredentials returns a pointer to a new Credentials object
+// NewCredentials returns a pointer to a new Credentials object
 // wrapping the EC2RoleProvider.
 //
 // Takes a custom http.Client which can be configured for custom handling of
@@ -64,9 +62,8 @@ type EC2RoleProvider struct {
 // Window is the expiry window that will be subtracted from the expiry returned
 // by the role credential request. This is done so that the credentials will
 // expire sooner than their actual lifespan.
-func NewEC2RoleCredentials(client *http.Client, endpoint string, window time.Duration) *Credentials {
-	return NewCredentials(&EC2RoleProvider{
-		Endpoint:     endpoint,
+func NewCredentials(client *ec2metadata.Client, window time.Duration) *credentials.Credentials {
+	return credentials.NewCredentials(&EC2RoleProvider{
 		Client:       client,
 		ExpiryWindow: window,
 	})
@@ -75,32 +72,29 @@ func NewEC2RoleCredentials(client *http.Client, endpoint string, window time.Dur
 // Retrieve retrieves credentials from the EC2 service.
 // Error will be returned if the request fails, or unable to extract
 // the desired credentials.
-func (m *EC2RoleProvider) Retrieve() (Value, error) {
+func (m *EC2RoleProvider) Retrieve() (credentials.Value, error) {
 	if m.Client == nil {
-		m.Client = http.DefaultClient
-	}
-	if m.Endpoint == "" {
-		m.Endpoint = metadataCredentialsEndpoint
+		m.Client = ec2metadata.New(nil)
 	}
 
-	credsList, err := requestCredList(m.Client, m.Endpoint)
+	credsList, err := requestCredList(m.Client)
 	if err != nil {
-		return Value{}, err
+		return credentials.Value{}, err
 	}
 
 	if len(credsList) == 0 {
-		return Value{}, awserr.New("EmptyEC2RoleList", "empty EC2 Role list", nil)
+		return credentials.Value{}, awserr.New("EmptyEC2RoleList", "empty EC2 Role list", nil)
 	}
 	credsName := credsList[0]
 
-	roleCreds, err := requestCred(m.Client, m.Endpoint, credsName)
+	roleCreds, err := requestCred(m.Client, credsName)
 	if err != nil {
-		return Value{}, err
+		return credentials.Value{}, err
 	}
 
 	m.SetExpiration(roleCreds.Expiration, m.ExpiryWindow)
 
-	return Value{
+	return credentials.Value{
 		AccessKeyID:     roleCreds.AccessKeyID,
 		SecretAccessKey: roleCreds.SecretAccessKey,
 		SessionToken:    roleCreds.Token,
@@ -110,29 +104,35 @@ func (m *EC2RoleProvider) Retrieve() (Value, error) {
 // A ec2RoleCredRespBody provides the shape for deserializing credential
 // request responses.
 type ec2RoleCredRespBody struct {
+	// Success State
 	Expiration      time.Time
 	AccessKeyID     string
 	SecretAccessKey string
 	Token           string
+
+	// Error state
+	Code    string
+	Message string
 }
 
+const iamSecurityCredsPath = "/iam/security-credentials"
+
 // requestCredList requests a list of credentials from the EC2 service.
 // If there are no credentials, or there is an error making or receiving the request
-func requestCredList(client *http.Client, endpoint string) ([]string, error) {
-	resp, err := client.Get(endpoint)
+func requestCredList(client *ec2metadata.Client) ([]string, error) {
+	resp, err := client.GetMetadata(iamSecurityCredsPath)
 	if err != nil {
-		return nil, awserr.New("ListEC2Role", "failed to list EC2 Roles", err)
+		return nil, awserr.New("EC2RoleRequestError", "failed to list EC2 Roles", err)
 	}
-	defer resp.Body.Close()
 
 	credsList := []string{}
-	s := bufio.NewScanner(resp.Body)
+	s := bufio.NewScanner(strings.NewReader(resp))
 	for s.Scan() {
 		credsList = append(credsList, s.Text())
 	}
 
 	if err := s.Err(); err != nil {
-		return nil, awserr.New("ReadEC2Role", "failed to read list of EC2 Roles", err)
+		return nil, awserr.New("SerializationError", "failed to read list of EC2 Roles", err)
 	}
 
 	return credsList, nil
@@ -142,20 +142,26 @@ func requestCredList(client *http.Client, endpoint string) ([]string, error) {
 //
 // If the credentials cannot be found, or there is an error reading the response
 // and error will be returned.
-func requestCred(client *http.Client, endpoint, credsName string) (*ec2RoleCredRespBody, error) {
-	resp, err := client.Get(endpoint + credsName)
+func requestCred(client *ec2metadata.Client, credsName string) (ec2RoleCredRespBody, error) {
+	resp, err := client.GetMetadata(path.Join(iamSecurityCredsPath, credsName))
 	if err != nil {
-		return nil, awserr.New("GetEC2RoleCredentials",
-			fmt.Sprintf("failed to get %s EC2 Role credentials", credsName),
-			err)
+		return ec2RoleCredRespBody{},
+			awserr.New("EC2RoleRequestError",
+				fmt.Sprintf("failed to get %s EC2 Role credentials", credsName),
+				err)
+	}
+
+	respCreds := ec2RoleCredRespBody{}
+	if err := json.NewDecoder(strings.NewReader(resp)).Decode(&respCreds); err != nil {
+		return ec2RoleCredRespBody{},
+			awserr.New("SerializationError",
+				fmt.Sprintf("failed to decode %s EC2 Role credentials", credsName),
+				err)
 	}
-	defer resp.Body.Close()
 
-	respCreds := &ec2RoleCredRespBody{}
-	if err := json.NewDecoder(resp.Body).Decode(respCreds); err != nil {
-		return nil, awserr.New("DecodeEC2RoleCredentials",
-			fmt.Sprintf("failed to decode %s EC2 Role credentials", credsName),
-			err)
+	if respCreds.Code != "Success" {
+		// If an error code was returned something failed requesting the role.
+		return ec2RoleCredRespBody{}, awserr.New(respCreds.Code, respCreds.Message, nil)
 	}
 
 	return respCreds, nil

+ 10 - 2
vendor/src/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider.go

@@ -22,8 +22,12 @@ var (
 //
 // Profile ini file example: $HOME/.aws/credentials
 type SharedCredentialsProvider struct {
-	// Path to the shared credentials file. If empty will default to current user's
-	// home directory.
+	// Path to the shared credentials file.
+	//
+	// If empty will look for "AWS_SHARED_CREDENTIALS_FILE" env variable. If the
+	// env value is empty will default to current user's home directory.
+	// Linux/OSX: "$HOME/.aws/credentials"
+	// Windows:   "%USERPROFILE%\.aws\credentials"
 	Filename string
 
 	// AWS Profile to extract credentials from the shared credentials file. If empty
@@ -106,6 +110,10 @@ func loadProfile(filename, profile string) (Value, error) {
 // Will return an error if the user's home directory path cannot be found.
 func (p *SharedCredentialsProvider) filename() (string, error) {
 	if p.Filename == "" {
+		if p.Filename = os.Getenv("AWS_SHARED_CREDENTIALS_FILE"); p.Filename != "" {
+			return p.Filename, nil
+		}
+
 		homeDir := os.Getenv("HOME") // *nix
 		if homeDir == "" {           // Windows
 			homeDir = os.Getenv("USERPROFILE")

+ 39 - 0
vendor/src/github.com/aws/aws-sdk-go/aws/defaults/defaults.go

@@ -0,0 +1,39 @@
+package defaults
+
+import (
+	"net/http"
+	"os"
+	"time"
+
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/aws/credentials"
+	"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
+)
+
+// DefaultChainCredentials is a Credentials which will find the first available
+// credentials Value from the list of Providers.
+//
+// This should be used in the default case. Once the type of credentials are
+// known switching to the specific Credentials will be more efficient.
+var DefaultChainCredentials = credentials.NewChainCredentials(
+	[]credentials.Provider{
+		&credentials.EnvProvider{},
+		&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
+		&ec2rolecreds.EC2RoleProvider{ExpiryWindow: 5 * time.Minute},
+	})
+
+// DefaultConfig is the default all service configuration will be based off of.
+// By default, all clients use this structure for initialization options unless
+// a custom configuration object is passed in.
+//
+// You may modify this global structure to change all default configuration
+// in the SDK. Note that configuration options are copied by value, so any
+// modifications must happen before constructing a client.
+var DefaultConfig = aws.NewConfig().
+	WithCredentials(DefaultChainCredentials).
+	WithRegion(os.Getenv("AWS_REGION")).
+	WithHTTPClient(http.DefaultClient).
+	WithMaxRetries(aws.DefaultRetries).
+	WithLogger(aws.NewDefaultLogger()).
+	WithLogLevel(aws.LogOff).
+	WithSleepDelay(time.Sleep)

+ 43 - 0
vendor/src/github.com/aws/aws-sdk-go/aws/ec2metadata/api.go

@@ -0,0 +1,43 @@
+package ec2metadata
+
+import (
+	"path"
+
+	"github.com/aws/aws-sdk-go/aws/request"
+)
+
+// GetMetadata uses the path provided to request
+func (c *Client) GetMetadata(p string) (string, error) {
+	op := &request.Operation{
+		Name:       "GetMetadata",
+		HTTPMethod: "GET",
+		HTTPPath:   path.Join("/", "meta-data", p),
+	}
+
+	output := &metadataOutput{}
+	req := request.New(c.Service.ServiceInfo, c.Service.Handlers, c.Service.Retryer, op, nil, output)
+
+	return output.Content, req.Send()
+}
+
+// Region returns the region the instance is running in.
+func (c *Client) Region() (string, error) {
+	resp, err := c.GetMetadata("placement/availability-zone")
+	if err != nil {
+		return "", err
+	}
+
+	// returns region without the suffix. Eg: us-west-2a becomes us-west-2
+	return resp[:len(resp)-1], nil
+}
+
+// Available returns if the application has access to the EC2 Metadata service.
+// Can be used to determine if application is running within an EC2 Instance and
+// the metadata service is available.
+func (c *Client) Available() bool {
+	if _, err := c.GetMetadata("instance-id"); err != nil {
+		return false
+	}
+
+	return true
+}

+ 135 - 0
vendor/src/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go

@@ -0,0 +1,135 @@
+package ec2metadata
+
+import (
+	"io/ioutil"
+	"net/http"
+
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/aws/awserr"
+	"github.com/aws/aws-sdk-go/aws/credentials"
+	"github.com/aws/aws-sdk-go/aws/request"
+	"github.com/aws/aws-sdk-go/aws/service"
+	"github.com/aws/aws-sdk-go/aws/service/serviceinfo"
+)
+
+// DefaultRetries states the default number of times the service client will
+// attempt to retry a failed request before failing.
+const DefaultRetries = 3
+
+// A Config provides the configuration for the EC2 Metadata service.
+type Config struct {
+	// An optional endpoint URL (hostname only or fully qualified URI)
+	// that overrides the default service endpoint for a client. Set this
+	// to nil, or `""` to use the default service endpoint.
+	Endpoint *string
+
+	// The HTTP client to use when sending requests. Defaults to
+	// `http.DefaultClient`.
+	HTTPClient *http.Client
+
+	// An integer value representing the logging level. The default log level
+	// is zero (LogOff), which represents no logging. To enable logging set
+	// to a LogLevel Value.
+	Logger aws.Logger
+
+	// The logger writer interface to write logging messages to. Defaults to
+	// standard out.
+	LogLevel *aws.LogLevelType
+
+	// The maximum number of times that a request will be retried for failures.
+	// Defaults to DefaultRetries for the number of retries to be performed
+	// per request.
+	MaxRetries *int
+}
+
+// A Client is an EC2 Metadata service Client.
+type Client struct {
+	*service.Service
+}
+
+// New creates a new instance of the EC2 Metadata service client.
+//
+// In the general use case the configuration for this service client should not
+// be needed and `nil` can be provided. Configuration is only needed if the
+// `ec2metadata.Config` defaults need to be overridden. Eg. Setting LogLevel.
+//
+// @note This configuration will NOT be merged with the default AWS service
+// client configuration `defaults.DefaultConfig`. Due to circular dependencies
+// with the defaults package and credentials EC2 Role Provider.
+func New(config *Config) *Client {
+	service := &service.Service{
+		ServiceInfo: serviceinfo.ServiceInfo{
+			Config:      copyConfig(config),
+			ServiceName: "Client",
+			Endpoint:    "http://169.254.169.254/latest",
+			APIVersion:  "latest",
+		},
+	}
+	service.Initialize()
+	service.Handlers.Unmarshal.PushBack(unmarshalHandler)
+	service.Handlers.UnmarshalError.PushBack(unmarshalError)
+	service.Handlers.Validate.Clear()
+	service.Handlers.Validate.PushBack(validateEndpointHandler)
+
+	return &Client{service}
+}
+
+func copyConfig(config *Config) *aws.Config {
+	if config == nil {
+		config = &Config{}
+	}
+	c := &aws.Config{
+		Credentials: credentials.AnonymousCredentials,
+		Endpoint:    config.Endpoint,
+		HTTPClient:  config.HTTPClient,
+		Logger:      config.Logger,
+		LogLevel:    config.LogLevel,
+		MaxRetries:  config.MaxRetries,
+	}
+
+	if c.HTTPClient == nil {
+		c.HTTPClient = http.DefaultClient
+	}
+	if c.Logger == nil {
+		c.Logger = aws.NewDefaultLogger()
+	}
+	if c.LogLevel == nil {
+		c.LogLevel = aws.LogLevel(aws.LogOff)
+	}
+	if c.MaxRetries == nil {
+		c.MaxRetries = aws.Int(DefaultRetries)
+	}
+
+	return c
+}
+
+type metadataOutput struct {
+	Content string
+}
+
+func unmarshalHandler(r *request.Request) {
+	defer r.HTTPResponse.Body.Close()
+	b, err := ioutil.ReadAll(r.HTTPResponse.Body)
+	if err != nil {
+		r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata respose", err)
+	}
+
+	data := r.Data.(*metadataOutput)
+	data.Content = string(b)
+}
+
+func unmarshalError(r *request.Request) {
+	defer r.HTTPResponse.Body.Close()
+	_, err := ioutil.ReadAll(r.HTTPResponse.Body)
+	if err != nil {
+		r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata error respose", err)
+	}
+
+	// TODO extract the error...
+}
+
+func validateEndpointHandler(r *request.Request) {
+	if r.Service.Endpoint == "" {
+		r.Error = aws.ErrMissingEndpoint
+	}
+}

+ 17 - 0
vendor/src/github.com/aws/aws-sdk-go/aws/errors.go

@@ -0,0 +1,17 @@
+package aws
+
+import "github.com/aws/aws-sdk-go/aws/awserr"
+
+var (
+	// ErrMissingRegion is an error that is returned if region configuration is
+	// not found.
+	//
+	// @readonly
+	ErrMissingRegion error = awserr.New("MissingRegion", "could not find region configuration", nil)
+
+	// ErrMissingEndpoint is an error that is returned if an endpoint cannot be
+	// resolved for a service.
+	//
+	// @readonly
+	ErrMissingEndpoint error = awserr.New("MissingEndpoint", "'Endpoint' configuration is required for this service", nil)
+)

+ 9 - 0
vendor/src/github.com/aws/aws-sdk-go/aws/logger.go

@@ -62,6 +62,15 @@ const (
 	// see the body content of requests and responses made while using the SDK
 	// Will also enable LogDebug.
 	LogDebugWithHTTPBody
+
+	// LogDebugWithRequestRetries states the SDK should log when service requests will
+	// be retried. This should be used to log when you want to log when service
+	// requests are being retried. Will also enable LogDebug.
+	LogDebugWithRequestRetries
+
+	// LogDebugWithRequestErrors states the SDK should log when service requests fail
+	// to build, send, validate, or unmarshal.
+	LogDebugWithRequestErrors
 )
 
 // A Logger is a minimalistic interface for the SDK to log messages to. Should

+ 0 - 89
vendor/src/github.com/aws/aws-sdk-go/aws/param_validator.go

@@ -1,89 +0,0 @@
-package aws
-
-import (
-	"fmt"
-	"reflect"
-	"strings"
-
-	"github.com/aws/aws-sdk-go/aws/awserr"
-)
-
-// ValidateParameters is a request handler to validate the input parameters.
-// Validating parameters only has meaning if done prior to the request being sent.
-func ValidateParameters(r *Request) {
-	if r.ParamsFilled() {
-		v := validator{errors: []string{}}
-		v.validateAny(reflect.ValueOf(r.Params), "")
-
-		if count := len(v.errors); count > 0 {
-			format := "%d validation errors:\n- %s"
-			msg := fmt.Sprintf(format, count, strings.Join(v.errors, "\n- "))
-			r.Error = awserr.New("InvalidParameter", msg, nil)
-		}
-	}
-}
-
-// A validator validates values. Collects validations errors which occurs.
-type validator struct {
-	errors []string
-}
-
-// validateAny will validate any struct, slice or map type. All validations
-// are also performed recursively for nested types.
-func (v *validator) validateAny(value reflect.Value, path string) {
-	value = reflect.Indirect(value)
-	if !value.IsValid() {
-		return
-	}
-
-	switch value.Kind() {
-	case reflect.Struct:
-		v.validateStruct(value, path)
-	case reflect.Slice:
-		for i := 0; i < value.Len(); i++ {
-			v.validateAny(value.Index(i), path+fmt.Sprintf("[%d]", i))
-		}
-	case reflect.Map:
-		for _, n := range value.MapKeys() {
-			v.validateAny(value.MapIndex(n), path+fmt.Sprintf("[%q]", n.String()))
-		}
-	}
-}
-
-// validateStruct will validate the struct value's fields. If the structure has
-// nested types those types will be validated also.
-func (v *validator) validateStruct(value reflect.Value, path string) {
-	prefix := "."
-	if path == "" {
-		prefix = ""
-	}
-
-	for i := 0; i < value.Type().NumField(); i++ {
-		f := value.Type().Field(i)
-		if strings.ToLower(f.Name[0:1]) == f.Name[0:1] {
-			continue
-		}
-		fvalue := value.FieldByName(f.Name)
-
-		notset := false
-		if f.Tag.Get("required") != "" {
-			switch fvalue.Kind() {
-			case reflect.Ptr, reflect.Slice, reflect.Map:
-				if fvalue.IsNil() {
-					notset = true
-				}
-			default:
-				if !fvalue.IsValid() {
-					notset = true
-				}
-			}
-		}
-
-		if notset {
-			msg := "missing required parameter: " + path + prefix + f.Name
-			v.errors = append(v.errors, msg)
-		} else {
-			v.validateAny(fvalue, path+prefix+f.Name)
-		}
-	}
-}

+ 40 - 13
vendor/src/github.com/aws/aws-sdk-go/aws/handlers.go → vendor/src/github.com/aws/aws-sdk-go/aws/request/handlers.go

@@ -1,4 +1,4 @@
-package aws
+package request
 
 // A Handlers provides a collection of request handlers for various
 // stages of handling requests.
@@ -15,8 +15,8 @@ type Handlers struct {
 	AfterRetry       HandlerList
 }
 
-// copy returns of this handler's lists.
-func (h *Handlers) copy() Handlers {
+// Copy returns of this handler's lists.
+func (h *Handlers) Copy() Handlers {
 	return Handlers{
 		Validate:         h.Validate.copy(),
 		Build:            h.Build.copy(),
@@ -47,19 +47,25 @@ func (h *Handlers) Clear() {
 
 // A HandlerList manages zero or more handlers in a list.
 type HandlerList struct {
-	list []func(*Request)
+	list []NamedHandler
+}
+
+// A NamedHandler is a struct that contains a name and function callback.
+type NamedHandler struct {
+	Name string
+	Fn   func(*Request)
 }
 
 // copy creates a copy of the handler list.
 func (l *HandlerList) copy() HandlerList {
 	var n HandlerList
-	n.list = append([]func(*Request){}, l.list...)
+	n.list = append([]NamedHandler{}, l.list...)
 	return n
 }
 
 // Clear clears the handler list.
 func (l *HandlerList) Clear() {
-	l.list = []func(*Request){}
+	l.list = []NamedHandler{}
 }
 
 // Len returns the number of handlers in the list.
@@ -67,19 +73,40 @@ func (l *HandlerList) Len() int {
 	return len(l.list)
 }
 
-// PushBack pushes handlers f to the back of the handler list.
-func (l *HandlerList) PushBack(f ...func(*Request)) {
-	l.list = append(l.list, f...)
+// PushBack pushes handler f to the back of the handler list.
+func (l *HandlerList) PushBack(f func(*Request)) {
+	l.list = append(l.list, NamedHandler{"__anonymous", f})
 }
 
-// PushFront pushes handlers f to the front of the handler list.
-func (l *HandlerList) PushFront(f ...func(*Request)) {
-	l.list = append(f, l.list...)
+// PushFront pushes handler f to the front of the handler list.
+func (l *HandlerList) PushFront(f func(*Request)) {
+	l.list = append([]NamedHandler{{"__anonymous", f}}, l.list...)
+}
+
+// PushBackNamed pushes named handler f to the back of the handler list.
+func (l *HandlerList) PushBackNamed(n NamedHandler) {
+	l.list = append(l.list, n)
+}
+
+// PushFrontNamed pushes named handler f to the front of the handler list.
+func (l *HandlerList) PushFrontNamed(n NamedHandler) {
+	l.list = append([]NamedHandler{n}, l.list...)
+}
+
+// Remove removes a NamedHandler n
+func (l *HandlerList) Remove(n NamedHandler) {
+	newlist := []NamedHandler{}
+	for _, m := range l.list {
+		if m.Name != n.Name {
+			newlist = append(newlist, m)
+		}
+	}
+	l.list = newlist
 }
 
 // Run executes all handlers in the list with a given request object.
 func (l *HandlerList) Run(r *Request) {
 	for _, f := range l.list {
-		f(r)
+		f.Fn(r)
 	}
 }

+ 46 - 10
vendor/src/github.com/aws/aws-sdk-go/aws/request.go → vendor/src/github.com/aws/aws-sdk-go/aws/request/request.go

@@ -1,7 +1,8 @@
-package aws
+package request
 
 import (
 	"bytes"
+	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -10,12 +11,15 @@ import (
 	"strings"
 	"time"
 
+	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws/awsutil"
+	"github.com/aws/aws-sdk-go/aws/service/serviceinfo"
 )
 
 // A Request is the service request to be made.
 type Request struct {
-	*Service
+	Retryer
+	Service      serviceinfo.ServiceInfo
 	Handlers     Handlers
 	Time         time.Time
 	ExpireTime   time.Duration
@@ -23,7 +27,7 @@ type Request struct {
 	HTTPRequest  *http.Request
 	HTTPResponse *http.Response
 	Body         io.ReadSeeker
-	bodyStart    int64 // offset from beginning of Body that the request body starts
+	BodyStart    int64 // offset from beginning of Body that the request body starts
 	Params       interface{}
 	Error        error
 	Data         interface{}
@@ -51,13 +55,13 @@ type Paginator struct {
 	TruncationToken string
 }
 
-// NewRequest returns a new Request pointer for the service API
+// New returns a new Request pointer for the service API
 // operation and parameters.
 //
 // Params is any value of input parameters to be the request payload.
 // Data is pointer value to an object which the request's response
 // payload will be deserialized to.
-func NewRequest(service *Service, operation *Operation, params interface{}, data interface{}) *Request {
+func New(service serviceinfo.ServiceInfo, handlers Handlers, retryer Retryer, operation *Operation, params interface{}, data interface{}) *Request {
 	method := operation.HTTPMethod
 	if method == "" {
 		method = "POST"
@@ -71,8 +75,9 @@ func NewRequest(service *Service, operation *Operation, params interface{}, data
 	httpReq.URL, _ = url.Parse(service.Endpoint + p)
 
 	r := &Request{
+		Retryer:     retryer,
 		Service:     service,
-		Handlers:    service.Handlers.copy(),
+		Handlers:    handlers.Copy(),
 		Time:        time.Now(),
 		ExpireTime:  0,
 		Operation:   operation,
@@ -89,7 +94,7 @@ func NewRequest(service *Service, operation *Operation, params interface{}, data
 
 // WillRetry returns if the request's can be retried.
 func (r *Request) WillRetry() bool {
-	return r.Error != nil && BoolValue(r.Retryable) && r.RetryCount < r.Service.MaxRetries()
+	return r.Error != nil && aws.BoolValue(r.Retryable) && r.RetryCount < r.MaxRetries()
 }
 
 // ParamsFilled returns if the request's parameters have been populated
@@ -134,6 +139,20 @@ func (r *Request) Presign(expireTime time.Duration) (string, error) {
 	return r.HTTPRequest.URL.String(), nil
 }
 
+func debugLogReqError(r *Request, stage string, retrying bool, err error) {
+	if !r.Service.Config.LogLevel.Matches(aws.LogDebugWithRequestErrors) {
+		return
+	}
+
+	retryStr := "not retrying"
+	if retrying {
+		retryStr = "will retry"
+	}
+
+	r.Service.Config.Logger.Log(fmt.Sprintf("DEBUG: %s %s/%s failed, %s, error %v",
+		stage, r.Service.ServiceName, r.Operation.Name, retryStr, err))
+}
+
 // Build will build the request's object so it can be signed and sent
 // to the service. Build will also validate all the request's parameters.
 // Anny additional build Handlers set on this request will be run
@@ -149,6 +168,7 @@ func (r *Request) Build() error {
 		r.Error = nil
 		r.Handlers.Validate.Run(r)
 		if r.Error != nil {
+			debugLogReqError(r, "Validate Request", false, r.Error)
 			return r.Error
 		}
 		r.Handlers.Build.Run(r)
@@ -165,6 +185,7 @@ func (r *Request) Build() error {
 func (r *Request) Sign() error {
 	r.Build()
 	if r.Error != nil {
+		debugLogReqError(r, "Build Request", false, r.Error)
 		return r.Error
 	}
 
@@ -183,42 +204,57 @@ func (r *Request) Send() error {
 			return r.Error
 		}
 
-		if BoolValue(r.Retryable) {
+		if aws.BoolValue(r.Retryable) {
+			if r.Service.Config.LogLevel.Matches(aws.LogDebugWithRequestRetries) {
+				r.Service.Config.Logger.Log(fmt.Sprintf("DEBUG: Retrying Request %s/%s, attempt %d",
+					r.Service.ServiceName, r.Operation.Name, r.RetryCount))
+			}
+
 			// Re-seek the body back to the original point in for a retry so that
 			// send will send the body's contents again in the upcoming request.
-			r.Body.Seek(r.bodyStart, 0)
+			r.Body.Seek(r.BodyStart, 0)
+			r.HTTPRequest.Body = ioutil.NopCloser(r.Body)
 		}
 		r.Retryable = nil
 
 		r.Handlers.Send.Run(r)
 		if r.Error != nil {
+			err := r.Error
 			r.Handlers.Retry.Run(r)
 			r.Handlers.AfterRetry.Run(r)
 			if r.Error != nil {
+				debugLogReqError(r, "Send Request", false, r.Error)
 				return r.Error
 			}
+			debugLogReqError(r, "Send Request", true, err)
 			continue
 		}
 
 		r.Handlers.UnmarshalMeta.Run(r)
 		r.Handlers.ValidateResponse.Run(r)
 		if r.Error != nil {
+			err := r.Error
 			r.Handlers.UnmarshalError.Run(r)
 			r.Handlers.Retry.Run(r)
 			r.Handlers.AfterRetry.Run(r)
 			if r.Error != nil {
+				debugLogReqError(r, "Validate Response", false, r.Error)
 				return r.Error
 			}
+			debugLogReqError(r, "Validate Response", true, err)
 			continue
 		}
 
 		r.Handlers.Unmarshal.Run(r)
 		if r.Error != nil {
+			err := r.Error
 			r.Handlers.Retry.Run(r)
 			r.Handlers.AfterRetry.Run(r)
 			if r.Error != nil {
+				debugLogReqError(r, "Unmarshal Response", false, r.Error)
 				return r.Error
 			}
+			debugLogReqError(r, "Unmarshal Response", true, err)
 			continue
 		}
 
@@ -279,7 +315,7 @@ func (r *Request) NextPage() *Request {
 	}
 
 	data := reflect.New(reflect.TypeOf(r.Data).Elem()).Interface()
-	nr := NewRequest(r.Service, r.Operation, awsutil.CopyOf(r.Params), data)
+	nr := New(r.Service, r.Handlers, r.Retryer, r.Operation, awsutil.CopyOf(r.Params), data)
 	for i, intok := range nr.Operation.InputTokens {
 		awsutil.SetValueAtAnyPath(nr.Params, intok, tokens[i])
 	}

+ 71 - 0
vendor/src/github.com/aws/aws-sdk-go/aws/request/retryer.go

@@ -0,0 +1,71 @@
+package request
+
+import (
+	"time"
+
+	"github.com/aws/aws-sdk-go/aws/awserr"
+)
+
+// Retryer is an interface to control retry logic for a given service.
+// The default implementation used by most services is the service.DefaultRetryer
+// structure, which contains basic retry logic using exponential backoff.
+type Retryer interface {
+	RetryRules(*Request) time.Duration
+	ShouldRetry(*Request) bool
+	MaxRetries() uint
+}
+
+// retryableCodes is a collection of service response codes which are retry-able
+// without any further action.
+var retryableCodes = map[string]struct{}{
+	"RequestError":                           {},
+	"ProvisionedThroughputExceededException": {},
+	"Throttling":                             {},
+	"ThrottlingException":                    {},
+	"RequestLimitExceeded":                   {},
+	"RequestThrottled":                       {},
+}
+
+// credsExpiredCodes is a collection of error codes which signify the credentials
+// need to be refreshed. Expired tokens require refreshing of credentials, and
+// resigning before the request can be retried.
+var credsExpiredCodes = map[string]struct{}{
+	"ExpiredToken":          {},
+	"ExpiredTokenException": {},
+	"RequestExpired":        {}, // EC2 Only
+}
+
+func isCodeRetryable(code string) bool {
+	if _, ok := retryableCodes[code]; ok {
+		return true
+	}
+
+	return isCodeExpiredCreds(code)
+}
+
+func isCodeExpiredCreds(code string) bool {
+	_, ok := credsExpiredCodes[code]
+	return ok
+}
+
+// IsErrorRetryable returns whether the error is retryable, based on its Code.
+// Returns false if the request has no Error set.
+func (r *Request) IsErrorRetryable() bool {
+	if r.Error != nil {
+		if err, ok := r.Error.(awserr.Error); ok {
+			return isCodeRetryable(err.Code())
+		}
+	}
+	return false
+}
+
+// IsErrorExpired returns whether the error code is a credential expiry error.
+// Returns false if the request has no Error set.
+func (r *Request) IsErrorExpired() bool {
+	if r.Error != nil {
+		if err, ok := r.Error.(awserr.Error); ok {
+			return isCodeExpiredCreds(err.Code())
+		}
+	}
+	return false
+}

+ 0 - 194
vendor/src/github.com/aws/aws-sdk-go/aws/service.go

@@ -1,194 +0,0 @@
-package aws
-
-import (
-	"fmt"
-	"math"
-	"math/rand"
-	"net/http"
-	"net/http/httputil"
-	"regexp"
-	"time"
-
-	"github.com/aws/aws-sdk-go/aws/awserr"
-	"github.com/aws/aws-sdk-go/internal/endpoints"
-)
-
-// A Service implements the base service request and response handling
-// used by all services.
-type Service struct {
-	Config            *Config
-	Handlers          Handlers
-	ServiceName       string
-	APIVersion        string
-	Endpoint          string
-	SigningName       string
-	SigningRegion     string
-	JSONVersion       string
-	TargetPrefix      string
-	RetryRules        func(*Request) time.Duration
-	ShouldRetry       func(*Request) bool
-	DefaultMaxRetries uint
-}
-
-var schemeRE = regexp.MustCompile("^([^:]+)://")
-
-// NewService will return a pointer to a new Server object initialized.
-func NewService(config *Config) *Service {
-	svc := &Service{Config: config}
-	svc.Initialize()
-	return svc
-}
-
-// Initialize initializes the service.
-func (s *Service) Initialize() {
-	if s.Config == nil {
-		s.Config = &Config{}
-	}
-	if s.Config.HTTPClient == nil {
-		s.Config.HTTPClient = http.DefaultClient
-	}
-
-	if s.RetryRules == nil {
-		s.RetryRules = retryRules
-	}
-
-	if s.ShouldRetry == nil {
-		s.ShouldRetry = shouldRetry
-	}
-
-	s.DefaultMaxRetries = 3
-	s.Handlers.Validate.PushBack(ValidateEndpointHandler)
-	s.Handlers.Build.PushBack(UserAgentHandler)
-	s.Handlers.Sign.PushBack(BuildContentLength)
-	s.Handlers.Send.PushBack(SendHandler)
-	s.Handlers.AfterRetry.PushBack(AfterRetryHandler)
-	s.Handlers.ValidateResponse.PushBack(ValidateResponseHandler)
-	s.AddDebugHandlers()
-	s.buildEndpoint()
-
-	if !BoolValue(s.Config.DisableParamValidation) {
-		s.Handlers.Validate.PushBack(ValidateParameters)
-	}
-}
-
-// buildEndpoint builds the endpoint values the service will use to make requests with.
-func (s *Service) buildEndpoint() {
-	if StringValue(s.Config.Endpoint) != "" {
-		s.Endpoint = *s.Config.Endpoint
-	} else {
-		s.Endpoint, s.SigningRegion =
-			endpoints.EndpointForRegion(s.ServiceName, StringValue(s.Config.Region))
-	}
-
-	if s.Endpoint != "" && !schemeRE.MatchString(s.Endpoint) {
-		scheme := "https"
-		if BoolValue(s.Config.DisableSSL) {
-			scheme = "http"
-		}
-		s.Endpoint = scheme + "://" + s.Endpoint
-	}
-}
-
-// AddDebugHandlers injects debug logging handlers into the service to log request
-// debug information.
-func (s *Service) AddDebugHandlers() {
-	if !s.Config.LogLevel.AtLeast(LogDebug) {
-		return
-	}
-
-	s.Handlers.Send.PushFront(logRequest)
-	s.Handlers.Send.PushBack(logResponse)
-}
-
-const logReqMsg = `DEBUG: Request %s/%s Details:
----[ REQUEST POST-SIGN ]-----------------------------
-%s
------------------------------------------------------`
-
-func logRequest(r *Request) {
-	logBody := r.Config.LogLevel.Matches(LogDebugWithHTTPBody)
-	dumpedBody, _ := httputil.DumpRequestOut(r.HTTPRequest, logBody)
-
-	r.Config.Logger.Log(fmt.Sprintf(logReqMsg, r.ServiceName, r.Operation.Name, string(dumpedBody)))
-}
-
-const logRespMsg = `DEBUG: Response %s/%s Details:
----[ RESPONSE ]--------------------------------------
-%s
------------------------------------------------------`
-
-func logResponse(r *Request) {
-	var msg = "no reponse data"
-	if r.HTTPResponse != nil {
-		logBody := r.Config.LogLevel.Matches(LogDebugWithHTTPBody)
-		dumpedBody, _ := httputil.DumpResponse(r.HTTPResponse, logBody)
-		msg = string(dumpedBody)
-	} else if r.Error != nil {
-		msg = r.Error.Error()
-	}
-	r.Config.Logger.Log(fmt.Sprintf(logRespMsg, r.ServiceName, r.Operation.Name, msg))
-}
-
-// MaxRetries returns the number of maximum returns the service will use to make
-// an individual API request.
-func (s *Service) MaxRetries() uint {
-	if IntValue(s.Config.MaxRetries) < 0 {
-		return s.DefaultMaxRetries
-	}
-	return uint(IntValue(s.Config.MaxRetries))
-}
-
-var seededRand = rand.New(rand.NewSource(time.Now().UnixNano()))
-
-// retryRules returns the delay duration before retrying this request again
-func retryRules(r *Request) time.Duration {
-
-	delay := int(math.Pow(2, float64(r.RetryCount))) * (seededRand.Intn(30) + 30)
-	return time.Duration(delay) * time.Millisecond
-}
-
-// retryableCodes is a collection of service response codes which are retry-able
-// without any further action.
-var retryableCodes = map[string]struct{}{
-	"RequestError":                           {},
-	"ProvisionedThroughputExceededException": {},
-	"Throttling":                             {},
-	"ThrottlingException":                    {},
-	"RequestLimitExceeded":                   {},
-	"RequestThrottled":                       {},
-}
-
-// credsExpiredCodes is a collection of error codes which signify the credentials
-// need to be refreshed. Expired tokens require refreshing of credentials, and
-// resigning before the request can be retried.
-var credsExpiredCodes = map[string]struct{}{
-	"ExpiredToken":          {},
-	"ExpiredTokenException": {},
-	"RequestExpired":        {}, // EC2 Only
-}
-
-func isCodeRetryable(code string) bool {
-	if _, ok := retryableCodes[code]; ok {
-		return true
-	}
-
-	return isCodeExpiredCreds(code)
-}
-
-func isCodeExpiredCreds(code string) bool {
-	_, ok := credsExpiredCodes[code]
-	return ok
-}
-
-// shouldRetry returns if the request should be retried.
-func shouldRetry(r *Request) bool {
-	if r.HTTPResponse.StatusCode >= 500 {
-		return true
-	}
-	if r.Error != nil {
-		if err, ok := r.Error.(awserr.Error); ok {
-			return isCodeRetryable(err.Code())
-		}
-	}
-	return false
-}

+ 51 - 0
vendor/src/github.com/aws/aws-sdk-go/aws/service/default_retryer.go

@@ -0,0 +1,51 @@
+package service
+
+import (
+	"math"
+	"math/rand"
+	"time"
+
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/aws/request"
+)
+
+// DefaultRetryer implements basic retry logic using exponential backoff for
+// most services. If you want to implement custom retry logic, implement the
+// request.Retryer interface or create a structure type that composes this
+// struct and override the specific methods. For example, to override only
+// the MaxRetries method:
+//
+//		type retryer struct {
+//      service.DefaultRetryer
+//    }
+//
+//    // This implementation always has 100 max retries
+//    func (d retryer) MaxRetries() uint { return 100 }
+type DefaultRetryer struct {
+	*Service
+}
+
+// MaxRetries returns the number of maximum returns the service will use to make
+// an individual API request.
+func (d DefaultRetryer) MaxRetries() uint {
+	if aws.IntValue(d.Service.Config.MaxRetries) < 0 {
+		return d.DefaultMaxRetries
+	}
+	return uint(aws.IntValue(d.Service.Config.MaxRetries))
+}
+
+var seededRand = rand.New(rand.NewSource(time.Now().UnixNano()))
+
+// RetryRules returns the delay duration before retrying this request again
+func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration {
+	delay := int(math.Pow(2, float64(r.RetryCount))) * (seededRand.Intn(30) + 30)
+	return time.Duration(delay) * time.Millisecond
+}
+
+// ShouldRetry returns if the request should be retried.
+func (d DefaultRetryer) ShouldRetry(r *request.Request) bool {
+	if r.HTTPResponse.StatusCode >= 500 {
+		return true
+	}
+	return r.IsErrorRetryable()
+}

+ 133 - 0
vendor/src/github.com/aws/aws-sdk-go/aws/service/service.go

@@ -0,0 +1,133 @@
+package service
+
+import (
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"net/http/httputil"
+	"regexp"
+	"time"
+
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/aws/corehandlers"
+	"github.com/aws/aws-sdk-go/aws/request"
+	"github.com/aws/aws-sdk-go/aws/service/serviceinfo"
+	"github.com/aws/aws-sdk-go/internal/endpoints"
+)
+
+// A Service implements the base service request and response handling
+// used by all services.
+type Service struct {
+	serviceinfo.ServiceInfo
+	request.Retryer
+	DefaultMaxRetries uint
+	Handlers          request.Handlers
+}
+
+var schemeRE = regexp.MustCompile("^([^:]+)://")
+
+// New will return a pointer to a new Server object initialized.
+func New(config *aws.Config) *Service {
+	svc := &Service{ServiceInfo: serviceinfo.ServiceInfo{Config: config}}
+	svc.Initialize()
+	return svc
+}
+
+// Initialize initializes the service.
+func (s *Service) Initialize() {
+	if s.Config == nil {
+		s.Config = &aws.Config{}
+	}
+	if s.Config.HTTPClient == nil {
+		s.Config.HTTPClient = http.DefaultClient
+	}
+	if s.Config.SleepDelay == nil {
+		s.Config.SleepDelay = time.Sleep
+	}
+
+	s.Retryer = DefaultRetryer{s}
+	s.DefaultMaxRetries = 3
+	s.Handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler)
+	s.Handlers.Build.PushBackNamed(corehandlers.UserAgentHandler)
+	s.Handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler)
+	s.Handlers.Send.PushBackNamed(corehandlers.SendHandler)
+	s.Handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler)
+	s.Handlers.ValidateResponse.PushBackNamed(corehandlers.ValidateResponseHandler)
+	if !aws.BoolValue(s.Config.DisableParamValidation) {
+		s.Handlers.Validate.PushBackNamed(corehandlers.ValidateParametersHandler)
+	}
+	s.AddDebugHandlers()
+	s.buildEndpoint()
+}
+
+// NewRequest returns a new Request pointer for the service API
+// operation and parameters.
+func (s *Service) NewRequest(operation *request.Operation, params interface{}, data interface{}) *request.Request {
+	return request.New(s.ServiceInfo, s.Handlers, s.Retryer, operation, params, data)
+}
+
+// buildEndpoint builds the endpoint values the service will use to make requests with.
+func (s *Service) buildEndpoint() {
+	if aws.StringValue(s.Config.Endpoint) != "" {
+		s.Endpoint = *s.Config.Endpoint
+	} else if s.Endpoint == "" {
+		s.Endpoint, s.SigningRegion =
+			endpoints.EndpointForRegion(s.ServiceName, aws.StringValue(s.Config.Region))
+	}
+
+	if s.Endpoint != "" && !schemeRE.MatchString(s.Endpoint) {
+		scheme := "https"
+		if aws.BoolValue(s.Config.DisableSSL) {
+			scheme = "http"
+		}
+		s.Endpoint = scheme + "://" + s.Endpoint
+	}
+}
+
+// AddDebugHandlers injects debug logging handlers into the service to log request
+// debug information.
+func (s *Service) AddDebugHandlers() {
+	if !s.Config.LogLevel.AtLeast(aws.LogDebug) {
+		return
+	}
+
+	s.Handlers.Send.PushFront(logRequest)
+	s.Handlers.Send.PushBack(logResponse)
+}
+
+const logReqMsg = `DEBUG: Request %s/%s Details:
+---[ REQUEST POST-SIGN ]-----------------------------
+%s
+-----------------------------------------------------`
+
+func logRequest(r *request.Request) {
+	logBody := r.Service.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
+	dumpedBody, _ := httputil.DumpRequestOut(r.HTTPRequest, logBody)
+
+	if logBody {
+		// Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's
+		// Body as a NoOpCloser and will not be reset after read by the HTTP
+		// client reader.
+		r.Body.Seek(r.BodyStart, 0)
+		r.HTTPRequest.Body = ioutil.NopCloser(r.Body)
+	}
+
+	r.Service.Config.Logger.Log(fmt.Sprintf(logReqMsg, r.Service.ServiceName, r.Operation.Name, string(dumpedBody)))
+}
+
+const logRespMsg = `DEBUG: Response %s/%s Details:
+---[ RESPONSE ]--------------------------------------
+%s
+-----------------------------------------------------`
+
+func logResponse(r *request.Request) {
+	var msg = "no reponse data"
+	if r.HTTPResponse != nil {
+		logBody := r.Service.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
+		dumpedBody, _ := httputil.DumpResponse(r.HTTPResponse, logBody)
+		msg = string(dumpedBody)
+	} else if r.Error != nil {
+		msg = r.Error.Error()
+	}
+	r.Service.Config.Logger.Log(fmt.Sprintf(logRespMsg, r.Service.ServiceName, r.Operation.Name, msg))
+}

+ 15 - 0
vendor/src/github.com/aws/aws-sdk-go/aws/service/serviceinfo/service_info.go

@@ -0,0 +1,15 @@
+package serviceinfo
+
+import "github.com/aws/aws-sdk-go/aws"
+
+// ServiceInfo wraps immutable data from the service.Service structure.
+type ServiceInfo struct {
+	Config        *aws.Config
+	ServiceName   string
+	APIVersion    string
+	Endpoint      string
+	SigningName   string
+	SigningRegion string
+	JSONVersion   string
+	TargetPrefix  string
+}

+ 33 - 0
vendor/src/github.com/aws/aws-sdk-go/aws/types.go

@@ -2,6 +2,7 @@ package aws
 
 import (
 	"io"
+	"sync"
 )
 
 // ReadSeekCloser wraps a io.Reader returning a ReaderSeakerCloser
@@ -53,3 +54,35 @@ func (r ReaderSeekerCloser) Close() error {
 	}
 	return nil
 }
+
+// A WriteAtBuffer provides a in memory buffer supporting the io.WriterAt interface
+// Can be used with the s3manager.Downloader to download content to a buffer
+// in memory. Safe to use concurrently.
+type WriteAtBuffer struct {
+	buf []byte
+	m   sync.Mutex
+}
+
+// WriteAt writes a slice of bytes to a buffer starting at the position provided
+// The number of bytes written will be returned, or error. Can overwrite previous
+// written slices if the write ats overlap.
+func (b *WriteAtBuffer) WriteAt(p []byte, pos int64) (n int, err error) {
+	b.m.Lock()
+	defer b.m.Unlock()
+
+	expLen := pos + int64(len(p))
+	if int64(len(b.buf)) < expLen {
+		newBuf := make([]byte, expLen)
+		copy(newBuf, b.buf)
+		b.buf = newBuf
+	}
+	copy(b.buf[pos:], p)
+	return len(p), nil
+}
+
+// Bytes returns a slice of bytes written to the buffer.
+func (b *WriteAtBuffer) Bytes() []byte {
+	b.m.Lock()
+	defer b.m.Unlock()
+	return b.buf[:len(b.buf):len(b.buf)]
+}

+ 1 - 1
vendor/src/github.com/aws/aws-sdk-go/aws/version.go

@@ -5,4 +5,4 @@ package aws
 const SDKName = "aws-sdk-go"
 
 // SDKVersion is the version of this SDK
-const SDKVersion = "0.7.1"
+const SDKVersion = "0.9.9"

+ 19 - 0
vendor/src/github.com/aws/aws-sdk-go/internal/protocol/json/jsonutil/build.go

@@ -66,6 +66,17 @@ func buildStruct(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag)
 		return nil
 	}
 
+	// unwrap payloads
+	if payload := tag.Get("payload"); payload != "" {
+		field, _ := value.Type().FieldByName(payload)
+		tag = field.Tag
+		value = elemOf(value.FieldByName(payload))
+
+		if !value.IsValid() {
+			return nil
+		}
+	}
+
 	buf.WriteString("{")
 
 	t, fields := value.Type(), []*reflect.StructField{}
@@ -197,3 +208,11 @@ func writeString(s string, buf *bytes.Buffer) {
 	}
 	buf.WriteByte('"')
 }
+
+// Returns the reflection element of a value, if it is a pointer.
+func elemOf(value reflect.Value) reflect.Value {
+	for value.Kind() == reflect.Ptr {
+		value = value.Elem()
+	}
+	return value
+}

+ 1 - 2
vendor/src/github.com/aws/aws-sdk-go/internal/protocol/json/jsonutil/unmarshal.go

@@ -7,7 +7,6 @@ import (
 	"io"
 	"io/ioutil"
 	"reflect"
-	"strings"
 	"time"
 )
 
@@ -99,7 +98,7 @@ func unmarshalStruct(value reflect.Value, data interface{}, tag reflect.StructTa
 
 	for i := 0; i < t.NumField(); i++ {
 		field := t.Field(i)
-		if c := field.Name[0:1]; strings.ToLower(c) == c {
+		if field.PkgPath != "" {
 			continue // ignore unexported fields
 		}
 

+ 8 - 7
vendor/src/github.com/aws/aws-sdk-go/internal/protocol/jsonrpc/jsonrpc.go

@@ -10,15 +10,16 @@ import (
 	"io/ioutil"
 	"strings"
 
-	"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/internal/protocol/json/jsonutil"
+	"github.com/aws/aws-sdk-go/internal/protocol/rest"
 )
 
 var emptyJSON = []byte("{}")
 
 // Build builds a JSON payload for a JSON RPC request.
-func Build(req *aws.Request) {
+func Build(req *request.Request) {
 	var buf []byte
 	var err error
 	if req.ParamsFilled() {
@@ -46,7 +47,7 @@ func Build(req *aws.Request) {
 }
 
 // Unmarshal unmarshals a response for a JSON RPC service.
-func Unmarshal(req *aws.Request) {
+func Unmarshal(req *request.Request) {
 	defer req.HTTPResponse.Body.Close()
 	if req.DataFilled() {
 		err := jsonutil.UnmarshalJSON(req.Data, req.HTTPResponse.Body)
@@ -58,12 +59,12 @@ func Unmarshal(req *aws.Request) {
 }
 
 // UnmarshalMeta unmarshals headers from a response for a JSON RPC service.
-func UnmarshalMeta(req *aws.Request) {
-	req.RequestID = req.HTTPResponse.Header.Get("x-amzn-requestid")
+func UnmarshalMeta(req *request.Request) {
+	rest.UnmarshalMeta(req)
 }
 
 // UnmarshalError unmarshals an error response for a JSON RPC service.
-func UnmarshalError(req *aws.Request) {
+func UnmarshalError(req *request.Request) {
 	defer req.HTTPResponse.Body.Close()
 	bodyBytes, err := ioutil.ReadAll(req.HTTPResponse.Body)
 	if err != nil {
@@ -88,7 +89,7 @@ func UnmarshalError(req *aws.Request) {
 	req.Error = awserr.NewRequestFailure(
 		awserr.New(codes[len(codes)-1], jsonErr.Message, nil),
 		req.HTTPResponse.StatusCode,
-		"",
+		req.RequestID,
 	)
 }
 

+ 14 - 9
vendor/src/github.com/aws/aws-sdk-go/internal/protocol/rest/build.go

@@ -1,4 +1,4 @@
-// Package rest provides RESTful serialisation of AWS requests and responses.
+// Package rest provides RESTful serialization of AWS requests and responses.
 package rest
 
 import (
@@ -13,8 +13,8 @@ import (
 	"strings"
 	"time"
 
-	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws/awserr"
+	"github.com/aws/aws-sdk-go/aws/request"
 )
 
 // RFC822 returns an RFC822 formatted timestamp for AWS protocols
@@ -37,7 +37,7 @@ func init() {
 }
 
 // Build builds the REST component of a service request.
-func Build(r *aws.Request) {
+func Build(r *request.Request) {
 	if r.ParamsFilled() {
 		v := reflect.ValueOf(r.Params).Elem()
 		buildLocationElements(r, v)
@@ -45,7 +45,7 @@ func Build(r *aws.Request) {
 	}
 }
 
-func buildLocationElements(r *aws.Request, v reflect.Value) {
+func buildLocationElements(r *request.Request, v reflect.Value) {
 	query := r.HTTPRequest.URL.Query()
 
 	for i := 0; i < v.NumField(); i++ {
@@ -87,7 +87,7 @@ func buildLocationElements(r *aws.Request, v reflect.Value) {
 	updatePath(r.HTTPRequest.URL, r.HTTPRequest.URL.Path)
 }
 
-func buildBody(r *aws.Request, v reflect.Value) {
+func buildBody(r *request.Request, v reflect.Value) {
 	if field, ok := v.Type().FieldByName("SDKShapeTraits"); ok {
 		if payloadName := field.Tag.Get("payload"); payloadName != "" {
 			pfield, _ := v.Type().FieldByName(payloadName)
@@ -112,7 +112,7 @@ func buildBody(r *aws.Request, v reflect.Value) {
 	}
 }
 
-func buildHeader(r *aws.Request, v reflect.Value, name string) {
+func buildHeader(r *request.Request, v reflect.Value, name string) {
 	str, err := convertType(v)
 	if err != nil {
 		r.Error = awserr.New("SerializationError", "failed to encode REST request", err)
@@ -121,7 +121,7 @@ func buildHeader(r *aws.Request, v reflect.Value, name string) {
 	}
 }
 
-func buildHeaderMap(r *aws.Request, v reflect.Value, prefix string) {
+func buildHeaderMap(r *request.Request, v reflect.Value, prefix string) {
 	for _, key := range v.MapKeys() {
 		str, err := convertType(v.MapIndex(key))
 		if err != nil {
@@ -132,7 +132,7 @@ func buildHeaderMap(r *aws.Request, v reflect.Value, prefix string) {
 	}
 }
 
-func buildURI(r *aws.Request, v reflect.Value, name string) {
+func buildURI(r *request.Request, v reflect.Value, name string) {
 	value, err := convertType(v)
 	if err != nil {
 		r.Error = awserr.New("SerializationError", "failed to encode REST request", err)
@@ -144,7 +144,7 @@ func buildURI(r *aws.Request, v reflect.Value, name string) {
 	}
 }
 
-func buildQueryString(r *aws.Request, v reflect.Value, name string, query url.Values) {
+func buildQueryString(r *request.Request, v reflect.Value, name string, query url.Values) {
 	str, err := convertType(v)
 	if err != nil {
 		r.Error = awserr.New("SerializationError", "failed to encode REST request", err)
@@ -156,8 +156,13 @@ func buildQueryString(r *aws.Request, v reflect.Value, name string, query url.Va
 func updatePath(url *url.URL, urlPath string) {
 	scheme, query := url.Scheme, url.RawQuery
 
+	hasSlash := strings.HasSuffix(urlPath, "/")
+
 	// clean up path
 	urlPath = path.Clean(urlPath)
+	if hasSlash && !strings.HasSuffix(urlPath, "/") {
+		urlPath += "/"
+	}
 
 	// get formatted URL minus scheme so we can build this into Opaque
 	url.Scheme, url.Path, url.RawQuery = "", "", ""

+ 12 - 3
vendor/src/github.com/aws/aws-sdk-go/internal/protocol/rest/unmarshal.go

@@ -12,18 +12,27 @@ import (
 
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws/awserr"
+	"github.com/aws/aws-sdk-go/aws/request"
 )
 
 // Unmarshal unmarshals the REST component of a response in a REST service.
-func Unmarshal(r *aws.Request) {
+func Unmarshal(r *request.Request) {
 	if r.DataFilled() {
 		v := reflect.Indirect(reflect.ValueOf(r.Data))
 		unmarshalBody(r, v)
+	}
+}
+
+// UnmarshalMeta unmarshals the REST metadata of a response in a REST service
+func UnmarshalMeta(r *request.Request) {
+	r.RequestID = r.HTTPResponse.Header.Get("X-Amzn-Requestid")
+	if r.DataFilled() {
+		v := reflect.Indirect(reflect.ValueOf(r.Data))
 		unmarshalLocationElements(r, v)
 	}
 }
 
-func unmarshalBody(r *aws.Request, v reflect.Value) {
+func unmarshalBody(r *request.Request, v reflect.Value) {
 	if field, ok := v.Type().FieldByName("SDKShapeTraits"); ok {
 		if payloadName := field.Tag.Get("payload"); payloadName != "" {
 			pfield, _ := v.Type().FieldByName(payloadName)
@@ -64,7 +73,7 @@ func unmarshalBody(r *aws.Request, v reflect.Value) {
 	}
 }
 
-func unmarshalLocationElements(r *aws.Request, v reflect.Value) {
+func unmarshalLocationElements(r *request.Request, v reflect.Value) {
 	for i := 0; i < v.NumField(); i++ {
 		m, field := v.Field(i), v.Type().Field(i)
 		if n := field.Name; n[0:1] == strings.ToLower(n[0:1]) {

+ 2 - 1
vendor/src/github.com/aws/aws-sdk-go/internal/signer/v4/v4.go

@@ -16,6 +16,7 @@ import (
 
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws/credentials"
+	"github.com/aws/aws-sdk-go/aws/request"
 	"github.com/aws/aws-sdk-go/internal/protocol/rest"
 )
 
@@ -63,7 +64,7 @@ type signer struct {
 // Will sign the requests with the service config's Credentials object
 // Signing is skipped if the credentials is the credentials.AnonymousCredentials
 // object.
-func Sign(req *aws.Request) {
+func Sign(req *request.Request) {
 	// If the request does not need to be signed ignore the signing of the
 	// request if the AnonymousCredentials object is used.
 	if req.Service.Config.Credentials == credentials.AnonymousCredentials {

ファイルの差分が大きいため隠しています
+ 498 - 95
vendor/src/github.com/aws/aws-sdk-go/service/cloudwatchlogs/api.go


+ 17 - 11
vendor/src/github.com/aws/aws-sdk-go/service/cloudwatchlogs/service.go

@@ -4,6 +4,10 @@ package cloudwatchlogs
 
 import (
 	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/aws/defaults"
+	"github.com/aws/aws-sdk-go/aws/request"
+	"github.com/aws/aws-sdk-go/aws/service"
+	"github.com/aws/aws-sdk-go/aws/service/serviceinfo"
 	"github.com/aws/aws-sdk-go/internal/protocol/jsonrpc"
 	"github.com/aws/aws-sdk-go/internal/signer/v4"
 )
@@ -41,23 +45,25 @@ import (
 // AWS Ruby Developer Center (http://aws.amazon.com/ruby/) AWS Windows and .NET
 // Developer Center (http://aws.amazon.com/net/)
 type CloudWatchLogs struct {
-	*aws.Service
+	*service.Service
 }
 
 // Used for custom service initialization logic
-var initService func(*aws.Service)
+var initService func(*service.Service)
 
 // Used for custom request initialization logic
-var initRequest func(*aws.Request)
+var initRequest func(*request.Request)
 
 // New returns a new CloudWatchLogs client.
 func New(config *aws.Config) *CloudWatchLogs {
-	service := &aws.Service{
-		Config:       aws.DefaultConfig.Merge(config),
-		ServiceName:  "logs",
-		APIVersion:   "2014-03-28",
-		JSONVersion:  "1.1",
-		TargetPrefix: "Logs_20140328",
+	service := &service.Service{
+		ServiceInfo: serviceinfo.ServiceInfo{
+			Config:       defaults.DefaultConfig.Merge(config),
+			ServiceName:  "logs",
+			APIVersion:   "2014-03-28",
+			JSONVersion:  "1.1",
+			TargetPrefix: "Logs_20140328",
+		},
 	}
 	service.Initialize()
 
@@ -78,8 +84,8 @@ func New(config *aws.Config) *CloudWatchLogs {
 
 // newRequest creates a new request for a CloudWatchLogs operation and runs any
 // custom request initialization.
-func (c *CloudWatchLogs) newRequest(op *aws.Operation, params, data interface{}) *aws.Request {
-	req := aws.NewRequest(c.Service, op, params, data)
+func (c *CloudWatchLogs) newRequest(op *request.Operation, params, data interface{}) *request.Request {
+	req := c.NewRequest(op, params, data)
 
 	// Run custom request initialization if present
 	if initRequest != nil {

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません