Skip to content

Commit

Permalink
r/kms_key: Retry lookups after creation (#1039)
Browse files Browse the repository at this point in the history
  • Loading branch information
radeksimko authored Jul 8, 2017
1 parent 2fbcf0e commit 94295b0
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 16 deletions.
19 changes: 19 additions & 0 deletions aws/awserr.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package aws

import (
"strings"
"time"

"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/hashicorp/terraform/helper/resource"
)

func isAWSErr(err error, code string, message string) bool {
Expand All @@ -12,3 +14,20 @@ func isAWSErr(err error, code string, message string) bool {
}
return false
}

func retryOnAwsCode(code string, f func() (interface{}, error)) (interface{}, error) {
var resp interface{}
err := resource.Retry(1*time.Minute, func() *resource.RetryError {
var err error
resp, err = f()
if err != nil {
awsErr, ok := err.(awserr.Error)
if ok && awsErr.Code() == code {
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
return nil
})
return resp, err
}
44 changes: 30 additions & 14 deletions aws/resource_aws_kms_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ func resourceAwsKmsKeyCreate(d *schema.ResourceData, meta interface{}) error {
d.SetId(*resp.KeyMetadata.KeyId)
d.Set("key_id", resp.KeyMetadata.KeyId)

return _resourceAwsKmsKeyUpdate(d, meta, true)
return resourceAwsKmsKeyUpdate(d, meta)
}

func resourceAwsKmsKeyRead(d *schema.ResourceData, meta interface{}) error {
Expand All @@ -134,7 +134,18 @@ func resourceAwsKmsKeyRead(d *schema.ResourceData, meta interface{}) error {
req := &kms.DescribeKeyInput{
KeyId: aws.String(d.Id()),
}
resp, err := conn.DescribeKey(req)

var resp *kms.DescribeKeyOutput
var err error
if d.IsNewResource() {
var out interface{}
out, err = retryOnAwsCode("NotFoundException", func() (interface{}, error) {
return conn.DescribeKey(req)
})
resp, _ = out.(*kms.DescribeKeyOutput)
} else {
resp, err = conn.DescribeKey(req)
}
if err != nil {
return err
}
Expand Down Expand Up @@ -188,16 +199,10 @@ func resourceAwsKmsKeyRead(d *schema.ResourceData, meta interface{}) error {
}

func resourceAwsKmsKeyUpdate(d *schema.ResourceData, meta interface{}) error {
return _resourceAwsKmsKeyUpdate(d, meta, false)
}

// We expect new keys to be enabled already
// but there is no easy way to differentiate between Update()
// called from Create() and regular update, so we have this wrapper
func _resourceAwsKmsKeyUpdate(d *schema.ResourceData, meta interface{}, isFresh bool) error {
conn := meta.(*AWSClient).kmsconn

if d.HasChange("is_enabled") && d.Get("is_enabled").(bool) && !isFresh {
// We expect new keys to be enabled already
if d.HasChange("is_enabled") && d.Get("is_enabled").(bool) && !d.IsNewResource() {
// Enable before any attributes will be modified
if err := updateKmsKeyStatus(conn, d.Id(), d.Get("is_enabled").(bool)); err != nil {
return err
Expand Down Expand Up @@ -246,7 +251,9 @@ func resourceAwsKmsKeyDescriptionUpdate(conn *kms.KMS, d *schema.ResourceData) e
Description: aws.String(description),
KeyId: aws.String(keyId),
}
_, err := conn.UpdateKeyDescription(req)
_, err := retryOnAwsCode("NotFoundException", func() (interface{}, error) {
return conn.UpdateKeyDescription(req)
})
return err
}

Expand All @@ -264,7 +271,9 @@ func resourceAwsKmsKeyPolicyUpdate(conn *kms.KMS, d *schema.ResourceData) error
Policy: aws.String(policy),
PolicyName: aws.String("default"),
}
_, err = conn.PutKeyPolicy(req)
_, err = retryOnAwsCode("NotFoundException", func() (interface{}, error) {
return conn.PutKeyPolicy(req)
})
return err
}

Expand Down Expand Up @@ -294,14 +303,18 @@ func updateKmsKeyStatus(conn *kms.KMS, id string, shouldBeEnabled bool) error {
Target: []string{fmt.Sprintf("%t", shouldBeEnabled)},
Timeout: 20 * time.Minute,
MinTimeout: 2 * time.Second,
ContinuousTargetOccurence: 10,
ContinuousTargetOccurence: 15,
Refresh: func() (interface{}, string, error) {
log.Printf("[DEBUG] Checking if KMS key %s enabled status is %t",
id, shouldBeEnabled)
resp, err := conn.DescribeKey(&kms.DescribeKeyInput{
KeyId: aws.String(id),
})
if err != nil {
awsErr, ok := err.(awserr.Error)
if ok && awsErr.Code() == "NotFoundException" {
return nil, fmt.Sprintf("%t", !shouldBeEnabled), nil
}
return resp, "FAILED", err
}
status := fmt.Sprintf("%t", *resp.KeyMetadata.Enabled)
Expand All @@ -322,7 +335,7 @@ func updateKmsKeyStatus(conn *kms.KMS, id string, shouldBeEnabled bool) error {
func updateKmsKeyRotationStatus(conn *kms.KMS, d *schema.ResourceData) error {
shouldEnableRotation := d.Get("enable_key_rotation").(bool)

err := resource.Retry(5*time.Minute, func() *resource.RetryError {
err := resource.Retry(10*time.Minute, func() *resource.RetryError {
var err error
if shouldEnableRotation {
log.Printf("[DEBUG] Enabling key rotation for KMS key %q", d.Id())
Expand All @@ -341,6 +354,9 @@ func updateKmsKeyRotationStatus(conn *kms.KMS, d *schema.ResourceData) error {
if ok && awsErr.Code() == "DisabledException" {
return resource.RetryableError(err)
}
if ok && awsErr.Code() == "NotFoundException" {
return resource.RetryableError(err)
}

return resource.NonRetryableError(err)
}
Expand Down
7 changes: 5 additions & 2 deletions aws/resource_aws_kms_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,12 +212,15 @@ func testAccCheckAWSKmsKeyExists(name string, key *kms.KeyMetadata) resource.Tes

conn := testAccProvider.Meta().(*AWSClient).kmsconn

out, err := conn.DescribeKey(&kms.DescribeKeyInput{
KeyId: aws.String(rs.Primary.ID),
o, err := retryOnAwsCode("NotFoundException", func() (interface{}, error) {
return conn.DescribeKey(&kms.DescribeKeyInput{
KeyId: aws.String(rs.Primary.ID),
})
})
if err != nil {
return err
}
out := o.(*kms.DescribeKeyOutput)

*key = *out.KeyMetadata

Expand Down

0 comments on commit 94295b0

Please sign in to comment.