diff --git a/builtin/providers/aws/resource_aws_api_gateway_api_key.go b/builtin/providers/aws/resource_aws_api_gateway_api_key.go index bfa8cb5c456a..b70ad490a951 100644 --- a/builtin/providers/aws/resource_aws_api_gateway_api_key.go +++ b/builtin/providers/aws/resource_aws_api_gateway_api_key.go @@ -148,7 +148,7 @@ func resourceAwsApiGatewayApiKeyDelete(d *schema.ResourceData, meta interface{}) conn := meta.(*AWSClient).apigateway log.Printf("[DEBUG] Deleting API Gateway API Key: %s", d.Id()) - return resource.Retry(5*time.Minute, func() error { + return resource.Retry(5*time.Minute, func() *resource.RetryError { _, err := conn.DeleteApiKey(&apigateway.DeleteApiKeyInput{ ApiKey: aws.String(d.Id()), }) @@ -161,6 +161,6 @@ func resourceAwsApiGatewayApiKeyDelete(d *schema.ResourceData, meta interface{}) return nil } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) }) } diff --git a/builtin/providers/aws/resource_aws_api_gateway_deployment.go b/builtin/providers/aws/resource_aws_api_gateway_deployment.go index 4d7517bfb257..ca8aecafac3e 100644 --- a/builtin/providers/aws/resource_aws_api_gateway_deployment.go +++ b/builtin/providers/aws/resource_aws_api_gateway_deployment.go @@ -138,7 +138,7 @@ func resourceAwsApiGatewayDeploymentDelete(d *schema.ResourceData, meta interfac conn := meta.(*AWSClient).apigateway log.Printf("[DEBUG] Deleting API Gateway Deployment: %s", d.Id()) - return resource.Retry(5*time.Minute, func() error { + return resource.Retry(5*time.Minute, func() *resource.RetryError { log.Printf("[DEBUG] schema is %#v", d) if _, err := conn.DeleteStage(&apigateway.DeleteStageInput{ StageName: aws.String(d.Get("stage_name").(string)), @@ -161,9 +161,9 @@ func resourceAwsApiGatewayDeploymentDelete(d *schema.ResourceData, meta interfac } if !ok { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) }) } diff --git a/builtin/providers/aws/resource_aws_api_gateway_integration.go b/builtin/providers/aws/resource_aws_api_gateway_integration.go index 01e90968f2aa..c1dedd8777cc 100644 --- a/builtin/providers/aws/resource_aws_api_gateway_integration.go +++ b/builtin/providers/aws/resource_aws_api_gateway_integration.go @@ -161,7 +161,7 @@ func resourceAwsApiGatewayIntegrationDelete(d *schema.ResourceData, meta interfa conn := meta.(*AWSClient).apigateway log.Printf("[DEBUG] Deleting API Gateway Integration: %s", d.Id()) - return resource.Retry(5*time.Minute, func() error { + return resource.Retry(5*time.Minute, func() *resource.RetryError { _, err := conn.DeleteIntegration(&apigateway.DeleteIntegrationInput{ HttpMethod: aws.String(d.Get("http_method").(string)), ResourceId: aws.String(d.Get("resource_id").(string)), @@ -177,9 +177,9 @@ func resourceAwsApiGatewayIntegrationDelete(d *schema.ResourceData, meta interfa } if !ok { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) }) } diff --git a/builtin/providers/aws/resource_aws_api_gateway_integration_response.go b/builtin/providers/aws/resource_aws_api_gateway_integration_response.go index c8b629a69ce6..0f2a9af00526 100644 --- a/builtin/providers/aws/resource_aws_api_gateway_integration_response.go +++ b/builtin/providers/aws/resource_aws_api_gateway_integration_response.go @@ -116,7 +116,7 @@ func resourceAwsApiGatewayIntegrationResponseDelete(d *schema.ResourceData, meta conn := meta.(*AWSClient).apigateway log.Printf("[DEBUG] Deleting API Gateway Integration Response: %s", d.Id()) - return resource.Retry(5*time.Minute, func() error { + return resource.Retry(5*time.Minute, func() *resource.RetryError { _, err := conn.DeleteIntegrationResponse(&apigateway.DeleteIntegrationResponseInput{ HttpMethod: aws.String(d.Get("http_method").(string)), ResourceId: aws.String(d.Get("resource_id").(string)), @@ -133,9 +133,9 @@ func resourceAwsApiGatewayIntegrationResponseDelete(d *schema.ResourceData, meta } if !ok { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) }) } diff --git a/builtin/providers/aws/resource_aws_api_gateway_method.go b/builtin/providers/aws/resource_aws_api_gateway_method.go index c5c1da391ee1..31e90640d143 100644 --- a/builtin/providers/aws/resource_aws_api_gateway_method.go +++ b/builtin/providers/aws/resource_aws_api_gateway_method.go @@ -154,7 +154,7 @@ func resourceAwsApiGatewayMethodDelete(d *schema.ResourceData, meta interface{}) conn := meta.(*AWSClient).apigateway log.Printf("[DEBUG] Deleting API Gateway Method: %s", d.Id()) - return resource.Retry(5*time.Minute, func() error { + return resource.Retry(5*time.Minute, func() *resource.RetryError { _, err := conn.DeleteMethod(&apigateway.DeleteMethodInput{ HttpMethod: aws.String(d.Get("http_method").(string)), ResourceId: aws.String(d.Get("resource_id").(string)), @@ -170,9 +170,9 @@ func resourceAwsApiGatewayMethodDelete(d *schema.ResourceData, meta interface{}) } if !ok { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) }) } diff --git a/builtin/providers/aws/resource_aws_api_gateway_method_response.go b/builtin/providers/aws/resource_aws_api_gateway_method_response.go index 3d77b2ea7447..778ba4ea2139 100644 --- a/builtin/providers/aws/resource_aws_api_gateway_method_response.go +++ b/builtin/providers/aws/resource_aws_api_gateway_method_response.go @@ -136,7 +136,7 @@ func resourceAwsApiGatewayMethodResponseDelete(d *schema.ResourceData, meta inte conn := meta.(*AWSClient).apigateway log.Printf("[DEBUG] Deleting API Gateway Method Response: %s", d.Id()) - return resource.Retry(5*time.Minute, func() error { + return resource.Retry(5*time.Minute, func() *resource.RetryError { _, err := conn.DeleteMethodResponse(&apigateway.DeleteMethodResponseInput{ HttpMethod: aws.String(d.Get("http_method").(string)), ResourceId: aws.String(d.Get("resource_id").(string)), @@ -153,9 +153,9 @@ func resourceAwsApiGatewayMethodResponseDelete(d *schema.ResourceData, meta inte } if !ok { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) }) } diff --git a/builtin/providers/aws/resource_aws_api_gateway_model.go b/builtin/providers/aws/resource_aws_api_gateway_model.go index cca7517f7034..3f2721889d07 100644 --- a/builtin/providers/aws/resource_aws_api_gateway_model.go +++ b/builtin/providers/aws/resource_aws_api_gateway_model.go @@ -144,7 +144,7 @@ func resourceAwsApiGatewayModelDelete(d *schema.ResourceData, meta interface{}) conn := meta.(*AWSClient).apigateway log.Printf("[DEBUG] Deleting API Gateway Model: %s", d.Id()) - return resource.Retry(5*time.Minute, func() error { + return resource.Retry(5*time.Minute, func() *resource.RetryError { log.Printf("[DEBUG] schema is %#v", d) _, err := conn.DeleteModel(&apigateway.DeleteModelInput{ ModelName: aws.String(d.Get("name").(string)), @@ -160,9 +160,9 @@ func resourceAwsApiGatewayModelDelete(d *schema.ResourceData, meta interface{}) } if !ok { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) }) } diff --git a/builtin/providers/aws/resource_aws_api_gateway_resource.go b/builtin/providers/aws/resource_aws_api_gateway_resource.go index a0f138c13b92..77df10c31f57 100644 --- a/builtin/providers/aws/resource_aws_api_gateway_resource.go +++ b/builtin/providers/aws/resource_aws_api_gateway_resource.go @@ -129,7 +129,7 @@ func resourceAwsApiGatewayResourceDelete(d *schema.ResourceData, meta interface{ conn := meta.(*AWSClient).apigateway log.Printf("[DEBUG] Deleting API Gateway Resource: %s", d.Id()) - return resource.Retry(5*time.Minute, func() error { + return resource.Retry(5*time.Minute, func() *resource.RetryError { log.Printf("[DEBUG] schema is %#v", d) _, err := conn.DeleteResource(&apigateway.DeleteResourceInput{ ResourceId: aws.String(d.Id()), @@ -143,6 +143,6 @@ func resourceAwsApiGatewayResourceDelete(d *schema.ResourceData, meta interface{ return nil } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) }) } diff --git a/builtin/providers/aws/resource_aws_api_gateway_rest_api.go b/builtin/providers/aws/resource_aws_api_gateway_rest_api.go index 65d3afdc568d..2d6f6dc26a23 100644 --- a/builtin/providers/aws/resource_aws_api_gateway_rest_api.go +++ b/builtin/providers/aws/resource_aws_api_gateway_rest_api.go @@ -144,7 +144,7 @@ func resourceAwsApiGatewayRestApiDelete(d *schema.ResourceData, meta interface{} conn := meta.(*AWSClient).apigateway log.Printf("[DEBUG] Deleting API Gateway: %s", d.Id()) - return resource.Retry(5*time.Minute, func() error { + return resource.Retry(5*time.Minute, func() *resource.RetryError { _, err := conn.DeleteRestApi(&apigateway.DeleteRestApiInput{ RestApiId: aws.String(d.Id()), }) @@ -156,6 +156,6 @@ func resourceAwsApiGatewayRestApiDelete(d *schema.ResourceData, meta interface{} return nil } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) }) } diff --git a/builtin/providers/aws/resource_aws_autoscaling_group.go b/builtin/providers/aws/resource_aws_autoscaling_group.go index 7c5b38769803..fc47756c794b 100644 --- a/builtin/providers/aws/resource_aws_autoscaling_group.go +++ b/builtin/providers/aws/resource_aws_autoscaling_group.go @@ -450,7 +450,7 @@ func resourceAwsAutoscalingGroupDelete(d *schema.ResourceData, meta interface{}) // We retry the delete operation to handle InUse/InProgress errors coming // from scaling operations. We should be able to sneak in a delete in between // scaling operations within 5m. - err = resource.Retry(5*time.Minute, func() error { + err = resource.Retry(5*time.Minute, func() *resource.RetryError { if _, err := conn.DeleteAutoScalingGroup(&deleteopts); err != nil { if awserr, ok := err.(awserr.Error); ok { switch awserr.Code() { @@ -459,11 +459,11 @@ func resourceAwsAutoscalingGroupDelete(d *schema.ResourceData, meta interface{}) return nil case "ResourceInUse", "ScalingActivityInProgress": // These are retryable - return awserr + return resource.RetryableError(awserr) } } // Didn't recognize the error, so shouldn't retry. - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } // Successful delete return nil @@ -472,9 +472,10 @@ func resourceAwsAutoscalingGroupDelete(d *schema.ResourceData, meta interface{}) return err } - return resource.Retry(5*time.Minute, func() error { + return resource.Retry(5*time.Minute, func() *resource.RetryError { if g, _ = getAwsAutoscalingGroup(d.Id(), conn); g != nil { - return fmt.Errorf("Auto Scaling Group still exists") + return resource.RetryableError( + fmt.Errorf("Auto Scaling Group still exists")) } return nil }) @@ -531,10 +532,10 @@ func resourceAwsAutoscalingGroupDrain(d *schema.ResourceData, meta interface{}) // Next, wait for the autoscale group to drain log.Printf("[DEBUG] Waiting for group to have zero instances") - return resource.Retry(10*time.Minute, func() error { + return resource.Retry(10*time.Minute, func() *resource.RetryError { g, err := getAwsAutoscalingGroup(d.Id(), conn) if err != nil { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } if g == nil { log.Printf("[INFO] Autoscaling Group %q not found", d.Id()) @@ -546,7 +547,8 @@ func resourceAwsAutoscalingGroupDrain(d *schema.ResourceData, meta interface{}) return nil } - return fmt.Errorf("group still has %d instances", len(g.Instances)) + return resource.RetryableError( + fmt.Errorf("group still has %d instances", len(g.Instances))) }) } diff --git a/builtin/providers/aws/resource_aws_autoscaling_group_waiting.go b/builtin/providers/aws/resource_aws_autoscaling_group_waiting.go index 7ebb5ee8f3cc..bfafa9b3364f 100644 --- a/builtin/providers/aws/resource_aws_autoscaling_group_waiting.go +++ b/builtin/providers/aws/resource_aws_autoscaling_group_waiting.go @@ -32,10 +32,10 @@ func waitForASGCapacity( log.Printf("[DEBUG] Waiting on %s for capacity...", d.Id()) - return resource.Retry(wait, func() error { + return resource.Retry(wait, func() *resource.RetryError { g, err := getAwsAutoscalingGroup(d.Id(), meta.(*AWSClient).autoscalingconn) if err != nil { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } if g == nil { log.Printf("[INFO] Autoscaling Group %q not found", d.Id()) @@ -44,7 +44,7 @@ func waitForASGCapacity( } lbis, err := getLBInstanceStates(g, meta) if err != nil { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } haveASG := 0 @@ -86,7 +86,8 @@ func waitForASGCapacity( return nil } - return fmt.Errorf("%q: Waiting up to %s: %s", d.Id(), wait, reason) + return resource.RetryableError( + fmt.Errorf("%q: Waiting up to %s: %s", d.Id(), wait, reason)) }) } diff --git a/builtin/providers/aws/resource_aws_autoscaling_lifecycle_hook.go b/builtin/providers/aws/resource_aws_autoscaling_lifecycle_hook.go index d13ba17aef4a..bb6d1c2e32cc 100644 --- a/builtin/providers/aws/resource_aws_autoscaling_lifecycle_hook.go +++ b/builtin/providers/aws/resource_aws_autoscaling_lifecycle_hook.go @@ -64,16 +64,16 @@ func resourceAwsAutoscalingLifecycleHookPut(d *schema.ResourceData, meta interfa params := getAwsAutoscalingPutLifecycleHookInput(d) log.Printf("[DEBUG] AutoScaling PutLifecyleHook: %s", params) - err := resource.Retry(5*time.Minute, func() error { + err := resource.Retry(5*time.Minute, func() *resource.RetryError { _, err := conn.PutLifecycleHook(¶ms) if err != nil { if awsErr, ok := err.(awserr.Error); ok { if strings.Contains(awsErr.Message(), "Unable to publish test message to notification target") { - return fmt.Errorf("[DEBUG] Retrying AWS AutoScaling Lifecycle Hook: %s", params) + return resource.RetryableError(fmt.Errorf("[DEBUG] Retrying AWS AutoScaling Lifecycle Hook: %s", params)) } } - return resource.RetryError{Err: fmt.Errorf("Error putting lifecycle hook: %s", err)} + return resource.NonRetryableError(fmt.Errorf("Error putting lifecycle hook: %s", err)) } return nil }) diff --git a/builtin/providers/aws/resource_aws_cloudwatch_event_rule.go b/builtin/providers/aws/resource_aws_cloudwatch_event_rule.go index f94303a711af..341b2a305238 100644 --- a/builtin/providers/aws/resource_aws_cloudwatch_event_rule.go +++ b/builtin/providers/aws/resource_aws_cloudwatch_event_rule.go @@ -70,7 +70,7 @@ func resourceAwsCloudWatchEventRuleCreate(d *schema.ResourceData, meta interface // IAM Roles take some time to propagate var out *events.PutRuleOutput - err := resource.Retry(30*time.Second, func() error { + err := resource.Retry(30*time.Second, func() *resource.RetryError { var err error out, err = conn.PutRule(input) pattern := regexp.MustCompile("cannot be assumed by principal '[a-z]+\\.amazonaws\\.com'\\.$") @@ -78,12 +78,10 @@ func resourceAwsCloudWatchEventRuleCreate(d *schema.ResourceData, meta interface if awsErr, ok := err.(awserr.Error); ok { if awsErr.Code() == "ValidationException" && pattern.MatchString(awsErr.Message()) { log.Printf("[DEBUG] Retrying creation of CloudWatch Event Rule %q", *input.Name) - return err + return resource.RetryableError(err) } } - return resource.RetryError{ - Err: err, - } + return resource.NonRetryableError(err) } return nil }) @@ -157,7 +155,7 @@ func resourceAwsCloudWatchEventRuleUpdate(d *schema.ResourceData, meta interface // IAM Roles take some time to propagate var out *events.PutRuleOutput - err := resource.Retry(30*time.Second, func() error { + err := resource.Retry(30*time.Second, func() *resource.RetryError { var err error out, err = conn.PutRule(input) pattern := regexp.MustCompile("cannot be assumed by principal '[a-z]+\\.amazonaws\\.com'\\.$") @@ -165,12 +163,10 @@ func resourceAwsCloudWatchEventRuleUpdate(d *schema.ResourceData, meta interface if awsErr, ok := err.(awserr.Error); ok { if awsErr.Code() == "ValidationException" && pattern.MatchString(awsErr.Message()) { log.Printf("[DEBUG] Retrying update of CloudWatch Event Rule %q", *input.Name) - return err + return resource.RetryableError(err) } } - return resource.RetryError{ - Err: err, - } + return resource.NonRetryableError(err) } return nil }) diff --git a/builtin/providers/aws/resource_aws_codedeploy_deployment_group.go b/builtin/providers/aws/resource_aws_codedeploy_deployment_group.go index 26cc3ff38f57..ed4177e423c3 100644 --- a/builtin/providers/aws/resource_aws_codedeploy_deployment_group.go +++ b/builtin/providers/aws/resource_aws_codedeploy_deployment_group.go @@ -158,20 +158,20 @@ func resourceAwsCodeDeployDeploymentGroupCreate(d *schema.ResourceData, meta int // Retry to handle IAM role eventual consistency. var resp *codedeploy.CreateDeploymentGroupOutput var err error - err = resource.Retry(2*time.Minute, func() error { + err = resource.Retry(2*time.Minute, func() *resource.RetryError { resp, err = conn.CreateDeploymentGroup(&input) if err != nil { codedeployErr, ok := err.(awserr.Error) if !ok { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } if codedeployErr.Code() == "InvalidRoleException" { log.Printf("[DEBUG] Trying to create deployment group again: %q", codedeployErr.Message()) - return err + return resource.RetryableError(err) } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } return nil }) diff --git a/builtin/providers/aws/resource_aws_db_instance.go b/builtin/providers/aws/resource_aws_db_instance.go index 7a67187305a9..981e87d9a88b 100644 --- a/builtin/providers/aws/resource_aws_db_instance.go +++ b/builtin/providers/aws/resource_aws_db_instance.go @@ -534,15 +534,15 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error log.Printf("[DEBUG] DB Instance create configuration: %#v", opts) var err error - err = resource.Retry(5*time.Minute, func() error { + err = resource.Retry(5*time.Minute, func() *resource.RetryError { _, err = conn.CreateDBInstance(&opts) if err != nil { if awsErr, ok := err.(awserr.Error); ok { if awsErr.Code() == "InvalidParameterValue" && strings.Contains(awsErr.Message(), "ENHANCED_MONITORING") { - return awsErr + return resource.RetryableError(awsErr) } } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } return nil }) diff --git a/builtin/providers/aws/resource_aws_dynamodb_table.go b/builtin/providers/aws/resource_aws_dynamodb_table.go index d52194333467..2d356ab177d6 100644 --- a/builtin/providers/aws/resource_aws_dynamodb_table.go +++ b/builtin/providers/aws/resource_aws_dynamodb_table.go @@ -676,25 +676,25 @@ func resourceAwsDynamoDbTableDelete(d *schema.ResourceData, meta interface{}) er TableName: aws.String(d.Id()), } - err = resource.Retry(10*time.Minute, func() error { + err = resource.Retry(10*time.Minute, func() *resource.RetryError { t, err := dynamodbconn.DescribeTable(params) if err != nil { if awserr, ok := err.(awserr.Error); ok && awserr.Code() == "ResourceNotFoundException" { return nil } // Didn't recognize the error, so shouldn't retry. - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } if t != nil { if t.Table.TableStatus != nil && strings.ToLower(*t.Table.TableStatus) == "deleting" { log.Printf("[DEBUG] AWS Dynamo DB table (%s) is still deleting", d.Id()) - return fmt.Errorf("still deleting") + return resource.RetryableError(fmt.Errorf("still deleting")) } } // we should be not found or deleting, so error here - return resource.RetryError{Err: fmt.Errorf("[ERR] Error deleting Dynamo DB table, unexpected state: %s", t)} + return resource.NonRetryableError(err) }) // check error from retry diff --git a/builtin/providers/aws/resource_aws_ecs_cluster.go b/builtin/providers/aws/resource_aws_ecs_cluster.go index df17ee58ce13..c1a115e9d277 100644 --- a/builtin/providers/aws/resource_aws_ecs_cluster.go +++ b/builtin/providers/aws/resource_aws_ecs_cluster.go @@ -85,7 +85,7 @@ func resourceAwsEcsClusterDelete(d *schema.ResourceData, meta interface{}) error log.Printf("[DEBUG] Deleting ECS cluster %s", d.Id()) - err := resource.Retry(10*time.Minute, func() error { + err := resource.Retry(10*time.Minute, func() *resource.RetryError { out, err := conn.DeleteCluster(&ecs.DeleteClusterInput{ Cluster: aws.String(d.Id()), }) @@ -97,27 +97,27 @@ func resourceAwsEcsClusterDelete(d *schema.ResourceData, meta interface{}) error awsErr, ok := err.(awserr.Error) if !ok { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } if awsErr.Code() == "ClusterContainsContainerInstancesException" { log.Printf("[TRACE] Retrying ECS cluster %q deletion after %q", d.Id(), awsErr.Code()) - return err + return resource.RetryableError(err) } if awsErr.Code() == "ClusterContainsServicesException" { log.Printf("[TRACE] Retrying ECS cluster %q deletion after %q", d.Id(), awsErr.Code()) - return err + return resource.RetryableError(err) } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) }) if err != nil { return err } clusterName := d.Get("name").(string) - err = resource.Retry(5*time.Minute, func() error { + err = resource.Retry(5*time.Minute, func() *resource.RetryError { log.Printf("[DEBUG] Checking if ECS Cluster %q is INACTIVE", d.Id()) out, err := conn.DescribeClusters(&ecs.DescribeClustersInput{ Clusters: []*string{aws.String(clusterName)}, @@ -129,12 +129,13 @@ func resourceAwsEcsClusterDelete(d *schema.ResourceData, meta interface{}) error return nil } - return fmt.Errorf("ECS Cluster %q is still %q", clusterName, *c.Status) + return resource.RetryableError( + fmt.Errorf("ECS Cluster %q is still %q", clusterName, *c.Status)) } } if err != nil { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } return nil diff --git a/builtin/providers/aws/resource_aws_ecs_service.go b/builtin/providers/aws/resource_aws_ecs_service.go index 5ad9a61e0a16..aa629829b465 100644 --- a/builtin/providers/aws/resource_aws_ecs_service.go +++ b/builtin/providers/aws/resource_aws_ecs_service.go @@ -131,21 +131,21 @@ func resourceAwsEcsServiceCreate(d *schema.ResourceData, meta interface{}) error // See https://github.com/hashicorp/terraform/issues/2869 var out *ecs.CreateServiceOutput var err error - err = resource.Retry(2*time.Minute, func() error { + err = resource.Retry(2*time.Minute, func() *resource.RetryError { out, err = conn.CreateService(&input) if err != nil { ec2err, ok := err.(awserr.Error) if !ok { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } if ec2err.Code() == "InvalidParameterException" { log.Printf("[DEBUG] Trying to create ECS service again: %q", ec2err.Message()) - return err + return resource.RetryableError(err) } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } return nil @@ -308,7 +308,7 @@ func resourceAwsEcsServiceDelete(d *schema.ResourceData, meta interface{}) error } // Wait until the ECS service is drained - err = resource.Retry(5*time.Minute, func() error { + err = resource.Retry(5*time.Minute, func() *resource.RetryError { input := ecs.DeleteServiceInput{ Service: aws.String(d.Id()), Cluster: aws.String(d.Get("cluster").(string)), @@ -322,16 +322,16 @@ func resourceAwsEcsServiceDelete(d *schema.ResourceData, meta interface{}) error ec2err, ok := err.(awserr.Error) if !ok { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } if ec2err.Code() == "InvalidParameterException" { // Prevent "The service cannot be stopped while deployments are active." log.Printf("[DEBUG] Trying to delete ECS service again: %q", ec2err.Message()) - return err + return resource.RetryableError(err) } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) }) if err != nil { diff --git a/builtin/providers/aws/resource_aws_eip.go b/builtin/providers/aws/resource_aws_eip.go index 8bc71c9a3d44..b147b99caa9d 100644 --- a/builtin/providers/aws/resource_aws_eip.go +++ b/builtin/providers/aws/resource_aws_eip.go @@ -243,7 +243,7 @@ func resourceAwsEipDelete(d *schema.ResourceData, meta interface{}) error { } domain := resourceAwsEipDomain(d) - return resource.Retry(3*time.Minute, func() error { + return resource.Retry(3*time.Minute, func() *resource.RetryError { var err error switch domain { case "vpc": @@ -264,10 +264,10 @@ func resourceAwsEipDelete(d *schema.ResourceData, meta interface{}) error { return nil } if _, ok := err.(awserr.Error); !ok { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } - return err + return resource.RetryableError(err) }) } diff --git a/builtin/providers/aws/resource_aws_elastic_beanstalk_application.go b/builtin/providers/aws/resource_aws_elastic_beanstalk_application.go index 89fe92ae6559..8f41b0f26070 100644 --- a/builtin/providers/aws/resource_aws_elastic_beanstalk_application.go +++ b/builtin/providers/aws/resource_aws_elastic_beanstalk_application.go @@ -109,9 +109,10 @@ func resourceAwsElasticBeanstalkApplicationDelete(d *schema.ResourceData, meta i ApplicationName: aws.String(d.Id()), }) - return resource.Retry(10*time.Second, func() error { + return resource.Retry(10*time.Second, func() *resource.RetryError { if a, _ = getBeanstalkApplication(d, meta); a != nil { - return fmt.Errorf("Beanstalk Application still exists") + return resource.RetryableError( + fmt.Errorf("Beanstalk Application still exists")) } return nil }) diff --git a/builtin/providers/aws/resource_aws_elasticache_security_group.go b/builtin/providers/aws/resource_aws_elasticache_security_group.go index e28b9aff988e..1d09ee2e08f9 100644 --- a/builtin/providers/aws/resource_aws_elasticache_security_group.go +++ b/builtin/providers/aws/resource_aws_elasticache_security_group.go @@ -118,24 +118,24 @@ func resourceAwsElasticacheSecurityGroupDelete(d *schema.ResourceData, meta inte log.Printf("[DEBUG] Cache security group delete: %s", d.Id()) - return resource.Retry(5*time.Minute, func() error { + return resource.Retry(5*time.Minute, func() *resource.RetryError { _, err := conn.DeleteCacheSecurityGroup(&elasticache.DeleteCacheSecurityGroupInput{ CacheSecurityGroupName: aws.String(d.Id()), }) if err != nil { apierr, ok := err.(awserr.Error) if !ok { - return err + return resource.RetryableError(err) } log.Printf("[DEBUG] APIError.Code: %v", apierr.Code()) switch apierr.Code() { case "InvalidCacheSecurityGroupState": - return err + return resource.RetryableError(err) case "DependencyViolation": // If it is a dependency violation, we want to retry - return err + return resource.RetryableError(err) default: - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } } return nil diff --git a/builtin/providers/aws/resource_aws_elasticache_subnet_group.go b/builtin/providers/aws/resource_aws_elasticache_subnet_group.go index c521ae590568..b191f829ecbe 100644 --- a/builtin/providers/aws/resource_aws_elasticache_subnet_group.go +++ b/builtin/providers/aws/resource_aws_elasticache_subnet_group.go @@ -143,22 +143,22 @@ func resourceAwsElasticacheSubnetGroupDelete(d *schema.ResourceData, meta interf log.Printf("[DEBUG] Cache subnet group delete: %s", d.Id()) - return resource.Retry(5*time.Minute, func() error { + return resource.Retry(5*time.Minute, func() *resource.RetryError { _, err := conn.DeleteCacheSubnetGroup(&elasticache.DeleteCacheSubnetGroupInput{ CacheSubnetGroupName: aws.String(d.Id()), }) if err != nil { apierr, ok := err.(awserr.Error) if !ok { - return err + return resource.RetryableError(err) } log.Printf("[DEBUG] APIError.Code: %v", apierr.Code()) switch apierr.Code() { case "DependencyViolation": // If it is a dependency violation, we want to retry - return err + return resource.RetryableError(err) default: - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } } return nil diff --git a/builtin/providers/aws/resource_aws_elasticsearch_domain.go b/builtin/providers/aws/resource_aws_elasticsearch_domain.go index 5f4b184eea71..38f5c601b492 100644 --- a/builtin/providers/aws/resource_aws_elasticsearch_domain.go +++ b/builtin/providers/aws/resource_aws_elasticsearch_domain.go @@ -207,19 +207,20 @@ func resourceAwsElasticSearchDomainCreate(d *schema.ResourceData, meta interface d.SetId(*out.DomainStatus.ARN) log.Printf("[DEBUG] Waiting for ElasticSearch domain %q to be created", d.Id()) - err = resource.Retry(15*time.Minute, func() error { + err = resource.Retry(15*time.Minute, func() *resource.RetryError { out, err := conn.DescribeElasticsearchDomain(&elasticsearch.DescribeElasticsearchDomainInput{ DomainName: aws.String(d.Get("domain_name").(string)), }) if err != nil { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } if !*out.DomainStatus.Processing && out.DomainStatus.Endpoint != nil { return nil } - return fmt.Errorf("%q: Timeout while waiting for the domain to be created", d.Id()) + return resource.RetryableError( + fmt.Errorf("%q: Timeout while waiting for the domain to be created", d.Id())) }) if err != nil { return err @@ -366,19 +367,20 @@ func resourceAwsElasticSearchDomainUpdate(d *schema.ResourceData, meta interface return err } - err = resource.Retry(25*time.Minute, func() error { + err = resource.Retry(25*time.Minute, func() *resource.RetryError { out, err := conn.DescribeElasticsearchDomain(&elasticsearch.DescribeElasticsearchDomainInput{ DomainName: aws.String(d.Get("domain_name").(string)), }) if err != nil { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } if *out.DomainStatus.Processing == false { return nil } - return fmt.Errorf("%q: Timeout while waiting for changes to be processed", d.Id()) + return resource.RetryableError( + fmt.Errorf("%q: Timeout while waiting for changes to be processed", d.Id())) }) if err != nil { return err @@ -401,7 +403,7 @@ func resourceAwsElasticSearchDomainDelete(d *schema.ResourceData, meta interface } log.Printf("[DEBUG] Waiting for ElasticSearch domain %q to be deleted", d.Get("domain_name").(string)) - err = resource.Retry(15*time.Minute, func() error { + err = resource.Retry(15*time.Minute, func() *resource.RetryError { out, err := conn.DescribeElasticsearchDomain(&elasticsearch.DescribeElasticsearchDomainInput{ DomainName: aws.String(d.Get("domain_name").(string)), }) @@ -409,21 +411,22 @@ func resourceAwsElasticSearchDomainDelete(d *schema.ResourceData, meta interface if err != nil { awsErr, ok := err.(awserr.Error) if !ok { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } if awsErr.Code() == "ResourceNotFoundException" { return nil } - return resource.RetryError{Err: awsErr} + return resource.NonRetryableError(err) } if !*out.DomainStatus.Processing { return nil } - return fmt.Errorf("%q: Timeout while waiting for the domain to be deleted", d.Id()) + return resource.RetryableError( + fmt.Errorf("%q: Timeout while waiting for the domain to be deleted", d.Id())) }) d.SetId("") diff --git a/builtin/providers/aws/resource_aws_elb.go b/builtin/providers/aws/resource_aws_elb.go index 4601d83b56db..bbd4cc4ce8d6 100644 --- a/builtin/providers/aws/resource_aws_elb.go +++ b/builtin/providers/aws/resource_aws_elb.go @@ -253,17 +253,18 @@ func resourceAwsElbCreate(d *schema.ResourceData, meta interface{}) error { } log.Printf("[DEBUG] ELB create configuration: %#v", elbOpts) - err = resource.Retry(1*time.Minute, func() error { + err = resource.Retry(1*time.Minute, func() *resource.RetryError { _, err := elbconn.CreateLoadBalancer(elbOpts) if err != nil { if awsErr, ok := err.(awserr.Error); ok { // Check for IAM SSL Cert error, eventual consistancy issue if awsErr.Code() == "CertificateNotFound" { - return fmt.Errorf("[WARN] Error creating ELB Listener with SSL Cert, retrying: %s", err) + return resource.RetryableError( + fmt.Errorf("[WARN] Error creating ELB Listener with SSL Cert, retrying: %s", err)) } } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } return nil }) @@ -422,22 +423,22 @@ func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error { // Occasionally AWS will error with a 'duplicate listener', without any // other listeners on the ELB. Retry here to eliminate that. - err := resource.Retry(1*time.Minute, func() error { + err := resource.Retry(1*time.Minute, func() *resource.RetryError { log.Printf("[DEBUG] ELB Create Listeners opts: %s", createListenersOpts) if _, err := elbconn.CreateLoadBalancerListeners(createListenersOpts); err != nil { if awsErr, ok := err.(awserr.Error); ok { if awsErr.Code() == "DuplicateListener" { log.Printf("[DEBUG] Duplicate listener found for ELB (%s), retrying", d.Id()) - return awsErr + return resource.RetryableError(awsErr) } if awsErr.Code() == "CertificateNotFound" && strings.Contains(awsErr.Message(), "Server Certificate not found for the key: arn") { log.Printf("[DEBUG] SSL Cert not found for given ARN, retrying") - return awsErr + return resource.RetryableError(awsErr) } } // Didn't recognize the error, so shouldn't retry. - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } // Successful creation return nil diff --git a/builtin/providers/aws/resource_aws_iam_policy_attachment.go b/builtin/providers/aws/resource_aws_iam_policy_attachment.go index eea1ac396d84..8b48509a760c 100644 --- a/builtin/providers/aws/resource_aws_iam_policy_attachment.go +++ b/builtin/providers/aws/resource_aws_iam_policy_attachment.go @@ -215,7 +215,7 @@ func attachPolicyToRoles(conn *iam.IAM, roles []*string, arn string) error { } var attachmentErr error - attachmentErr = resource.Retry(2*time.Minute, func() error { + attachmentErr = resource.Retry(2*time.Minute, func() *resource.RetryError { input := iam.ListRolePoliciesInput{ RoleName: r, @@ -223,7 +223,7 @@ func attachPolicyToRoles(conn *iam.IAM, roles []*string, arn string) error { attachedPolicies, err := conn.ListRolePolicies(&input) if err != nil { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } if len(attachedPolicies.PolicyNames) > 0 { @@ -236,7 +236,7 @@ func attachPolicyToRoles(conn *iam.IAM, roles []*string, arn string) error { } if !foundPolicy { - return resource.RetryError{Err: fmt.Errorf("Policy (%q) not yet found", arn)} + return resource.NonRetryableError(err) } } diff --git a/builtin/providers/aws/resource_aws_iam_server_certificate.go b/builtin/providers/aws/resource_aws_iam_server_certificate.go index c747df619c24..678f13d07c33 100644 --- a/builtin/providers/aws/resource_aws_iam_server_certificate.go +++ b/builtin/providers/aws/resource_aws_iam_server_certificate.go @@ -161,7 +161,7 @@ func resourceAwsIAMServerCertificateRead(d *schema.ResourceData, meta interface{ func resourceAwsIAMServerCertificateDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).iamconn log.Printf("[INFO] Deleting IAM Server Certificate: %s", d.Id()) - err := resource.Retry(1*time.Minute, func() error { + err := resource.Retry(1*time.Minute, func() *resource.RetryError { _, err := conn.DeleteServerCertificate(&iam.DeleteServerCertificateInput{ ServerCertificateName: aws.String(d.Get("name").(string)), }) @@ -170,10 +170,10 @@ func resourceAwsIAMServerCertificateDelete(d *schema.ResourceData, meta interfac if awsErr, ok := err.(awserr.Error); ok { if awsErr.Code() == "DeleteConflict" && strings.Contains(awsErr.Message(), "currently in use by arn") { log.Printf("[WARN] Conflict deleting server certificate: %s, retrying", awsErr.Message()) - return err + return resource.RetryableError(err) } } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } return nil }) diff --git a/builtin/providers/aws/resource_aws_internet_gateway.go b/builtin/providers/aws/resource_aws_internet_gateway.go index 2ede96932c1a..c2561a7b8d23 100644 --- a/builtin/providers/aws/resource_aws_internet_gateway.go +++ b/builtin/providers/aws/resource_aws_internet_gateway.go @@ -114,7 +114,7 @@ func resourceAwsInternetGatewayDelete(d *schema.ResourceData, meta interface{}) log.Printf("[INFO] Deleting Internet Gateway: %s", d.Id()) - return resource.Retry(5*time.Minute, func() error { + return resource.Retry(5*time.Minute, func() *resource.RetryError { _, err := conn.DeleteInternetGateway(&ec2.DeleteInternetGatewayInput{ InternetGatewayId: aws.String(d.Id()), }) @@ -124,17 +124,17 @@ func resourceAwsInternetGatewayDelete(d *schema.ResourceData, meta interface{}) ec2err, ok := err.(awserr.Error) if !ok { - return err + return resource.RetryableError(err) } switch ec2err.Code() { case "InvalidInternetGatewayID.NotFound": return nil case "DependencyViolation": - return err // retry + return resource.RetryableError(err) // retry } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) }) } diff --git a/builtin/providers/aws/resource_aws_lambda_event_source_mapping.go b/builtin/providers/aws/resource_aws_lambda_event_source_mapping.go index 053b2adafa84..72804ac9ddd9 100644 --- a/builtin/providers/aws/resource_aws_lambda_event_source_mapping.go +++ b/builtin/providers/aws/resource_aws_lambda_event_source_mapping.go @@ -98,17 +98,15 @@ func resourceAwsLambdaEventSourceMappingCreate(d *schema.ResourceData, meta inte // // The role may exist, but the permissions may not have propagated, so we // retry - err := resource.Retry(1*time.Minute, func() error { + err := resource.Retry(1*time.Minute, func() *resource.RetryError { eventSourceMappingConfiguration, err := conn.CreateEventSourceMapping(params) if err != nil { if awserr, ok := err.(awserr.Error); ok { if awserr.Code() == "InvalidParameterValueException" { - // Retryable - return awserr + return resource.RetryableError(awserr) } } - // Not retryable - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } // No error d.Set("uuid", eventSourceMappingConfiguration.UUID) @@ -186,19 +184,16 @@ func resourceAwsLambdaEventSourceMappingUpdate(d *schema.ResourceData, meta inte Enabled: aws.Bool(d.Get("enabled").(bool)), } - err := resource.Retry(1*time.Minute, func() error { + err := resource.Retry(1*time.Minute, func() *resource.RetryError { _, err := conn.UpdateEventSourceMapping(params) if err != nil { if awserr, ok := err.(awserr.Error); ok { if awserr.Code() == "InvalidParameterValueException" { - // Retryable - return awserr + return resource.RetryableError(awserr) } } - // Not retryable - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } - // No error return nil }) diff --git a/builtin/providers/aws/resource_aws_lambda_function.go b/builtin/providers/aws/resource_aws_lambda_function.go index b12e64d1534b..bc8517d6b632 100644 --- a/builtin/providers/aws/resource_aws_lambda_function.go +++ b/builtin/providers/aws/resource_aws_lambda_function.go @@ -199,21 +199,18 @@ func resourceAwsLambdaFunctionCreate(d *schema.ResourceData, meta interface{}) e // IAM profiles can take ~10 seconds to propagate in AWS: // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#launch-instance-with-role-console // Error creating Lambda function: InvalidParameterValueException: The role defined for the task cannot be assumed by Lambda. - err := resource.Retry(1*time.Minute, func() error { + err := resource.Retry(1*time.Minute, func() *resource.RetryError { _, err := conn.CreateFunction(params) if err != nil { if awserr, ok := err.(awserr.Error); ok { if awserr.Code() == "InvalidParameterValueException" { log.Printf("[DEBUG] InvalidParameterValueException creating Lambda Function: %s", awserr) - // Retryable - return awserr + return resource.RetryableError(awserr) } } log.Printf("[DEBUG] Error creating Lambda Function: %s", err) - // Not retryable - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } - // No error return nil }) if err != nil { diff --git a/builtin/providers/aws/resource_aws_lambda_permission.go b/builtin/providers/aws/resource_aws_lambda_permission.go index 69e351568a4b..de300a7ff9f3 100644 --- a/builtin/providers/aws/resource_aws_lambda_permission.go +++ b/builtin/providers/aws/resource_aws_lambda_permission.go @@ -99,7 +99,7 @@ func resourceAwsLambdaPermissionCreate(d *schema.ResourceData, meta interface{}) log.Printf("[DEBUG] Adding new Lambda permission: %s", input) var out *lambda.AddPermissionOutput - err := resource.Retry(1*time.Minute, func() error { + err := resource.Retry(1*time.Minute, func() *resource.RetryError { var err error out, err = conn.AddPermission(&input) @@ -107,11 +107,12 @@ func resourceAwsLambdaPermissionCreate(d *schema.ResourceData, meta interface{}) if awsErr, ok := err.(awserr.Error); ok { // IAM is eventually consistent :/ if awsErr.Code() == "ResourceConflictException" { - return fmt.Errorf("[WARN] Error adding new Lambda Permission for %s, retrying: %s", - *input.FunctionName, err) + return resource.RetryableError( + fmt.Errorf("[WARN] Error adding new Lambda Permission for %s, retrying: %s", + *input.FunctionName, err)) } } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } return nil }) @@ -124,21 +125,23 @@ func resourceAwsLambdaPermissionCreate(d *schema.ResourceData, meta interface{}) d.SetId(d.Get("statement_id").(string)) - err = resource.Retry(5*time.Minute, func() error { + err = resource.Retry(5*time.Minute, func() *resource.RetryError { // IAM is eventually cosistent :/ err := resourceAwsLambdaPermissionRead(d, meta) if err != nil { if strings.HasPrefix(err.Error(), "Error reading Lambda policy: ResourceNotFoundException") { - return fmt.Errorf("[WARN] Error reading newly created Lambda Permission for %s, retrying: %s", - *input.FunctionName, err) + return resource.RetryableError( + fmt.Errorf("[WARN] Error reading newly created Lambda Permission for %s, retrying: %s", + *input.FunctionName, err)) } if strings.HasPrefix(err.Error(), "Failed to find statement \""+d.Id()) { - return fmt.Errorf("[WARN] Error reading newly created Lambda Permission statement for %s, retrying: %s", - *input.FunctionName, err) + return resource.RetryableError( + fmt.Errorf("[WARN] Error reading newly created Lambda Permission statement for %s, retrying: %s", + *input.FunctionName, err)) } log.Printf("[ERROR] An actual error occured when expecting Lambda policy to be there: %s", err) - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } return nil }) @@ -159,28 +162,28 @@ func resourceAwsLambdaPermissionRead(d *schema.ResourceData, meta interface{}) e log.Printf("[DEBUG] Looking for Lambda permission: %s", input) var out *lambda.GetPolicyOutput var statement *LambdaPolicyStatement - err := resource.Retry(1*time.Minute, func() error { + err := resource.Retry(1*time.Minute, func() *resource.RetryError { // IAM is eventually cosistent :/ var err error out, err = conn.GetPolicy(&input) if err != nil { if awsErr, ok := err.(awserr.Error); ok { if awsErr.Code() == "ResourceNotFoundException" { - return err + return resource.RetryableError(err) } } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } policyInBytes := []byte(*out.Policy) policy := LambdaPolicy{} err = json.Unmarshal(policyInBytes, &policy) if err != nil { - return resource.RetryError{Err: fmt.Errorf("Error unmarshalling Lambda policy: %s", err)} + return resource.NonRetryableError(err) } statement, err = findLambdaPolicyStatementById(&policy, d.Id()) - return err + return resource.RetryableError(err) }) if err != nil { return err @@ -244,7 +247,7 @@ func resourceAwsLambdaPermissionDelete(d *schema.ResourceData, meta interface{}) return err } - err = resource.Retry(5*time.Minute, func() error { + err = resource.Retry(5*time.Minute, func() *resource.RetryError { log.Printf("[DEBUG] Checking if Lambda permission %q is deleted", d.Id()) params := &lambda.GetPolicyInput{ @@ -262,7 +265,7 @@ func resourceAwsLambdaPermissionDelete(d *schema.ResourceData, meta interface{}) return nil } } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } if resp.Policy == nil { @@ -273,7 +276,8 @@ func resourceAwsLambdaPermissionDelete(d *schema.ResourceData, meta interface{}) policy := LambdaPolicy{} err = json.Unmarshal(policyInBytes, &policy) if err != nil { - return fmt.Errorf("Error unmarshalling Lambda policy: %s", err) + return resource.RetryableError( + fmt.Errorf("Error unmarshalling Lambda policy: %s", err)) } _, err = findLambdaPolicyStatementById(&policy, d.Id()) diff --git a/builtin/providers/aws/resource_aws_lambda_permission_test.go b/builtin/providers/aws/resource_aws_lambda_permission_test.go index 99e8f8b29780..3145e068d4f5 100644 --- a/builtin/providers/aws/resource_aws_lambda_permission_test.go +++ b/builtin/providers/aws/resource_aws_lambda_permission_test.go @@ -329,20 +329,20 @@ func testAccCheckLambdaPermissionExists(n string, statement *LambdaPolicyStateme // IAM is eventually consistent var foundStatement *LambdaPolicyStatement - err := resource.Retry(5*time.Minute, func() error { + err := resource.Retry(5*time.Minute, func() *resource.RetryError { var err error foundStatement, err = lambdaPermissionExists(rs, conn) if err != nil { if strings.HasPrefix(err.Error(), "ResourceNotFoundException") { - return err + return resource.RetryableError(err) } if strings.HasPrefix(err.Error(), "Lambda policy not found") { - return err + return resource.RetryableError(err) } if strings.HasPrefix(err.Error(), "Failed to find statement") { - return err + return resource.RetryableError(err) } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } return nil }) @@ -365,13 +365,13 @@ func testAccCheckAWSLambdaPermissionDestroy(s *terraform.State) error { } // IAM is eventually consistent - err := resource.Retry(5*time.Minute, func() error { + err := resource.Retry(5*time.Minute, func() *resource.RetryError { err := isLambdaPermissionGone(rs, conn) if err != nil { if !strings.HasPrefix(err.Error(), "Error unmarshalling Lambda policy") { - return err + return resource.RetryableError(err) } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } return nil }) diff --git a/builtin/providers/aws/resource_aws_launch_configuration.go b/builtin/providers/aws/resource_aws_launch_configuration.go index facacfad4a52..bbcf7a91d69e 100644 --- a/builtin/providers/aws/resource_aws_launch_configuration.go +++ b/builtin/providers/aws/resource_aws_launch_configuration.go @@ -428,17 +428,15 @@ func resourceAwsLaunchConfigurationCreate(d *schema.ResourceData, meta interface // IAM profiles can take ~10 seconds to propagate in AWS: // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#launch-instance-with-role-console - err := resource.Retry(30*time.Second, func() error { + err := resource.Retry(30*time.Second, func() *resource.RetryError { _, err := autoscalingconn.CreateLaunchConfiguration(&createLaunchConfigurationOpts) if err != nil { if awsErr, ok := err.(awserr.Error); ok { if awsErr.Message() == "Invalid IamInstanceProfile" { - return err + return resource.RetryableError(err) } } - return resource.RetryError{ - Err: err, - } + return resource.NonRetryableError(err) } return nil }) @@ -452,8 +450,12 @@ func resourceAwsLaunchConfigurationCreate(d *schema.ResourceData, meta interface // We put a Retry here since sometimes eventual consistency bites // us and we need to retry a few times to get the LC to load properly - return resource.Retry(30*time.Second, func() error { - return resourceAwsLaunchConfigurationRead(d, meta) + return resource.Retry(30*time.Second, func() *resource.RetryError { + err := resourceAwsLaunchConfigurationRead(d, meta) + if err != nil { + return resource.RetryableError(err) + } + return nil }) } diff --git a/builtin/providers/aws/resource_aws_network_acl.go b/builtin/providers/aws/resource_aws_network_acl.go index ede84ed958c5..7d24c07d77dd 100644 --- a/builtin/providers/aws/resource_aws_network_acl.go +++ b/builtin/providers/aws/resource_aws_network_acl.go @@ -410,7 +410,7 @@ func resourceAwsNetworkAclDelete(d *schema.ResourceData, meta interface{}) error conn := meta.(*AWSClient).ec2conn log.Printf("[INFO] Deleting Network Acl: %s", d.Id()) - return resource.Retry(5*time.Minute, func() error { + return resource.Retry(5*time.Minute, func() *resource.RetryError { _, err := conn.DeleteNetworkAcl(&ec2.DeleteNetworkAclInput{ NetworkAclId: aws.String(d.Id()), }) @@ -427,7 +427,7 @@ func resourceAwsNetworkAclDelete(d *schema.ResourceData, meta interface{}) error a, err := findNetworkAclAssociation(v.(string), conn) if err != nil { - return resource.RetryError{Err: fmt.Errorf("Dependency violation: Cannot find ACL %s: %s", d.Id(), err)} + return resource.NonRetryableError(err) } associations = append(associations, a) } else if v, ok := d.GetOk("subnet_ids"); ok { @@ -435,14 +435,14 @@ func resourceAwsNetworkAclDelete(d *schema.ResourceData, meta interface{}) error for _, i := range ids { a, err := findNetworkAclAssociation(i.(string), conn) if err != nil { - return resource.RetryError{Err: fmt.Errorf("Dependency violation: Cannot delete acl %s: %s", d.Id(), err)} + return resource.NonRetryableError(err) } associations = append(associations, a) } } defaultAcl, err := getDefaultNetworkAcl(d.Get("vpc_id").(string), conn) if err != nil { - return resource.RetryError{Err: fmt.Errorf("Dependency violation: Cannot delete acl %s: %s", d.Id(), err)} + return resource.NonRetryableError(err) } for _, a := range associations { @@ -451,10 +451,10 @@ func resourceAwsNetworkAclDelete(d *schema.ResourceData, meta interface{}) error NetworkAclId: defaultAcl.NetworkAclId, }) } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) default: // Any other error, we want to quit the retry loop immediately - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } } log.Printf("[Info] Deleted network ACL %s successfully", d.Id()) diff --git a/builtin/providers/aws/resource_aws_network_acl_rule.go b/builtin/providers/aws/resource_aws_network_acl_rule.go index 16b174d0c13f..b27f908d2b38 100644 --- a/builtin/providers/aws/resource_aws_network_acl_rule.go +++ b/builtin/providers/aws/resource_aws_network_acl_rule.go @@ -124,10 +124,10 @@ func resourceAwsNetworkAclRuleCreate(d *schema.ResourceData, meta interface{}) e // It appears it might be a while until the newly created rule is visible via the // API (see issue GH-4721). Retry the `findNetworkAclRule` function until it is // visible (which in most cases is likely immediately). - err = resource.Retry(3*time.Minute, func() error { + err = resource.Retry(3*time.Minute, func() *resource.RetryError { _, findErr := findNetworkAclRule(d, meta) if findErr != nil { - return findErr + return resource.RetryableError(findErr) } return nil diff --git a/builtin/providers/aws/resource_aws_opsworks_stack.go b/builtin/providers/aws/resource_aws_opsworks_stack.go index 19cbba9ecd0c..19e64a56af79 100644 --- a/builtin/providers/aws/resource_aws_opsworks_stack.go +++ b/builtin/providers/aws/resource_aws_opsworks_stack.go @@ -324,7 +324,7 @@ func resourceAwsOpsworksStackCreate(d *schema.ResourceData, meta interface{}) er log.Printf("[DEBUG] Creating OpsWorks stack: %s", req) var resp *opsworks.CreateStackOutput - err = resource.Retry(20*time.Minute, func() error { + err = resource.Retry(20*time.Minute, func() *resource.RetryError { var cerr error resp, cerr = client.CreateStack(req) if cerr != nil { @@ -342,10 +342,10 @@ func resourceAwsOpsworksStackCreate(d *schema.ResourceData, meta interface{}) er trustErr := "not the necessary trust relationship" if opserr.Code() == "ValidationException" && (strings.Contains(opserr.Message(), trustErr) || strings.Contains(opserr.Message(), propErr)) { log.Printf("[INFO] Waiting for service IAM role to propagate") - return cerr + return resource.RetryableError(cerr) } } - return resource.RetryError{Err: cerr} + return resource.NonRetryableError(cerr) } return nil }) diff --git a/builtin/providers/aws/resource_aws_s3_bucket.go b/builtin/providers/aws/resource_aws_s3_bucket.go index fc3c5deabb4a..6cb98db8e557 100644 --- a/builtin/providers/aws/resource_aws_s3_bucket.go +++ b/builtin/providers/aws/resource_aws_s3_bucket.go @@ -217,18 +217,19 @@ func resourceAwsS3BucketCreate(d *schema.ResourceData, meta interface{}) error { } } - err := resource.Retry(5*time.Minute, func() error { + err := resource.Retry(5*time.Minute, func() *resource.RetryError { log.Printf("[DEBUG] Trying to create new S3 bucket: %q", bucket) _, err := s3conn.CreateBucket(req) if awsErr, ok := err.(awserr.Error); ok { if awsErr.Code() == "OperationAborted" { log.Printf("[WARN] Got an error while trying to create S3 bucket %s: %s", bucket, err) - return fmt.Errorf("[WARN] Error creating S3 bucket %s, retrying: %s", - bucket, err) + return resource.RetryableError( + fmt.Errorf("[WARN] Error creating S3 bucket %s, retrying: %s", + bucket, err)) } } if err != nil { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } return nil @@ -565,18 +566,15 @@ func resourceAwsS3BucketPolicyUpdate(s3conn *s3.S3, d *schema.ResourceData) erro Policy: aws.String(policy), } - err := resource.Retry(1*time.Minute, func() error { + err := resource.Retry(1*time.Minute, func() *resource.RetryError { if _, err := s3conn.PutBucketPolicy(params); err != nil { if awserr, ok := err.(awserr.Error); ok { if awserr.Code() == "MalformedPolicy" { - // Retryable - return awserr + return resource.RetryableError(awserr) } } - // Not retryable - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } - // No error return nil }) diff --git a/builtin/providers/aws/resource_aws_security_group.go b/builtin/providers/aws/resource_aws_security_group.go index e45b7dc71db6..fba2e1604952 100644 --- a/builtin/providers/aws/resource_aws_security_group.go +++ b/builtin/providers/aws/resource_aws_security_group.go @@ -345,14 +345,14 @@ func resourceAwsSecurityGroupDelete(d *schema.ResourceData, meta interface{}) er log.Printf("[DEBUG] Security Group destroy: %v", d.Id()) - return resource.Retry(5*time.Minute, func() error { + return resource.Retry(5*time.Minute, func() *resource.RetryError { _, err := conn.DeleteSecurityGroup(&ec2.DeleteSecurityGroupInput{ GroupId: aws.String(d.Id()), }) if err != nil { ec2err, ok := err.(awserr.Error) if !ok { - return err + return resource.RetryableError(err) } switch ec2err.Code() { @@ -360,10 +360,10 @@ func resourceAwsSecurityGroupDelete(d *schema.ResourceData, meta interface{}) er return nil case "DependencyViolation": // If it is a dependency violation, we want to retry - return err + return resource.RetryableError(err) default: // Any other error, we want to quit the retry loop immediately - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } } diff --git a/builtin/providers/aws/resource_aws_sns_topic_subscription.go b/builtin/providers/aws/resource_aws_sns_topic_subscription.go index 0b29fd0aeaae..310d241f2304 100644 --- a/builtin/providers/aws/resource_aws_sns_topic_subscription.go +++ b/builtin/providers/aws/resource_aws_sns_topic_subscription.go @@ -214,7 +214,7 @@ func subscribeToSNSTopic(d *schema.ResourceData, snsconn *sns.SNS) (output *sns. log.Printf("[DEBUG] SNS create topic subscription is pending so fetching the subscription list for topic : %s (%s) @ '%s'", endpoint, protocol, topic_arn) - err = resource.Retry(time.Duration(confirmation_timeout_in_minutes)*time.Minute, func() error { + err = resource.Retry(time.Duration(confirmation_timeout_in_minutes)*time.Minute, func() *resource.RetryError { subscription, err := findSubscriptionByNonID(d, snsconn) @@ -224,10 +224,12 @@ func subscribeToSNSTopic(d *schema.ResourceData, snsconn *sns.SNS) (output *sns. } if err != nil { - return fmt.Errorf("Error fetching subscriptions for SNS topic %s: %s", topic_arn, err) + return resource.RetryableError( + fmt.Errorf("Error fetching subscriptions for SNS topic %s: %s", topic_arn, err)) } - return fmt.Errorf("Endpoint (%s) did not autoconfirm the subscription for topic %s", endpoint, topic_arn) + return resource.RetryableError( + fmt.Errorf("Endpoint (%s) did not autoconfirm the subscription for topic %s", endpoint, topic_arn)) }) if err != nil { diff --git a/builtin/providers/aws/resource_aws_vpc.go b/builtin/providers/aws/resource_aws_vpc.go index b28ed0feed6c..d4689c5ad6f8 100644 --- a/builtin/providers/aws/resource_aws_vpc.go +++ b/builtin/providers/aws/resource_aws_vpc.go @@ -308,7 +308,7 @@ func resourceAwsVpcDelete(d *schema.ResourceData, meta interface{}) error { } log.Printf("[INFO] Deleting VPC: %s", d.Id()) - return resource.Retry(5*time.Minute, func() error { + return resource.Retry(5*time.Minute, func() *resource.RetryError { _, err := conn.DeleteVpc(DeleteVpcOpts) if err == nil { return nil @@ -316,19 +316,17 @@ func resourceAwsVpcDelete(d *schema.ResourceData, meta interface{}) error { ec2err, ok := err.(awserr.Error) if !ok { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } switch ec2err.Code() { case "InvalidVpcID.NotFound": return nil case "DependencyViolation": - return err + return resource.RetryableError(err) } - return resource.RetryError{ - Err: fmt.Errorf("Error deleting VPC: %s", err), - } + return resource.NonRetryableError(fmt.Errorf("Error deleting VPC: %s", err)) }) } diff --git a/builtin/providers/aws/resource_aws_vpc_dhcp_options.go b/builtin/providers/aws/resource_aws_vpc_dhcp_options.go index d7ad02d90128..156654b495fd 100644 --- a/builtin/providers/aws/resource_aws_vpc_dhcp_options.go +++ b/builtin/providers/aws/resource_aws_vpc_dhcp_options.go @@ -180,7 +180,7 @@ func resourceAwsVpcDhcpOptionsUpdate(d *schema.ResourceData, meta interface{}) e func resourceAwsVpcDhcpOptionsDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - return resource.Retry(3*time.Minute, func() error { + return resource.Retry(3*time.Minute, func() *resource.RetryError { log.Printf("[INFO] Deleting DHCP Options ID %s...", d.Id()) _, err := conn.DeleteDhcpOptions(&ec2.DeleteDhcpOptionsInput{ DhcpOptionsId: aws.String(d.Id()), @@ -194,7 +194,7 @@ func resourceAwsVpcDhcpOptionsDelete(d *schema.ResourceData, meta interface{}) e ec2err, ok := err.(awserr.Error) if !ok { - return err + return resource.RetryableError(err) } switch ec2err.Code() { @@ -206,7 +206,7 @@ func resourceAwsVpcDhcpOptionsDelete(d *schema.ResourceData, meta interface{}) e vpcs, err2 := findVPCsByDHCPOptionsID(conn, d.Id()) if err2 != nil { log.Printf("[ERROR] %s", err2) - return err2 + return resource.RetryableError(err2) } for _, vpc := range vpcs { @@ -215,13 +215,12 @@ func resourceAwsVpcDhcpOptionsDelete(d *schema.ResourceData, meta interface{}) e DhcpOptionsId: aws.String("default"), VpcId: vpc.VpcId, }); err != nil { - return err + return resource.RetryableError(err) } } - return err //retry + return resource.RetryableError(err) default: - // Any other error, we want to quit the retry loop immediately - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } }) } diff --git a/builtin/providers/aws/resource_aws_vpn_gateway.go b/builtin/providers/aws/resource_aws_vpn_gateway.go index 4a07e716d8f3..057ee8d77afc 100644 --- a/builtin/providers/aws/resource_aws_vpn_gateway.go +++ b/builtin/providers/aws/resource_aws_vpn_gateway.go @@ -129,7 +129,7 @@ func resourceAwsVpnGatewayDelete(d *schema.ResourceData, meta interface{}) error log.Printf("[INFO] Deleting VPN gateway: %s", d.Id()) - return resource.Retry(5*time.Minute, func() error { + return resource.Retry(5*time.Minute, func() *resource.RetryError { _, err := conn.DeleteVpnGateway(&ec2.DeleteVpnGatewayInput{ VpnGatewayId: aws.String(d.Id()), }) @@ -139,17 +139,17 @@ func resourceAwsVpnGatewayDelete(d *schema.ResourceData, meta interface{}) error ec2err, ok := err.(awserr.Error) if !ok { - return err + return resource.RetryableError(err) } switch ec2err.Code() { case "InvalidVpnGatewayID.NotFound": return nil case "IncorrectState": - return err // retry + return resource.RetryableError(err) } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) }) } @@ -173,16 +173,16 @@ func resourceAwsVpnGatewayAttach(d *schema.ResourceData, meta interface{}) error VpcId: aws.String(d.Get("vpc_id").(string)), } - err := resource.Retry(30*time.Second, func() error { + err := resource.Retry(30*time.Second, func() *resource.RetryError { _, err := conn.AttachVpnGateway(req) if err != nil { if ec2err, ok := err.(awserr.Error); ok { if "InvalidVpnGatewayID.NotFound" == ec2err.Code() { - //retry - return fmt.Errorf("Gateway not found, retry for eventual consistancy") + return resource.RetryableError( + fmt.Errorf("Gateway not found, retry for eventual consistancy")) } } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } return nil }) diff --git a/builtin/providers/azure/resource_azure_instance.go b/builtin/providers/azure/resource_azure_instance.go index 1ad82c1f6276..9bb74ffff6f9 100644 --- a/builtin/providers/azure/resource_azure_instance.go +++ b/builtin/providers/azure/resource_azure_instance.go @@ -622,16 +622,17 @@ func resourceAzureInstanceDelete(d *schema.ResourceData, meta interface{}) error return err } - err = resource.Retry(15*time.Minute, func() error { + err = resource.Retry(15*time.Minute, func() *resource.RetryError { exists, err := blobClient.BlobExists( storageContainterName, fmt.Sprintf(osDiskBlobNameFormat, name), ) if err != nil { - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } if exists { - return fmt.Errorf("Instance '%s''s disk storage blob still exists.", name) + return resource.RetryableError( + fmt.Errorf("Instance '%s''s disk storage blob still exists.", name)) } return nil diff --git a/builtin/providers/azure/resource_azure_sql_database_server_firewall_rule_test.go b/builtin/providers/azure/resource_azure_sql_database_server_firewall_rule_test.go index ff64f3b95abb..e85e02412dec 100644 --- a/builtin/providers/azure/resource_azure_sql_database_server_firewall_rule_test.go +++ b/builtin/providers/azure/resource_azure_sql_database_server_firewall_rule_test.go @@ -117,11 +117,12 @@ func testAccAzureDatabaseServerFirewallRuleExists(name string, servers []string) for _, server := range servers { var rules sql.ListFirewallRulesResponse - err := resource.Retry(15*time.Minute, func() error { + err := resource.Retry(15*time.Minute, func() *resource.RetryError { var erri error rules, erri = sqlClient.ListFirewallRules(server) if erri != nil { - return fmt.Errorf("Error listing Azure Database Server Firewall Rules for Server %q: %s", server, erri) + return resource.RetryableError( + fmt.Errorf("Error listing Azure Database Server Firewall Rules for Server %q: %s", server, erri)) } return nil diff --git a/builtin/providers/heroku/resource_heroku_drain.go b/builtin/providers/heroku/resource_heroku_drain.go index 9abe3cd9a349..6735cdb0fb37 100644 --- a/builtin/providers/heroku/resource_heroku_drain.go +++ b/builtin/providers/heroku/resource_heroku_drain.go @@ -49,13 +49,13 @@ func resourceHerokuDrainCreate(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Drain create configuration: %#v, %#v", app, url) var dr *heroku.LogDrain - err := resource.Retry(2*time.Minute, func() error { + err := resource.Retry(2*time.Minute, func() *resource.RetryError { d, err := client.LogDrainCreate(app, heroku.LogDrainCreateOpts{URL: url}) if err != nil { if strings.Contains(err.Error(), retryableError) { - return err + return resource.RetryableError(err) } - return resource.RetryError{Err: err} + return resource.NonRetryableError(err) } dr = d return nil diff --git a/builtin/providers/mailgun/resource_mailgun_domain.go b/builtin/providers/mailgun/resource_mailgun_domain.go index fb180bc0c38e..c3e2f94895e0 100644 --- a/builtin/providers/mailgun/resource_mailgun_domain.go +++ b/builtin/providers/mailgun/resource_mailgun_domain.go @@ -146,11 +146,12 @@ func resourceMailgunDomainDelete(d *schema.ResourceData, meta interface{}) error } // Give the destroy a chance to take effect - return resource.Retry(1*time.Minute, func() error { + return resource.Retry(1*time.Minute, func() *resource.RetryError { _, err = client.RetrieveDomain(d.Id()) if err == nil { log.Printf("[INFO] Retrying until domain disappears...") - return fmt.Errorf("Domain seems to still exist; will check again.") + return resource.RetryableError( + fmt.Errorf("Domain seems to still exist; will check again.")) } log.Printf("[INFO] Got error looking for domain, seems gone: %s", err) return nil diff --git a/builtin/providers/vcd/resource_vcd_dnat.go b/builtin/providers/vcd/resource_vcd_dnat.go index b764e13ba7d0..4b3d159532c4 100644 --- a/builtin/providers/vcd/resource_vcd_dnat.go +++ b/builtin/providers/vcd/resource_vcd_dnat.go @@ -3,6 +3,7 @@ package vcd import ( "fmt" + "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" ) @@ -60,15 +61,16 @@ func resourceVcdDNATCreate(d *schema.ResourceData, meta interface{}) error { // constrained by out lock. If the edge gateway reurns with a busy error, wait // 3 seconds and then try again. Continue until a non-busy error or success - err = retryCall(vcdClient.MaxRetryTimeout, func() error { + err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError { task, err := edgeGateway.AddNATMapping("DNAT", d.Get("external_ip").(string), d.Get("internal_ip").(string), portString) if err != nil { - return fmt.Errorf("Error setting DNAT rules: %#v", err) + return resource.RetryableError( + fmt.Errorf("Error setting DNAT rules: %#v", err)) } - return task.WaitTaskCompletion() + return resource.RetryableError(task.WaitTaskCompletion()) }) if err != nil { @@ -119,15 +121,16 @@ func resourceVcdDNATDelete(d *schema.ResourceData, meta interface{}) error { if err != nil { return fmt.Errorf("Unable to find edge gateway: %#v", err) } - err = retryCall(vcdClient.MaxRetryTimeout, func() error { + err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError { task, err := edgeGateway.RemoveNATMapping("DNAT", d.Get("external_ip").(string), d.Get("internal_ip").(string), portString) if err != nil { - return fmt.Errorf("Error setting DNAT rules: %#v", err) + return resource.RetryableError( + fmt.Errorf("Error setting DNAT rules: %#v", err)) } - return task.WaitTaskCompletion() + return resource.RetryableError(task.WaitTaskCompletion()) }) if err != nil { return fmt.Errorf("Error completing tasks: %#v", err) diff --git a/builtin/providers/vcd/resource_vcd_firewall_rules.go b/builtin/providers/vcd/resource_vcd_firewall_rules.go index 325af24cd3c3..5a2a86ca60e5 100644 --- a/builtin/providers/vcd/resource_vcd_firewall_rules.go +++ b/builtin/providers/vcd/resource_vcd_firewall_rules.go @@ -5,6 +5,7 @@ import ( "log" "strings" + "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" types "github.com/hmrc/vmware-govcd/types/v56" ) @@ -91,16 +92,17 @@ func resourceVcdFirewallRulesCreate(d *schema.ResourceData, meta interface{}) er return fmt.Errorf("Unable to find edge gateway: %s", err) } - err = retryCall(vcdClient.MaxRetryTimeout, func() error { + err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError { edgeGateway.Refresh() firewallRules, _ := expandFirewallRules(d, edgeGateway.EdgeGateway) task, err := edgeGateway.CreateFirewallRules(d.Get("default_action").(string), firewallRules) if err != nil { log.Printf("[INFO] Error setting firewall rules: %s", err) - return fmt.Errorf("Error setting firewall rules: %#v", err) + return resource.RetryableError( + fmt.Errorf("Error setting firewall rules: %#v", err)) } - return task.WaitTaskCompletion() + return resource.RetryableError(task.WaitTaskCompletion()) }) if err != nil { return fmt.Errorf("Error completing tasks: %#v", err) diff --git a/builtin/providers/vcd/resource_vcd_network.go b/builtin/providers/vcd/resource_vcd_network.go index 389f37b6a048..113e9091c2e9 100644 --- a/builtin/providers/vcd/resource_vcd_network.go +++ b/builtin/providers/vcd/resource_vcd_network.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/hashicorp/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" types "github.com/hmrc/vmware-govcd/types/v56" ) @@ -156,8 +157,8 @@ func resourceVcdNetworkCreate(d *schema.ResourceData, meta interface{}) error { log.Printf("[INFO] NETWORK: %#v", newnetwork) - err = retryCall(vcdClient.MaxRetryTimeout, func() error { - return vcdClient.OrgVdc.CreateOrgVDCNetwork(newnetwork) + err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError { + return resource.RetryableError(vcdClient.OrgVdc.CreateOrgVDCNetwork(newnetwork)) }) if err != nil { return fmt.Errorf("Error: %#v", err) @@ -174,13 +175,13 @@ func resourceVcdNetworkCreate(d *schema.ResourceData, meta interface{}) error { } if dhcp, ok := d.GetOk("dhcp_pool"); ok { - err = retryCall(vcdClient.MaxRetryTimeout, func() error { + err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError { task, err := edgeGateway.AddDhcpPool(network.OrgVDCNetwork, dhcp.(*schema.Set).List()) if err != nil { - return fmt.Errorf("Error adding DHCP pool: %#v", err) + return resource.RetryableError(fmt.Errorf("Error adding DHCP pool: %#v", err)) } - return task.WaitTaskCompletion() + return resource.RetryableError(task.WaitTaskCompletion()) }) if err != nil { return fmt.Errorf("Error completing tasks: %#v", err) @@ -239,12 +240,13 @@ func resourceVcdNetworkDelete(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Error finding network: %#v", err) } - err = retryCall(vcdClient.MaxRetryTimeout, func() error { + err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError { task, err := network.Delete() if err != nil { - return fmt.Errorf("Error Deleting Network: %#v", err) + return resource.RetryableError( + fmt.Errorf("Error Deleting Network: %#v", err)) } - return task.WaitTaskCompletion() + return resource.RetryableError(task.WaitTaskCompletion()) }) if err != nil { return err diff --git a/builtin/providers/vcd/resource_vcd_snat.go b/builtin/providers/vcd/resource_vcd_snat.go index 4ad018c863aa..477fbd8111c6 100644 --- a/builtin/providers/vcd/resource_vcd_snat.go +++ b/builtin/providers/vcd/resource_vcd_snat.go @@ -3,6 +3,7 @@ package vcd import ( "fmt" + "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" ) @@ -51,14 +52,14 @@ func resourceVcdSNATCreate(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Unable to find edge gateway: %#v", err) } - err = retryCall(vcdClient.MaxRetryTimeout, func() error { + err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError { task, err := edgeGateway.AddNATMapping("SNAT", d.Get("internal_ip").(string), d.Get("external_ip").(string), "any") if err != nil { - return fmt.Errorf("Error setting SNAT rules: %#v", err) + return resource.RetryableError(fmt.Errorf("Error setting SNAT rules: %#v", err)) } - return task.WaitTaskCompletion() + return resource.RetryableError(task.WaitTaskCompletion()) }) if err != nil { return err @@ -106,14 +107,14 @@ func resourceVcdSNATDelete(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Unable to find edge gateway: %#v", err) } - err = retryCall(vcdClient.MaxRetryTimeout, func() error { + err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError { task, err := edgeGateway.RemoveNATMapping("SNAT", d.Get("internal_ip").(string), d.Get("external_ip").(string), "") if err != nil { - return fmt.Errorf("Error setting SNAT rules: %#v", err) + return resource.RetryableError(fmt.Errorf("Error setting SNAT rules: %#v", err)) } - return task.WaitTaskCompletion() + return resource.RetryableError(task.WaitTaskCompletion()) }) if err != nil { return err diff --git a/builtin/providers/vcd/resource_vcd_vapp.go b/builtin/providers/vcd/resource_vcd_vapp.go index 65055ce0005d..10fbdb694552 100644 --- a/builtin/providers/vcd/resource_vcd_vapp.go +++ b/builtin/providers/vcd/resource_vcd_vapp.go @@ -4,6 +4,7 @@ import ( "fmt" "log" + "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" types "github.com/hmrc/vmware-govcd/types/v56" ) @@ -133,16 +134,16 @@ func resourceVcdVAppCreate(d *schema.ResourceData, meta interface{}) error { }, } - err = retryCall(vcdClient.MaxRetryTimeout, func() error { + err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError { e := vcdClient.OrgVdc.InstantiateVAppTemplate(createvapp) if e != nil { - return fmt.Errorf("Error: %#v", e) + return resource.RetryableError(fmt.Errorf("Error: %#v", e)) } e = vcdClient.OrgVdc.Refresh() if e != nil { - return fmt.Errorf("Error: %#v", e) + return resource.RetryableError(fmt.Errorf("Error: %#v", e)) } return nil }) @@ -152,36 +153,36 @@ func resourceVcdVAppCreate(d *schema.ResourceData, meta interface{}) error { vapp, err := vcdClient.OrgVdc.FindVAppByName(d.Get("name").(string)) - err = retryCall(vcdClient.MaxRetryTimeout, func() error { + err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError { task, err := vapp.ChangeVMName(d.Get("name").(string)) if err != nil { - return fmt.Errorf("Error with vm name change: %#v", err) + return resource.RetryableError(fmt.Errorf("Error with vm name change: %#v", err)) } - return task.WaitTaskCompletion() + return resource.RetryableError(task.WaitTaskCompletion()) }) if err != nil { return fmt.Errorf("Error changing vmname: %#v", err) } - err = retryCall(vcdClient.MaxRetryTimeout, func() error { + err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError { task, err := vapp.ChangeNetworkConfig(d.Get("network_name").(string), d.Get("ip").(string)) if err != nil { - return fmt.Errorf("Error with Networking change: %#v", err) + return resource.RetryableError(fmt.Errorf("Error with Networking change: %#v", err)) } - return task.WaitTaskCompletion() + return resource.RetryableError(task.WaitTaskCompletion()) }) if err != nil { return fmt.Errorf("Error changing network: %#v", err) } if initscript, ok := d.GetOk("initscript"); ok { - err = retryCall(vcdClient.MaxRetryTimeout, func() error { + err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError { task, err := vapp.RunCustomizationScript(d.Get("name").(string), initscript.(string)) if err != nil { - return fmt.Errorf("Error with setting init script: %#v", err) + return resource.RetryableError(fmt.Errorf("Error with setting init script: %#v", err)) } - return task.WaitTaskCompletion() + return resource.RetryableError(task.WaitTaskCompletion()) }) if err != nil { return fmt.Errorf("Error completing tasks: %#v", err) @@ -246,13 +247,13 @@ func resourceVcdVAppUpdate(d *schema.ResourceData, meta interface{}) error { } if d.HasChange("memory") { - err = retryCall(vcdClient.MaxRetryTimeout, func() error { + err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError { task, err := vapp.ChangeMemorySize(d.Get("memory").(int)) if err != nil { - return fmt.Errorf("Error changing memory size: %#v", err) + return resource.RetryableError(fmt.Errorf("Error changing memory size: %#v", err)) } - return task.WaitTaskCompletion() + return resource.RetryableError(task.WaitTaskCompletion()) }) if err != nil { return err @@ -260,13 +261,13 @@ func resourceVcdVAppUpdate(d *schema.ResourceData, meta interface{}) error { } if d.HasChange("cpus") { - err = retryCall(vcdClient.MaxRetryTimeout, func() error { + err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError { task, err := vapp.ChangeCPUcount(d.Get("cpus").(int)) if err != nil { - return fmt.Errorf("Error changing cpu count: %#v", err) + return resource.RetryableError(fmt.Errorf("Error changing cpu count: %#v", err)) } - return task.WaitTaskCompletion() + return resource.RetryableError(task.WaitTaskCompletion()) }) if err != nil { return fmt.Errorf("Error completing task: %#v", err) @@ -317,18 +318,18 @@ func getVAppIPAddress(d *schema.ResourceData, meta interface{}) (string, error) vcdClient := meta.(*VCDClient) var ip string - err := retryCall(vcdClient.MaxRetryTimeout, func() error { + err := retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError { err := vcdClient.OrgVdc.Refresh() if err != nil { - return fmt.Errorf("Error refreshing vdc: %#v", err) + return resource.RetryableError(fmt.Errorf("Error refreshing vdc: %#v", err)) } vapp, err := vcdClient.OrgVdc.FindVAppByName(d.Id()) if err != nil { - return fmt.Errorf("Unable to find vapp.") + return resource.RetryableError(fmt.Errorf("Unable to find vapp.")) } ip = vapp.VApp.Children.VM[0].NetworkConnectionSection.NetworkConnection.IPAddress if ip == "" { - return fmt.Errorf("Timeout: VM did not aquire IP address") + return resource.RetryableError(fmt.Errorf("Timeout: VM did not aquire IP address")) } return nil }) @@ -348,22 +349,22 @@ func resourceVcdVAppDelete(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Error getting VApp status: %#v", err) } - _ = retryCall(vcdClient.MaxRetryTimeout, func() error { + _ = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError { task, err := vapp.Undeploy() if err != nil { - return fmt.Errorf("Error undeploying: %#v", err) + return resource.RetryableError(fmt.Errorf("Error undeploying: %#v", err)) } - return task.WaitTaskCompletion() + return resource.RetryableError(task.WaitTaskCompletion()) }) - err = retryCall(vcdClient.MaxRetryTimeout, func() error { + err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError { task, err := vapp.Delete() if err != nil { - return fmt.Errorf("Error deleting: %#v", err) + return resource.RetryableError(fmt.Errorf("Error deleting: %#v", err)) } - return task.WaitTaskCompletion() + return resource.RetryableError(task.WaitTaskCompletion()) }) return err diff --git a/helper/resource/wait.go b/helper/resource/wait.go index cf5f72f3f439..8e9f1b9d3972 100644 --- a/helper/resource/wait.go +++ b/helper/resource/wait.go @@ -5,9 +5,6 @@ import ( "time" ) -// RetryFunc is the function retried until it succeeds. -type RetryFunc func() error - // Retry is a basic wrapper around StateChangeConf that will just retry // a function until it no longer returns an error. func Retry(timeout time.Duration, f RetryFunc) error { @@ -17,25 +14,24 @@ func Retry(timeout time.Duration, f RetryFunc) error { var resultErrMu sync.Mutex c := &StateChangeConf{ - Pending: []string{"error"}, + Pending: []string{"retryableerror"}, Target: []string{"success"}, Timeout: timeout, MinTimeout: 500 * time.Millisecond, Refresh: func() (interface{}, string, error) { - err := f() - if err == nil { + rerr := f() + if rerr == nil { return 42, "success", nil } resultErrMu.Lock() defer resultErrMu.Unlock() - resultErr = err - if rerr, ok := err.(RetryError); ok { - resultErr = rerr.Err - return nil, "quit", rerr.Err - } + resultErr = rerr.Err - return 42, "error", nil + if rerr.Retryable { + return 42, "retryableerror", nil + } + return nil, "quit", rerr.Err }, } @@ -48,12 +44,30 @@ func Retry(timeout time.Duration, f RetryFunc) error { return resultErr } -// RetryError, if returned, will quit the retry immediately with the -// Err. +// RetryFunc is the function retried until it succeeds. +type RetryFunc func() *RetryError + +// RetryError is the required return type of RetryFunc. It forces client code +// to choose whether or not a given error is retryable. type RetryError struct { - Err error + Err error + Retryable bool } -func (e RetryError) Error() string { - return e.Err.Error() +// RetryableError is a helper to create a RetryError that's retryable from a +// given error. +func RetryableError(err error) *RetryError { + if err == nil { + return nil + } + return &RetryError{Err: err, Retryable: true} +} + +// NonRetryableError is a helper to create a RetryError that's _not)_ retryable +// from a given error. +func NonRetryableError(err error) *RetryError { + if err == nil { + return nil + } + return &RetryError{Err: err, Retryable: false} } diff --git a/helper/resource/wait_test.go b/helper/resource/wait_test.go index f79d27656721..3681c737b074 100644 --- a/helper/resource/wait_test.go +++ b/helper/resource/wait_test.go @@ -10,13 +10,13 @@ func TestRetry(t *testing.T) { t.Parallel() tries := 0 - f := func() error { + f := func() *RetryError { tries++ if tries == 1 { return nil } - return fmt.Errorf("error") + return RetryableError(fmt.Errorf("error")) } err := Retry(2*time.Second, f) @@ -28,8 +28,8 @@ func TestRetry(t *testing.T) { func TestRetry_timeout(t *testing.T) { t.Parallel() - f := func() error { - return fmt.Errorf("always") + f := func() *RetryError { + return RetryableError(fmt.Errorf("always")) } err := Retry(1*time.Second, f) @@ -42,8 +42,8 @@ func TestRetry_error(t *testing.T) { t.Parallel() expected := fmt.Errorf("nope") - f := func() error { - return RetryError{expected} + f := func() *RetryError { + return NonRetryableError(expected) } errCh := make(chan error)