summaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws
diff options
context:
space:
mode:
Diffstat (limited to 'Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws')
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/awsutil/path_value.go142
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/awsutil/path_value_test.go60
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/awsutil/string_value.go88
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/config.go101
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/credentials.go288
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/credentials_test.go236
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/error.go26
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/example.ini8
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/handler_functions.go78
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/handlers.go65
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/handlers_test.go24
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/param_validator.go80
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/param_validator_test.go85
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/request.go149
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/request_test.go118
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/service.go142
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/types.go63
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/version.go5
18 files changed, 1758 insertions, 0 deletions
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/awsutil/path_value.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/awsutil/path_value.go
new file mode 100644
index 000000000..ce4c5e27a
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/awsutil/path_value.go
@@ -0,0 +1,142 @@
+package awsutil
+
+import (
+ "reflect"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+var indexRe = regexp.MustCompile(`(.+)\[(-?\d+)?\]$`)
+
+func rValuesAtPath(v interface{}, path string, create bool) []reflect.Value {
+ pathparts := strings.Split(path, "||")
+ if len(pathparts) > 1 {
+ for _, pathpart := range pathparts {
+ vals := rValuesAtPath(v, pathpart, create)
+ if vals != nil && len(vals) > 0 {
+ return vals
+ }
+ }
+ return nil
+ }
+
+ values := []reflect.Value{reflect.Indirect(reflect.ValueOf(v))}
+ components := strings.Split(path, ".")
+ for len(values) > 0 && len(components) > 0 {
+ var index *int64
+ var indexStar bool
+ c := strings.TrimSpace(components[0])
+ if c == "" { // no actual component, illegal syntax
+ return nil
+ } else if c != "*" && strings.ToLower(c[0:1]) == c[0:1] {
+ // TODO normalize case for user
+ return nil // don't support unexported fields
+ }
+
+ // parse this component
+ if m := indexRe.FindStringSubmatch(c); m != nil {
+ c = m[1]
+ if m[2] == "" {
+ index = nil
+ indexStar = true
+ } else {
+ i, _ := strconv.ParseInt(m[2], 10, 32)
+ index = &i
+ indexStar = false
+ }
+ }
+
+ nextvals := []reflect.Value{}
+ for _, value := range values {
+ // pull component name out of struct member
+ if value.Kind() != reflect.Struct {
+ continue
+ }
+
+ if c == "*" { // pull all members
+ for i := 0; i < value.NumField(); i++ {
+ if f := reflect.Indirect(value.Field(i)); f.IsValid() {
+ nextvals = append(nextvals, f)
+ }
+ }
+ continue
+ }
+
+ value = value.FieldByName(c)
+ if create && value.Kind() == reflect.Ptr && value.IsNil() {
+ value.Set(reflect.New(value.Type().Elem()))
+ value = value.Elem()
+ } else {
+ value = reflect.Indirect(value)
+ }
+
+ if value.IsValid() {
+ nextvals = append(nextvals, value)
+ }
+ }
+ values = nextvals
+
+ if indexStar || index != nil {
+ nextvals = []reflect.Value{}
+ for _, value := range values {
+ value := reflect.Indirect(value)
+ if value.Kind() != reflect.Slice {
+ continue
+ }
+
+ if indexStar { // grab all indices
+ for i := 0; i < value.Len(); i++ {
+ idx := reflect.Indirect(value.Index(i))
+ if idx.IsValid() {
+ nextvals = append(nextvals, idx)
+ }
+ }
+ continue
+ }
+
+ // pull out index
+ i := int(*index)
+ if i >= value.Len() { // check out of bounds
+ if create {
+ // TODO resize slice
+ } else {
+ continue
+ }
+ } else if i < 0 { // support negative indexing
+ i = value.Len() + i
+ }
+ value = reflect.Indirect(value.Index(i))
+
+ if value.IsValid() {
+ nextvals = append(nextvals, value)
+ }
+ }
+ values = nextvals
+ }
+
+ components = components[1:]
+ }
+ return values
+}
+
+// ValuesAtPath returns a list of objects at the lexical path inside of a structure
+func ValuesAtPath(i interface{}, path string) []interface{} {
+ if rvals := rValuesAtPath(i, path, false); rvals != nil {
+ vals := make([]interface{}, len(rvals))
+ for i, rval := range rvals {
+ vals[i] = rval.Interface()
+ }
+ return vals
+ }
+ return nil
+}
+
+// SetValueAtPath sets an object at the lexical path inside of a structure
+func SetValueAtPath(i interface{}, path string, v interface{}) {
+ if rvals := rValuesAtPath(i, path, true); rvals != nil {
+ for _, rval := range rvals {
+ rval.Set(reflect.ValueOf(v))
+ }
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/awsutil/path_value_test.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/awsutil/path_value_test.go
new file mode 100644
index 000000000..881927365
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/awsutil/path_value_test.go
@@ -0,0 +1,60 @@
+package awsutil_test
+
+import (
+ "testing"
+
+ "github.com/awslabs/aws-sdk-go/aws/awsutil"
+ "github.com/stretchr/testify/assert"
+)
+
+type Struct struct {
+ A []Struct
+ a []Struct
+ B *Struct
+ D *Struct
+ C string
+}
+
+var data = Struct{
+ A: []Struct{Struct{C: "value1"}, Struct{C: "value2"}, Struct{C: "value3"}},
+ a: []Struct{Struct{C: "value1"}, Struct{C: "value2"}, Struct{C: "value3"}},
+ B: &Struct{B: &Struct{C: "terminal"}, D: &Struct{C: "terminal2"}},
+ C: "initial",
+}
+
+func TestValueAtPathSuccess(t *testing.T) {
+ assert.Equal(t, []interface{}{"initial"}, awsutil.ValuesAtPath(data, "C"))
+ assert.Equal(t, []interface{}{"value1"}, awsutil.ValuesAtPath(data, "A[0].C"))
+ assert.Equal(t, []interface{}{"value2"}, awsutil.ValuesAtPath(data, "A[1].C"))
+ assert.Equal(t, []interface{}{"value3"}, awsutil.ValuesAtPath(data, "A[2].C"))
+ assert.Equal(t, []interface{}{"value3"}, awsutil.ValuesAtPath(data, "A[-1].C"))
+ assert.Equal(t, []interface{}{"value1", "value2", "value3"}, awsutil.ValuesAtPath(data, "A[].C"))
+ assert.Equal(t, []interface{}{"terminal"}, awsutil.ValuesAtPath(data, "B . B . C"))
+ assert.Equal(t, []interface{}{"terminal", "terminal2"}, awsutil.ValuesAtPath(data, "B.*.C"))
+ assert.Equal(t, []interface{}{"initial"}, awsutil.ValuesAtPath(data, "A.D.X || C"))
+}
+
+func TestValueAtPathFailure(t *testing.T) {
+ assert.Equal(t, []interface{}(nil), awsutil.ValuesAtPath(data, "C.x"))
+ assert.Equal(t, []interface{}(nil), awsutil.ValuesAtPath(data, ".x"))
+ assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(data, "X.Y.Z"))
+ assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(data, "A[100].C"))
+ assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(data, "A[3].C"))
+ assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(data, "B.B.C.Z"))
+ assert.Equal(t, []interface{}(nil), awsutil.ValuesAtPath(data, "a[-1].C"))
+ assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(nil, "A.B.C"))
+}
+
+func TestSetValueAtPathSuccess(t *testing.T) {
+ var s Struct
+ awsutil.SetValueAtPath(&s, "C", "test1")
+ awsutil.SetValueAtPath(&s, "B.B.C", "test2")
+ awsutil.SetValueAtPath(&s, "B.D.C", "test3")
+ assert.Equal(t, "test1", s.C)
+ assert.Equal(t, "test2", s.B.B.C)
+ assert.Equal(t, "test3", s.B.D.C)
+
+ awsutil.SetValueAtPath(&s, "B.*.C", "test0")
+ assert.Equal(t, "test0", s.B.B.C)
+ assert.Equal(t, "test0", s.B.D.C)
+}
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/awsutil/string_value.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/awsutil/string_value.go
new file mode 100644
index 000000000..2e90f8da4
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/awsutil/string_value.go
@@ -0,0 +1,88 @@
+package awsutil
+
+import (
+ "bytes"
+ "fmt"
+ "reflect"
+ "strings"
+)
+
+func StringValue(i interface{}) string {
+ var buf bytes.Buffer
+ stringValue(reflect.ValueOf(i), 0, &buf)
+ return buf.String()
+}
+
+func stringValue(v reflect.Value, indent int, buf *bytes.Buffer) {
+ for v.Kind() == reflect.Ptr {
+ v = v.Elem()
+ }
+
+ switch v.Kind() {
+ case reflect.Struct:
+ buf.WriteString("{\n")
+
+ names := []string{}
+ for i := 0; i < v.Type().NumField(); i++ {
+ name := v.Type().Field(i).Name
+ f := v.Field(i)
+ if name[0:1] == strings.ToLower(name[0:1]) {
+ continue // ignore unexported fields
+ }
+ if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice) && f.IsNil() {
+ continue // ignore unset fields
+ }
+ names = append(names, name)
+ }
+
+ for i, n := range names {
+ val := v.FieldByName(n)
+ buf.WriteString(strings.Repeat(" ", indent+2))
+ buf.WriteString(n + ": ")
+ stringValue(val, indent+2, buf)
+
+ if i < len(names)-1 {
+ buf.WriteString(",\n")
+ }
+ }
+
+ buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
+ case reflect.Slice:
+ nl, id, id2 := "", "", ""
+ if v.Len() > 3 {
+ nl, id, id2 = "\n", strings.Repeat(" ", indent), strings.Repeat(" ", indent+2)
+ }
+ buf.WriteString("[" + nl)
+ for i := 0; i < v.Len(); i++ {
+ buf.WriteString(id2)
+ stringValue(v.Index(i), indent+2, buf)
+
+ if i < v.Len()-1 {
+ buf.WriteString("," + nl)
+ }
+ }
+
+ buf.WriteString(nl + id + "]")
+ case reflect.Map:
+ buf.WriteString("{\n")
+
+ for i, k := range v.MapKeys() {
+ buf.WriteString(strings.Repeat(" ", indent+2))
+ buf.WriteString(k.String() + ": ")
+ stringValue(v.MapIndex(k), indent+2, buf)
+
+ if i < v.Len()-1 {
+ buf.WriteString(",\n")
+ }
+ }
+
+ buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
+ default:
+ format := "%v"
+ switch v.Interface().(type) {
+ case string:
+ format = "%q"
+ }
+ fmt.Fprintf(buf, format, v.Interface())
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/config.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/config.go
new file mode 100644
index 000000000..6cc6da42e
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/config.go
@@ -0,0 +1,101 @@
+package aws
+
+import (
+ "io"
+ "net/http"
+ "os"
+)
+
+const DEFAULT_RETRIES = -1
+
+var DefaultConfig = &Config{
+ Credentials: DefaultCreds(),
+ Endpoint: "",
+ Region: os.Getenv("AWS_REGION"),
+ DisableSSL: false,
+ ManualSend: false,
+ HTTPClient: http.DefaultClient,
+ LogLevel: 0,
+ Logger: os.Stdout,
+ MaxRetries: DEFAULT_RETRIES,
+ DisableParamValidation: false,
+}
+
+type Config struct {
+ Credentials CredentialsProvider
+ Endpoint string
+ Region string
+ DisableSSL bool
+ ManualSend bool
+ HTTPClient *http.Client
+ LogLevel uint
+ Logger io.Writer
+ MaxRetries int
+ DisableParamValidation bool
+}
+
+func (c Config) Merge(newcfg *Config) *Config {
+ cfg := Config{}
+
+ if newcfg != nil && newcfg.Credentials != nil {
+ cfg.Credentials = newcfg.Credentials
+ } else {
+ cfg.Credentials = c.Credentials
+ }
+
+ if newcfg != nil && newcfg.Endpoint != "" {
+ cfg.Endpoint = newcfg.Endpoint
+ } else {
+ cfg.Endpoint = c.Endpoint
+ }
+
+ if newcfg != nil && newcfg.Region != "" {
+ cfg.Region = newcfg.Region
+ } else {
+ cfg.Region = c.Region
+ }
+
+ if newcfg != nil && newcfg.DisableSSL {
+ cfg.DisableSSL = newcfg.DisableSSL
+ } else {
+ cfg.DisableSSL = c.DisableSSL
+ }
+
+ if newcfg != nil && newcfg.ManualSend {
+ cfg.ManualSend = newcfg.ManualSend
+ } else {
+ cfg.ManualSend = c.ManualSend
+ }
+
+ if newcfg != nil && newcfg.HTTPClient != nil {
+ cfg.HTTPClient = newcfg.HTTPClient
+ } else {
+ cfg.HTTPClient = c.HTTPClient
+ }
+
+ if newcfg != nil && newcfg.LogLevel != 0 {
+ cfg.LogLevel = newcfg.LogLevel
+ } else {
+ cfg.LogLevel = c.LogLevel
+ }
+
+ if newcfg != nil && newcfg.Logger != nil {
+ cfg.Logger = newcfg.Logger
+ } else {
+ cfg.Logger = c.Logger
+ }
+
+ if newcfg != nil && newcfg.MaxRetries != DEFAULT_RETRIES {
+ cfg.MaxRetries = newcfg.MaxRetries
+ } else {
+ cfg.MaxRetries = c.MaxRetries
+ }
+
+ if newcfg != nil && newcfg.DisableParamValidation {
+ cfg.DisableParamValidation = newcfg.DisableParamValidation
+ } else {
+ cfg.DisableParamValidation = c.DisableParamValidation
+ }
+
+ return &cfg
+}
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/credentials.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/credentials.go
new file mode 100644
index 000000000..4490c674a
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/credentials.go
@@ -0,0 +1,288 @@
+package aws
+
+import (
+ "bufio"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "net/http"
+ "os"
+ "path/filepath"
+ "sync"
+ "time"
+
+ "github.com/vaughan0/go-ini"
+)
+
+var currentTime = time.Now
+
+// Credentials are used to authenticate and authorize calls that you make to
+// AWS.
+type Credentials struct {
+ AccessKeyID string
+ SecretAccessKey string
+ SessionToken string
+}
+
+// A CredentialsProvider is a provider of credentials.
+type CredentialsProvider interface {
+ // Credentials returns a set of credentials (or an error if no credentials
+ // could be provided).
+ Credentials() (*Credentials, error)
+}
+
+var (
+ // ErrAccessKeyIDNotFound is returned when the AWS Access Key ID can't be
+ // found in the process's environment.
+ ErrAccessKeyIDNotFound = fmt.Errorf("AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY not found in environment")
+ // ErrSecretAccessKeyNotFound is returned when the AWS Secret Access Key
+ // can't be found in the process's environment.
+ ErrSecretAccessKeyNotFound = fmt.Errorf("AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY not found in environment")
+)
+
+type DefaultCredentialsProvider struct {
+}
+
+func (p *DefaultCredentialsProvider) Credentials() (*Credentials, error) {
+ env, err := EnvCreds()
+ if err == nil {
+ return env.Credentials()
+ }
+
+ profile, err := ProfileCreds("", "", 10*time.Minute)
+ if err == nil {
+ profileCreds, err := profile.Credentials()
+ if err == nil {
+ return profileCreds, nil
+ }
+ }
+
+ return IAMCreds().Credentials()
+}
+
+func DefaultCreds() CredentialsProvider {
+ return &DefaultCredentialsProvider{}
+}
+
+// DetectCreds returns a CredentialsProvider based on the available information.
+//
+// If the access key ID and secret access key are provided, it returns a basic
+// provider.
+//
+// If credentials are available via environment variables, it returns an
+// environment provider.
+//
+// If a profile configuration file is available in the default location and has
+// a default profile configured, it returns a profile provider.
+//
+// Otherwise, it returns an IAM instance provider.
+func DetectCreds(accessKeyID, secretAccessKey, sessionToken string) CredentialsProvider {
+ if accessKeyID != "" && secretAccessKey != "" {
+ return Creds(accessKeyID, secretAccessKey, sessionToken)
+ }
+
+ env, err := EnvCreds()
+ if err == nil {
+ return env
+ }
+
+ profile, err := ProfileCreds("", "", 10*time.Minute)
+ if err != nil {
+ return IAMCreds()
+ }
+
+ _, err = profile.Credentials()
+ if err != nil {
+ return IAMCreds()
+ }
+
+ return profile
+}
+
+// EnvCreds returns a static provider of AWS credentials from the process's
+// environment, or an error if none are found.
+func EnvCreds() (CredentialsProvider, error) {
+ id := os.Getenv("AWS_ACCESS_KEY_ID")
+ if id == "" {
+ id = os.Getenv("AWS_ACCESS_KEY")
+ }
+
+ secret := os.Getenv("AWS_SECRET_ACCESS_KEY")
+ if secret == "" {
+ secret = os.Getenv("AWS_SECRET_KEY")
+ }
+
+ if id == "" {
+ return nil, ErrAccessKeyIDNotFound
+ }
+
+ if secret == "" {
+ return nil, ErrSecretAccessKeyNotFound
+ }
+
+ return Creds(id, secret, os.Getenv("AWS_SESSION_TOKEN")), nil
+}
+
+// Creds returns a static provider of credentials.
+func Creds(accessKeyID, secretAccessKey, sessionToken string) CredentialsProvider {
+ return staticCredentialsProvider{
+ creds: Credentials{
+ AccessKeyID: accessKeyID,
+ SecretAccessKey: secretAccessKey,
+ SessionToken: sessionToken,
+ },
+ }
+}
+
+// IAMCreds returns a provider which pulls credentials from the local EC2
+// instance's IAM roles.
+func IAMCreds() CredentialsProvider {
+ return &iamProvider{}
+}
+
+// ProfileCreds returns a provider which pulls credentials from the profile
+// configuration file.
+func ProfileCreds(filename, profile string, expiry time.Duration) (CredentialsProvider, error) {
+ if filename == "" {
+ homeDir := os.Getenv("HOME") // *nix
+ if homeDir == "" { // Windows
+ homeDir = os.Getenv("USERPROFILE")
+ }
+ if homeDir == "" {
+ return nil, errors.New("User home directory not found.")
+ }
+
+ filename = filepath.Join(homeDir, ".aws", "credentials")
+ }
+
+ if profile == "" {
+ profile = "default"
+ }
+
+ return &profileProvider{
+ filename: filename,
+ profile: profile,
+ expiry: expiry,
+ }, nil
+}
+
+type profileProvider struct {
+ filename string
+ profile string
+ expiry time.Duration
+
+ creds Credentials
+ m sync.Mutex
+ expiration time.Time
+}
+
+func (p *profileProvider) Credentials() (*Credentials, error) {
+ p.m.Lock()
+ defer p.m.Unlock()
+
+ if p.expiration.After(currentTime()) {
+ return &p.creds, nil
+ }
+
+ config, err := ini.LoadFile(p.filename)
+ if err != nil {
+ return nil, err
+ }
+ profile := config.Section(p.profile)
+
+ accessKeyID, ok := profile["aws_access_key_id"]
+ if !ok {
+ return nil, fmt.Errorf("profile %s in %s did not contain aws_access_key_id", p.profile, p.filename)
+ }
+
+ secretAccessKey, ok := profile["aws_secret_access_key"]
+ if !ok {
+ return nil, fmt.Errorf("profile %s in %s did not contain aws_secret_access_key", p.profile, p.filename)
+ }
+
+ sessionToken := profile["aws_session_token"]
+
+ p.creds = Credentials{
+ AccessKeyID: accessKeyID,
+ SecretAccessKey: secretAccessKey,
+ SessionToken: sessionToken,
+ }
+ p.expiration = currentTime().Add(p.expiry)
+
+ return &p.creds, nil
+}
+
+type iamProvider struct {
+ creds Credentials
+ m sync.Mutex
+ expiration time.Time
+}
+
+var metadataCredentialsEndpoint = "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
+
+// IAMClient is the HTTP client used to query the metadata endpoint for IAM
+// credentials.
+var IAMClient = http.Client{
+ Timeout: 1 * time.Second,
+}
+
+func (p *iamProvider) Credentials() (*Credentials, error) {
+ p.m.Lock()
+ defer p.m.Unlock()
+
+ if p.expiration.After(currentTime()) {
+ return &p.creds, nil
+ }
+
+ var body struct {
+ Expiration time.Time
+ AccessKeyID string
+ SecretAccessKey string
+ Token string
+ }
+
+ resp, err := IAMClient.Get(metadataCredentialsEndpoint)
+ if err != nil {
+ return nil, fmt.Errorf("listing IAM credentials")
+ }
+ defer func() {
+ _ = resp.Body.Close()
+ }()
+
+ // Take the first line of the body of the metadata endpoint
+ s := bufio.NewScanner(resp.Body)
+ if !s.Scan() {
+ return nil, fmt.Errorf("unable to find default IAM credentials")
+ } else if s.Err() != nil {
+ return nil, fmt.Errorf("%s listing IAM credentials", s.Err())
+ }
+
+ resp, err = IAMClient.Get(metadataCredentialsEndpoint + s.Text())
+ if err != nil {
+ return nil, fmt.Errorf("getting %s IAM credentials", s.Text())
+ }
+ defer func() {
+ _ = resp.Body.Close()
+ }()
+
+ if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
+ return nil, fmt.Errorf("decoding %s IAM credentials", s.Text())
+ }
+
+ p.creds = Credentials{
+ AccessKeyID: body.AccessKeyID,
+ SecretAccessKey: body.SecretAccessKey,
+ SessionToken: body.Token,
+ }
+ p.expiration = body.Expiration
+
+ return &p.creds, nil
+}
+
+type staticCredentialsProvider struct {
+ creds Credentials
+}
+
+func (p staticCredentialsProvider) Credentials() (*Credentials, error) {
+ return &p.creds, nil
+}
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/credentials_test.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/credentials_test.go
new file mode 100644
index 000000000..3143cebd6
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/credentials_test.go
@@ -0,0 +1,236 @@
+package aws
+
+import (
+ "fmt"
+ "net/http"
+ "net/http/httptest"
+ "os"
+ "testing"
+ "time"
+)
+
+func TestEnvCreds(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("AWS_ACCESS_KEY_ID", "access")
+ os.Setenv("AWS_SECRET_ACCESS_KEY", "secret")
+ os.Setenv("AWS_SESSION_TOKEN", "token")
+
+ prov, err := EnvCreds()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ creds, err := prov.Credentials()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if v, want := creds.AccessKeyID, "access"; v != want {
+ t.Errorf("Access key ID was %v, expected %v", v, want)
+ }
+
+ if v, want := creds.SecretAccessKey, "secret"; v != want {
+ t.Errorf("Secret access key was %v, expected %v", v, want)
+ }
+
+ if v, want := creds.SessionToken, "token"; v != want {
+ t.Errorf("Security token was %v, expected %v", v, want)
+ }
+}
+
+func TestEnvCredsNoAccessKeyID(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("AWS_SECRET_ACCESS_KEY", "secret")
+
+ prov, err := EnvCreds()
+ if err != ErrAccessKeyIDNotFound {
+ t.Fatalf("ErrAccessKeyIDNotFound expected, but was %#v/%#v", prov, err)
+ }
+}
+
+func TestEnvCredsNoSecretAccessKey(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("AWS_ACCESS_KEY_ID", "access")
+
+ prov, err := EnvCreds()
+ if err != ErrSecretAccessKeyNotFound {
+ t.Fatalf("ErrSecretAccessKeyNotFound expected, but was %#v/%#v", prov, err)
+ }
+}
+
+func TestEnvCredsAlternateNames(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("AWS_ACCESS_KEY", "access")
+ os.Setenv("AWS_SECRET_KEY", "secret")
+
+ prov, err := EnvCreds()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ creds, err := prov.Credentials()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if v, want := creds.AccessKeyID, "access"; v != want {
+ t.Errorf("Access key ID was %v, expected %v", v, want)
+ }
+
+ if v, want := creds.SecretAccessKey, "secret"; v != want {
+ t.Errorf("Secret access key was %v, expected %v", v, want)
+ }
+}
+
+func TestIAMCreds(t *testing.T) {
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.RequestURI == "/" {
+ fmt.Fprintln(w, "/creds")
+ } else {
+ fmt.Fprintln(w, `{
+ "AccessKeyId" : "accessKey",
+ "SecretAccessKey" : "secret",
+ "Token" : "token",
+ "Expiration" : "2014-12-16T01:51:37Z"
+}`)
+ }
+ }))
+ defer server.Close()
+
+ defer func(s string) {
+ metadataCredentialsEndpoint = s
+ }(metadataCredentialsEndpoint)
+ metadataCredentialsEndpoint = server.URL
+
+ defer func() {
+ currentTime = time.Now
+ }()
+ currentTime = func() time.Time {
+ return time.Date(2014, 12, 15, 21, 26, 0, 0, time.UTC)
+ }
+
+ prov := IAMCreds()
+ creds, err := prov.Credentials()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if v, want := creds.AccessKeyID, "accessKey"; v != want {
+ t.Errorf("AcccessKeyID was %v, but expected %v", v, want)
+ }
+
+ if v, want := creds.SecretAccessKey, "secret"; v != want {
+ t.Errorf("SecretAccessKey was %v, but expected %v", v, want)
+ }
+
+ if v, want := creds.SessionToken, "token"; v != want {
+ t.Errorf("SessionToken was %v, but expected %v", v, want)
+ }
+}
+
+func TestProfileCreds(t *testing.T) {
+ prov, err := ProfileCreds("example.ini", "", 10*time.Minute)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ creds, err := prov.Credentials()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if v, want := creds.AccessKeyID, "accessKey"; v != want {
+ t.Errorf("AcccessKeyID was %v, but expected %v", v, want)
+ }
+
+ if v, want := creds.SecretAccessKey, "secret"; v != want {
+ t.Errorf("SecretAccessKey was %v, but expected %v", v, want)
+ }
+
+ if v, want := creds.SessionToken, "token"; v != want {
+ t.Errorf("SessionToken was %v, but expected %v", v, want)
+ }
+}
+
+func TestProfileCredsWithoutToken(t *testing.T) {
+ prov, err := ProfileCreds("example.ini", "no_token", 10*time.Minute)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ creds, err := prov.Credentials()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if v, want := creds.AccessKeyID, "accessKey"; v != want {
+ t.Errorf("AcccessKeyID was %v, but expected %v", v, want)
+ }
+
+ if v, want := creds.SecretAccessKey, "secret"; v != want {
+ t.Errorf("SecretAccessKey was %v, but expected %v", v, want)
+ }
+
+ if v, want := creds.SessionToken, ""; v != want {
+ t.Errorf("SessionToken was %v, but expected %v", v, want)
+ }
+}
+
+func BenchmarkProfileCreds(b *testing.B) {
+ prov, err := ProfileCreds("example.ini", "", 10*time.Minute)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ b.ResetTimer()
+
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ _, err := prov.Credentials()
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+ })
+}
+
+func BenchmarkIAMCreds(b *testing.B) {
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.RequestURI == "/" {
+ fmt.Fprintln(w, "/creds")
+ } else {
+ fmt.Fprintln(w, `{
+ "AccessKeyId" : "accessKey",
+ "SecretAccessKey" : "secret",
+ "Token" : "token",
+ "Expiration" : "2014-12-16T01:51:37Z"
+}`)
+ }
+ }))
+ defer server.Close()
+
+ defer func(s string) {
+ metadataCredentialsEndpoint = s
+ }(metadataCredentialsEndpoint)
+ metadataCredentialsEndpoint = server.URL
+
+ defer func() {
+ currentTime = time.Now
+ }()
+ currentTime = func() time.Time {
+ return time.Date(2014, 12, 15, 21, 26, 0, 0, time.UTC)
+ }
+
+ b.ResetTimer()
+
+ prov := IAMCreds()
+
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ _, err := prov.Credentials()
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+ })
+}
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/error.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/error.go
new file mode 100644
index 000000000..6b8989911
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/error.go
@@ -0,0 +1,26 @@
+package aws
+
+import "time"
+
+// An APIError is an error returned by an AWS API.
+type APIError struct {
+ StatusCode int // HTTP status code e.g. 200
+ Code string
+ Message string
+ RequestID string
+ Retryable bool
+ RetryDelay time.Duration
+ RetryCount uint
+}
+
+func (e APIError) Error() string {
+ return e.Message
+}
+
+func Error(e error) *APIError {
+ if err, ok := e.(APIError); ok {
+ return &err
+ } else {
+ return nil
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/example.ini b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/example.ini
new file mode 100644
index 000000000..aa2dc506a
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/example.ini
@@ -0,0 +1,8 @@
+[default]
+aws_access_key_id = accessKey
+aws_secret_access_key = secret
+aws_session_token = token
+
+[no_token]
+aws_access_key_id = accessKey
+aws_secret_access_key = secret
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/handler_functions.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/handler_functions.go
new file mode 100644
index 000000000..4de0f4a11
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/handler_functions.go
@@ -0,0 +1,78 @@
+package aws
+
+import (
+ "fmt"
+ "io"
+ "time"
+)
+
+var sleepDelay = func(delay time.Duration) {
+ time.Sleep(delay)
+}
+
+type lener interface {
+ Len() int
+}
+
+func BuildContentLength(r *Request) {
+ if r.HTTPRequest.Header.Get("Content-Length") != "" {
+ return
+ }
+
+ var length int64
+ switch body := r.Body.(type) {
+ case nil:
+ length = 0
+ case lener:
+ length = int64(body.Len())
+ case io.Seeker:
+ cur, _ := body.Seek(0, 1)
+ end, _ := body.Seek(0, 2)
+ body.Seek(cur, 0) // make sure to seek back to original location
+ length = end - cur
+ default:
+ panic("Cannot get length of body, must provide `ContentLength`")
+ }
+
+ r.HTTPRequest.ContentLength = length
+ r.HTTPRequest.Header.Set("Content-Length", fmt.Sprintf("%d", length))
+}
+
+func UserAgentHandler(r *Request) {
+ r.HTTPRequest.Header.Set("User-Agent", SDKName+"/"+SDKVersion)
+}
+
+func SendHandler(r *Request) {
+ r.HTTPResponse, r.Error = r.Service.Config.HTTPClient.Do(r.HTTPRequest)
+}
+
+func ValidateResponseHandler(r *Request) {
+ if r.HTTPResponse.StatusCode == 0 || r.HTTPResponse.StatusCode >= 400 {
+ err := APIError{
+ StatusCode: r.HTTPResponse.StatusCode,
+ RetryCount: r.RetryCount,
+ }
+ r.Error = err
+ err.Retryable = r.Service.ShouldRetry(r)
+ err.RetryDelay = r.Service.RetryRules(r)
+ r.Error = err
+ }
+}
+
+func AfterRetryHandler(r *Request) {
+ delay := 0 * time.Second
+ willRetry := false
+
+ if err := Error(r.Error); err != nil {
+ delay = err.RetryDelay
+ if err.Retryable && r.RetryCount < r.Service.MaxRetries() {
+ r.RetryCount++
+ willRetry = true
+ }
+ }
+
+ if willRetry {
+ r.Error = nil
+ sleepDelay(delay)
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/handlers.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/handlers.go
new file mode 100644
index 000000000..f7c135fed
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/handlers.go
@@ -0,0 +1,65 @@
+package aws
+
+import "container/list"
+
+type Handlers struct {
+ Validate HandlerList
+ Build HandlerList
+ Sign HandlerList
+ Send HandlerList
+ ValidateResponse HandlerList
+ Unmarshal HandlerList
+ UnmarshalMeta HandlerList
+ UnmarshalError HandlerList
+ Retry HandlerList
+ AfterRetry HandlerList
+}
+
+func (h *Handlers) copy() Handlers {
+ return Handlers{
+ Validate: h.Validate.copy(),
+ Build: h.Build.copy(),
+ Sign: h.Sign.copy(),
+ Send: h.Send.copy(),
+ ValidateResponse: h.ValidateResponse.copy(),
+ Unmarshal: h.Unmarshal.copy(),
+ UnmarshalError: h.UnmarshalError.copy(),
+ UnmarshalMeta: h.UnmarshalMeta.copy(),
+ Retry: h.Retry.copy(),
+ AfterRetry: h.AfterRetry.copy(),
+ }
+}
+
+// Clear removes callback functions for all handlers
+func (h *Handlers) Clear() {
+ h.Validate.Init()
+ h.Build.Init()
+ h.Send.Init()
+ h.Sign.Init()
+ h.Unmarshal.Init()
+ h.UnmarshalMeta.Init()
+ h.UnmarshalError.Init()
+ h.ValidateResponse.Init()
+ h.Retry.Init()
+ h.AfterRetry.Init()
+}
+
+type HandlerList struct {
+ list.List
+}
+
+func (l HandlerList) copy() HandlerList {
+ var n HandlerList
+ for e := l.Front(); e != nil; e = e.Next() {
+ h := e.Value.(func(*Request))
+ n.PushBack(h)
+ }
+ return n
+}
+
+func (l *HandlerList) Run(r *Request) {
+ for e := l.Front(); e != nil; e = e.Next() {
+ h := e.Value.(func(*Request))
+ h(r)
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/handlers_test.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/handlers_test.go
new file mode 100644
index 000000000..89e87cc49
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/handlers_test.go
@@ -0,0 +1,24 @@
+package aws
+
+import "testing"
+
+func TestHandlerList(t *testing.T) {
+ r := &Request{}
+ l := HandlerList{}
+ l.PushBack(func(r *Request) { r.Data = Boolean(true) })
+ l.Run(r)
+ if r.Data == nil {
+ t.Error("Expected handler to execute")
+ }
+}
+
+func TestMultipleHandlers(t *testing.T) {
+ r := &Request{}
+ l := HandlerList{}
+ l.PushBack(func(r *Request) { r.Data = Boolean(true) })
+ l.PushBack(func(r *Request) { r.Data = nil })
+ l.Run(r)
+ if r.Data != nil {
+ t.Error("Expected handler to execute")
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/param_validator.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/param_validator.go
new file mode 100644
index 000000000..e1cb5cea5
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/param_validator.go
@@ -0,0 +1,80 @@
+package aws
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+)
+
+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 = APIError{Code: "InvalidParameter", Message: msg}
+ }
+ }
+}
+
+type validator struct {
+ errors []string
+}
+
+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()))
+ }
+ }
+}
+
+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:
+ 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)
+ }
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/param_validator_test.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/param_validator_test.go
new file mode 100644
index 000000000..08deca15a
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/param_validator_test.go
@@ -0,0 +1,85 @@
+package aws_test
+
+import (
+ "testing"
+
+ "github.com/awslabs/aws-sdk-go/aws"
+ "github.com/stretchr/testify/assert"
+)
+
+var service = func() *aws.Service {
+ s := &aws.Service{
+ Config: &aws.Config{},
+ ServiceName: "mock-service",
+ APIVersion: "2015-01-01",
+ }
+ return s
+}()
+
+type StructShape struct {
+ RequiredList []*ConditionalStructShape `required:"true"`
+ RequiredMap *map[string]*ConditionalStructShape `required:"true"`
+ RequiredBool *bool `required:"true"`
+ OptionalStruct *ConditionalStructShape
+
+ hiddenParameter *string
+
+ metadataStructureShape
+}
+
+type metadataStructureShape struct {
+ SDKShapeTraits bool
+}
+
+type ConditionalStructShape struct {
+ Name *string `required:"true"`
+ SDKShapeTraits bool
+}
+
+func TestNoErrors(t *testing.T) {
+ input := &StructShape{
+ RequiredList: []*ConditionalStructShape{},
+ RequiredMap: &map[string]*ConditionalStructShape{
+ "key1": &ConditionalStructShape{Name: aws.String("Name")},
+ "key2": &ConditionalStructShape{Name: aws.String("Name")},
+ },
+ RequiredBool: aws.Boolean(true),
+ OptionalStruct: &ConditionalStructShape{Name: aws.String("Name")},
+ }
+
+ req := aws.NewRequest(service, &aws.Operation{}, input, nil)
+ aws.ValidateParameters(req)
+ assert.NoError(t, req.Error)
+}
+
+func TestMissingRequiredParameters(t *testing.T) {
+ input := &StructShape{}
+ req := aws.NewRequest(service, &aws.Operation{}, input, nil)
+ aws.ValidateParameters(req)
+ err := aws.Error(req.Error)
+
+ assert.Error(t, err)
+ assert.Equal(t, "InvalidParameter", err.Code)
+ assert.Equal(t, "3 validation errors:\n- missing required parameter: RequiredList\n- missing required parameter: RequiredMap\n- missing required parameter: RequiredBool", err.Message)
+}
+
+func TestNestedMissingRequiredParameters(t *testing.T) {
+ input := &StructShape{
+ RequiredList: []*ConditionalStructShape{&ConditionalStructShape{}},
+ RequiredMap: &map[string]*ConditionalStructShape{
+ "key1": &ConditionalStructShape{Name: aws.String("Name")},
+ "key2": &ConditionalStructShape{},
+ },
+ RequiredBool: aws.Boolean(true),
+ OptionalStruct: &ConditionalStructShape{},
+ }
+
+ req := aws.NewRequest(service, &aws.Operation{}, input, nil)
+ aws.ValidateParameters(req)
+ err := aws.Error(req.Error)
+
+ assert.Error(t, err)
+ assert.Equal(t, "InvalidParameter", err.Code)
+ assert.Equal(t, "3 validation errors:\n- missing required parameter: RequiredList[0].Name\n- missing required parameter: RequiredMap[\"key2\"].Name\n- missing required parameter: OptionalStruct.Name", err.Message)
+
+}
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/request.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/request.go
new file mode 100644
index 000000000..1c442b1cd
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/request.go
@@ -0,0 +1,149 @@
+package aws
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "reflect"
+ "time"
+)
+
+type Request struct {
+ *Service
+ Handlers Handlers
+ Time time.Time
+ ExpireTime time.Duration
+ Operation *Operation
+ HTTPRequest *http.Request
+ HTTPResponse *http.Response
+ Body io.ReadSeeker
+ Params interface{}
+ Error error
+ Data interface{}
+ RequestID string
+ RetryCount uint
+
+ built bool
+}
+
+type Operation struct {
+ Name string
+ HTTPMethod string
+ HTTPPath string
+}
+
+func NewRequest(service *Service, operation *Operation, params interface{}, data interface{}) *Request {
+ method := operation.HTTPMethod
+ if method == "" {
+ method = "POST"
+ }
+ p := operation.HTTPPath
+ if p == "" {
+ p = "/"
+ }
+
+ httpReq, _ := http.NewRequest(method, "", nil)
+ httpReq.URL, _ = url.Parse(service.Endpoint + p)
+
+ r := &Request{
+ Service: service,
+ Handlers: service.Handlers.copy(),
+ Time: time.Now(),
+ ExpireTime: 0,
+ Operation: operation,
+ HTTPRequest: httpReq,
+ Body: nil,
+ Params: params,
+ Error: nil,
+ Data: data,
+ }
+ r.SetBufferBody([]byte{})
+
+ return r
+}
+
+func (r *Request) ParamsFilled() bool {
+ return r.Params != nil && reflect.ValueOf(r.Params).Elem().IsValid()
+}
+
+func (r *Request) DataFilled() bool {
+ return r.Data != nil && reflect.ValueOf(r.Data).Elem().IsValid()
+}
+
+func (r *Request) SetBufferBody(buf []byte) {
+ r.SetReaderBody(bytes.NewReader(buf))
+}
+
+func (r *Request) SetReaderBody(reader io.ReadSeeker) {
+ r.HTTPRequest.Body = ioutil.NopCloser(reader)
+ r.Body = reader
+}
+
+func (r *Request) Presign(expireTime time.Duration) (string, error) {
+ r.ExpireTime = expireTime
+ r.Sign()
+ if r.Error != nil {
+ return "", r.Error
+ } else {
+ return r.HTTPRequest.URL.String(), nil
+ }
+}
+
+func (r *Request) Build() error {
+ if !r.built {
+ r.Error = nil
+ r.Handlers.Validate.Run(r)
+ if r.Error != nil {
+ return r.Error
+ }
+ r.Handlers.Build.Run(r)
+ r.built = true
+ }
+
+ return r.Error
+}
+
+func (r *Request) Sign() error {
+ r.Build()
+ if r.Error != nil {
+ return r.Error
+ }
+
+ r.Handlers.Sign.Run(r)
+ return r.Error
+}
+
+func (r *Request) Send() error {
+ r.Sign()
+ if r.Error != nil {
+ return r.Error
+ }
+
+ for {
+ r.Handlers.Send.Run(r)
+ if r.Error != nil {
+ return r.Error
+ }
+
+ r.Handlers.UnmarshalMeta.Run(r)
+ r.Handlers.ValidateResponse.Run(r)
+ if r.Error != nil {
+ r.Handlers.Retry.Run(r)
+ r.Handlers.AfterRetry.Run(r)
+ if r.Error != nil {
+ r.Handlers.UnmarshalError.Run(r)
+ return r.Error
+ }
+ continue
+ }
+
+ r.Handlers.Unmarshal.Run(r)
+ if r.Error != nil {
+ return r.Error
+ }
+
+ return nil
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/request_test.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/request_test.go
new file mode 100644
index 000000000..b27b55067
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/request_test.go
@@ -0,0 +1,118 @@
+package aws
+
+import (
+ "bytes"
+ "encoding/json"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "reflect"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+)
+
+type testData struct {
+ Data string
+}
+
+func body(str string) io.ReadCloser {
+ return ioutil.NopCloser(bytes.NewReader([]byte(str)))
+}
+
+func unmarshal(req *Request) {
+ defer req.HTTPResponse.Body.Close()
+ if req.Data != nil {
+ json.NewDecoder(req.HTTPResponse.Body).Decode(req.Data)
+ }
+ return
+}
+
+func unmarshalError(req *Request) {
+ bodyBytes, err := ioutil.ReadAll(req.HTTPResponse.Body)
+ if err != nil {
+ req.Error = err
+ return
+ }
+ if len(bodyBytes) == 0 {
+ req.Error = APIError{
+ StatusCode: req.HTTPResponse.StatusCode,
+ Message: req.HTTPResponse.Status,
+ }
+ return
+ }
+ var jsonErr jsonErrorResponse
+ if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil {
+ req.Error = err
+ return
+ }
+ req.Error = APIError{
+ StatusCode: req.HTTPResponse.StatusCode,
+ Code: jsonErr.Code,
+ Message: jsonErr.Message,
+ }
+}
+
+type jsonErrorResponse struct {
+ Code string `json:"__type"`
+ Message string `json:"message"`
+}
+
+func TestRequestRecoverRetry(t *testing.T) {
+ reqNum := 0
+ reqs := []http.Response{
+ http.Response{StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)},
+ http.Response{StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)},
+ http.Response{StatusCode: 200, Body: body(`{"data":"valid"}`)},
+ }
+
+ s := NewService(&Config{MaxRetries: -1})
+ s.Handlers.Unmarshal.PushBack(unmarshal)
+ s.Handlers.UnmarshalError.PushBack(unmarshalError)
+ s.Handlers.Send.Init() // mock sending
+ s.Handlers.Send.PushBack(func(r *Request) {
+ r.HTTPResponse = &reqs[reqNum]
+ reqNum++
+ })
+ out := &testData{}
+ r := NewRequest(s, &Operation{Name: "Operation"}, nil, out)
+ err := r.Send()
+ assert.Nil(t, err)
+ assert.Equal(t, 2, int(r.RetryCount))
+ assert.Equal(t, "valid", out.Data)
+}
+
+func TestRequestExhaustRetries(t *testing.T) {
+ delays := []time.Duration{}
+ sleepDelay = func(delay time.Duration) {
+ delays = append(delays, delay)
+ }
+
+ reqNum := 0
+ reqs := []http.Response{
+ http.Response{StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)},
+ http.Response{StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)},
+ http.Response{StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)},
+ http.Response{StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)},
+ }
+
+ s := NewService(&Config{MaxRetries: -1})
+ s.Handlers.Unmarshal.PushBack(unmarshal)
+ s.Handlers.UnmarshalError.PushBack(unmarshalError)
+ s.Handlers.Send.Init() // mock sending
+ s.Handlers.Send.PushBack(func(r *Request) {
+ r.HTTPResponse = &reqs[reqNum]
+ reqNum++
+ })
+ r := NewRequest(s, &Operation{Name: "Operation"}, nil, nil)
+ err := r.Send()
+ apiErr := Error(err)
+ assert.NotNil(t, err)
+ assert.NotNil(t, apiErr)
+ assert.Equal(t, 500, apiErr.StatusCode)
+ assert.Equal(t, "UnknownError", apiErr.Code)
+ assert.Equal(t, "An error occurred.", apiErr.Message)
+ assert.Equal(t, 3, int(r.RetryCount))
+ assert.True(t, reflect.DeepEqual([]time.Duration{30 * time.Millisecond, 60 * time.Millisecond, 120 * time.Millisecond}, delays))
+}
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/service.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/service.go
new file mode 100644
index 000000000..95d590b91
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/service.go
@@ -0,0 +1,142 @@
+package aws
+
+import (
+ "fmt"
+ "math"
+ "net/http"
+ "net/http/httputil"
+ "regexp"
+ "time"
+
+ "github.com/awslabs/aws-sdk-go/internal/endpoints"
+)
+
+type Service struct {
+ Config *Config
+ Handlers Handlers
+ ManualSend bool
+ ServiceName string
+ APIVersion string
+ Endpoint string
+ JSONVersion string
+ TargetPrefix string
+ RetryRules func(*Request) time.Duration
+ ShouldRetry func(*Request) bool
+ DefaultMaxRetries uint
+}
+
+var schemeRE = regexp.MustCompile("^([^:]+)://")
+
+func NewService(config *Config) *Service {
+ svc := &Service{Config: config}
+ svc.Initialize()
+ return svc
+}
+
+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.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 !s.Config.DisableParamValidation {
+ s.Handlers.Validate.PushBack(ValidateParameters)
+ }
+}
+
+func (s *Service) buildEndpoint() {
+ if s.Config.Endpoint != "" {
+ s.Endpoint = s.Config.Endpoint
+ } else {
+ s.Endpoint = endpoints.EndpointForRegion(s.ServiceName, s.Config.Region)
+ }
+
+ if !schemeRE.MatchString(s.Endpoint) {
+ scheme := "https"
+ if s.Config.DisableSSL {
+ scheme = "http"
+ }
+ s.Endpoint = scheme + "://" + s.Endpoint
+ }
+}
+
+func (s *Service) AddDebugHandlers() {
+ out := s.Config.Logger
+ if s.Config.LogLevel == 0 {
+ return
+ }
+
+ s.Handlers.Sign.PushBack(func(r *Request) {
+ dumpedBody, _ := httputil.DumpRequest(r.HTTPRequest, true)
+
+ fmt.Fprintf(out, "=> [%s] %s.%s(%+v)\n", r.Time,
+ r.Service.ServiceName, r.Operation.Name, r.Params)
+ fmt.Fprintf(out, "---[ REQUEST PRE-SIGN ]------------------------------\n")
+ fmt.Fprintf(out, "%s\n", string(dumpedBody))
+ fmt.Fprintf(out, "-----------------------------------------------------\n")
+ })
+ s.Handlers.Send.PushFront(func(r *Request) {
+ dumpedBody, _ := httputil.DumpRequest(r.HTTPRequest, true)
+
+ fmt.Fprintf(out, "---[ REQUEST POST-SIGN ]-----------------------------\n")
+ fmt.Fprintf(out, "%s\n", string(dumpedBody))
+ fmt.Fprintf(out, "-----------------------------------------------------\n")
+ })
+ s.Handlers.Send.PushBack(func(r *Request) {
+ fmt.Fprintf(out, "---[ RESPONSE ]--------------------------------------\n")
+ if r.HTTPResponse != nil {
+ dumpedBody, _ := httputil.DumpResponse(r.HTTPResponse, true)
+ fmt.Fprintf(out, "%s\n", string(dumpedBody))
+ } else if r.Error != nil {
+ fmt.Fprintf(out, "%s\n", r.Error)
+ }
+ fmt.Fprintf(out, "-----------------------------------------------------\n")
+ })
+}
+
+func (s *Service) MaxRetries() uint {
+ if s.Config.MaxRetries < 0 {
+ return s.DefaultMaxRetries
+ } else {
+ return uint(s.Config.MaxRetries)
+ }
+}
+
+func retryRules(r *Request) time.Duration {
+ delay := time.Duration(math.Pow(2, float64(r.RetryCount))) * 30
+ return delay * time.Millisecond
+}
+
+func shouldRetry(r *Request) bool {
+ if err := Error(r.Error); err != nil {
+ if err.StatusCode >= 500 {
+ return true
+ }
+
+ switch err.Code {
+ case "ExpiredTokenException":
+ case "ProvisionedThroughputExceededException", "Throttling":
+ return true
+ }
+ }
+ return false
+}
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/types.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/types.go
new file mode 100644
index 000000000..5da09114c
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/types.go
@@ -0,0 +1,63 @@
+package aws
+
+import (
+ "io"
+ "time"
+)
+
+// String converts a Go string into a string pointer.
+func String(v string) *string {
+ return &v
+}
+
+// Boolean converts a Go bool into a boolean pointer.
+func Boolean(v bool) *bool {
+ return &v
+}
+
+// Long converts a Go int64 into a long pointer.
+func Long(v int64) *int64 {
+ return &v
+}
+
+// Double converts a Go float64 into a double pointer.
+func Double(v float64) *float64 {
+ return &v
+}
+
+// Time converts a Go Time into a Time pointer
+func Time(t time.Time) *time.Time {
+ return &t
+}
+
+func ReadSeekCloser(r io.Reader) ReaderSeekerCloser {
+ return ReaderSeekerCloser{r}
+}
+
+type ReaderSeekerCloser struct {
+ r io.Reader
+}
+
+func (r ReaderSeekerCloser) Read(p []byte) (int, error) {
+ switch t := r.r.(type) {
+ case io.Reader:
+ return t.Read(p)
+ }
+ return 0, nil
+}
+
+func (r ReaderSeekerCloser) Seek(offset int64, whence int) (int64, error) {
+ switch t := r.r.(type) {
+ case io.Seeker:
+ return t.Seek(offset, whence)
+ }
+ return int64(0), nil
+}
+
+func (r ReaderSeekerCloser) Close() error {
+ switch t := r.r.(type) {
+ case io.Closer:
+ return t.Close()
+ }
+ return nil
+}
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/version.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/version.go
new file mode 100644
index 000000000..f673d470a
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/version.go
@@ -0,0 +1,5 @@
+// Package aws provides core functionality for making requests to AWS services.
+package aws
+
+const SDKName = "aws-sdk-go"
+const SDKVersion = "0.5.0"