diff --git a/.changelog/26654.txt b/.changelog/26654.txt new file mode 100644 index 00000000000..01a407b2200 --- /dev/null +++ b/.changelog/26654.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_autoscaling_attachment: Retry errors like `ValidationError: Trying to update too many Load Balancers/Target Groups at once. The limit is 10` when creating or deleting resource +``` diff --git a/internal/service/autoscaling/attachment.go b/internal/service/autoscaling/attachment.go index 33c069bbbf8..2223ec6f2fa 100644 --- a/internal/service/autoscaling/attachment.go +++ b/internal/service/autoscaling/attachment.go @@ -58,7 +58,14 @@ func resourceAttachmentCreate(d *schema.ResourceData, meta interface{}) error { LoadBalancerNames: aws.StringSlice([]string{lbName}), } - if _, err := conn.AttachLoadBalancers(input); err != nil { + _, err := tfresource.RetryWhenAWSErrMessageContains(d.Timeout(schema.TimeoutCreate), + func() (interface{}, error) { + return conn.AttachLoadBalancers(input) + }, + // ValidationError: Trying to update too many Load Balancers/Target Groups at once. The limit is 10 + ErrCodeValidationError, "update too many") + + if err != nil { return fmt.Errorf("attaching Auto Scaling Group (%s) load balancer (%s): %w", asgName, lbName, err) } } else { @@ -74,7 +81,13 @@ func resourceAttachmentCreate(d *schema.ResourceData, meta interface{}) error { TargetGroupARNs: aws.StringSlice([]string{targetGroupARN}), } - if _, err := conn.AttachLoadBalancerTargetGroups(input); err != nil { + _, err := tfresource.RetryWhenAWSErrMessageContains(d.Timeout(schema.TimeoutCreate), + func() (interface{}, error) { + return conn.AttachLoadBalancerTargetGroups(input) + }, + ErrCodeValidationError, "update too many") + + if err != nil { return fmt.Errorf("attaching Auto Scaling Group (%s) target group (%s): %w", asgName, targetGroupARN, err) } } @@ -128,7 +141,13 @@ func resourceAttachmentDelete(d *schema.ResourceData, meta interface{}) error { LoadBalancerNames: aws.StringSlice([]string{lbName}), } - if _, err := conn.DetachLoadBalancers(input); err != nil { + _, err := tfresource.RetryWhenAWSErrMessageContains(d.Timeout(schema.TimeoutCreate), + func() (interface{}, error) { + return conn.DetachLoadBalancers(input) + }, + ErrCodeValidationError, "update too many") + + if err != nil { return fmt.Errorf("detaching Auto Scaling Group (%s) load balancer (%s): %w", asgName, lbName, err) } } else { @@ -144,7 +163,13 @@ func resourceAttachmentDelete(d *schema.ResourceData, meta interface{}) error { TargetGroupARNs: aws.StringSlice([]string{targetGroupARN}), } - if _, err := conn.DetachLoadBalancerTargetGroups(input); err != nil { + _, err := tfresource.RetryWhenAWSErrMessageContains(d.Timeout(schema.TimeoutCreate), + func() (interface{}, error) { + return conn.DetachLoadBalancerTargetGroups(input) + }, + ErrCodeValidationError, "update too many") + + if err != nil { return fmt.Errorf("detaching Auto Scaling Group (%s) target group (%s): %w", asgName, targetGroupARN, err) } } diff --git a/internal/service/autoscaling/attachment_test.go b/internal/service/autoscaling/attachment_test.go index e2074bfcee3..fa5754f9932 100644 --- a/internal/service/autoscaling/attachment_test.go +++ b/internal/service/autoscaling/attachment_test.go @@ -16,8 +16,7 @@ import ( func TestAccAutoScalingAttachment_elb(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resource1Name := "aws_autoscaling_attachment.test1" - resource2Name := "aws_autoscaling_attachment.test2" + resourceName := "aws_autoscaling_attachment.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -26,32 +25,68 @@ func TestAccAutoScalingAttachment_elb(t *testing.T) { CheckDestroy: testAccCheckAttachmentDestroy, Steps: []resource.TestStep{ { - Config: testAccAttachmentConfig_elbOneAssociation(rName), + Config: testAccAttachmentConfig_elb(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAttachmentByLoadBalancerNameExists(resource1Name), + testAccCheckAttachmentByLoadBalancerNameExists(resourceName), ), }, + }, + }) +} + +func TestAccAutoScalingAttachment_albTargetGroup(t *testing.T) { + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_autoscaling_attachment.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, autoscaling.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAttachmentDestroy, + Steps: []resource.TestStep{ { - Config: testAccAttachmentConfig_elbTwoAssociations(rName), + Config: testAccAttachmentConfig_targetGroup(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAttachmentByLoadBalancerNameExists(resource1Name), - testAccCheckAttachmentByLoadBalancerNameExists(resource2Name), + testAccCheckAttachmentByTargetGroupARNExists(resourceName), ), }, + }, + }) +} + +func TestAccAutoScalingAttachment_multipleELBs(t *testing.T) { + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resource1Name := "aws_autoscaling_attachment.test.0" + resource11Name := "aws_autoscaling_attachment.test.10" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, autoscaling.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAttachmentDestroy, + Steps: []resource.TestStep{ + // Create all the ELBs first. { - Config: testAccAttachmentConfig_elbOneAssociation(rName), + Config: testAccAttachmentConfig_elbBase(rName, 11), + }, + { + Config: testAccAttachmentConfig_multipleELBs(rName, 11), Check: resource.ComposeTestCheckFunc( testAccCheckAttachmentByLoadBalancerNameExists(resource1Name), + testAccCheckAttachmentByLoadBalancerNameExists(resource11Name), ), }, + { + Config: testAccAttachmentConfig_elbBase(rName, 11), + }, }, }) } -func TestAccAutoScalingAttachment_albTargetGroup(t *testing.T) { +func TestAccAutoScalingAttachment_multipleALBTargetGroups(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resource1Name := "aws_autoscaling_attachment.test1" - resource2Name := "aws_autoscaling_attachment.test2" + resource1Name := "aws_autoscaling_attachment.test.0" + resource11Name := "aws_autoscaling_attachment.test.10" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -59,24 +94,19 @@ func TestAccAutoScalingAttachment_albTargetGroup(t *testing.T) { ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckAttachmentDestroy, Steps: []resource.TestStep{ + // Create all the target groups first. { - Config: testAccAttachmentConfig_targetGroupOneAssociation(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAttachmentByTargetGroupARNExists(resource1Name), - ), + Config: testAccAttachmentConfig_targetGroupBase(rName, 11), }, { - Config: testAccAttachmentConfig_targetGroupTwoAssociations(rName), + Config: testAccAttachmentConfig_multipleTargetGroups(rName, 11), Check: resource.ComposeTestCheckFunc( testAccCheckAttachmentByTargetGroupARNExists(resource1Name), - testAccCheckAttachmentByTargetGroupARNExists(resource2Name), + testAccCheckAttachmentByTargetGroupARNExists(resource11Name), ), }, { - Config: testAccAttachmentConfig_targetGroupOneAssociation(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAttachmentByTargetGroupARNExists(resource1Name), - ), + Config: testAccAttachmentConfig_targetGroupBase(rName, 11), }, }, }) @@ -145,10 +175,10 @@ func testAccCheckAttachmentByTargetGroupARNExists(n string) resource.TestCheckFu } } -func testAccAttachmentConfig_elbBase(rName string) string { +func testAccAttachmentConfig_elbBase(rName string, elbCount int) string { return acctest.ConfigCompose(testAccGroupConfig_launchConfigurationBase(rName, "t2.micro"), fmt.Sprintf(` resource "aws_elb" "test" { - count = 2 + count = %[2]d # "name" cannot be longer than 32 characters. name = format("%%s-%%d", substr(%[1]q, 0, 28), count.index) @@ -182,16 +212,16 @@ resource "aws_autoscaling_group" "test" { ignore_changes = [load_balancers] } } -`, rName)) +`, rName, elbCount)) } -func testAccAttachmentConfig_targetGroupBase(rName string) string { +func testAccAttachmentConfig_targetGroupBase(rName string, targetGroupCount int) string { return acctest.ConfigCompose( acctest.ConfigLatestAmazonLinuxHVMEBSAMI(), acctest.ConfigVPCWithSubnets(rName, 1), fmt.Sprintf(` resource "aws_lb_target_group" "test" { - count = 2 + count = %[2]d # "name" cannot be longer than 32 characters. name = format("%%s-%%d", substr(%[1]q, 0, 28), count.index) @@ -226,41 +256,45 @@ resource "aws_autoscaling_group" "test" { ignore_changes = [target_group_arns] } } -`, rName)) +`, rName, targetGroupCount)) } -func testAccAttachmentConfig_elbOneAssociation(rName string) string { - return acctest.ConfigCompose(testAccAttachmentConfig_elbBase(rName), ` -resource "aws_autoscaling_attachment" "test1" { +func testAccAttachmentConfig_elb(rName string) string { + return acctest.ConfigCompose(testAccAttachmentConfig_elbBase(rName, 1), ` +resource "aws_autoscaling_attachment" "test" { autoscaling_group_name = aws_autoscaling_group.test.id elb = aws_elb.test[0].id } `) } -func testAccAttachmentConfig_elbTwoAssociations(rName string) string { - return acctest.ConfigCompose(testAccAttachmentConfig_elbOneAssociation(rName), ` -resource "aws_autoscaling_attachment" "test2" { +func testAccAttachmentConfig_multipleELBs(rName string, n int) string { + return acctest.ConfigCompose(testAccAttachmentConfig_elbBase(rName, n), fmt.Sprintf(` +resource "aws_autoscaling_attachment" "test" { + count = %[1]d + autoscaling_group_name = aws_autoscaling_group.test.id - elb = aws_elb.test[1].id + elb = aws_elb.test[count.index].id } -`) +`, n)) } -func testAccAttachmentConfig_targetGroupOneAssociation(rName string) string { - return acctest.ConfigCompose(testAccAttachmentConfig_targetGroupBase(rName), ` -resource "aws_autoscaling_attachment" "test1" { +func testAccAttachmentConfig_targetGroup(rName string) string { + return acctest.ConfigCompose(testAccAttachmentConfig_targetGroupBase(rName, 1), ` +resource "aws_autoscaling_attachment" "test" { autoscaling_group_name = aws_autoscaling_group.test.id lb_target_group_arn = aws_lb_target_group.test[0].arn } `) } -func testAccAttachmentConfig_targetGroupTwoAssociations(rName string) string { - return acctest.ConfigCompose(testAccAttachmentConfig_targetGroupOneAssociation(rName), ` -resource "aws_autoscaling_attachment" "test2" { +func testAccAttachmentConfig_multipleTargetGroups(rName string, n int) string { + return acctest.ConfigCompose(testAccAttachmentConfig_targetGroupBase(rName, n), fmt.Sprintf(` +resource "aws_autoscaling_attachment" "test" { + count = %[1]d + autoscaling_group_name = aws_autoscaling_group.test.id - alb_target_group_arn = aws_lb_target_group.test[1].arn + lb_target_group_arn = aws_lb_target_group.test[0].arn } -`) +`, n)) }