Skip to content

Commit

Permalink
Add Alarm Specification feature to auto scaling groups instance refre…
Browse files Browse the repository at this point in the history
…sh preferences
  • Loading branch information
siddhartha.yashwanth committed Apr 17, 2024
1 parent a680053 commit 5bd622b
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/36954.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_autoscaling_group: Add `alarm_specification` to the `instance_refresh.preferences` configuration block
```
30 changes: 30 additions & 0 deletions internal/service/autoscaling/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -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": {

Check failure on line 245 in internal/service/autoscaling/group.go

View workflow job for this annotation

GitHub Actions / providerlint

S001: schema of TypeList or TypeSet should include Elem

Check failure on line 245 in internal/service/autoscaling/group.go

View workflow job for this annotation

GitHub Actions / providerlint

S013: schema should configure one of Computed, Optional, or Required
Type: schema.TypeList,
},
},
},
},
"checkpoint_delay": {
Type: nullable.TypeNullableInt,
Optional: true,
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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))

Expand Down
102 changes: 102 additions & 0 deletions internal/service/autoscaling/group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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", ""),
Expand All @@ -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", ""),
Expand All @@ -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", ""),
Expand All @@ -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", ""),
Expand All @@ -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", ""),
Expand All @@ -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"),
Expand Down Expand Up @@ -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", ""),
Expand All @@ -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", ""),
Expand Down Expand Up @@ -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" {
Expand Down
2 changes: 2 additions & 0 deletions website/docs/r/autoscaling_group.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down

0 comments on commit 5bd622b

Please sign in to comment.