Skip to content

Commit

Permalink
Merge pull request #9818 from terraform-providers/rfd-retry-opsworkz
Browse files Browse the repository at this point in the history
Retries and retry removal for opsworks resources
  • Loading branch information
ryndaniels authored Aug 20, 2019
2 parents 879c07a + b0d74b8 commit 234537f
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 114 deletions.
39 changes: 5 additions & 34 deletions aws/resource_aws_opsworks_application.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ import (
"fmt"
"log"
"strings"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/opsworks"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
)
Expand Down Expand Up @@ -312,24 +310,9 @@ func resourceAwsOpsworksApplicationCreate(d *schema.ResourceData, meta interface
Attributes: resourceAwsOpsworksApplicationAttributes(d),
}

var resp *opsworks.CreateAppOutput
err = resource.Retry(2*time.Minute, func() *resource.RetryError {
var cerr error
resp, cerr = client.CreateApp(req)
if cerr != nil {
log.Printf("[INFO] client error")
if opserr, ok := cerr.(awserr.Error); ok {
// XXX: handle errors
log.Printf("[ERROR] OpsWorks error: %s message: %s", opserr.Code(), opserr.Message())
return resource.RetryableError(cerr)
}
return resource.NonRetryableError(cerr)
}
return nil
})

resp, err := client.CreateApp(req)
if err != nil {
return err
return fmt.Errorf("Error creating OpsWorks application: %s", err)
}

appID := *resp.AppId
Expand Down Expand Up @@ -362,23 +345,11 @@ func resourceAwsOpsworksApplicationUpdate(d *schema.ResourceData, meta interface

log.Printf("[DEBUG] Updating OpsWorks layer: %s", d.Id())

err = resource.Retry(2*time.Minute, func() *resource.RetryError {
_, cerr := client.UpdateApp(req)
if cerr != nil {
log.Printf("[INFO] client error")
if opserr, ok := cerr.(awserr.Error); ok {
// XXX: handle errors
log.Printf("[ERROR] OpsWorks error: %s message: %s", opserr.Code(), opserr.Message())
return resource.NonRetryableError(cerr)
}
return resource.RetryableError(cerr)
}
return nil
})

_, err = client.UpdateApp(req)
if err != nil {
return err
return fmt.Errorf("Error updating OpsWorks app: %s", err)
}

return resourceAwsOpsworksApplicationRead(d, meta)
}

Expand Down
65 changes: 13 additions & 52 deletions aws/resource_aws_opsworks_rds_db_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@ package aws
import (
"fmt"
"log"
"time"

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

Expand Down Expand Up @@ -68,23 +65,10 @@ func resourceAwsOpsworksRdsDbInstanceUpdate(d *schema.ResourceData, meta interfa
if requestUpdate {
log.Printf("[DEBUG] Opsworks RDS DB Instance Modification request: %s", req)

err := resource.Retry(2*time.Minute, func() *resource.RetryError {
var cerr error
_, cerr = client.UpdateRdsDbInstance(req)
if cerr != nil {
log.Printf("[INFO] client error")
if opserr, ok := cerr.(awserr.Error); ok {
log.Printf("[ERROR] OpsWorks error: %s message: %s", opserr.Code(), opserr.Message())
}
return resource.NonRetryableError(cerr)
}
return nil
})

_, err := client.UpdateRdsDbInstance(req)
if err != nil {
return err
return fmt.Errorf("Error updating Opsworks RDS DB instance: %s", err)
}

}

d.Partial(false)
Expand All @@ -101,27 +85,17 @@ func resourceAwsOpsworksRdsDbInstanceDeregister(d *schema.ResourceData, meta int

log.Printf("[DEBUG] Unregistering rds db instance '%s' from stack: %s", d.Get("rds_db_instance_arn"), d.Get("stack_id"))

err := resource.Retry(2*time.Minute, func() *resource.RetryError {
var cerr error
_, cerr = client.DeregisterRdsDbInstance(req)
if cerr != nil {
log.Printf("[INFO] client error")
if opserr, ok := cerr.(awserr.Error); ok {
if opserr.Code() == "ResourceNotFoundException" {
log.Printf("[INFO] The db instance could not be found. Remove it from state.")
d.SetId("")

return nil
}
log.Printf("[ERROR] OpsWorks error: %s message: %s", opserr.Code(), opserr.Message())
}
return resource.NonRetryableError(cerr)
_, err := client.DeregisterRdsDbInstance(req)
if err != nil {
if isAWSErr(err, "ResourceNotFoundException", "") {
log.Printf("[INFO] The db instance could not be found. Remove it from state.")
d.SetId("")
return nil
}
return fmt.Errorf("Error deregistering Opsworks RDS DB instance: %s", err)
}

return nil
})

return err
return nil
}

func resourceAwsOpsworksRdsDbInstanceRead(d *schema.ResourceData, meta interface{}) error {
Expand Down Expand Up @@ -171,22 +145,9 @@ func resourceAwsOpsworksRdsDbInstanceRegister(d *schema.ResourceData, meta inter
DbPassword: aws.String(d.Get("db_password").(string)),
}

err := resource.Retry(2*time.Minute, func() *resource.RetryError {
var cerr error
_, cerr = client.RegisterRdsDbInstance(req)
if cerr != nil {
log.Printf("[INFO] client error")
if opserr, ok := cerr.(awserr.Error); ok {
log.Printf("[ERROR] OpsWorks error: %s message: %s", opserr.Code(), opserr.Message())
}
return resource.NonRetryableError(cerr)
}

return nil
})

_, err := client.RegisterRdsDbInstance(req)
if err != nil {
return err
return fmt.Errorf("Error registering Opsworks RDS DB instance: %s", err)
}

return resourceAwsOpsworksRdsDbInstanceRead(d, meta)
Expand Down
43 changes: 20 additions & 23 deletions aws/resource_aws_opsworks_stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package aws
import (
"fmt"
"log"
"strings"
"time"

"github.com/hashicorp/terraform/helper/resource"
Expand Down Expand Up @@ -436,33 +435,31 @@ func resourceAwsOpsworksStackCreate(d *schema.ResourceData, meta interface{}) er

var resp *opsworks.CreateStackOutput
err = resource.Retry(20*time.Minute, func() *resource.RetryError {
var cerr error
resp, cerr = client.CreateStack(req)
if cerr != nil {
if opserr, ok := cerr.(awserr.Error); ok {
// If Terraform is also managing the service IAM role,
// it may have just been created and not yet be
// propagated.
// AWS doesn't provide a machine-readable code for this
// specific error, so we're forced to do fragile message
// matching.
// The full error we're looking for looks something like
// the following:
// Service Role Arn: [...] is not yet propagated, please try again in a couple of minutes
propErr := "not yet propagated"
trustErr := "not the necessary trust relationship"
validateErr := "validate IAM role permission"
if opserr.Code() == "ValidationException" && (strings.Contains(opserr.Message(), trustErr) || strings.Contains(opserr.Message(), propErr) || strings.Contains(opserr.Message(), validateErr)) {
log.Printf("[INFO] Waiting for service IAM role to propagate")
return resource.RetryableError(cerr)
}
resp, err = client.CreateStack(req)
if err != nil {
// If Terraform is also managing the service IAM role, it may have just been created and not yet be
// propagated. AWS doesn't provide a machine-readable code for this specific error, so we're forced
// to do fragile message matching.
// The full error we're looking for looks something like the following:
// Service Role Arn: [...] is not yet propagated, please try again in a couple of minutes
propErr := "not yet propagated"
trustErr := "not the necessary trust relationship"
validateErr := "validate IAM role permission"

if isAWSErr(err, "ValidationException", propErr) || isAWSErr(err, "ValidationException", trustErr) || isAWSErr(err, "ValidationException", validateErr) {
log.Printf("[INFO] Waiting for service IAM role to propagate")
return resource.RetryableError(err)
}
return resource.NonRetryableError(cerr)

return resource.NonRetryableError(err)
}
return nil
})
if isResourceTimeoutError(err) {
resp, err = client.CreateStack(req)
}
if err != nil {
return err
return fmt.Errorf("Error creating Opsworks stack: %s", err)
}

stackId := *resp.StackId
Expand Down
10 changes: 5 additions & 5 deletions aws/resource_aws_opsworks_stack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/aws/aws-sdk-go/service/opsworks"
)

func TestAccAWSOpsworksStackImportBasic(t *testing.T) {
func TestAccAWSOpsworksStack_ImportBasic(t *testing.T) {
name := acctest.RandString(10)

resourceName := "aws_opsworks_stack.tf-acc"
Expand All @@ -40,7 +40,7 @@ func TestAccAWSOpsworksStackImportBasic(t *testing.T) {
//// Tests for the No-VPC case
///////////////////////////////

func TestAccAWSOpsworksStackNoVpc(t *testing.T) {
func TestAccAWSOpsworksStack_NoVpc(t *testing.T) {
stackName := fmt.Sprintf("tf-opsworks-acc-%d", acctest.RandInt())
var opsstack opsworks.Stack
resource.ParallelTest(t, resource.TestCase{
Expand All @@ -63,7 +63,7 @@ func TestAccAWSOpsworksStackNoVpc(t *testing.T) {
})
}

func TestAccAWSOpsworksStackNoVpcChangeServiceRoleForceNew(t *testing.T) {
func TestAccAWSOpsworksStack_NoVpcChangeServiceRoleForceNew(t *testing.T) {
stackName := fmt.Sprintf("tf-opsworks-acc-%d", acctest.RandInt())
var before, after opsworks.Stack
resource.ParallelTest(t, resource.TestCase{
Expand All @@ -90,7 +90,7 @@ func TestAccAWSOpsworksStackNoVpcChangeServiceRoleForceNew(t *testing.T) {
})
}

func TestAccAWSOpsworksStackVpc(t *testing.T) {
func TestAccAWSOpsworksStack_Vpc(t *testing.T) {
stackName := fmt.Sprintf("tf-opsworks-acc-%d", acctest.RandInt())
var opsstack opsworks.Stack
resource.ParallelTest(t, resource.TestCase{
Expand Down Expand Up @@ -124,7 +124,7 @@ func TestAccAWSOpsworksStackVpc(t *testing.T) {
})
}

func TestAccAWSOpsworksStackNoVpcCreateTags(t *testing.T) {
func TestAccAWSOpsworksStack_NoVpcCreateTags(t *testing.T) {
stackName := fmt.Sprintf("tf-opsworks-acc-%d", acctest.RandInt())
var opsstack opsworks.Stack
resource.ParallelTest(t, resource.TestCase{
Expand Down

0 comments on commit 234537f

Please sign in to comment.