provider/aws: Handle LimitExceededException for subscriber limits

- Updates aws-sdk-go/request for retryer fix
 - Fixes dynamoDB exception handling to catch subscriber limit error

When the `aws-sdk-go` dep releases the next release, we can tag the vendor with the new
release version, and merge this. Until then, soft-updated the vendor solely for the `request` package to post fix.

DynamoDB Fix:
```
aws_dynamodb_table.bar: Creating...
  arn:                       "" => "<computed>"
  attribute.#:               "" => "1"
  attribute.4228504427.name: "" => "id"
  attribute.4228504427.type: "" => "S"
  hash_key:                  "" => "id"
  name:                      "" => "over-cap-test"
  read_capacity:             "" => "5"
  stream_arn:                "" => "<computed>"
  stream_enabled:            "" => "<computed>"
  stream_view_type:          "" => "<computed>"
  write_capacity:            "" => "5"
Error applying plan:

1 error(s) occurred:

* aws_dynamodb_table.bar: 1 error(s) occurred:

* aws_dynamodb_table.bar: AWS Error creating DynamoDB table: LimitExceededException: Subscriber limit exceeded: There is a limit of 256 tables per subscriber
        status code: 400, request id: J2MC7MR060VKBPHP9P6JG5B6Q3VV4KQNSO5AEMVJF66Q9ASUAAJG
```
This commit is contained in:
Jake Champlin 2017-05-17 08:59:47 -04:00
parent 492618f8cf
commit d05fc51aa0
No known key found for this signature in database
GPG Key ID: DC31F41958EF4AC2
8 changed files with 32 additions and 17 deletions

View File

@ -321,15 +321,20 @@ func resourceAwsDynamoDbTableCreate(d *schema.ResourceData, meta interface{}) er
output, err := dynamodbconn.CreateTable(req)
if err != nil {
if awsErr, ok := err.(awserr.Error); ok {
if awsErr.Code() == "ThrottlingException" {
switch code := awsErr.Code(); code {
case "ThrottlingException":
log.Printf("[DEBUG] Attempt %d/%d: Sleeping for a bit to throttle back create request", attemptCount, DYNAMODB_MAX_THROTTLE_RETRIES)
time.Sleep(DYNAMODB_THROTTLE_SLEEP)
attemptCount += 1
} else if awsErr.Code() == "LimitExceededException" {
case "LimitExceededException":
// If we're at resource capacity, error out without retry
if strings.Contains(awsErr.Message(), "Subscriber limit exceeded:") {
return fmt.Errorf("AWS Error creating DynamoDB table: %s", err)
}
log.Printf("[DEBUG] Limit on concurrent table creations hit, sleeping for a bit")
time.Sleep(DYNAMODB_LIMIT_EXCEEDED_SLEEP)
attemptCount += 1
} else {
default:
// Some other non-retryable exception occurred
return fmt.Errorf("AWS Error creating DynamoDB table: %s", err)
}

View File

@ -1,4 +1,4 @@
// +build !appengine
// +build !appengine,!plan9
package request

View File

@ -0,0 +1,11 @@
// +build appengine plan9
package request
import (
"strings"
)
func isErrConnectionReset(err error) bool {
return strings.Contains(err.Error(), "connection reset")
}

View File

@ -368,7 +368,7 @@ func (r *Request) ResetBody() {
}
if l == 0 {
r.HTTPRequest.Body = noBodyReader
r.HTTPRequest.Body = NoBody
} else if l > 0 {
r.HTTPRequest.Body = r.safeBody
} else {
@ -382,7 +382,7 @@ func (r *Request) ResetBody() {
// a io.Reader that was not also an io.Seeker.
switch r.Operation.HTTPMethod {
case "GET", "HEAD", "DELETE":
r.HTTPRequest.Body = noBodyReader
r.HTTPRequest.Body = NoBody
default:
r.HTTPRequest.Body = r.safeBody
}

View File

@ -16,6 +16,6 @@ func (noBody) Read([]byte) (int, error) { return 0, io.EOF }
func (noBody) Close() error { return nil }
func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil }
// Is an empty reader that will trigger the Go HTTP client to not include
// NoBody is an empty reader that will trigger the Go HTTP client to not include
// and body in the HTTP request.
var noBodyReader = noBody{}
var NoBody = noBody{}

View File

@ -2,8 +2,10 @@
package request
import "net/http"
import (
"net/http"
)
// Is a http.NoBody reader instructing Go HTTP client to not include
// NoBody is a http.NoBody reader instructing Go HTTP client to not include
// and body in the HTTP request.
var noBodyReader = http.NoBody
var NoBody = http.NoBody

View File

@ -38,7 +38,6 @@ var throttleCodes = map[string]struct{}{
"ThrottlingException": {},
"RequestLimitExceeded": {},
"RequestThrottled": {},
"LimitExceededException": {}, // Deleting 10+ DynamoDb tables at once
"TooManyRequestsException": {}, // Lambda functions
"PriorRequestNotComplete": {}, // Route53
}

8
vendor/vendor.json vendored
View File

@ -621,12 +621,10 @@
"versionExact": "v1.8.21"
},
{
"checksumSHA1": "4y3OXdVeAE/Upux6FZp/0T0gAz4=",
"checksumSHA1": "dsVwPNbrXbXMAXZY9ZkXG7vR+Oc=",
"path": "github.com/aws/aws-sdk-go/aws/request",
"revision": "49c7a5e645b5eca5aabd1fd6a676dbddaf7b2a1a",
"revisionTime": "2017-05-09T17:42:03Z",
"version": "v1.8.21",
"versionExact": "v1.8.21"
"revision": "fed27f4bd16c8c63d01003b978e5bc85fe727519",
"revisionTime": "2017-05-16T23:28:54Z"
},
{
"checksumSHA1": "sxShwDYt1duG922FOwU0/hbu/uc=",