diff --git a/.changelog/36954.txt b/.changelog/36954.txt new file mode 100644 index 000000000000..4b1fb3ff3bd8 --- /dev/null +++ b/.changelog/36954.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_autoscaling_group: Add `alarm_specification` to the `instance_refresh.preferences` configuration block +``` \ No newline at end of file diff --git a/internal/service/autoscaling/group.go b/internal/service/autoscaling/group.go index 27eafb9b4a99..41bbdc3a7c46 100644 --- a/internal/service/autoscaling/group.go +++ b/internal/service/autoscaling/group.go @@ -236,6 +236,18 @@ func resourceGroup() *schema.Resource { Type: schema.TypeBool, Optional: true, }, + "alarm_specification": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "alarms": { + Type: schema.TypeList, + }, + }, + }, + }, "checkpoint_delay": { Type: nullable.TypeNullableInt, Optional: true, @@ -3306,6 +3318,10 @@ func expandRefreshPreferences(tfMap map[string]interface{}) *awstypes.RefreshPre apiObject.AutoRollback = aws.Bool(v) } + if v, ok := tfMap["alarm_specification"].([]interface{}); ok && len(v) > 0 { + apiObject.AlarmSpecification = expandRefreshAlarmSpecification(v[0].(map[string]interface{})) + } + if v, ok := tfMap["checkpoint_delay"].(string); ok { if v, null, _ := nullable.Int(v).Value(); !null { apiObject.CheckpointDelay = aws.Int32(int32(v)) @@ -3345,6 +3361,20 @@ func expandRefreshPreferences(tfMap map[string]interface{}) *awstypes.RefreshPre return apiObject } +func expandRefreshAlarmSpecification(tfMap map[string]interface{}) *awstypes.AlarmSpecification { + if tfMap == nil { + return nil + } + + apiObject := &awstypes.AlarmSpecification{} + + if v, ok := tfMap["alarms"].([]interface{}); ok { + apiObject.Alarms = flex.ExpandStringValueList(v) + } + + return apiObject +} + func expandVPCZoneIdentifiers(tfList []interface{}) *string { vpcZoneIDs := make([]string, len(tfList)) diff --git a/internal/service/autoscaling/group_test.go b/internal/service/autoscaling/group_test.go index a29b8701b3a7..63fd3ea4d869 100644 --- a/internal/service/autoscaling/group_test.go +++ b/internal/service/autoscaling/group_test.go @@ -1400,6 +1400,7 @@ func TestAccAutoScalingGroup_InstanceRefresh_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "instance_refresh.#", "1"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.#", "1"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.auto_rollback", "false"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.alarm_specification.#", "0"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_delay", ""), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_percentages.#", "0"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.instance_warmup", ""), @@ -1419,6 +1420,7 @@ func TestAccAutoScalingGroup_InstanceRefresh_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "instance_refresh.#", "1"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.#", "1"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.auto_rollback", "false"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.alarm_specification.#", "0"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_delay", ""), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_percentages.#", "0"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.instance_warmup", ""), @@ -1438,6 +1440,7 @@ func TestAccAutoScalingGroup_InstanceRefresh_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "instance_refresh.#", "1"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.#", "1"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.auto_rollback", "false"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.alarm_specification.#", "0"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_delay", ""), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_percentages.#", "0"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.instance_warmup", ""), @@ -1457,6 +1460,7 @@ func TestAccAutoScalingGroup_InstanceRefresh_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "instance_refresh.#", "1"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.#", "1"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.auto_rollback", "false"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.alarm_specification.#", "0"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_delay", ""), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_percentages.#", "0"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.instance_warmup", ""), @@ -1476,6 +1480,7 @@ func TestAccAutoScalingGroup_InstanceRefresh_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "instance_refresh.#", "1"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.#", "1"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.auto_rollback", "false"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.alarm_specification.#", "0"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_delay", ""), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_percentages.#", "0"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.instance_warmup", ""), @@ -1495,6 +1500,7 @@ func TestAccAutoScalingGroup_InstanceRefresh_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "instance_refresh.#", "1"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.#", "1"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.auto_rollback", "false"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.alarm_specification.#", "0"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_delay", "25"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_percentages.#", "5"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_percentages.0", "1"), @@ -1626,6 +1632,7 @@ func TestAccAutoScalingGroup_InstanceRefresh_autoRollback(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "instance_refresh.#", "1"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.#", "1"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.auto_rollback", "true"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.alarm_specification.#", "0"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_delay", ""), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_percentages.#", "0"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.instance_warmup", ""), @@ -1644,6 +1651,67 @@ func TestAccAutoScalingGroup_InstanceRefresh_autoRollback(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "instance_refresh.#", "1"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.#", "1"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.auto_rollback", "true"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.alarm_specification.#", "0"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_delay", ""), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_percentages.#", "0"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.instance_warmup", ""), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.min_healthy_percentage", "0"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.scale_in_protected_instances", "Ignore"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.skip_matching", "false"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.standby_instances", "Ignore"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.strategy", "Rolling"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.triggers.#", "0"), + ), + }, + }, + }) +} + +func TestAccAutoScalingGroup_InstanceRefresh_alarmSpecification(t *testing.T) { + ctx := acctest.Context(t) + var group awstypes.AutoScalingGroup + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_autoscaling_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.AutoScalingServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccGroupConfig_instanceRefreshAlarmSpecification(rName, "t2.micro"), + Check: resource.ComposeTestCheckFunc( + testAccCheckGroupExists(ctx, resourceName, &group), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.auto_rollback", "false"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.alarm_specification.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.alarm_specification.0.alarms.#", "2"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.alarm_specification.0.alarms.0", "my-alarm-1"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.alarm_specification.0.alarms.1", "my-alarm-2"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_delay", ""), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_percentages.#", "0"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.instance_warmup", ""), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.min_healthy_percentage", "0"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.scale_in_protected_instances", "Ignore"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.skip_matching", "false"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.standby_instances", "Ignore"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.strategy", "Rolling"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.triggers.#", "0"), + ), + }, + { + Config: testAccGroupConfig_instanceRefreshAlarmSpecification(rName, "t3.micro"), + Check: resource.ComposeTestCheckFunc( + testAccCheckGroupExists(ctx, resourceName, &group), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.auto_rollback", "false"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.alarm_specification.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.alarm_specification.0.alarms.#", "2"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.alarm_specification.0.alarms.0", "my-alarm-1"), + resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.alarm_specification.0.alarms.1", "my-alarm-2"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_delay", ""), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.checkpoint_percentages.#", "0"), resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.0.instance_warmup", ""), @@ -5268,6 +5336,40 @@ resource "aws_autoscaling_group" "test" { `, rName)) } +func testAccGroupConfig_instanceRefreshAlarmSpecification(rName, instanceType string) string { + return acctest.ConfigCompose(testAccGroupConfig_launchTemplateBase(rName, instanceType), fmt.Sprintf(` +resource "aws_autoscaling_group" "test" { + availability_zones = [data.aws_availability_zones.available.names[0]] + name = %[1]q + max_size = 2 + min_size = 1 + desired_capacity = 1 + + launch_template { + id = aws_launch_template.test.id + version = aws_launch_template.test.default_version + } + + instance_refresh { + strategy = "Rolling" + + preferences { + min_healthy_percentage = 0 + alarm_specification { + alarms = [ "my-alarm-1", "my-alarm-2" ] + } + } + } + + tag { + key = "Name" + value = %[1]q + propagate_at_launch = true + } +} +`, rName)) +} + func testAccGroupConfig_instanceRefreshFull(rName string) string { return acctest.ConfigCompose(testAccGroupConfig_launchConfigurationBase(rName, "t3.nano"), fmt.Sprintf(` resource "aws_autoscaling_group" "test" { diff --git a/website/docs/r/autoscaling_group.html.markdown b/website/docs/r/autoscaling_group.html.markdown index 80cf416c0430..1ed55aab69dd 100644 --- a/website/docs/r/autoscaling_group.html.markdown +++ b/website/docs/r/autoscaling_group.html.markdown @@ -666,6 +666,8 @@ This configuration block supports the following: - `min_healthy_percentage` - (Optional) Amount of capacity in the Auto Scaling group that must remain healthy during an instance refresh to allow the operation to continue, as a percentage of the desired capacity of the Auto Scaling group. Defaults to `90`. - `skip_matching` - (Optional) Replace instances that already have your desired configuration. Defaults to `false`. - `auto_rollback` - (Optional) Automatically rollback if instance refresh fails. Defaults to `false`. This option may only be set to `true` when specifying a `launch_template` or `mixed_instances_policy`. + - `alarm_specification` - (Optional) Alarm Specification for Instance Refresh. + - `alarms` - (Required) List of Cloudwatch alarms. If any of these alarms goes into ALARM state, Instance Refresh is failed. - `scale_in_protected_instances` - (Optional) Behavior when encountering instances protected from scale in are found. Available behaviors are `Refresh`, `Ignore`, and `Wait`. Default is `Ignore`. - `standby_instances` - (Optional) Behavior when encountering instances in the `Standby` state in are found. Available behaviors are `Terminate`, `Ignore`, and `Wait`. Default is `Ignore`. - `triggers` - (Optional) Set of additional property names that will trigger an Instance Refresh. A refresh will always be triggered by a change in any of `launch_configuration`, `launch_template`, or `mixed_instances_policy`.