diff --git a/.changelog/34086.txt b/.changelog/34086.txt new file mode 100644 index 00000000000..30c2b1ab274 --- /dev/null +++ b/.changelog/34086.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_autoscaling_group: Fix error when `launch_template` name is updated. +``` \ No newline at end of file diff --git a/internal/service/autoscaling/consts.go b/internal/service/autoscaling/consts.go index 84b7d8a2dff..2c3ccd07169 100644 --- a/internal/service/autoscaling/consts.go +++ b/internal/service/autoscaling/consts.go @@ -85,3 +85,7 @@ const ( TrafficSourceStateRemoving = "Removing" TrafficSourceStateRemoved = "Removed" ) + +const ( + launchTemplateIDUnknown = "unknown" +) diff --git a/internal/service/autoscaling/group.go b/internal/service/autoscaling/group.go index 90e01c8a1cc..ccd6598eca9 100644 --- a/internal/service/autoscaling/group.go +++ b/internal/service/autoscaling/group.go @@ -253,6 +253,7 @@ func ResourceGroup() *schema.Resource { Type: schema.TypeList, MaxItems: 1, Optional: true, + Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "id": { @@ -309,6 +310,7 @@ func ResourceGroup() *schema.Resource { "mixed_instances_policy": { Type: schema.TypeList, Optional: true, + Computed: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -396,6 +398,7 @@ func ResourceGroup() *schema.Resource { "override": { Type: schema.TypeList, Optional: true, + Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "instance_requirements": { @@ -865,16 +868,63 @@ func ResourceGroup() *schema.Resource { }, CustomizeDiff: customdiff.Sequence( - customdiff.ComputedIf("launch_template.0.id", func(_ context.Context, diff *schema.ResourceDiff, meta interface{}) bool { - return diff.HasChange("launch_template.0.name") - }), - customdiff.ComputedIf("launch_template.0.name", func(_ context.Context, diff *schema.ResourceDiff, meta interface{}) bool { - return diff.HasChange("launch_template.0.id") - }), + launchTemplateCustomDiff("launch_template", "launch_template.0.name"), + launchTemplateCustomDiff("mixed_instances_policy", "mixed_instances_policy.0.launch_template.0.launch_template_specification.0.launch_template_name"), + launchTemplateCustomDiff("mixed_instances_policy", "mixed_instances_policy.0.launch_template.0.override"), ), } } +func launchTemplateCustomDiff(baseAttribute, subAttribute string) schema.CustomizeDiffFunc { + return func(_ context.Context, diff *schema.ResourceDiff, _ interface{}) error { + if diff.HasChange(subAttribute) { + n := diff.Get(baseAttribute) + ba, ok := n.([]interface{}) + if !ok { + return nil + } + + if baseAttribute == "launch_template" { + launchTemplate := ba[0].(map[string]interface{}) + launchTemplate["id"] = launchTemplateIDUnknown + + if err := diff.SetNew(baseAttribute, ba); err != nil { + return err + } + } + + if baseAttribute == "mixed_instances_policy" && !strings.Contains(subAttribute, "override") { + launchTemplate := ba[0].(map[string]interface{})["launch_template"].([]interface{})[0].(map[string]interface{})["launch_template_specification"].([]interface{})[0] + launchTemplateSpecification := launchTemplate.(map[string]interface{}) + launchTemplateSpecification["launch_template_id"] = launchTemplateIDUnknown + + if err := diff.SetNew(baseAttribute, ba); err != nil { + return err + } + } + + if baseAttribute == "mixed_instances_policy" && strings.Contains(subAttribute, "override") { + launchTemplate := ba[0].(map[string]interface{})["launch_template"].([]interface{})[0].(map[string]interface{})["override"].([]interface{}) + + for i := range launchTemplate { + key := fmt.Sprintf("mixed_instances_policy.0.launch_template.0.override.%d.launch_template_specification.0.launch_template_name", i) + + if diff.HasChange(key) { + launchTemplateSpecification := launchTemplate[i].(map[string]interface{})["launch_template_specification"].([]interface{})[0].(map[string]interface{}) + launchTemplateSpecification["launch_template_id"] = launchTemplateIDUnknown + } + } + + if err := diff.SetNew(baseAttribute, ba); err != nil { + return err + } + } + } + + return nil + } +} + func resourceGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).AutoScalingConn(ctx) @@ -3035,7 +3085,7 @@ func expandLaunchTemplateSpecificationForMixedInstancesPolicy(tfMap map[string]i // API returns both ID and name, which Terraform saves to state. Next update returns: // ValidationError: Valid requests must contain either launchTemplateId or LaunchTemplateName // Prefer the ID if we have both. - if v, ok := tfMap["launch_template_id"]; ok && v != "" { + if v, ok := tfMap["launch_template_id"]; ok && v != "" && v != launchTemplateIDUnknown { apiObject.LaunchTemplateId = aws.String(v.(string)) } else if v, ok := tfMap["launch_template_name"]; ok && v != "" { apiObject.LaunchTemplateName = aws.String(v.(string)) @@ -3057,7 +3107,7 @@ func expandLaunchTemplateSpecification(tfMap map[string]interface{}) *autoscalin // DescribeAutoScalingGroups returns both name and id but LaunchTemplateSpecification // allows only one of them to be set. - if v, ok := tfMap["id"]; ok && v != "" { + if v, ok := tfMap["id"]; ok && v != "" && v != launchTemplateIDUnknown { apiObject.LaunchTemplateId = aws.String(v.(string)) } else if v, ok := tfMap["name"]; ok && v != "" { apiObject.LaunchTemplateName = aws.String(v.(string)) diff --git a/internal/service/autoscaling/group_test.go b/internal/service/autoscaling/group_test.go index e16b9429a31..af591cc2c91 100644 --- a/internal/service/autoscaling/group_test.go +++ b/internal/service/autoscaling/group_test.go @@ -1098,6 +1098,7 @@ func TestAccAutoScalingGroup_LaunchTemplate_update(t *testing.T) { ctx := acctest.Context(t) var group autoscaling.Group rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + launchTemplateNameUpdated := fmt.Sprintf("%s_updated", rName) resourceName := "aws_autoscaling_group.test" resource.ParallelTest(t, resource.TestCase{ @@ -1127,7 +1128,7 @@ func TestAccAutoScalingGroup_LaunchTemplate_update(t *testing.T) { ), }, { - Config: testAccGroupConfig_launchTemplateName(rName), + Config: testAccGroupConfig_launchTemplateName(rName, rName), Check: resource.ComposeTestCheckFunc( testAccCheckGroupExists(ctx, resourceName, &group), resource.TestCheckResourceAttr(resourceName, "launch_configuration", ""), @@ -1159,6 +1160,17 @@ func TestAccAutoScalingGroup_LaunchTemplate_update(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "launch_template.0.version", "aws_launch_template.test", "default_version"), ), }, + { + Config: testAccGroupConfig_launchTemplateName(rName, launchTemplateNameUpdated), + Check: resource.ComposeTestCheckFunc( + testAccCheckGroupExists(ctx, resourceName, &group), + resource.TestCheckResourceAttr(resourceName, "launch_configuration", ""), + resource.TestCheckResourceAttr(resourceName, "launch_template.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template.0.id", "aws_launch_template.test", "id"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template.0.name", "aws_launch_template.test", "name"), + resource.TestCheckResourceAttr(resourceName, "launch_template.0.version", ""), + ), + }, }, }) } @@ -1974,7 +1986,7 @@ func TestAccAutoScalingGroup_MixedInstancesPolicyLaunchTemplateLaunchTemplateSpe var group autoscaling.Group resourceName := "aws_autoscaling_group.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - + launchTemplateNameUpdated := fmt.Sprintf("%s_updated", rName) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, autoscaling.EndpointsID), @@ -1982,7 +1994,7 @@ func TestAccAutoScalingGroup_MixedInstancesPolicyLaunchTemplateLaunchTemplateSpe CheckDestroy: testAccCheckGroupDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccGroupConfig_mixedInstancesPolicyLaunchTemplateLaunchTemplateSpecificationLaunchTemplateName(rName), + Config: testAccGroupConfig_mixedInstancesPolicyLaunchTemplateLaunchTemplateSpecificationLaunchTemplateName(rName, rName), Check: resource.ComposeTestCheckFunc( testAccCheckGroupExists(ctx, resourceName, &group), resource.TestCheckResourceAttr(resourceName, "mixed_instances_policy.#", "1"), @@ -1992,6 +2004,16 @@ func TestAccAutoScalingGroup_MixedInstancesPolicyLaunchTemplateLaunchTemplateSpe ), }, testAccGroupImportStep(resourceName), + { + Config: testAccGroupConfig_mixedInstancesPolicyLaunchTemplateLaunchTemplateSpecificationLaunchTemplateName(rName, launchTemplateNameUpdated), + Check: resource.ComposeTestCheckFunc( + testAccCheckGroupExists(ctx, resourceName, &group), + resource.TestCheckResourceAttr(resourceName, "mixed_instances_policy.#", "1"), + resource.TestCheckResourceAttr(resourceName, "mixed_instances_policy.0.launch_template.#", "1"), + resource.TestCheckResourceAttr(resourceName, "mixed_instances_policy.0.launch_template.0.launch_template_specification.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "mixed_instances_policy.0.launch_template.0.launch_template_specification.0.launch_template_name"), + ), + }, }, }) } @@ -4801,8 +4823,8 @@ resource "aws_autoscaling_group" "test" { `, rName)) } -func testAccGroupConfig_launchTemplateName(rName string) string { - return acctest.ConfigCompose(testAccGroupConfig_launchTemplateBase(rName, "t2.micro"), fmt.Sprintf(` +func testAccGroupConfig_launchTemplateName(rName, launchTemplateName string) string { + return acctest.ConfigCompose(testAccGroupConfig_launchTemplateBase(launchTemplateName, "t2.micro"), fmt.Sprintf(` resource "aws_autoscaling_group" "test" { availability_zones = [data.aws_availability_zones.available.names[0]] max_size = 0 @@ -5718,8 +5740,8 @@ resource "aws_autoscaling_group" "test" { `, rName, spotMaxPrice)) } -func testAccGroupConfig_mixedInstancesPolicyLaunchTemplateLaunchTemplateSpecificationLaunchTemplateName(rName string) string { - return acctest.ConfigCompose(testAccGroupConfig_launchTemplateBase(rName, "t3.micro"), fmt.Sprintf(` +func testAccGroupConfig_mixedInstancesPolicyLaunchTemplateLaunchTemplateSpecificationLaunchTemplateName(rName, launchTemplateName string) string { + return acctest.ConfigCompose(testAccGroupConfig_launchTemplateBase(launchTemplateName, "t3.micro"), fmt.Sprintf(` resource "aws_autoscaling_group" "test" { availability_zones = [data.aws_availability_zones.available.names[0]] desired_capacity = 0