Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resource/aws_lb_target_group: Handle read-after-create eventual consistency #18634

Merged
merged 2 commits into from
Apr 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/18634.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
resource/aws_lb_target_group: Handle read-after-create eventual consistency
```
36 changes: 36 additions & 0 deletions aws/internal/service/elbv2/finder/finder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package finder

import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/elbv2"
)

func TargetGroupByARN(conn *elbv2.ELBV2, arn string) (*elbv2.TargetGroup, error) {
input := &elbv2.DescribeTargetGroupsInput{
TargetGroupArns: aws.StringSlice([]string{arn}),
}

output, err := conn.DescribeTargetGroups(input)

if err != nil {
return nil, err
}

if output == nil {
return nil, nil
}

for _, targetGroup := range output.TargetGroups {
if targetGroup == nil {
continue
}

if aws.StringValue(targetGroup.TargetGroupArn) != arn {
continue
}

return targetGroup, nil
}

return nil, nil
}
2 changes: 2 additions & 0 deletions aws/internal/service/elbv2/waiter/waiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ const (
LoadBalancerListenerCreateTimeout = 5 * time.Minute
LoadBalancerListenerReadTimeout = 2 * time.Minute
LoadBalancerListenerUpdateTimeout = 5 * time.Minute

PropagationTimeout = 2 * time.Minute
)

// LoadBalancerActive waits for a Load Balancer to return active
Expand Down
55 changes: 44 additions & 11 deletions aws/resource_aws_lb_target_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/elbv2/finder"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/elbv2/waiter"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource"
)
Expand Down Expand Up @@ -371,23 +372,55 @@ func resourceAwsLbTargetGroupCreate(d *schema.ResourceData, meta interface{}) er
func resourceAwsLbTargetGroupRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).elbv2conn

resp, err := conn.DescribeTargetGroups(&elbv2.DescribeTargetGroupsInput{
TargetGroupArns: aws.StringSlice([]string{d.Id()}),
var targetGroup *elbv2.TargetGroup

err := resource.Retry(waiter.PropagationTimeout, func() *resource.RetryError {
var err error

targetGroup, err = finder.TargetGroupByARN(conn, d.Id())

if d.IsNewResource() && tfawserr.ErrCodeEquals(err, elbv2.ErrCodeTargetGroupNotFoundException) {
return resource.RetryableError(err)
}

if err != nil {
return resource.NonRetryableError(err)
}

if d.IsNewResource() && targetGroup == nil {
return resource.RetryableError(&resource.NotFoundError{
LastError: fmt.Errorf("ELBv2 Target Group (%s) not found", d.Id()),
})
}

return nil
})

if tfresource.TimedOut(err) {
targetGroup, err = finder.TargetGroupByARN(conn, d.Id())
}

if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, elbv2.ErrCodeTargetGroupNotFoundException) {
log.Printf("[WARN] ELBv2 Target Group (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
if isAWSErr(err, elbv2.ErrCodeTargetGroupNotFoundException, "") {
log.Printf("[DEBUG] DescribeTargetGroups - removing %s from state", d.Id())
d.SetId("")
return nil
}
return fmt.Errorf("error retrieving Target Group: %w", err)
return fmt.Errorf("error reading ELBv2 Target Group (%s): %w", d.Id(), err)
}

if len(resp.TargetGroups) != 1 {
return fmt.Errorf("error retrieving Target Group %q", d.Id())
if targetGroup == nil {
if d.IsNewResource() {
return fmt.Errorf("error reading ELBv2 Target Group (%s): not found after creation", d.Id())
}

log.Printf("[WARN] ELBv2 Target Group (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

return flattenAwsLbTargetGroupResource(d, meta, resp.TargetGroups[0])
return flattenAwsLbTargetGroupResource(d, meta, targetGroup)
}

func resourceAwsLbTargetGroupUpdate(d *schema.ResourceData, meta interface{}) error {
Expand Down