Commit ce2b46d0 authored by Quinton Hoole's avatar Quinton Hoole

Merge pull request #9240 from tpounds/update-aws-sdk-go

Update AWS Go SDK (v0.6.0)
parents 02f3142f 6eea2716
...@@ -49,36 +49,54 @@ ...@@ -49,36 +49,54 @@
"Rev": "87808a37061a4a2e6204ccea5fd2fc930576db94" "Rev": "87808a37061a4a2e6204ccea5fd2fc930576db94"
}, },
{ {
"ImportPath": "github.com/awslabs/aws-sdk-go/aws", "ImportPath": "github.com/aws/aws-sdk-go/aws",
"Rev": "c0a38f106248742920a2b786dcae81457af003d3" "Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
}, },
{ {
"ImportPath": "github.com/awslabs/aws-sdk-go/internal/endpoints", "ImportPath": "github.com/aws/aws-sdk-go/internal/apierr",
"Rev": "c0a38f106248742920a2b786dcae81457af003d3" "Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
}, },
{ {
"ImportPath": "github.com/awslabs/aws-sdk-go/internal/protocol/ec2query", "ImportPath": "github.com/aws/aws-sdk-go/internal/endpoints",
"Rev": "c0a38f106248742920a2b786dcae81457af003d3" "Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
}, },
{ {
"ImportPath": "github.com/awslabs/aws-sdk-go/internal/protocol/query", "ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/ec2query",
"Rev": "c0a38f106248742920a2b786dcae81457af003d3" "Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
}, },
{ {
"ImportPath": "github.com/awslabs/aws-sdk-go/internal/protocol/xml/xmlutil", "ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/query",
"Rev": "c0a38f106248742920a2b786dcae81457af003d3" "Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
}, },
{ {
"ImportPath": "github.com/awslabs/aws-sdk-go/internal/signer/v4", "ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/rest",
"Rev": "c0a38f106248742920a2b786dcae81457af003d3" "Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
}, },
{ {
"ImportPath": "github.com/awslabs/aws-sdk-go/service/ec2", "ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/xml/xmlutil",
"Rev": "c0a38f106248742920a2b786dcae81457af003d3" "Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
}, },
{ {
"ImportPath": "github.com/awslabs/aws-sdk-go/service/elb", "ImportPath": "github.com/aws/aws-sdk-go/internal/signer/v4",
"Rev": "c0a38f106248742920a2b786dcae81457af003d3" "Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/service/ec2",
"Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/service/elb",
"Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
}, },
{ {
"ImportPath": "github.com/beorn7/perks/quantile", "ImportPath": "github.com/beorn7/perks/quantile",
......
// Package awserr represents API error interface accessors for the SDK.
package awserr
// An Error wraps lower level errors with code, message and an original error.
// The underlying concrete error type may also satisfy other interfaces which
// can be to used to obtain more specific information about the error.
//
// Calling Error() or String() will always include the full information about
// an error based on its underlying type.
//
// Example:
//
// output, err := s3manage.Upload(svc, input, opts)
// if err != nil {
// if awsErr, ok := err.(awserr.Error); ok {
// // Get error details
// log.Println("Error:", err.Code(), err.Message())
//
// Prints out full error message, including original error if there was one.
// log.Println("Error:", err.Error())
//
// // Get original error
// if origErr := err.Err(); origErr != nil {
// // operate on original error.
// }
// } else {
// fmt.Println(err.Error())
// }
// }
//
type Error interface {
// Satisfy the generic error interface.
error
// Returns the short phrase depicting the classification of the error.
Code() string
// Returns the error details message.
Message() string
// Returns the original error if one was set. Nil is returned if not set.
OrigErr() error
}
// A RequestFailure is an interface to extract request failure information from
// an Error such as the request ID of the failed request returned by a service.
// RequestFailures may not always have a requestID value if the request failed
// prior to reaching the service such as a connection error.
//
// Example:
//
// output, err := s3manage.Upload(svc, input, opts)
// if err != nil {
// if reqerr, ok := err.(RequestFailure); ok {
// log.Printf("Request failed", reqerr.Code(), reqerr.Message(), reqerr.RequestID())
// } else {
// log.Printf("Error:", err.Error()
// }
// }
//
// Combined with awserr.Error:
//
// output, err := s3manage.Upload(svc, input, opts)
// if err != nil {
// if awsErr, ok := err.(awserr.Error); ok {
// // Generic AWS Error with Code, Message, and original error (if any)
// fmt.Println(awsErr.Code(), awsErr.Message(), awsErr.OrigErr())
//
// if reqErr, ok := err.(awserr.RequestFailure); ok {
// // A service error occurred
// fmt.Println(reqErr.StatusCode(), reqErr.RequestID())
// }
// } else {
// fmt.Println(err.Error())
// }
// }
//
type RequestFailure interface {
Error
// The status code of the HTTP response.
StatusCode() int
// The request ID returned by the service for a request failure. This will
// be empty if no request ID is available such as the request failed due
// to a connection error.
RequestID() string
}
...@@ -7,8 +7,17 @@ import ( ...@@ -7,8 +7,17 @@ import (
// Copy deeply copies a src structure to dst. Useful for copying request and // Copy deeply copies a src structure to dst. Useful for copying request and
// response structures. // response structures.
//
// Can copy between structs of different type, but will only copy fields which
// are assignable, and exist in both structs. Fields which are not assignable,
// or do not exist in both structs are ignored.
func Copy(dst, src interface{}) { func Copy(dst, src interface{}) {
rcopy(reflect.ValueOf(dst), reflect.ValueOf(src)) dstval := reflect.ValueOf(dst)
if !dstval.IsValid() {
panic("Copy dst cannot be nil")
}
rcopy(dstval, reflect.ValueOf(src), true)
} }
// CopyOf returns a copy of src while also allocating the memory for dst. // CopyOf returns a copy of src while also allocating the memory for dst.
...@@ -16,12 +25,15 @@ func Copy(dst, src interface{}) { ...@@ -16,12 +25,15 @@ func Copy(dst, src interface{}) {
func CopyOf(src interface{}) (dst interface{}) { func CopyOf(src interface{}) (dst interface{}) {
dsti := reflect.New(reflect.TypeOf(src).Elem()) dsti := reflect.New(reflect.TypeOf(src).Elem())
dst = dsti.Interface() dst = dsti.Interface()
rcopy(dsti, reflect.ValueOf(src)) rcopy(dsti, reflect.ValueOf(src), true)
return return
} }
// rcopy performs a recursive copy of values from the source to destination. // rcopy performs a recursive copy of values from the source to destination.
func rcopy(dst, src reflect.Value) { //
// root is used to skip certain aspects of the copy which are not valid
// for the root node of a object.
func rcopy(dst, src reflect.Value, root bool) {
if !src.IsValid() { if !src.IsValid() {
return return
} }
...@@ -36,23 +48,32 @@ func rcopy(dst, src reflect.Value) { ...@@ -36,23 +48,32 @@ func rcopy(dst, src reflect.Value) {
} }
} else { } else {
e := src.Type().Elem() e := src.Type().Elem()
if dst.CanSet() { if dst.CanSet() && !src.IsNil() {
dst.Set(reflect.New(e)) dst.Set(reflect.New(e))
} }
if src.Elem().IsValid() { if src.Elem().IsValid() {
rcopy(dst.Elem(), src.Elem()) // Keep the current root state since the depth hasn't changed
rcopy(dst.Elem(), src.Elem(), root)
} }
} }
case reflect.Struct: case reflect.Struct:
dst.Set(reflect.New(src.Type()).Elem()) if !root {
for i := 0; i < src.NumField(); i++ { dst.Set(reflect.New(src.Type()).Elem())
rcopy(dst.Field(i), src.Field(i)) }
t := dst.Type()
for i := 0; i < t.NumField(); i++ {
name := t.Field(i).Name
srcval := src.FieldByName(name)
if srcval.IsValid() {
rcopy(dst.FieldByName(name), srcval, false)
}
} }
case reflect.Slice: case reflect.Slice:
s := reflect.MakeSlice(src.Type(), src.Len(), src.Cap()) s := reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
dst.Set(s) dst.Set(s)
for i := 0; i < src.Len(); i++ { for i := 0; i < src.Len(); i++ {
rcopy(dst.Index(i), src.Index(i)) rcopy(dst.Index(i), src.Index(i), false)
} }
case reflect.Map: case reflect.Map:
s := reflect.MakeMap(src.Type()) s := reflect.MakeMap(src.Type())
...@@ -60,10 +81,15 @@ func rcopy(dst, src reflect.Value) { ...@@ -60,10 +81,15 @@ func rcopy(dst, src reflect.Value) {
for _, k := range src.MapKeys() { for _, k := range src.MapKeys() {
v := src.MapIndex(k) v := src.MapIndex(k)
v2 := reflect.New(v.Type()).Elem() v2 := reflect.New(v.Type()).Elem()
rcopy(v2, v) rcopy(v2, v, false)
dst.SetMapIndex(k, v2) dst.SetMapIndex(k, v2)
} }
default: default:
dst.Set(src) // Assign the value if possible. If its not assignable, the value would
// need to be converted and the impact of that may be unexpected, or is
// not compatible with the dst type.
if src.Type().AssignableTo(dst.Type()) {
dst.Set(src)
}
} }
} }
...@@ -7,7 +7,7 @@ import ( ...@@ -7,7 +7,7 @@ import (
"io/ioutil" "io/ioutil"
"testing" "testing"
"github.com/awslabs/aws-sdk-go/aws/awsutil" "github.com/aws/aws-sdk-go/aws/awsutil"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
...@@ -77,6 +77,23 @@ func TestCopy(t *testing.T) { ...@@ -77,6 +77,23 @@ func TestCopy(t *testing.T) {
assert.NotEqual(t, f2.C, f1.C) assert.NotEqual(t, f2.C, f1.C)
} }
func TestCopyIgnoreNilMembers(t *testing.T) {
type Foo struct {
A *string
}
f := &Foo{}
assert.Nil(t, f.A)
var f2 Foo
awsutil.Copy(&f2, f)
assert.Nil(t, f2.A)
fcopy := awsutil.CopyOf(f)
f3 := fcopy.(*Foo)
assert.Nil(t, f3.A)
}
func TestCopyPrimitive(t *testing.T) { func TestCopyPrimitive(t *testing.T) {
str := "hello" str := "hello"
var s string var s string
...@@ -104,6 +121,52 @@ func TestCopyReader(t *testing.T) { ...@@ -104,6 +121,52 @@ func TestCopyReader(t *testing.T) {
assert.Equal(t, []byte(""), b) assert.Equal(t, []byte(""), b)
} }
func TestCopyDifferentStructs(t *testing.T) {
type SrcFoo struct {
A int
B []*string
C map[string]*int
SrcUnique string
SameNameDiffType int
}
type DstFoo struct {
A int
B []*string
C map[string]*int
DstUnique int
SameNameDiffType string
}
// Create the initial value
str1 := "hello"
str2 := "bye bye"
int1 := 1
int2 := 2
f1 := &SrcFoo{
A: 1,
B: []*string{&str1, &str2},
C: map[string]*int{
"A": &int1,
"B": &int2,
},
SrcUnique: "unique",
SameNameDiffType: 1,
}
// Do the copy
var f2 DstFoo
awsutil.Copy(&f2, f1)
// Values are equal
assert.Equal(t, f2.A, f1.A)
assert.Equal(t, f2.B, f1.B)
assert.Equal(t, f2.C, f1.C)
assert.Equal(t, "unique", f1.SrcUnique)
assert.Equal(t, 1, f1.SameNameDiffType)
assert.Equal(t, 0, f2.DstUnique)
assert.Equal(t, "", f2.SameNameDiffType)
}
func ExampleCopyOf() { func ExampleCopyOf() {
type Foo struct { type Foo struct {
A int A int
......
...@@ -11,11 +11,11 @@ var indexRe = regexp.MustCompile(`(.+)\[(-?\d+)?\]$`) ...@@ -11,11 +11,11 @@ var indexRe = regexp.MustCompile(`(.+)\[(-?\d+)?\]$`)
// rValuesAtPath returns a slice of values found in value v. The values // rValuesAtPath returns a slice of values found in value v. The values
// in v are explored recursively so all nested values are collected. // in v are explored recursively so all nested values are collected.
func rValuesAtPath(v interface{}, path string, create bool) []reflect.Value { func rValuesAtPath(v interface{}, path string, create bool, caseSensitive bool) []reflect.Value {
pathparts := strings.Split(path, "||") pathparts := strings.Split(path, "||")
if len(pathparts) > 1 { if len(pathparts) > 1 {
for _, pathpart := range pathparts { for _, pathpart := range pathparts {
vals := rValuesAtPath(v, pathpart, create) vals := rValuesAtPath(v, pathpart, create, caseSensitive)
if vals != nil && len(vals) > 0 { if vals != nil && len(vals) > 0 {
return vals return vals
} }
...@@ -31,7 +31,7 @@ func rValuesAtPath(v interface{}, path string, create bool) []reflect.Value { ...@@ -31,7 +31,7 @@ func rValuesAtPath(v interface{}, path string, create bool) []reflect.Value {
c := strings.TrimSpace(components[0]) c := strings.TrimSpace(components[0])
if c == "" { // no actual component, illegal syntax if c == "" { // no actual component, illegal syntax
return nil return nil
} else if c != "*" && strings.ToLower(c[0:1]) == c[0:1] { } else if caseSensitive && c != "*" && strings.ToLower(c[0:1]) == c[0:1] {
// TODO normalize case for user // TODO normalize case for user
return nil // don't support unexported fields return nil // don't support unexported fields
} }
...@@ -65,7 +65,15 @@ func rValuesAtPath(v interface{}, path string, create bool) []reflect.Value { ...@@ -65,7 +65,15 @@ func rValuesAtPath(v interface{}, path string, create bool) []reflect.Value {
continue continue
} }
value = value.FieldByName(c) value = value.FieldByNameFunc(func(name string) bool {
if c == name {
return true
} else if !caseSensitive && strings.ToLower(name) == strings.ToLower(c) {
return true
}
return false
})
if create && value.Kind() == reflect.Ptr && value.IsNil() { if create && value.Kind() == reflect.Ptr && value.IsNil() {
value.Set(reflect.New(value.Type().Elem())) value.Set(reflect.New(value.Type().Elem()))
value = value.Elem() value = value.Elem()
...@@ -124,7 +132,20 @@ func rValuesAtPath(v interface{}, path string, create bool) []reflect.Value { ...@@ -124,7 +132,20 @@ func rValuesAtPath(v interface{}, path string, create bool) []reflect.Value {
// ValuesAtPath returns a list of objects at the lexical path inside of a structure // ValuesAtPath returns a list of objects at the lexical path inside of a structure
func ValuesAtPath(i interface{}, path string) []interface{} { func ValuesAtPath(i interface{}, path string) []interface{} {
if rvals := rValuesAtPath(i, path, false); rvals != nil { if rvals := rValuesAtPath(i, path, false, true); rvals != nil {
vals := make([]interface{}, len(rvals))
for i, rval := range rvals {
vals[i] = rval.Interface()
}
return vals
}
return nil
}
// ValuesAtAnyPath returns a list of objects at the case-insensitive lexical
// path inside of a structure
func ValuesAtAnyPath(i interface{}, path string) []interface{} {
if rvals := rValuesAtPath(i, path, false, false); rvals != nil {
vals := make([]interface{}, len(rvals)) vals := make([]interface{}, len(rvals))
for i, rval := range rvals { for i, rval := range rvals {
vals[i] = rval.Interface() vals[i] = rval.Interface()
...@@ -136,7 +157,17 @@ func ValuesAtPath(i interface{}, path string) []interface{} { ...@@ -136,7 +157,17 @@ func ValuesAtPath(i interface{}, path string) []interface{} {
// SetValueAtPath sets an object at the lexical path inside of a structure // SetValueAtPath sets an object at the lexical path inside of a structure
func SetValueAtPath(i interface{}, path string, v interface{}) { func SetValueAtPath(i interface{}, path string, v interface{}) {
if rvals := rValuesAtPath(i, path, true); rvals != nil { if rvals := rValuesAtPath(i, path, true, true); rvals != nil {
for _, rval := range rvals {
rval.Set(reflect.ValueOf(v))
}
}
}
// SetValueAtAnyPath sets an object at the case insensitive lexical path inside
// of a structure
func SetValueAtAnyPath(i interface{}, path string, v interface{}) {
if rvals := rValuesAtPath(i, path, true, false); rvals != nil {
for _, rval := range rvals { for _, rval := range rvals {
rval.Set(reflect.ValueOf(v)) rval.Set(reflect.ValueOf(v))
} }
......
...@@ -3,13 +3,13 @@ package awsutil_test ...@@ -3,13 +3,13 @@ package awsutil_test
import ( import (
"testing" "testing"
"github.com/awslabs/aws-sdk-go/aws/awsutil" "github.com/aws/aws-sdk-go/aws/awsutil"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
type Struct struct { type Struct struct {
A []Struct A []Struct
a []Struct z []Struct
B *Struct B *Struct
D *Struct D *Struct
C string C string
...@@ -17,7 +17,7 @@ type Struct struct { ...@@ -17,7 +17,7 @@ type Struct struct {
var data = Struct{ 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"}},
a: []Struct{Struct{C: "value1"}, Struct{C: "value2"}, Struct{C: "value3"}}, z: []Struct{Struct{C: "value1"}, Struct{C: "value2"}, Struct{C: "value3"}},
B: &Struct{B: &Struct{C: "terminal"}, D: &Struct{C: "terminal2"}}, B: &Struct{B: &Struct{C: "terminal"}, D: &Struct{C: "terminal2"}},
C: "initial", C: "initial",
} }
...@@ -27,6 +27,7 @@ func TestValueAtPathSuccess(t *testing.T) { ...@@ -27,6 +27,7 @@ func TestValueAtPathSuccess(t *testing.T) {
assert.Equal(t, []interface{}{"value1"}, awsutil.ValuesAtPath(data, "A[0].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{}{"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[2].C"))
assert.Equal(t, []interface{}{"value3"}, awsutil.ValuesAtAnyPath(data, "a[2].c"))
assert.Equal(t, []interface{}{"value3"}, awsutil.ValuesAtPath(data, "A[-1].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{}{"value1", "value2", "value3"}, awsutil.ValuesAtPath(data, "A[].C"))
assert.Equal(t, []interface{}{"terminal"}, awsutil.ValuesAtPath(data, "B . B . C")) assert.Equal(t, []interface{}{"terminal"}, awsutil.ValuesAtPath(data, "B . B . C"))
...@@ -41,7 +42,7 @@ func TestValueAtPathFailure(t *testing.T) { ...@@ -41,7 +42,7 @@ func TestValueAtPathFailure(t *testing.T) {
assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(data, "A[100].C")) 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, "A[3].C"))
assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(data, "B.B.C.Z")) 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{}(nil), awsutil.ValuesAtPath(data, "z[-1].C"))
assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(nil, "A.B.C")) assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(nil, "A.B.C"))
} }
...@@ -57,4 +58,8 @@ func TestSetValueAtPathSuccess(t *testing.T) { ...@@ -57,4 +58,8 @@ func TestSetValueAtPathSuccess(t *testing.T) {
awsutil.SetValueAtPath(&s, "B.*.C", "test0") awsutil.SetValueAtPath(&s, "B.*.C", "test0")
assert.Equal(t, "test0", s.B.B.C) assert.Equal(t, "test0", s.B.B.C)
assert.Equal(t, "test0", s.B.D.C) assert.Equal(t, "test0", s.B.D.C)
var s2 Struct
awsutil.SetValueAtAnyPath(&s2, "b.b.c", "test0")
assert.Equal(t, "test0", s2.B.B.C)
} }
...@@ -42,7 +42,7 @@ func stringValue(v reflect.Value, indent int, buf *bytes.Buffer) { ...@@ -42,7 +42,7 @@ func stringValue(v reflect.Value, indent int, buf *bytes.Buffer) {
if name[0:1] == strings.ToLower(name[0:1]) { if name[0:1] == strings.ToLower(name[0:1]) {
continue // ignore unexported fields continue // ignore unexported fields
} }
if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice) && f.IsNil() { if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice || f.Kind() == reflect.Map) && f.IsNil() {
continue // ignore unset fields continue // ignore unset fields
} }
names = append(names, name) names = append(names, name)
......
...@@ -4,8 +4,9 @@ import ( ...@@ -4,8 +4,9 @@ import (
"io" "io"
"net/http" "net/http"
"os" "os"
"time"
"github.com/awslabs/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials"
) )
// DefaultChainCredentials is a Credentials which will find the first available // DefaultChainCredentials is a Credentials which will find the first available
...@@ -17,7 +18,7 @@ var DefaultChainCredentials = credentials.NewChainCredentials( ...@@ -17,7 +18,7 @@ var DefaultChainCredentials = credentials.NewChainCredentials(
[]credentials.Provider{ []credentials.Provider{
&credentials.EnvProvider{}, &credentials.EnvProvider{},
&credentials.SharedCredentialsProvider{Filename: "", Profile: ""}, &credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
&credentials.EC2RoleProvider{}, &credentials.EC2RoleProvider{ExpiryWindow: 5 * time.Minute},
}) })
// The default number of retries for a service. The value of -1 indicates that // The default number of retries for a service. The value of -1 indicates that
...@@ -83,6 +84,10 @@ func (c Config) Copy() Config { ...@@ -83,6 +84,10 @@ func (c Config) Copy() Config {
// example bool attributes cannot be cleared using Merge, and must be explicitly // example bool attributes cannot be cleared using Merge, and must be explicitly
// set on the Config structure. // set on the Config structure.
func (c Config) Merge(newcfg *Config) *Config { func (c Config) Merge(newcfg *Config) *Config {
if newcfg == nil {
return &c
}
cfg := Config{} cfg := Config{}
if newcfg != nil && newcfg.Credentials != nil { if newcfg != nil && newcfg.Credentials != nil {
......
package credentials package credentials
import ( import (
"fmt" "github.com/aws/aws-sdk-go/internal/apierr"
) )
var ( var (
// ErrNoValidProvidersFoundInChain Is returned when there are no valid // ErrNoValidProvidersFoundInChain Is returned when there are no valid
// providers in the ChainProvider. // providers in the ChainProvider.
ErrNoValidProvidersFoundInChain = fmt.Errorf("no valid providers in chain") ErrNoValidProvidersFoundInChain = apierr.New("NoCredentialProviders", "no valid providers in chain", nil)
) )
// A ChainProvider will search for a provider which returns credentials // A ChainProvider will search for a provider which returns credentials
......
package credentials package credentials
import ( import (
"errors"
"github.com/stretchr/testify/assert"
"testing" "testing"
"github.com/aws/aws-sdk-go/internal/apierr"
"github.com/stretchr/testify/assert"
) )
func TestChainProviderGet(t *testing.T) { func TestChainProviderGet(t *testing.T) {
p := &ChainProvider{ p := &ChainProvider{
Providers: []Provider{ Providers: []Provider{
&stubProvider{err: errors.New("first provider error")}, &stubProvider{err: apierr.New("FirstError", "first provider error", nil)},
&stubProvider{err: errors.New("second provider error")}, &stubProvider{err: apierr.New("SecondError", "second provider error", nil)},
&stubProvider{ &stubProvider{
creds: Value{ creds: Value{
AccessKeyID: "AKID", AccessKeyID: "AKID",
...@@ -61,12 +62,12 @@ func TestChainProviderWithNoProvider(t *testing.T) { ...@@ -61,12 +62,12 @@ func TestChainProviderWithNoProvider(t *testing.T) {
func TestChainProviderWithNoValidProvider(t *testing.T) { func TestChainProviderWithNoValidProvider(t *testing.T) {
p := &ChainProvider{ p := &ChainProvider{
Providers: []Provider{ Providers: []Provider{
&stubProvider{err: errors.New("first provider error")}, &stubProvider{err: apierr.New("FirstError", "first provider error", nil)},
&stubProvider{err: errors.New("second provider error")}, &stubProvider{err: apierr.New("SecondError", "second provider error", nil)},
}, },
} }
assert.True(t, p.IsExpired(), "Expect expired with no providers") assert.True(t, p.IsExpired(), "Expect expired with no providers")
_, err := p.Retrieve() _, err := p.Retrieve()
assert.Contains(t, "no valid providers in chain", err.Error(), "Expect no providers error returned") assert.Equal(t, ErrNoValidProvidersFoundInChain, err, "Expect no providers error returned")
} }
package credentials package credentials
import ( import (
"errors"
"github.com/stretchr/testify/assert"
"testing" "testing"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/internal/apierr"
"github.com/stretchr/testify/assert"
) )
type stubProvider struct { type stubProvider struct {
...@@ -38,10 +40,10 @@ func TestCredentialsGet(t *testing.T) { ...@@ -38,10 +40,10 @@ func TestCredentialsGet(t *testing.T) {
} }
func TestCredentialsGetWithError(t *testing.T) { func TestCredentialsGetWithError(t *testing.T) {
c := NewCredentials(&stubProvider{err: errors.New("provider error"), expired: true}) c := NewCredentials(&stubProvider{err: apierr.New("provider error", "", nil), expired: true})
_, err := c.Get() _, err := c.Get()
assert.Equal(t, "provider error", err.Error(), "Expected provider error") assert.Equal(t, "provider error", err.(awserr.Error).Code(), "Expected provider error")
} }
func TestCredentialsExpire(t *testing.T) { func TestCredentialsExpire(t *testing.T) {
......
...@@ -6,6 +6,8 @@ import ( ...@@ -6,6 +6,8 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"time" "time"
"github.com/aws/aws-sdk-go/internal/apierr"
) )
const metadataCredentialsEndpoint = "http://169.254.169.254/latest/meta-data/iam/security-credentials/" const metadataCredentialsEndpoint = "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
...@@ -89,7 +91,7 @@ func (m *EC2RoleProvider) Retrieve() (Value, error) { ...@@ -89,7 +91,7 @@ func (m *EC2RoleProvider) Retrieve() (Value, error) {
} }
if len(credsList) == 0 { if len(credsList) == 0 {
return Value{}, fmt.Errorf("empty MetadataService credentials list") return Value{}, apierr.New("EmptyEC2RoleList", "empty EC2 Role list", nil)
} }
credsName := credsList[0] credsName := credsList[0]
...@@ -130,7 +132,7 @@ type ec2RoleCredRespBody struct { ...@@ -130,7 +132,7 @@ type ec2RoleCredRespBody struct {
func requestCredList(client *http.Client, endpoint string) ([]string, error) { func requestCredList(client *http.Client, endpoint string) ([]string, error) {
resp, err := client.Get(endpoint) resp, err := client.Get(endpoint)
if err != nil { if err != nil {
return nil, fmt.Errorf("%s listing MetadataService credentials", err) return nil, apierr.New("ListEC2Role", "failed to list EC2 Roles", err)
} }
defer resp.Body.Close() defer resp.Body.Close()
...@@ -141,7 +143,7 @@ func requestCredList(client *http.Client, endpoint string) ([]string, error) { ...@@ -141,7 +143,7 @@ func requestCredList(client *http.Client, endpoint string) ([]string, error) {
} }
if err := s.Err(); err != nil { if err := s.Err(); err != nil {
return nil, fmt.Errorf("%s reading list of MetadataService credentials", err) return nil, apierr.New("ReadEC2Role", "failed to read list of EC2 Roles", err)
} }
return credsList, nil return credsList, nil
...@@ -154,13 +156,17 @@ func requestCredList(client *http.Client, endpoint string) ([]string, error) { ...@@ -154,13 +156,17 @@ func requestCredList(client *http.Client, endpoint string) ([]string, error) {
func requestCred(client *http.Client, endpoint, credsName string) (*ec2RoleCredRespBody, error) { func requestCred(client *http.Client, endpoint, credsName string) (*ec2RoleCredRespBody, error) {
resp, err := client.Get(endpoint + credsName) resp, err := client.Get(endpoint + credsName)
if err != nil { if err != nil {
return nil, fmt.Errorf("getting %s MetadataService credentials", credsName) return nil, apierr.New("GetEC2RoleCredentials",
fmt.Sprintf("failed to get %s EC2 Role credentials", credsName),
err)
} }
defer resp.Body.Close() defer resp.Body.Close()
respCreds := &ec2RoleCredRespBody{} respCreds := &ec2RoleCredRespBody{}
if err := json.NewDecoder(resp.Body).Decode(respCreds); err != nil { if err := json.NewDecoder(resp.Body).Decode(respCreds); err != nil {
return nil, fmt.Errorf("decoding %s MetadataService credentials", credsName) return nil, apierr.New("DecodeEC2RoleCredentials",
fmt.Sprintf("failed to decode %s EC2 Role credentials", credsName),
err)
} }
return respCreds, nil return respCreds, nil
......
package credentials package credentials
import ( import (
"fmt"
"os" "os"
"github.com/aws/aws-sdk-go/internal/apierr"
) )
var ( var (
// ErrAccessKeyIDNotFound is returned when the AWS Access Key ID can't be // ErrAccessKeyIDNotFound is returned when the AWS Access Key ID can't be
// found in the process's environment. // found in the process's environment.
ErrAccessKeyIDNotFound = fmt.Errorf("AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY not found in environment") ErrAccessKeyIDNotFound = apierr.New("EnvAccessKeyNotFound", "AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY not found in environment", nil)
// ErrSecretAccessKeyNotFound is returned when the AWS Secret Access Key // ErrSecretAccessKeyNotFound is returned when the AWS Secret Access Key
// can't be found in the process's environment. // can't be found in the process's environment.
ErrSecretAccessKeyNotFound = fmt.Errorf("AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY not found in environment") ErrSecretAccessKeyNotFound = apierr.New("EnvSecretNotFound", "AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY not found in environment", nil)
) )
// A EnvProvider retrieves credentials from the environment variables of the // A EnvProvider retrieves credentials from the environment variables of the
......
...@@ -14,7 +14,7 @@ func TestEnvProviderRetrieve(t *testing.T) { ...@@ -14,7 +14,7 @@ func TestEnvProviderRetrieve(t *testing.T) {
e := EnvProvider{} e := EnvProvider{}
creds, err := e.Retrieve() creds, err := e.Retrieve()
assert.Nil(t, err, "Expect no error", err) assert.Nil(t, err, "Expect no error")
assert.Equal(t, "access", creds.AccessKeyID, "Expect access key ID to match") assert.Equal(t, "access", creds.AccessKeyID, "Expect access key ID to match")
assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match") assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match")
...@@ -32,7 +32,7 @@ func TestEnvProviderIsExpired(t *testing.T) { ...@@ -32,7 +32,7 @@ func TestEnvProviderIsExpired(t *testing.T) {
assert.True(t, e.IsExpired(), "Expect creds to be expired before retrieve.") assert.True(t, e.IsExpired(), "Expect creds to be expired before retrieve.")
_, err := e.Retrieve() _, err := e.Retrieve()
assert.Nil(t, err, "Expect no error", err) assert.Nil(t, err, "Expect no error")
assert.False(t, e.IsExpired(), "Expect creds to not be expired after retrieve.") assert.False(t, e.IsExpired(), "Expect creds to not be expired after retrieve.")
} }
......
...@@ -6,11 +6,13 @@ import ( ...@@ -6,11 +6,13 @@ import (
"path/filepath" "path/filepath"
"github.com/vaughan0/go-ini" "github.com/vaughan0/go-ini"
"github.com/aws/aws-sdk-go/internal/apierr"
) )
var ( var (
// ErrSharedCredentialsHomeNotFound is emitted when the user directory cannot be found. // ErrSharedCredentialsHomeNotFound is emitted when the user directory cannot be found.
ErrSharedCredentialsHomeNotFound = fmt.Errorf("User home directory not found.") ErrSharedCredentialsHomeNotFound = apierr.New("UserHomeNotFound", "user home directory not found.", nil)
) )
// A SharedCredentialsProvider retrieves credentials from the current user's home // A SharedCredentialsProvider retrieves credentials from the current user's home
...@@ -70,18 +72,22 @@ func (p *SharedCredentialsProvider) IsExpired() bool { ...@@ -70,18 +72,22 @@ func (p *SharedCredentialsProvider) IsExpired() bool {
func loadProfile(filename, profile string) (Value, error) { func loadProfile(filename, profile string) (Value, error) {
config, err := ini.LoadFile(filename) config, err := ini.LoadFile(filename)
if err != nil { if err != nil {
return Value{}, err return Value{}, apierr.New("SharedCredsLoad", "failed to load shared credentials file", err)
} }
iniProfile := config.Section(profile) iniProfile := config.Section(profile)
id, ok := iniProfile["aws_access_key_id"] id, ok := iniProfile["aws_access_key_id"]
if !ok { if !ok {
return Value{}, fmt.Errorf("shared credentials %s in %s did not contain aws_access_key_id", profile, filename) return Value{}, apierr.New("SharedCredsAccessKey",
fmt.Sprintf("shared credentials %s in %s did not contain aws_access_key_id", profile, filename),
nil)
} }
secret, ok := iniProfile["aws_secret_access_key"] secret, ok := iniProfile["aws_secret_access_key"]
if !ok { if !ok {
return Value{}, fmt.Errorf("shared credentials %s in %s did not contain aws_secret_access_key", profile, filename) return Value{}, apierr.New("SharedCredsSecret",
fmt.Sprintf("shared credentials %s in %s did not contain aws_secret_access_key", profile, filename),
nil)
} }
token := iniProfile["aws_session_token"] token := iniProfile["aws_session_token"]
......
package credentials package credentials
import ( import (
"fmt" "github.com/aws/aws-sdk-go/internal/apierr"
) )
var ( var (
// ErrStaticCredentialsEmpty is emitted when static credentials are empty. // ErrStaticCredentialsEmpty is emitted when static credentials are empty.
ErrStaticCredentialsEmpty = fmt.Errorf("static credentials are empty") ErrStaticCredentialsEmpty = apierr.New("EmptyStaticCreds", "static credentials are empty", nil)
) )
// A StaticProvider is a set of credentials which are set pragmatically, // A StaticProvider is a set of credentials which are set pragmatically,
......
...@@ -10,6 +10,9 @@ import ( ...@@ -10,6 +10,9 @@ import (
"regexp" "regexp"
"strconv" "strconv"
"time" "time"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/internal/apierr"
) )
var sleepDelay = func(delay time.Duration) { var sleepDelay = func(delay time.Duration) {
...@@ -59,19 +62,27 @@ var reStatusCode = regexp.MustCompile(`^(\d+)`) ...@@ -59,19 +62,27 @@ var reStatusCode = regexp.MustCompile(`^(\d+)`)
// SendHandler is a request handler to send service request using HTTP client. // SendHandler is a request handler to send service request using HTTP client.
func SendHandler(r *Request) { func SendHandler(r *Request) {
r.HTTPResponse, r.Error = r.Service.Config.HTTPClient.Do(r.HTTPRequest) var err error
if r.Error != nil { r.HTTPResponse, err = r.Service.Config.HTTPClient.Do(r.HTTPRequest)
if e, ok := r.Error.(*url.Error); ok { if err != nil {
if s := reStatusCode.FindStringSubmatch(e.Err.Error()); s != nil { // Capture the case where url.Error is returned for error processing
// 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 {
code, _ := strconv.ParseInt(s[1], 10, 64) code, _ := strconv.ParseInt(s[1], 10, 64)
r.Error = nil
r.HTTPResponse = &http.Response{ r.HTTPResponse = &http.Response{
StatusCode: int(code), StatusCode: int(code),
Status: http.StatusText(int(code)), Status: http.StatusText(int(code)),
Body: ioutil.NopCloser(bytes.NewReader([]byte{})), Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
} }
return
} }
} }
// Catch all other request errors.
r.Error = apierr.New("RequestError", "send request failed", err)
r.Retryable.Set(true) // network errors are retryable
} }
} }
...@@ -79,11 +90,7 @@ func SendHandler(r *Request) { ...@@ -79,11 +90,7 @@ func SendHandler(r *Request) {
func ValidateResponseHandler(r *Request) { func ValidateResponseHandler(r *Request) {
if r.HTTPResponse.StatusCode == 0 || r.HTTPResponse.StatusCode >= 300 { if r.HTTPResponse.StatusCode == 0 || r.HTTPResponse.StatusCode >= 300 {
// this may be replaced by an UnmarshalError handler // this may be replaced by an UnmarshalError handler
r.Error = &APIError{ r.Error = apierr.New("UnknownError", "unknown error", nil)
StatusCode: r.HTTPResponse.StatusCode,
Code: "UnknownError",
Message: "unknown error",
}
} }
} }
...@@ -103,10 +110,14 @@ func AfterRetryHandler(r *Request) { ...@@ -103,10 +110,14 @@ func AfterRetryHandler(r *Request) {
// when the expired token exception occurs the credentials // when the expired token exception occurs the credentials
// need to be expired locally so that the next request to // need to be expired locally so that the next request to
// get credentials will trigger a credentials refresh. // get credentials will trigger a credentials refresh.
if err := Error(r.Error); err != nil && err.Code == "ExpiredTokenException" { if r.Error != nil {
r.Config.Credentials.Expire() if err, ok := r.Error.(awserr.Error); ok {
// The credentials will need to be resigned with new credentials if isCodeExpiredCreds(err.Code()) {
r.signed = false r.Config.Credentials.Expire()
// The credentials will need to be resigned with new credentials
r.signed = false
}
}
} }
r.RetryCount++ r.RetryCount++
...@@ -117,11 +128,11 @@ func AfterRetryHandler(r *Request) { ...@@ -117,11 +128,11 @@ func AfterRetryHandler(r *Request) {
var ( var (
// ErrMissingRegion is an error that is returned if region configuration is // ErrMissingRegion is an error that is returned if region configuration is
// not found. // not found.
ErrMissingRegion = fmt.Errorf("could not find region configuration") ErrMissingRegion error = apierr.New("MissingRegion", "could not find region configuration", nil)
// ErrMissingEndpoint is an error that is returned if an endpoint cannot be // ErrMissingEndpoint is an error that is returned if an endpoint cannot be
// resolved for a service. // resolved for a service.
ErrMissingEndpoint = fmt.Errorf("`Endpoint' configuration is required for this service") ErrMissingEndpoint error = apierr.New("MissingEndpoint", "'Endpoint' configuration is required for this service", nil)
) )
// ValidateEndpointHandler is a request handler to validate a request had the // ValidateEndpointHandler is a request handler to validate a request had the
......
...@@ -5,7 +5,8 @@ import ( ...@@ -5,7 +5,8 @@ import (
"os" "os"
"testing" "testing"
"github.com/awslabs/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/internal/apierr"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
...@@ -55,11 +56,11 @@ func TestAfterRetryRefreshCreds(t *testing.T) { ...@@ -55,11 +56,11 @@ func TestAfterRetryRefreshCreds(t *testing.T) {
svc.Handlers.Clear() svc.Handlers.Clear()
svc.Handlers.ValidateResponse.PushBack(func(r *Request) { svc.Handlers.ValidateResponse.PushBack(func(r *Request) {
r.Error = &APIError{Code: "UnknownError"} r.Error = apierr.New("UnknownError", "", nil)
r.HTTPResponse = &http.Response{StatusCode: 400} r.HTTPResponse = &http.Response{StatusCode: 400}
}) })
svc.Handlers.UnmarshalError.PushBack(func(r *Request) { svc.Handlers.UnmarshalError.PushBack(func(r *Request) {
r.Error = &APIError{Code: "ExpiredTokenException"} r.Error = apierr.New("ExpiredTokenException", "", nil)
}) })
svc.Handlers.AfterRetry.PushBack(func(r *Request) { svc.Handlers.AfterRetry.PushBack(func(r *Request) {
AfterRetryHandler(r) AfterRetryHandler(r)
......
...@@ -4,6 +4,8 @@ import ( ...@@ -4,6 +4,8 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"strings" "strings"
"github.com/aws/aws-sdk-go/internal/apierr"
) )
// ValidateParameters is a request handler to validate the input parameters. // ValidateParameters is a request handler to validate the input parameters.
...@@ -16,7 +18,7 @@ func ValidateParameters(r *Request) { ...@@ -16,7 +18,7 @@ func ValidateParameters(r *Request) {
if count := len(v.errors); count > 0 { if count := len(v.errors); count > 0 {
format := "%d validation errors:\n- %s" format := "%d validation errors:\n- %s"
msg := fmt.Sprintf(format, count, strings.Join(v.errors, "\n- ")) msg := fmt.Sprintf(format, count, strings.Join(v.errors, "\n- "))
r.Error = APIError{Code: "InvalidParameter", Message: msg} r.Error = apierr.New("InvalidParameter", msg, nil)
} }
} }
} }
...@@ -66,7 +68,7 @@ func (v *validator) validateStruct(value reflect.Value, path string) { ...@@ -66,7 +68,7 @@ func (v *validator) validateStruct(value reflect.Value, path string) {
notset := false notset := false
if f.Tag.Get("required") != "" { if f.Tag.Get("required") != "" {
switch fvalue.Kind() { switch fvalue.Kind() {
case reflect.Ptr, reflect.Slice: case reflect.Ptr, reflect.Slice, reflect.Map:
if fvalue.IsNil() { if fvalue.IsNil() {
notset = true notset = true
} }
......
...@@ -3,7 +3,8 @@ package aws_test ...@@ -3,7 +3,8 @@ package aws_test
import ( import (
"testing" "testing"
"github.com/awslabs/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
...@@ -17,9 +18,9 @@ var service = func() *aws.Service { ...@@ -17,9 +18,9 @@ var service = func() *aws.Service {
}() }()
type StructShape struct { type StructShape struct {
RequiredList []*ConditionalStructShape `required:"true"` RequiredList []*ConditionalStructShape `required:"true"`
RequiredMap *map[string]*ConditionalStructShape `required:"true"` RequiredMap map[string]*ConditionalStructShape `required:"true"`
RequiredBool *bool `required:"true"` RequiredBool *bool `required:"true"`
OptionalStruct *ConditionalStructShape OptionalStruct *ConditionalStructShape
hiddenParameter *string hiddenParameter *string
...@@ -39,7 +40,7 @@ type ConditionalStructShape struct { ...@@ -39,7 +40,7 @@ type ConditionalStructShape struct {
func TestNoErrors(t *testing.T) { func TestNoErrors(t *testing.T) {
input := &StructShape{ input := &StructShape{
RequiredList: []*ConditionalStructShape{}, RequiredList: []*ConditionalStructShape{},
RequiredMap: &map[string]*ConditionalStructShape{ RequiredMap: map[string]*ConditionalStructShape{
"key1": &ConditionalStructShape{Name: aws.String("Name")}, "key1": &ConditionalStructShape{Name: aws.String("Name")},
"key2": &ConditionalStructShape{Name: aws.String("Name")}, "key2": &ConditionalStructShape{Name: aws.String("Name")},
}, },
...@@ -56,17 +57,16 @@ func TestMissingRequiredParameters(t *testing.T) { ...@@ -56,17 +57,16 @@ func TestMissingRequiredParameters(t *testing.T) {
input := &StructShape{} input := &StructShape{}
req := aws.NewRequest(service, &aws.Operation{}, input, nil) req := aws.NewRequest(service, &aws.Operation{}, input, nil)
aws.ValidateParameters(req) aws.ValidateParameters(req)
err := aws.Error(req.Error)
assert.Error(t, err) assert.Error(t, req.Error)
assert.Equal(t, "InvalidParameter", err.Code) assert.Equal(t, "InvalidParameter", req.Error.(awserr.Error).Code())
assert.Equal(t, "3 validation errors:\n- missing required parameter: RequiredList\n- missing required parameter: RequiredMap\n- missing required parameter: RequiredBool", err.Message) assert.Equal(t, "3 validation errors:\n- missing required parameter: RequiredList\n- missing required parameter: RequiredMap\n- missing required parameter: RequiredBool", req.Error.(awserr.Error).Message())
} }
func TestNestedMissingRequiredParameters(t *testing.T) { func TestNestedMissingRequiredParameters(t *testing.T) {
input := &StructShape{ input := &StructShape{
RequiredList: []*ConditionalStructShape{&ConditionalStructShape{}}, RequiredList: []*ConditionalStructShape{&ConditionalStructShape{}},
RequiredMap: &map[string]*ConditionalStructShape{ RequiredMap: map[string]*ConditionalStructShape{
"key1": &ConditionalStructShape{Name: aws.String("Name")}, "key1": &ConditionalStructShape{Name: aws.String("Name")},
"key2": &ConditionalStructShape{}, "key2": &ConditionalStructShape{},
}, },
...@@ -76,10 +76,9 @@ func TestNestedMissingRequiredParameters(t *testing.T) { ...@@ -76,10 +76,9 @@ func TestNestedMissingRequiredParameters(t *testing.T) {
req := aws.NewRequest(service, &aws.Operation{}, input, nil) req := aws.NewRequest(service, &aws.Operation{}, input, nil)
aws.ValidateParameters(req) aws.ValidateParameters(req)
err := aws.Error(req.Error)
assert.Error(t, err) assert.Error(t, req.Error)
assert.Equal(t, "InvalidParameter", err.Code) assert.Equal(t, "InvalidParameter", req.Error.(awserr.Error).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) 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", req.Error.(awserr.Error).Message())
} }
...@@ -9,6 +9,8 @@ import ( ...@@ -9,6 +9,8 @@ import (
"reflect" "reflect"
"strings" "strings"
"time" "time"
"github.com/aws/aws-sdk-go/aws/awsutil"
) )
// A Request is the service request to be made. // A Request is the service request to be made.
...@@ -39,6 +41,15 @@ type Operation struct { ...@@ -39,6 +41,15 @@ type Operation struct {
Name string Name string
HTTPMethod string HTTPMethod string
HTTPPath string HTTPPath string
*Paginator
}
// Paginator keeps track of pagination configuration for an API operation.
type Paginator struct {
InputTokens []string
OutputTokens []string
LimitToken string
TruncationToken string
} }
// NewRequest returns a new Request pointer for the service API // NewRequest returns a new Request pointer for the service API
...@@ -187,7 +198,12 @@ func (r *Request) Send() error { ...@@ -187,7 +198,12 @@ func (r *Request) Send() error {
r.Handlers.Send.Run(r) r.Handlers.Send.Run(r)
if r.Error != nil { if r.Error != nil {
return r.Error r.Handlers.Retry.Run(r)
r.Handlers.AfterRetry.Run(r)
if r.Error != nil {
return r.Error
}
continue
} }
r.Handlers.UnmarshalMeta.Run(r) r.Handlers.UnmarshalMeta.Run(r)
...@@ -217,3 +233,86 @@ func (r *Request) Send() error { ...@@ -217,3 +233,86 @@ func (r *Request) Send() error {
return nil return nil
} }
// HasNextPage returns true if this request has more pages of data available.
func (r *Request) HasNextPage() bool {
return r.nextPageTokens() != nil
}
// nextPageTokens returns the tokens to use when asking for the next page of
// data.
func (r *Request) nextPageTokens() []interface{} {
if r.Operation.Paginator == nil {
return nil
}
if r.Operation.TruncationToken != "" {
tr := awsutil.ValuesAtAnyPath(r.Data, r.Operation.TruncationToken)
if tr == nil || len(tr) == 0 {
return nil
}
switch v := tr[0].(type) {
case bool:
if v == false {
return nil
}
}
}
found := false
tokens := make([]interface{}, len(r.Operation.OutputTokens))
for i, outtok := range r.Operation.OutputTokens {
v := awsutil.ValuesAtAnyPath(r.Data, outtok)
if v != nil && len(v) > 0 {
found = true
tokens[i] = v[0]
}
}
if found {
return tokens
}
return nil
}
// NextPage returns a new Request that can be executed to return the next
// page of result data. Call .Send() on this request to execute it.
func (r *Request) NextPage() *Request {
tokens := r.nextPageTokens()
if tokens == nil {
return nil
}
data := reflect.New(reflect.TypeOf(r.Data).Elem()).Interface()
nr := NewRequest(r.Service, r.Operation, awsutil.CopyOf(r.Params), data)
for i, intok := range nr.Operation.InputTokens {
awsutil.SetValueAtAnyPath(nr.Params, intok, tokens[i])
}
return nr
}
// EachPage iterates over each page of a paginated request object. The fn
// parameter should be a function with the following sample signature:
//
// func(page *T, lastPage bool) bool {
// return true // return false to stop iterating
// }
//
// Where "T" is the structure type matching the output structure of the given
// operation. For example, a request object generated by
// DynamoDB.ListTablesRequest() would expect to see dynamodb.ListTablesOutput
// as the structure "T". The lastPage value represents whether the page is
// the last page of data or not. The return value of this function should
// return true to keep iterating or false to stop.
func (r *Request) EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error {
for page := r; page != nil; page = page.NextPage() {
page.Send()
shouldContinue := fn(page.Data, !page.HasNextPage())
if page.Error != nil || !shouldContinue {
return page.Error
}
}
return nil
}
...@@ -3,6 +3,7 @@ package aws ...@@ -3,6 +3,7 @@ package aws
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
...@@ -10,7 +11,9 @@ import ( ...@@ -10,7 +11,9 @@ import (
"testing" "testing"
"time" "time"
"github.com/awslabs/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/internal/apierr"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
...@@ -33,26 +36,27 @@ func unmarshal(req *Request) { ...@@ -33,26 +36,27 @@ func unmarshal(req *Request) {
func unmarshalError(req *Request) { func unmarshalError(req *Request) {
bodyBytes, err := ioutil.ReadAll(req.HTTPResponse.Body) bodyBytes, err := ioutil.ReadAll(req.HTTPResponse.Body)
if err != nil { if err != nil {
req.Error = err req.Error = apierr.New("UnmarshaleError", req.HTTPResponse.Status, err)
return return
} }
if len(bodyBytes) == 0 { if len(bodyBytes) == 0 {
req.Error = APIError{ req.Error = apierr.NewRequestError(
StatusCode: req.HTTPResponse.StatusCode, apierr.New("UnmarshaleError", req.HTTPResponse.Status, fmt.Errorf("empty body")),
Message: req.HTTPResponse.Status, req.HTTPResponse.StatusCode,
} "",
)
return return
} }
var jsonErr jsonErrorResponse var jsonErr jsonErrorResponse
if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil { if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil {
req.Error = err req.Error = apierr.New("UnmarshaleError", "JSON unmarshal", err)
return return
} }
req.Error = APIError{ req.Error = apierr.NewRequestError(
StatusCode: req.HTTPResponse.StatusCode, apierr.New(jsonErr.Code, jsonErr.Message, nil),
Code: jsonErr.Code, req.HTTPResponse.StatusCode,
Message: jsonErr.Message, "",
} )
} }
type jsonErrorResponse struct { type jsonErrorResponse struct {
...@@ -125,12 +129,14 @@ func TestRequest4xxUnretryable(t *testing.T) { ...@@ -125,12 +129,14 @@ func TestRequest4xxUnretryable(t *testing.T) {
out := &testData{} out := &testData{}
r := NewRequest(s, &Operation{Name: "Operation"}, nil, out) r := NewRequest(s, &Operation{Name: "Operation"}, nil, out)
err := r.Send() err := r.Send()
apiErr := Error(err)
assert.NotNil(t, err) assert.NotNil(t, err)
assert.NotNil(t, apiErr) if e, ok := err.(awserr.RequestFailure); ok {
assert.Equal(t, 401, apiErr.StatusCode) assert.Equal(t, 401, e.StatusCode())
assert.Equal(t, "SignatureDoesNotMatch", apiErr.Code) } else {
assert.Equal(t, "Signature does not match.", apiErr.Message) assert.Fail(t, "Expected error to be a service failure")
}
assert.Equal(t, "SignatureDoesNotMatch", err.(awserr.Error).Code())
assert.Equal(t, "Signature does not match.", err.(awserr.Error).Message())
assert.Equal(t, 0, int(r.RetryCount)) assert.Equal(t, 0, int(r.RetryCount))
} }
...@@ -159,12 +165,14 @@ func TestRequestExhaustRetries(t *testing.T) { ...@@ -159,12 +165,14 @@ func TestRequestExhaustRetries(t *testing.T) {
}) })
r := NewRequest(s, &Operation{Name: "Operation"}, nil, nil) r := NewRequest(s, &Operation{Name: "Operation"}, nil, nil)
err := r.Send() err := r.Send()
apiErr := Error(err)
assert.NotNil(t, err) assert.NotNil(t, err)
assert.NotNil(t, apiErr) if e, ok := err.(awserr.RequestFailure); ok {
assert.Equal(t, 500, apiErr.StatusCode) assert.Equal(t, 500, e.StatusCode())
assert.Equal(t, "UnknownError", apiErr.Code) } else {
assert.Equal(t, "An error occurred.", apiErr.Message) assert.Fail(t, "Expected error to be a service failure")
}
assert.Equal(t, "UnknownError", err.(awserr.Error).Code())
assert.Equal(t, "An error occurred.", err.(awserr.Error).Message())
assert.Equal(t, 3, int(r.RetryCount)) assert.Equal(t, 3, int(r.RetryCount))
assert.True(t, reflect.DeepEqual([]time.Duration{30 * time.Millisecond, 60 * time.Millisecond, 120 * time.Millisecond}, delays)) assert.True(t, reflect.DeepEqual([]time.Duration{30 * time.Millisecond, 60 * time.Millisecond, 120 * time.Millisecond}, delays))
} }
...@@ -185,12 +193,6 @@ func TestRequestRecoverExpiredCreds(t *testing.T) { ...@@ -185,12 +193,6 @@ func TestRequestRecoverExpiredCreds(t *testing.T) {
credExpiredBeforeRetry := false credExpiredBeforeRetry := false
credExpiredAfterRetry := false credExpiredAfterRetry := false
s.Handlers.Retry.PushBack(func(r *Request) {
if err := Error(r.Error); err != nil && err.Code == "ExpiredTokenException" {
credExpiredBeforeRetry = r.Config.Credentials.IsExpired()
}
})
s.Handlers.AfterRetry.PushBack(func(r *Request) { s.Handlers.AfterRetry.PushBack(func(r *Request) {
credExpiredAfterRetry = r.Config.Credentials.IsExpired() credExpiredAfterRetry = r.Config.Credentials.IsExpired()
}) })
......
...@@ -8,7 +8,8 @@ import ( ...@@ -8,7 +8,8 @@ import (
"regexp" "regexp"
"time" "time"
"github.com/awslabs/aws-sdk-go/internal/endpoints" "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 // A Service implements the base service request and response handling
...@@ -132,22 +133,44 @@ func retryRules(r *Request) time.Duration { ...@@ -132,22 +133,44 @@ func retryRules(r *Request) time.Duration {
return delay * time.Millisecond return delay * time.Millisecond
} }
// Collection of service response codes which are generically // retryableCodes is a collection of service response codes which are retry-able
// retryable for all services. // without any further action.
var retryableCodes = map[string]struct{}{ var retryableCodes = map[string]struct{}{
"ExpiredTokenException": struct{}{}, "RequestError": struct{}{},
"ProvisionedThroughputExceededException": struct{}{}, "ProvisionedThroughputExceededException": struct{}{},
"Throttling": struct{}{}, "Throttling": struct{}{},
} }
// 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": struct{}{},
"ExpiredTokenException": struct{}{},
"RequestExpired": struct{}{}, // 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. // shouldRetry returns if the request should be retried.
func shouldRetry(r *Request) bool { func shouldRetry(r *Request) bool {
if r.HTTPResponse.StatusCode >= 500 { if r.HTTPResponse.StatusCode >= 500 {
return true return true
} }
if err := Error(r.Error); err != nil { if r.Error != nil {
if _, ok := retryableCodes[err.Code]; ok { if err, ok := r.Error.(awserr.Error); ok {
return true return isCodeRetryable(err.Code())
} }
} }
return false return false
......
...@@ -5,4 +5,4 @@ package aws ...@@ -5,4 +5,4 @@ package aws
const SDKName = "aws-sdk-go" const SDKName = "aws-sdk-go"
// SDKVersion is the version of this SDK // SDKVersion is the version of this SDK
const SDKVersion = "0.5.0" const SDKVersion = "0.6.0"
// Package apierr represents API error types.
package apierr
import "fmt"
// A BaseError wraps the code and message which defines an error. It also
// can be used to wrap an original error object.
//
// Should be used as the root for errors satisfying the awserr.Error. Also
// for any error which does not fit into a specific error wrapper type.
type BaseError struct {
// Classification of error
code string
// Detailed information about error
message string
// Optional original error this error is based off of. Allows building
// chained errors.
origErr error
}
// New returns an error object for the code, message, and err.
//
// code is a short no whitespace phrase depicting the classification of
// the error that is being created.
//
// message is the free flow string containing detailed information about the error.
//
// origErr is the error object which will be nested under the new error to be returned.
func New(code, message string, origErr error) *BaseError {
return &BaseError{
code: code,
message: message,
origErr: origErr,
}
}
// Error returns the string representation of the error.
//
// See ErrorWithExtra for formatting.
//
// Satisfies the error interface.
func (b *BaseError) Error() string {
return b.ErrorWithExtra("")
}
// String returns the string representation of the error.
// Alias for Error to satisfy the stringer interface.
func (b *BaseError) String() string {
return b.Error()
}
// Code returns the short phrase depicting the classification of the error.
func (b *BaseError) Code() string {
return b.code
}
// Message returns the error details message.
func (b *BaseError) Message() string {
return b.message
}
// OrigErr returns the original error if one was set. Nil is returned if no error
// was set.
func (b *BaseError) OrigErr() error {
return b.origErr
}
// ErrorWithExtra is a helper method to add an extra string to the stratified
// error message. The extra message will be added on the next line below the
// error message like the following:
//
// <error code>: <error message>
// <extra message>
//
// If there is a original error the error will be included on a new line.
//
// <error code>: <error message>
// <extra message>
// caused by: <original error>
func (b *BaseError) ErrorWithExtra(extra string) string {
msg := fmt.Sprintf("%s: %s", b.code, b.message)
if extra != "" {
msg = fmt.Sprintf("%s\n\t%s", msg, extra)
}
if b.origErr != nil {
msg = fmt.Sprintf("%s\ncaused by: %s", msg, b.origErr.Error())
}
return msg
}
// A RequestError wraps a request or service error.
//
// Composed of BaseError for code, message, and original error.
type RequestError struct {
*BaseError
statusCode int
requestID string
}
// NewRequestError returns a wrapped error with additional information for request
// status code, and service requestID.
//
// Should be used to wrap all request which involve service requests. Even if
// the request failed without a service response, but had an HTTP status code
// that may be meaningful.
//
// Also wraps original errors via the BaseError.
func NewRequestError(base *BaseError, statusCode int, requestID string) *RequestError {
return &RequestError{
BaseError: base,
statusCode: statusCode,
requestID: requestID,
}
}
// Error returns the string representation of the error.
// Satisfies the error interface.
func (r *RequestError) Error() string {
return r.ErrorWithExtra(fmt.Sprintf("status code: %d, request id: [%s]",
r.statusCode, r.requestID))
}
// String returns the string representation of the error.
// Alias for Error to satisfy the stringer interface.
func (r *RequestError) String() string {
return r.Error()
}
// StatusCode returns the wrapped status code for the error
func (r *RequestError) StatusCode() int {
return r.statusCode
}
// RequestID returns the wrapped requestID
func (r *RequestError) RequestID() string {
return r.requestID
}
// Package endpoints validates regional endpoints for services.
package endpoints package endpoints
//go:generate go run ../model/cli/gen-endpoints/main.go endpoints.json endpoints_map.go //go:generate go run ../model/cli/gen-endpoints/main.go endpoints.json endpoints_map.go
......
// Package ec2query provides serialisation of AWS EC2 requests and responses.
package ec2query package ec2query
//go:generate go run ../../fixtures/protocol/generate.go ../../fixtures/protocol/input/ec2.json build_test.go //go:generate go run ../../fixtures/protocol/generate.go ../../fixtures/protocol/input/ec2.json build_test.go
...@@ -5,8 +6,9 @@ package ec2query ...@@ -5,8 +6,9 @@ package ec2query
import ( import (
"net/url" "net/url"
"github.com/awslabs/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/protocol/query/queryutil" "github.com/aws/aws-sdk-go/internal/apierr"
"github.com/aws/aws-sdk-go/internal/protocol/query/queryutil"
) )
// Build builds a request for the EC2 protocol. // Build builds a request for the EC2 protocol.
...@@ -16,8 +18,7 @@ func Build(r *aws.Request) { ...@@ -16,8 +18,7 @@ func Build(r *aws.Request) {
"Version": {r.Service.APIVersion}, "Version": {r.Service.APIVersion},
} }
if err := queryutil.Parse(body, r.Params, true); err != nil { if err := queryutil.Parse(body, r.Params, true); err != nil {
r.Error = err r.Error = apierr.New("Marshal", "failed encoding EC2 Query request", err)
return
} }
if r.ExpireTime == 0 { if r.ExpireTime == 0 {
......
package ec2query_test package ec2query_test
import ( import (
"github.com/awslabs/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/protocol/ec2query" "github.com/aws/aws-sdk-go/internal/protocol/ec2query"
"github.com/awslabs/aws-sdk-go/internal/signer/v4" "github.com/aws/aws-sdk-go/internal/signer/v4"
"bytes" "bytes"
"encoding/json" "encoding/json"
"encoding/xml" "encoding/xml"
"github.com/awslabs/aws-sdk-go/internal/protocol/xml/xmlutil"
"github.com/awslabs/aws-sdk-go/internal/util"
"github.com/stretchr/testify/assert"
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"testing" "testing"
"time" "time"
"github.com/aws/aws-sdk-go/internal/protocol/xml/xmlutil"
"github.com/aws/aws-sdk-go/internal/util"
"github.com/stretchr/testify/assert"
) )
var _ bytes.Buffer // always import bytes var _ bytes.Buffer // always import bytes
...@@ -37,10 +38,6 @@ type InputService1ProtocolTest struct { ...@@ -37,10 +38,6 @@ type InputService1ProtocolTest struct {
// New returns a new InputService1ProtocolTest client. // New returns a new InputService1ProtocolTest client.
func NewInputService1ProtocolTest(config *aws.Config) *InputService1ProtocolTest { func NewInputService1ProtocolTest(config *aws.Config) *InputService1ProtocolTest {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{ service := &aws.Service{
Config: aws.DefaultConfig.Merge(config), Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice1protocoltest", ServiceName: "inputservice1protocoltest",
...@@ -85,11 +82,10 @@ func (c *InputService1ProtocolTest) InputService1TestCaseOperation1Request(input ...@@ -85,11 +82,10 @@ func (c *InputService1ProtocolTest) InputService1TestCaseOperation1Request(input
return return
} }
func (c *InputService1ProtocolTest) InputService1TestCaseOperation1(input *InputService1TestShapeInputShape) (output *InputService1TestShapeInputService1TestCaseOperation1Output, err error) { func (c *InputService1ProtocolTest) InputService1TestCaseOperation1(input *InputService1TestShapeInputShape) (*InputService1TestShapeInputService1TestCaseOperation1Output, error) {
req, out := c.InputService1TestCaseOperation1Request(input) req, out := c.InputService1TestCaseOperation1Request(input)
output = out err := req.Send()
err = req.Send() return out, err
return
} }
var opInputService1TestCaseOperation1 *aws.Operation var opInputService1TestCaseOperation1 *aws.Operation
...@@ -121,10 +117,6 @@ type InputService2ProtocolTest struct { ...@@ -121,10 +117,6 @@ type InputService2ProtocolTest struct {
// New returns a new InputService2ProtocolTest client. // New returns a new InputService2ProtocolTest client.
func NewInputService2ProtocolTest(config *aws.Config) *InputService2ProtocolTest { func NewInputService2ProtocolTest(config *aws.Config) *InputService2ProtocolTest {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{ service := &aws.Service{
Config: aws.DefaultConfig.Merge(config), Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice2protocoltest", ServiceName: "inputservice2protocoltest",
...@@ -169,11 +161,10 @@ func (c *InputService2ProtocolTest) InputService2TestCaseOperation1Request(input ...@@ -169,11 +161,10 @@ func (c *InputService2ProtocolTest) InputService2TestCaseOperation1Request(input
return return
} }
func (c *InputService2ProtocolTest) InputService2TestCaseOperation1(input *InputService2TestShapeInputShape) (output *InputService2TestShapeInputService2TestCaseOperation1Output, err error) { func (c *InputService2ProtocolTest) InputService2TestCaseOperation1(input *InputService2TestShapeInputShape) (*InputService2TestShapeInputService2TestCaseOperation1Output, error) {
req, out := c.InputService2TestCaseOperation1Request(input) req, out := c.InputService2TestCaseOperation1Request(input)
output = out err := req.Send()
err = req.Send() return out, err
return
} }
var opInputService2TestCaseOperation1 *aws.Operation var opInputService2TestCaseOperation1 *aws.Operation
...@@ -207,10 +198,6 @@ type InputService3ProtocolTest struct { ...@@ -207,10 +198,6 @@ type InputService3ProtocolTest struct {
// New returns a new InputService3ProtocolTest client. // New returns a new InputService3ProtocolTest client.
func NewInputService3ProtocolTest(config *aws.Config) *InputService3ProtocolTest { func NewInputService3ProtocolTest(config *aws.Config) *InputService3ProtocolTest {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{ service := &aws.Service{
Config: aws.DefaultConfig.Merge(config), Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice3protocoltest", ServiceName: "inputservice3protocoltest",
...@@ -255,11 +242,10 @@ func (c *InputService3ProtocolTest) InputService3TestCaseOperation1Request(input ...@@ -255,11 +242,10 @@ func (c *InputService3ProtocolTest) InputService3TestCaseOperation1Request(input
return return
} }
func (c *InputService3ProtocolTest) InputService3TestCaseOperation1(input *InputService3TestShapeInputShape) (output *InputService3TestShapeInputService3TestCaseOperation1Output, err error) { func (c *InputService3ProtocolTest) InputService3TestCaseOperation1(input *InputService3TestShapeInputShape) (*InputService3TestShapeInputService3TestCaseOperation1Output, error) {
req, out := c.InputService3TestCaseOperation1Request(input) req, out := c.InputService3TestCaseOperation1Request(input)
output = out err := req.Send()
err = req.Send() return out, err
return
} }
var opInputService3TestCaseOperation1 *aws.Operation var opInputService3TestCaseOperation1 *aws.Operation
...@@ -299,10 +285,6 @@ type InputService4ProtocolTest struct { ...@@ -299,10 +285,6 @@ type InputService4ProtocolTest struct {
// New returns a new InputService4ProtocolTest client. // New returns a new InputService4ProtocolTest client.
func NewInputService4ProtocolTest(config *aws.Config) *InputService4ProtocolTest { func NewInputService4ProtocolTest(config *aws.Config) *InputService4ProtocolTest {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{ service := &aws.Service{
Config: aws.DefaultConfig.Merge(config), Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice4protocoltest", ServiceName: "inputservice4protocoltest",
...@@ -347,11 +329,10 @@ func (c *InputService4ProtocolTest) InputService4TestCaseOperation1Request(input ...@@ -347,11 +329,10 @@ func (c *InputService4ProtocolTest) InputService4TestCaseOperation1Request(input
return return
} }
func (c *InputService4ProtocolTest) InputService4TestCaseOperation1(input *InputService4TestShapeInputShape) (output *InputService4TestShapeInputService4TestCaseOperation1Output, err error) { func (c *InputService4ProtocolTest) InputService4TestCaseOperation1(input *InputService4TestShapeInputShape) (*InputService4TestShapeInputService4TestCaseOperation1Output, error) {
req, out := c.InputService4TestCaseOperation1Request(input) req, out := c.InputService4TestCaseOperation1Request(input)
output = out err := req.Send()
err = req.Send() return out, err
return
} }
var opInputService4TestCaseOperation1 *aws.Operation var opInputService4TestCaseOperation1 *aws.Operation
...@@ -381,10 +362,6 @@ type InputService5ProtocolTest struct { ...@@ -381,10 +362,6 @@ type InputService5ProtocolTest struct {
// New returns a new InputService5ProtocolTest client. // New returns a new InputService5ProtocolTest client.
func NewInputService5ProtocolTest(config *aws.Config) *InputService5ProtocolTest { func NewInputService5ProtocolTest(config *aws.Config) *InputService5ProtocolTest {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{ service := &aws.Service{
Config: aws.DefaultConfig.Merge(config), Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice5protocoltest", ServiceName: "inputservice5protocoltest",
...@@ -429,11 +406,10 @@ func (c *InputService5ProtocolTest) InputService5TestCaseOperation1Request(input ...@@ -429,11 +406,10 @@ func (c *InputService5ProtocolTest) InputService5TestCaseOperation1Request(input
return return
} }
func (c *InputService5ProtocolTest) InputService5TestCaseOperation1(input *InputService5TestShapeInputShape) (output *InputService5TestShapeInputService5TestCaseOperation1Output, err error) { func (c *InputService5ProtocolTest) InputService5TestCaseOperation1(input *InputService5TestShapeInputShape) (*InputService5TestShapeInputService5TestCaseOperation1Output, error) {
req, out := c.InputService5TestCaseOperation1Request(input) req, out := c.InputService5TestCaseOperation1Request(input)
output = out err := req.Send()
err = req.Send() return out, err
return
} }
var opInputService5TestCaseOperation1 *aws.Operation var opInputService5TestCaseOperation1 *aws.Operation
...@@ -463,10 +439,6 @@ type InputService6ProtocolTest struct { ...@@ -463,10 +439,6 @@ type InputService6ProtocolTest struct {
// New returns a new InputService6ProtocolTest client. // New returns a new InputService6ProtocolTest client.
func NewInputService6ProtocolTest(config *aws.Config) *InputService6ProtocolTest { func NewInputService6ProtocolTest(config *aws.Config) *InputService6ProtocolTest {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{ service := &aws.Service{
Config: aws.DefaultConfig.Merge(config), Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice6protocoltest", ServiceName: "inputservice6protocoltest",
...@@ -511,11 +483,10 @@ func (c *InputService6ProtocolTest) InputService6TestCaseOperation1Request(input ...@@ -511,11 +483,10 @@ func (c *InputService6ProtocolTest) InputService6TestCaseOperation1Request(input
return return
} }
func (c *InputService6ProtocolTest) InputService6TestCaseOperation1(input *InputService6TestShapeInputShape) (output *InputService6TestShapeInputService6TestCaseOperation1Output, err error) { func (c *InputService6ProtocolTest) InputService6TestCaseOperation1(input *InputService6TestShapeInputShape) (*InputService6TestShapeInputService6TestCaseOperation1Output, error) {
req, out := c.InputService6TestCaseOperation1Request(input) req, out := c.InputService6TestCaseOperation1Request(input)
output = out err := req.Send()
err = req.Send() return out, err
return
} }
var opInputService6TestCaseOperation1 *aws.Operation var opInputService6TestCaseOperation1 *aws.Operation
...@@ -545,10 +516,6 @@ type InputService7ProtocolTest struct { ...@@ -545,10 +516,6 @@ type InputService7ProtocolTest struct {
// New returns a new InputService7ProtocolTest client. // New returns a new InputService7ProtocolTest client.
func NewInputService7ProtocolTest(config *aws.Config) *InputService7ProtocolTest { func NewInputService7ProtocolTest(config *aws.Config) *InputService7ProtocolTest {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{ service := &aws.Service{
Config: aws.DefaultConfig.Merge(config), Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice7protocoltest", ServiceName: "inputservice7protocoltest",
...@@ -593,11 +560,10 @@ func (c *InputService7ProtocolTest) InputService7TestCaseOperation1Request(input ...@@ -593,11 +560,10 @@ func (c *InputService7ProtocolTest) InputService7TestCaseOperation1Request(input
return return
} }
func (c *InputService7ProtocolTest) InputService7TestCaseOperation1(input *InputService7TestShapeInputShape) (output *InputService7TestShapeInputService7TestCaseOperation1Output, err error) { func (c *InputService7ProtocolTest) InputService7TestCaseOperation1(input *InputService7TestShapeInputShape) (*InputService7TestShapeInputService7TestCaseOperation1Output, error) {
req, out := c.InputService7TestCaseOperation1Request(input) req, out := c.InputService7TestCaseOperation1Request(input)
output = out err := req.Send()
err = req.Send() return out, err
return
} }
var opInputService7TestCaseOperation1 *aws.Operation var opInputService7TestCaseOperation1 *aws.Operation
...@@ -627,10 +593,6 @@ type InputService8ProtocolTest struct { ...@@ -627,10 +593,6 @@ type InputService8ProtocolTest struct {
// New returns a new InputService8ProtocolTest client. // New returns a new InputService8ProtocolTest client.
func NewInputService8ProtocolTest(config *aws.Config) *InputService8ProtocolTest { func NewInputService8ProtocolTest(config *aws.Config) *InputService8ProtocolTest {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{ service := &aws.Service{
Config: aws.DefaultConfig.Merge(config), Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice8protocoltest", ServiceName: "inputservice8protocoltest",
...@@ -675,11 +637,10 @@ func (c *InputService8ProtocolTest) InputService8TestCaseOperation1Request(input ...@@ -675,11 +637,10 @@ func (c *InputService8ProtocolTest) InputService8TestCaseOperation1Request(input
return return
} }
func (c *InputService8ProtocolTest) InputService8TestCaseOperation1(input *InputService8TestShapeInputShape) (output *InputService8TestShapeInputService8TestCaseOperation1Output, err error) { func (c *InputService8ProtocolTest) InputService8TestCaseOperation1(input *InputService8TestShapeInputShape) (*InputService8TestShapeInputService8TestCaseOperation1Output, error) {
req, out := c.InputService8TestCaseOperation1Request(input) req, out := c.InputService8TestCaseOperation1Request(input)
output = out err := req.Send()
err = req.Send() return out, err
return
} }
var opInputService8TestCaseOperation1 *aws.Operation var opInputService8TestCaseOperation1 *aws.Operation
...@@ -930,4 +891,3 @@ func TestInputService8ProtocolTestTimestampValuesCase1(t *testing.T) { ...@@ -930,4 +891,3 @@ func TestInputService8ProtocolTestTimestampValuesCase1(t *testing.T) {
// assert headers // assert headers
} }
...@@ -6,8 +6,9 @@ import ( ...@@ -6,8 +6,9 @@ import (
"encoding/xml" "encoding/xml"
"io" "io"
"github.com/awslabs/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/protocol/xml/xmlutil" "github.com/aws/aws-sdk-go/internal/apierr"
"github.com/aws/aws-sdk-go/internal/protocol/xml/xmlutil"
) )
// Unmarshal unmarshals a response body for the EC2 protocol. // Unmarshal unmarshals a response body for the EC2 protocol.
...@@ -17,7 +18,7 @@ func Unmarshal(r *aws.Request) { ...@@ -17,7 +18,7 @@ func Unmarshal(r *aws.Request) {
decoder := xml.NewDecoder(r.HTTPResponse.Body) decoder := xml.NewDecoder(r.HTTPResponse.Body)
err := xmlutil.UnmarshalXML(r.Data, decoder, "") err := xmlutil.UnmarshalXML(r.Data, decoder, "")
if err != nil { if err != nil {
r.Error = err r.Error = apierr.New("Unmarshal", "failed decoding EC2 Query response", err)
return return
} }
} }
...@@ -42,12 +43,12 @@ func UnmarshalError(r *aws.Request) { ...@@ -42,12 +43,12 @@ func UnmarshalError(r *aws.Request) {
resp := &xmlErrorResponse{} resp := &xmlErrorResponse{}
err := xml.NewDecoder(r.HTTPResponse.Body).Decode(resp) err := xml.NewDecoder(r.HTTPResponse.Body).Decode(resp)
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
r.Error = err r.Error = apierr.New("Unmarshal", "failed decoding EC2 Query error response", err)
} else { } else {
r.Error = aws.APIError{ r.Error = apierr.NewRequestError(
StatusCode: r.HTTPResponse.StatusCode, apierr.New(resp.Code, resp.Message, nil),
Code: resp.Code, r.HTTPResponse.StatusCode,
Message: resp.Message, resp.RequestID,
} )
} }
} }
// Package query provides serialisation of AWS query requests, and responses.
package query package query
//go:generate go run ../../fixtures/protocol/generate.go ../../fixtures/protocol/input/query.json build_test.go //go:generate go run ../../fixtures/protocol/generate.go ../../fixtures/protocol/input/query.json build_test.go
...@@ -5,8 +6,9 @@ package query ...@@ -5,8 +6,9 @@ package query
import ( import (
"net/url" "net/url"
"github.com/awslabs/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/protocol/query/queryutil" "github.com/aws/aws-sdk-go/internal/apierr"
"github.com/aws/aws-sdk-go/internal/protocol/query/queryutil"
) )
// Build builds a request for an AWS Query service. // Build builds a request for an AWS Query service.
...@@ -16,7 +18,7 @@ func Build(r *aws.Request) { ...@@ -16,7 +18,7 @@ func Build(r *aws.Request) {
"Version": {r.Service.APIVersion}, "Version": {r.Service.APIVersion},
} }
if err := queryutil.Parse(body, r.Params, false); err != nil { if err := queryutil.Parse(body, r.Params, false); err != nil {
r.Error = err r.Error = apierr.New("Marshal", "failed encoding Query request", err)
return return
} }
......
...@@ -5,8 +5,9 @@ package query ...@@ -5,8 +5,9 @@ package query
import ( import (
"encoding/xml" "encoding/xml"
"github.com/awslabs/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/protocol/xml/xmlutil" "github.com/aws/aws-sdk-go/internal/apierr"
"github.com/aws/aws-sdk-go/internal/protocol/xml/xmlutil"
) )
// Unmarshal unmarshals a response for an AWS Query service. // Unmarshal unmarshals a response for an AWS Query service.
...@@ -16,7 +17,7 @@ func Unmarshal(r *aws.Request) { ...@@ -16,7 +17,7 @@ func Unmarshal(r *aws.Request) {
decoder := xml.NewDecoder(r.HTTPResponse.Body) decoder := xml.NewDecoder(r.HTTPResponse.Body)
err := xmlutil.UnmarshalXML(r.Data, decoder, r.Operation.Name+"Result") err := xmlutil.UnmarshalXML(r.Data, decoder, r.Operation.Name+"Result")
if err != nil { if err != nil {
r.Error = err r.Error = apierr.New("Unmarshal", "failed decoding Query response", err)
return return
} }
} }
......
...@@ -4,7 +4,8 @@ import ( ...@@ -4,7 +4,8 @@ import (
"encoding/xml" "encoding/xml"
"io" "io"
"github.com/awslabs/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/internal/apierr"
) )
type xmlErrorResponse struct { type xmlErrorResponse struct {
...@@ -21,12 +22,12 @@ func UnmarshalError(r *aws.Request) { ...@@ -21,12 +22,12 @@ func UnmarshalError(r *aws.Request) {
resp := &xmlErrorResponse{} resp := &xmlErrorResponse{}
err := xml.NewDecoder(r.HTTPResponse.Body).Decode(resp) err := xml.NewDecoder(r.HTTPResponse.Body).Decode(resp)
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
r.Error = err r.Error = apierr.New("Unmarshal", "failed to decode query XML error response", err)
} else { } else {
r.Error = aws.APIError{ r.Error = apierr.NewRequestError(
StatusCode: r.HTTPResponse.StatusCode, apierr.New(resp.Code, resp.Message, nil),
Code: resp.Code, r.HTTPResponse.StatusCode,
Message: resp.Message, resp.RequestID,
} )
} }
} }
// Package rest provides RESTful serialisation of AWS requests and responses.
package rest
import (
"bytes"
"encoding/base64"
"fmt"
"io"
"net/url"
"path"
"reflect"
"strconv"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/internal/apierr"
)
// RFC822 returns an RFC822 formatted timestamp for AWS protocols
const RFC822 = "Mon, 2 Jan 2006 15:04:05 GMT"
// Whether the byte value can be sent without escaping in AWS URLs
var noEscape [256]bool
func init() {
for i := 0; i < len(noEscape); i++ {
// AWS expects every character except these to be escaped
noEscape[i] = (i >= 'A' && i <= 'Z') ||
(i >= 'a' && i <= 'z') ||
(i >= '0' && i <= '9') ||
i == '-' ||
i == '.' ||
i == '_' ||
i == '~'
}
}
// Build builds the REST component of a service request.
func Build(r *aws.Request) {
if r.ParamsFilled() {
v := reflect.ValueOf(r.Params).Elem()
buildLocationElements(r, v)
buildBody(r, v)
}
}
func buildLocationElements(r *aws.Request, v reflect.Value) {
query := r.HTTPRequest.URL.Query()
for i := 0; i < v.NumField(); i++ {
m := v.Field(i)
if n := v.Type().Field(i).Name; n[0:1] == strings.ToLower(n[0:1]) {
continue
}
if m.IsValid() {
field := v.Type().Field(i)
name := field.Tag.Get("locationName")
if name == "" {
name = field.Name
}
if m.Kind() == reflect.Ptr {
m = m.Elem()
}
if !m.IsValid() {
continue
}
switch field.Tag.Get("location") {
case "headers": // header maps
buildHeaderMap(r, m, field.Tag.Get("locationName"))
case "header":
buildHeader(r, m, name)
case "uri":
buildURI(r, m, name)
case "querystring":
buildQueryString(r, m, name, query)
}
}
if r.Error != nil {
return
}
}
r.HTTPRequest.URL.RawQuery = query.Encode()
updatePath(r.HTTPRequest.URL, r.HTTPRequest.URL.Path)
}
func buildBody(r *aws.Request, v reflect.Value) {
if field, ok := v.Type().FieldByName("SDKShapeTraits"); ok {
if payloadName := field.Tag.Get("payload"); payloadName != "" {
pfield, _ := v.Type().FieldByName(payloadName)
if ptag := pfield.Tag.Get("type"); ptag != "" && ptag != "structure" {
payload := reflect.Indirect(v.FieldByName(payloadName))
if payload.IsValid() && payload.Interface() != nil {
switch reader := payload.Interface().(type) {
case io.ReadSeeker:
r.SetReaderBody(reader)
case []byte:
r.SetBufferBody(reader)
case string:
r.SetStringBody(reader)
default:
r.Error = apierr.New("Marshal",
"failed to encode REST request",
fmt.Errorf("unknown payload type %s", payload.Type()))
}
}
}
}
}
}
func buildHeader(r *aws.Request, v reflect.Value, name string) {
str, err := convertType(v)
if err != nil {
r.Error = apierr.New("Marshal", "failed to encode REST request", err)
} else if str != nil {
r.HTTPRequest.Header.Add(name, *str)
}
}
func buildHeaderMap(r *aws.Request, v reflect.Value, prefix string) {
for _, key := range v.MapKeys() {
str, err := convertType(v.MapIndex(key))
if err != nil {
r.Error = apierr.New("Marshal", "failed to encode REST request", err)
} else if str != nil {
r.HTTPRequest.Header.Add(prefix+key.String(), *str)
}
}
}
func buildURI(r *aws.Request, v reflect.Value, name string) {
value, err := convertType(v)
if err != nil {
r.Error = apierr.New("Marshal", "failed to encode REST request", err)
} else if value != nil {
uri := r.HTTPRequest.URL.Path
uri = strings.Replace(uri, "{"+name+"}", EscapePath(*value, true), -1)
uri = strings.Replace(uri, "{"+name+"+}", EscapePath(*value, false), -1)
r.HTTPRequest.URL.Path = uri
}
}
func buildQueryString(r *aws.Request, v reflect.Value, name string, query url.Values) {
str, err := convertType(v)
if err != nil {
r.Error = apierr.New("Marshal", "failed to encode REST request", err)
} else if str != nil {
query.Set(name, *str)
}
}
func updatePath(url *url.URL, urlPath string) {
scheme, query := url.Scheme, url.RawQuery
// clean up path
urlPath = path.Clean(urlPath)
// get formatted URL minus scheme so we can build this into Opaque
url.Scheme, url.Path, url.RawQuery = "", "", ""
s := url.String()
url.Scheme = scheme
url.RawQuery = query
// build opaque URI
url.Opaque = s + urlPath
}
// EscapePath escapes part of a URL path in Amazon style
func EscapePath(path string, encodeSep bool) string {
var buf bytes.Buffer
for i := 0; i < len(path); i++ {
c := path[i]
if noEscape[c] || (c == '/' && !encodeSep) {
buf.WriteByte(c)
} else {
buf.WriteByte('%')
buf.WriteString(strings.ToUpper(strconv.FormatUint(uint64(c), 16)))
}
}
return buf.String()
}
func convertType(v reflect.Value) (*string, error) {
v = reflect.Indirect(v)
if !v.IsValid() {
return nil, nil
}
var str string
switch value := v.Interface().(type) {
case string:
str = value
case []byte:
str = base64.StdEncoding.EncodeToString(value)
case bool:
str = strconv.FormatBool(value)
case int64:
str = strconv.FormatInt(value, 10)
case float64:
str = strconv.FormatFloat(value, 'f', -1, 64)
case time.Time:
str = value.UTC().Format(RFC822)
default:
err := fmt.Errorf("Unsupported value for param %v (%s)", v.Interface(), v.Type())
return nil, err
}
return &str, nil
}
package rest
import "reflect"
// PayloadMember returns the payload field member of i if there is one, or nil.
func PayloadMember(i interface{}) interface{} {
if i == nil {
return nil
}
v := reflect.ValueOf(i).Elem()
if !v.IsValid() {
return nil
}
if field, ok := v.Type().FieldByName("SDKShapeTraits"); ok {
if payloadName := field.Tag.Get("payload"); payloadName != "" {
field, _ := v.Type().FieldByName(payloadName)
if field.Tag.Get("type") != "structure" {
return nil
}
payload := v.FieldByName(payloadName)
if payload.IsValid() || (payload.Kind() == reflect.Ptr && !payload.IsNil()) {
return payload.Interface()
}
}
}
return nil
}
// PayloadType returns the type of a payload field member of i if there is one, or "".
func PayloadType(i interface{}) string {
v := reflect.Indirect(reflect.ValueOf(i))
if !v.IsValid() {
return ""
}
if field, ok := v.Type().FieldByName("SDKShapeTraits"); ok {
if payloadName := field.Tag.Get("payload"); payloadName != "" {
if member, ok := v.Type().FieldByName(payloadName); ok {
return member.Tag.Get("type")
}
}
}
return ""
}
package rest
import (
"encoding/base64"
"fmt"
"io/ioutil"
"net/http"
"reflect"
"strconv"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/internal/apierr"
)
// Unmarshal unmarshals the REST component of a response in a REST service.
func Unmarshal(r *aws.Request) {
if r.DataFilled() {
v := reflect.Indirect(reflect.ValueOf(r.Data))
unmarshalBody(r, v)
unmarshalLocationElements(r, v)
}
}
func unmarshalBody(r *aws.Request, v reflect.Value) {
if field, ok := v.Type().FieldByName("SDKShapeTraits"); ok {
if payloadName := field.Tag.Get("payload"); payloadName != "" {
pfield, _ := v.Type().FieldByName(payloadName)
if ptag := pfield.Tag.Get("type"); ptag != "" && ptag != "structure" {
payload := v.FieldByName(payloadName)
if payload.IsValid() {
switch payload.Interface().(type) {
case []byte:
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
if err != nil {
r.Error = apierr.New("Unmarshal", "failed to decode REST response", err)
} else {
payload.Set(reflect.ValueOf(b))
}
case *string:
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
if err != nil {
r.Error = apierr.New("Unmarshal", "failed to decode REST response", err)
} else {
str := string(b)
payload.Set(reflect.ValueOf(&str))
}
default:
switch payload.Type().String() {
case "io.ReadSeeker":
payload.Set(reflect.ValueOf(aws.ReadSeekCloser(r.HTTPResponse.Body)))
case "aws.ReadSeekCloser", "io.ReadCloser":
payload.Set(reflect.ValueOf(r.HTTPResponse.Body))
default:
r.Error = apierr.New("Unmarshal",
"failed to decode REST response",
fmt.Errorf("unknown payload type %s", payload.Type()))
}
}
}
}
}
}
}
func unmarshalLocationElements(r *aws.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]) {
continue
}
if m.IsValid() {
name := field.Tag.Get("locationName")
if name == "" {
name = field.Name
}
switch field.Tag.Get("location") {
case "statusCode":
unmarshalStatusCode(m, r.HTTPResponse.StatusCode)
case "header":
err := unmarshalHeader(m, r.HTTPResponse.Header.Get(name))
if err != nil {
r.Error = apierr.New("Unmarshal", "failed to decode REST response", err)
break
}
case "headers":
prefix := field.Tag.Get("locationName")
err := unmarshalHeaderMap(m, r.HTTPResponse.Header, prefix)
if err != nil {
r.Error = apierr.New("Unmarshal", "failed to decode REST response", err)
break
}
}
}
if r.Error != nil {
return
}
}
}
func unmarshalStatusCode(v reflect.Value, statusCode int) {
if !v.IsValid() {
return
}
switch v.Interface().(type) {
case *int64:
s := int64(statusCode)
v.Set(reflect.ValueOf(&s))
}
}
func unmarshalHeaderMap(r reflect.Value, headers http.Header, prefix string) error {
switch r.Interface().(type) {
case map[string]*string: // we only support string map value types
out := map[string]*string{}
for k, v := range headers {
k = http.CanonicalHeaderKey(k)
if strings.HasPrefix(strings.ToLower(k), strings.ToLower(prefix)) {
out[k[len(prefix):]] = &v[0]
}
}
r.Set(reflect.ValueOf(out))
}
return nil
}
func unmarshalHeader(v reflect.Value, header string) error {
if !v.IsValid() || (header == "" && v.Elem().Kind() != reflect.String) {
return nil
}
switch v.Interface().(type) {
case *string:
v.Set(reflect.ValueOf(&header))
case []byte:
b, err := base64.StdEncoding.DecodeString(header)
if err != nil {
return err
}
v.Set(reflect.ValueOf(&b))
case *bool:
b, err := strconv.ParseBool(header)
if err != nil {
return err
}
v.Set(reflect.ValueOf(&b))
case *int64:
i, err := strconv.ParseInt(header, 10, 64)
if err != nil {
return err
}
v.Set(reflect.ValueOf(&i))
case *float64:
f, err := strconv.ParseFloat(header, 64)
if err != nil {
return err
}
v.Set(reflect.ValueOf(&f))
case *time.Time:
t, err := time.Parse(RFC822, header)
if err != nil {
return err
}
v.Set(reflect.ValueOf(&t))
default:
err := fmt.Errorf("Unsupported value for param %v (%s)", v.Interface(), v.Type())
return err
}
return nil
}
...@@ -172,15 +172,8 @@ func parseList(r reflect.Value, node *XMLNode, tag reflect.StructTag) error { ...@@ -172,15 +172,8 @@ func parseList(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
// parseMap deserializes a map from an XMLNode. The direct children of the XMLNode // parseMap deserializes a map from an XMLNode. The direct children of the XMLNode
// will also be deserialized as map entries. // will also be deserialized as map entries.
func parseMap(r reflect.Value, node *XMLNode, tag reflect.StructTag) error { func parseMap(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
t := r.Type() if r.IsNil() {
if r.Kind() == reflect.Ptr { r.Set(reflect.MakeMap(r.Type()))
t = t.Elem()
if r.IsNil() {
r.Set(reflect.New(t))
r.Elem().Set(reflect.MakeMap(t))
}
r = r.Elem()
} }
if tag.Get("flattened") == "" { // look at all child entries if tag.Get("flattened") == "" { // look at all child entries
......
// +build !integration
package v4_test package v4_test
import ( import (
...@@ -7,9 +5,9 @@ import ( ...@@ -7,9 +5,9 @@ import (
"testing" "testing"
"time" "time"
"github.com/awslabs/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/test/unit" "github.com/aws/aws-sdk-go/internal/test/unit"
"github.com/awslabs/aws-sdk-go/service/s3" "github.com/aws/aws-sdk-go/service/s3"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
......
// Package v4 implements signing for AWS V4 signer
package v4 package v4
import ( import (
...@@ -13,9 +14,10 @@ import ( ...@@ -13,9 +14,10 @@ import (
"strings" "strings"
"time" "time"
"github.com/awslabs/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/internal/protocol/rest"
"github.com/awslabs/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
) )
const ( const (
...@@ -243,6 +245,10 @@ func (v4 *signer) buildCanonicalString() { ...@@ -243,6 +245,10 @@ func (v4 *signer) buildCanonicalString() {
uri = "/" uri = "/"
} }
if v4.ServiceName != "s3" {
uri = rest.EscapePath(uri, false)
}
v4.canonicalString = strings.Join([]string{ v4.canonicalString = strings.Join([]string{
v4.Request.Method, v4.Request.Method,
uri, uri,
......
...@@ -6,8 +6,8 @@ import ( ...@@ -6,8 +6,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/awslabs/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
...@@ -54,7 +54,7 @@ func TestPresignRequest(t *testing.T) { ...@@ -54,7 +54,7 @@ func TestPresignRequest(t *testing.T) {
expectedDate := "19700101T000000Z" expectedDate := "19700101T000000Z"
expectedHeaders := "host;x-amz-meta-other-header;x-amz-target" expectedHeaders := "host;x-amz-meta-other-header;x-amz-target"
expectedSig := "4c86bacebb78e458e8e898e93547513079d67ab95d3d5c02236889e21ea0df2b" expectedSig := "5eeedebf6f995145ce56daa02902d10485246d3defb34f97b973c1f40ab82d36"
expectedCred := "AKID/19700101/us-east-1/dynamodb/aws4_request" expectedCred := "AKID/19700101/us-east-1/dynamodb/aws4_request"
q := signer.Request.URL.Query() q := signer.Request.URL.Query()
...@@ -69,7 +69,7 @@ func TestSignRequest(t *testing.T) { ...@@ -69,7 +69,7 @@ func TestSignRequest(t *testing.T) {
signer.sign() signer.sign()
expectedDate := "19700101T000000Z" expectedDate := "19700101T000000Z"
expectedSig := "AWS4-HMAC-SHA256 Credential=AKID/19700101/us-east-1/dynamodb/aws4_request, SignedHeaders=host;x-amz-date;x-amz-meta-other-header;x-amz-security-token;x-amz-target, Signature=d4df864b291252d2c9206be75963db54db09ca70265622cc787cbe50ca0efcc8" expectedSig := "AWS4-HMAC-SHA256 Credential=AKID/19700101/us-east-1/dynamodb/aws4_request, SignedHeaders=host;x-amz-date;x-amz-meta-other-header;x-amz-security-token;x-amz-target, Signature=69ada33fec48180dab153576e4dd80c4e04124f80dda3eccfed8a67c2b91ed5e"
q := signer.Request.Header q := signer.Request.Header
assert.Equal(t, expectedSig, q.Get("Authorization")) assert.Equal(t, expectedSig, q.Get("Authorization"))
......
...@@ -3,8 +3,8 @@ package ec2 ...@@ -3,8 +3,8 @@ package ec2
import ( import (
"time" "time"
"github.com/awslabs/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/aws/awsutil" "github.com/aws/aws-sdk-go/aws/awsutil"
) )
func init() { func init() {
......
// +build !integration
package ec2_test package ec2_test
import ( import (
...@@ -7,9 +5,9 @@ import ( ...@@ -7,9 +5,9 @@ import (
"net/url" "net/url"
"testing" "testing"
"github.com/awslabs/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/test/unit" "github.com/aws/aws-sdk-go/internal/test/unit"
"github.com/awslabs/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
......
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
// Package ec2iface provides an interface for the Amazon Elastic Compute Cloud.
package ec2iface package ec2iface
import ( import (
"github.com/awslabs/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
) )
// EC2API is the interface type for ec2.EC2.
type EC2API interface { type EC2API interface {
AcceptVPCPeeringConnection(*ec2.AcceptVPCPeeringConnectionInput) (*ec2.AcceptVPCPeeringConnectionOutput, error) AcceptVPCPeeringConnection(*ec2.AcceptVPCPeeringConnectionInput) (*ec2.AcceptVPCPeeringConnectionOutput, error)
...@@ -43,6 +47,8 @@ type EC2API interface { ...@@ -43,6 +47,8 @@ type EC2API interface {
CancelReservedInstancesListing(*ec2.CancelReservedInstancesListingInput) (*ec2.CancelReservedInstancesListingOutput, error) CancelReservedInstancesListing(*ec2.CancelReservedInstancesListingInput) (*ec2.CancelReservedInstancesListingOutput, error)
CancelSpotFleetRequests(*ec2.CancelSpotFleetRequestsInput) (*ec2.CancelSpotFleetRequestsOutput, error)
CancelSpotInstanceRequests(*ec2.CancelSpotInstanceRequestsInput) (*ec2.CancelSpotInstanceRequestsOutput, error) CancelSpotInstanceRequests(*ec2.CancelSpotInstanceRequestsInput) (*ec2.CancelSpotInstanceRequestsOutput, error)
ConfirmProductInstance(*ec2.ConfirmProductInstanceInput) (*ec2.ConfirmProductInstanceOutput, error) ConfirmProductInstance(*ec2.ConfirmProductInstanceInput) (*ec2.ConfirmProductInstanceOutput, error)
...@@ -89,6 +95,8 @@ type EC2API interface { ...@@ -89,6 +95,8 @@ type EC2API interface {
CreateVPC(*ec2.CreateVPCInput) (*ec2.CreateVPCOutput, error) CreateVPC(*ec2.CreateVPCInput) (*ec2.CreateVPCOutput, error)
CreateVPCEndpoint(*ec2.CreateVPCEndpointInput) (*ec2.CreateVPCEndpointOutput, error)
CreateVPCPeeringConnection(*ec2.CreateVPCPeeringConnectionInput) (*ec2.CreateVPCPeeringConnectionOutput, error) CreateVPCPeeringConnection(*ec2.CreateVPCPeeringConnectionInput) (*ec2.CreateVPCPeeringConnectionOutput, error)
CreateVPNConnection(*ec2.CreateVPNConnectionInput) (*ec2.CreateVPNConnectionOutput, error) CreateVPNConnection(*ec2.CreateVPNConnectionInput) (*ec2.CreateVPNConnectionOutput, error)
...@@ -131,6 +139,8 @@ type EC2API interface { ...@@ -131,6 +139,8 @@ type EC2API interface {
DeleteVPC(*ec2.DeleteVPCInput) (*ec2.DeleteVPCOutput, error) DeleteVPC(*ec2.DeleteVPCInput) (*ec2.DeleteVPCOutput, error)
DeleteVPCEndpoints(*ec2.DeleteVPCEndpointsInput) (*ec2.DeleteVPCEndpointsOutput, error)
DeleteVPCPeeringConnection(*ec2.DeleteVPCPeeringConnectionInput) (*ec2.DeleteVPCPeeringConnectionOutput, error) DeleteVPCPeeringConnection(*ec2.DeleteVPCPeeringConnectionInput) (*ec2.DeleteVPCPeeringConnectionOutput, error)
DeleteVPNConnection(*ec2.DeleteVPNConnectionInput) (*ec2.DeleteVPNConnectionOutput, error) DeleteVPNConnection(*ec2.DeleteVPNConnectionInput) (*ec2.DeleteVPNConnectionOutput, error)
...@@ -179,6 +189,8 @@ type EC2API interface { ...@@ -179,6 +189,8 @@ type EC2API interface {
DescribeKeyPairs(*ec2.DescribeKeyPairsInput) (*ec2.DescribeKeyPairsOutput, error) DescribeKeyPairs(*ec2.DescribeKeyPairsInput) (*ec2.DescribeKeyPairsOutput, error)
DescribeMovingAddresses(*ec2.DescribeMovingAddressesInput) (*ec2.DescribeMovingAddressesOutput, error)
DescribeNetworkACLs(*ec2.DescribeNetworkACLsInput) (*ec2.DescribeNetworkACLsOutput, error) DescribeNetworkACLs(*ec2.DescribeNetworkACLsInput) (*ec2.DescribeNetworkACLsOutput, error)
DescribeNetworkInterfaceAttribute(*ec2.DescribeNetworkInterfaceAttributeInput) (*ec2.DescribeNetworkInterfaceAttributeOutput, error) DescribeNetworkInterfaceAttribute(*ec2.DescribeNetworkInterfaceAttributeInput) (*ec2.DescribeNetworkInterfaceAttributeOutput, error)
...@@ -187,6 +199,8 @@ type EC2API interface { ...@@ -187,6 +199,8 @@ type EC2API interface {
DescribePlacementGroups(*ec2.DescribePlacementGroupsInput) (*ec2.DescribePlacementGroupsOutput, error) DescribePlacementGroups(*ec2.DescribePlacementGroupsInput) (*ec2.DescribePlacementGroupsOutput, error)
DescribePrefixLists(*ec2.DescribePrefixListsInput) (*ec2.DescribePrefixListsOutput, error)
DescribeRegions(*ec2.DescribeRegionsInput) (*ec2.DescribeRegionsOutput, error) DescribeRegions(*ec2.DescribeRegionsInput) (*ec2.DescribeRegionsOutput, error)
DescribeReservedInstances(*ec2.DescribeReservedInstancesInput) (*ec2.DescribeReservedInstancesOutput, error) DescribeReservedInstances(*ec2.DescribeReservedInstancesInput) (*ec2.DescribeReservedInstancesOutput, error)
...@@ -207,6 +221,12 @@ type EC2API interface { ...@@ -207,6 +221,12 @@ type EC2API interface {
DescribeSpotDatafeedSubscription(*ec2.DescribeSpotDatafeedSubscriptionInput) (*ec2.DescribeSpotDatafeedSubscriptionOutput, error) DescribeSpotDatafeedSubscription(*ec2.DescribeSpotDatafeedSubscriptionInput) (*ec2.DescribeSpotDatafeedSubscriptionOutput, error)
DescribeSpotFleetInstances(*ec2.DescribeSpotFleetInstancesInput) (*ec2.DescribeSpotFleetInstancesOutput, error)
DescribeSpotFleetRequestHistory(*ec2.DescribeSpotFleetRequestHistoryInput) (*ec2.DescribeSpotFleetRequestHistoryOutput, error)
DescribeSpotFleetRequests(*ec2.DescribeSpotFleetRequestsInput) (*ec2.DescribeSpotFleetRequestsOutput, error)
DescribeSpotInstanceRequests(*ec2.DescribeSpotInstanceRequestsInput) (*ec2.DescribeSpotInstanceRequestsOutput, error) DescribeSpotInstanceRequests(*ec2.DescribeSpotInstanceRequestsInput) (*ec2.DescribeSpotInstanceRequestsOutput, error)
DescribeSpotPriceHistory(*ec2.DescribeSpotPriceHistoryInput) (*ec2.DescribeSpotPriceHistoryOutput, error) DescribeSpotPriceHistory(*ec2.DescribeSpotPriceHistoryInput) (*ec2.DescribeSpotPriceHistoryOutput, error)
...@@ -219,6 +239,10 @@ type EC2API interface { ...@@ -219,6 +239,10 @@ type EC2API interface {
DescribeVPCClassicLink(*ec2.DescribeVPCClassicLinkInput) (*ec2.DescribeVPCClassicLinkOutput, error) DescribeVPCClassicLink(*ec2.DescribeVPCClassicLinkInput) (*ec2.DescribeVPCClassicLinkOutput, error)
DescribeVPCEndpointServices(*ec2.DescribeVPCEndpointServicesInput) (*ec2.DescribeVPCEndpointServicesOutput, error)
DescribeVPCEndpoints(*ec2.DescribeVPCEndpointsInput) (*ec2.DescribeVPCEndpointsOutput, error)
DescribeVPCPeeringConnections(*ec2.DescribeVPCPeeringConnectionsInput) (*ec2.DescribeVPCPeeringConnectionsOutput, error) DescribeVPCPeeringConnections(*ec2.DescribeVPCPeeringConnectionsInput) (*ec2.DescribeVPCPeeringConnectionsOutput, error)
DescribeVPCs(*ec2.DescribeVPCsInput) (*ec2.DescribeVPCsOutput, error) DescribeVPCs(*ec2.DescribeVPCsInput) (*ec2.DescribeVPCsOutput, error)
...@@ -285,10 +309,14 @@ type EC2API interface { ...@@ -285,10 +309,14 @@ type EC2API interface {
ModifyVPCAttribute(*ec2.ModifyVPCAttributeInput) (*ec2.ModifyVPCAttributeOutput, error) ModifyVPCAttribute(*ec2.ModifyVPCAttributeInput) (*ec2.ModifyVPCAttributeOutput, error)
ModifyVPCEndpoint(*ec2.ModifyVPCEndpointInput) (*ec2.ModifyVPCEndpointOutput, error)
ModifyVolumeAttribute(*ec2.ModifyVolumeAttributeInput) (*ec2.ModifyVolumeAttributeOutput, error) ModifyVolumeAttribute(*ec2.ModifyVolumeAttributeInput) (*ec2.ModifyVolumeAttributeOutput, error)
MonitorInstances(*ec2.MonitorInstancesInput) (*ec2.MonitorInstancesOutput, error) MonitorInstances(*ec2.MonitorInstancesInput) (*ec2.MonitorInstancesOutput, error)
MoveAddressToVPC(*ec2.MoveAddressToVPCInput) (*ec2.MoveAddressToVPCOutput, error)
PurchaseReservedInstancesOffering(*ec2.PurchaseReservedInstancesOfferingInput) (*ec2.PurchaseReservedInstancesOfferingOutput, error) PurchaseReservedInstancesOffering(*ec2.PurchaseReservedInstancesOfferingInput) (*ec2.PurchaseReservedInstancesOfferingOutput, error)
RebootInstances(*ec2.RebootInstancesInput) (*ec2.RebootInstancesOutput, error) RebootInstances(*ec2.RebootInstancesInput) (*ec2.RebootInstancesOutput, error)
...@@ -309,6 +337,8 @@ type EC2API interface { ...@@ -309,6 +337,8 @@ type EC2API interface {
ReportInstanceStatus(*ec2.ReportInstanceStatusInput) (*ec2.ReportInstanceStatusOutput, error) ReportInstanceStatus(*ec2.ReportInstanceStatusInput) (*ec2.ReportInstanceStatusOutput, error)
RequestSpotFleet(*ec2.RequestSpotFleetInput) (*ec2.RequestSpotFleetOutput, error)
RequestSpotInstances(*ec2.RequestSpotInstancesInput) (*ec2.RequestSpotInstancesOutput, error) RequestSpotInstances(*ec2.RequestSpotInstancesInput) (*ec2.RequestSpotInstancesOutput, error)
ResetImageAttribute(*ec2.ResetImageAttributeInput) (*ec2.ResetImageAttributeOutput, error) ResetImageAttribute(*ec2.ResetImageAttributeInput) (*ec2.ResetImageAttributeOutput, error)
...@@ -319,6 +349,8 @@ type EC2API interface { ...@@ -319,6 +349,8 @@ type EC2API interface {
ResetSnapshotAttribute(*ec2.ResetSnapshotAttributeInput) (*ec2.ResetSnapshotAttributeOutput, error) ResetSnapshotAttribute(*ec2.ResetSnapshotAttributeInput) (*ec2.ResetSnapshotAttributeOutput, error)
RestoreAddressToClassic(*ec2.RestoreAddressToClassicInput) (*ec2.RestoreAddressToClassicOutput, error)
RevokeSecurityGroupEgress(*ec2.RevokeSecurityGroupEgressInput) (*ec2.RevokeSecurityGroupEgressOutput, error) RevokeSecurityGroupEgress(*ec2.RevokeSecurityGroupEgressInput) (*ec2.RevokeSecurityGroupEgressOutput, error)
RevokeSecurityGroupIngress(*ec2.RevokeSecurityGroupIngressInput) (*ec2.RevokeSecurityGroupIngressOutput, error) RevokeSecurityGroupIngress(*ec2.RevokeSecurityGroupIngressInput) (*ec2.RevokeSecurityGroupIngressOutput, error)
......
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
package ec2iface_test
import (
"testing"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
"github.com/stretchr/testify/assert"
)
func TestInterface(t *testing.T) {
assert.Implements(t, (*ec2iface.EC2API)(nil), ec2.New(nil))
}
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
package ec2 package ec2
import ( import (
"github.com/awslabs/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/protocol/ec2query" "github.com/aws/aws-sdk-go/internal/protocol/ec2query"
"github.com/awslabs/aws-sdk-go/internal/signer/v4" "github.com/aws/aws-sdk-go/internal/signer/v4"
) )
// EC2 is a client for Amazon EC2. // EC2 is a client for Amazon EC2.
...@@ -19,14 +21,10 @@ var initRequest func(*aws.Request) ...@@ -19,14 +21,10 @@ var initRequest func(*aws.Request)
// New returns a new EC2 client. // New returns a new EC2 client.
func New(config *aws.Config) *EC2 { func New(config *aws.Config) *EC2 {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{ service := &aws.Service{
Config: aws.DefaultConfig.Merge(config), Config: aws.DefaultConfig.Merge(config),
ServiceName: "ec2", ServiceName: "ec2",
APIVersion: "2015-03-01", APIVersion: "2015-04-15",
} }
service.Initialize() service.Initialize()
......
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
// Package elbiface provides an interface for the Elastic Load Balancing.
package elbiface package elbiface
import ( import (
"github.com/awslabs/aws-sdk-go/service/elb" "github.com/aws/aws-sdk-go/service/elb"
) )
// ELBAPI is the interface type for elb.ELB.
type ELBAPI interface { type ELBAPI interface {
AddTags(*elb.AddTagsInput) (*elb.AddTagsOutput, error) AddTags(*elb.AddTagsInput) (*elb.AddTagsOutput, error)
......
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
package elbiface_test
import (
"testing"
"github.com/aws/aws-sdk-go/service/elb"
"github.com/aws/aws-sdk-go/service/elb/elbiface"
"github.com/stretchr/testify/assert"
)
func TestInterface(t *testing.T) {
assert.Implements(t, (*elbiface.ELBAPI)(nil), elb.New(nil))
}
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
package elb package elb
import ( import (
"github.com/awslabs/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/protocol/query" "github.com/aws/aws-sdk-go/internal/protocol/query"
"github.com/awslabs/aws-sdk-go/internal/signer/v4" "github.com/aws/aws-sdk-go/internal/signer/v4"
) )
// ELB is a client for Elastic Load Balancing. // ELB is a client for Elastic Load Balancing.
...@@ -19,10 +21,6 @@ var initRequest func(*aws.Request) ...@@ -19,10 +21,6 @@ var initRequest func(*aws.Request)
// New returns a new ELB client. // New returns a new ELB client.
func New(config *aws.Config) *ELB { func New(config *aws.Config) *ELB {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{ service := &aws.Service{
Config: aws.DefaultConfig.Merge(config), Config: aws.DefaultConfig.Merge(config),
ServiceName: "elasticloadbalancing", ServiceName: "elasticloadbalancing",
......
package aws
// 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
}
// Error returns the error as a string. Satisfies error interface.
func (e APIError) Error() string {
return e.Code + ": " + e.Message
}
// Error returns an APIError pointer if the error e is an APIError type.
// If the error is not an APIError nil will be returned.
func Error(e error) *APIError {
if err, ok := e.(*APIError); ok {
return err
} else if err, ok := e.(APIError); ok {
return &err
} else {
return nil
}
}
// +build integration
package ec2_test
import (
"testing"
"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/test/integration"
"github.com/awslabs/aws-sdk-go/internal/util/utilassert"
"github.com/awslabs/aws-sdk-go/service/ec2"
"github.com/stretchr/testify/assert"
)
var (
_ = assert.Equal
_ = utilassert.Match
_ = integration.Imported
)
func TestMakingABasicRequest(t *testing.T) {
client := ec2.New(nil)
resp, e := client.DescribeRegions(&ec2.DescribeRegionsInput{})
err := aws.Error(e)
_, _, _ = resp, e, err // avoid unused warnings
assert.NoError(t, nil, err)
}
func TestErrorHandling(t *testing.T) {
client := ec2.New(nil)
resp, e := client.DescribeInstances(&ec2.DescribeInstancesInput{
InstanceIDs: []*string{
aws.String("i-12345678"),
},
})
err := aws.Error(e)
_, _, _ = resp, e, err // avoid unused warnings
assert.NotEqual(t, nil, err)
assert.Equal(t, "InvalidInstanceID.NotFound", err.Code)
utilassert.Match(t, "The instance ID 'i-12345678' does not exist", err.Message)
}
...@@ -30,10 +30,11 @@ import ( ...@@ -30,10 +30,11 @@ import (
"time" "time"
"code.google.com/p/gcfg" "code.google.com/p/gcfg"
"github.com/awslabs/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/awserr"
"github.com/awslabs/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/aws/credentials"
"github.com/awslabs/aws-sdk-go/service/elb" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/elb"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
...@@ -1294,8 +1295,8 @@ func (s *AWSCloud) describeLoadBalancer(region, name string) (*elb.LoadBalancerD ...@@ -1294,8 +1295,8 @@ func (s *AWSCloud) describeLoadBalancer(region, name string) (*elb.LoadBalancerD
response, err := elbClient.DescribeLoadBalancers(request) response, err := elbClient.DescribeLoadBalancers(request)
if err != nil { if err != nil {
if awsError := aws.Error(err); awsError != nil { if awsError, ok := err.(awserr.Error); ok {
if awsError.Code == "LoadBalancerNotFound" { if awsError.Code() == "LoadBalancerNotFound" {
return nil, nil return nil, nil
} }
} }
......
...@@ -22,9 +22,9 @@ import ( ...@@ -22,9 +22,9 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/awslabs/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/awslabs/aws-sdk-go/service/elb" "github.com/aws/aws-sdk-go/service/elb"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment