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

r/aws_autoscaling_group: Remove deprecated tags attribute #30842

Merged
merged 4 commits into from
Apr 26, 2023
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/30842.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:breaking-change
resource/aws_autoscaling_group: Remove deprecated `tags` attribute
```
96 changes: 5 additions & 91 deletions internal/service/autoscaling/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -744,52 +744,6 @@ func ResourceGroup() *schema.Resource {

return create.StringHashcode(buf.String())
},
ConflictsWith: []string{"tags"},
},
"tags": {
Deprecated: "Use tag instead",
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeMap,
Elem: &schema.Schema{Type: schema.TypeString},
},
// Terraform 0.11 and earlier can provide incorrect type
// information during difference handling, in which boolean
// values are represented as "0" and "1". This Set function
// normalizes these hashing variations, while the Terraform
// Plugin SDK automatically suppresses the boolean/string
// difference in the value itself.
Set: func(v interface{}) int {
var buf bytes.Buffer

m, ok := v.(map[string]interface{})

if !ok {
return 0
}

if v, ok := m["key"].(string); ok {
buf.WriteString(fmt.Sprintf("%s-", v))
}

if v, ok := m["value"].(string); ok {
buf.WriteString(fmt.Sprintf("%s-", v))
}

if v, ok := m["propagate_at_launch"].(bool); ok {
buf.WriteString(fmt.Sprintf("%t-", v))
} else if v, ok := m["propagate_at_launch"].(string); ok {
if b, err := strconv.ParseBool(v); err == nil {
buf.WriteString(fmt.Sprintf("%t-", b))
} else {
buf.WriteString(fmt.Sprintf("%s-", v))
}
}

return create.StringHashcode(buf.String())
},
ConflictsWith: []string{"tag"},
},
"target_group_arns": {
Type: schema.TypeSet,
Expand Down Expand Up @@ -977,10 +931,6 @@ func resourceGroupCreate(ctx context.Context, d *schema.ResourceData, meta inter
createInput.Tags = Tags(KeyValueTags(ctx, v, asgName, TagResourceTypeGroup).IgnoreAWS())
}

if v, ok := d.GetOk("tags"); ok {
createInput.Tags = Tags(KeyValueTags(ctx, v, asgName, TagResourceTypeGroup).IgnoreAWS())
}

if v, ok := d.GetOk("target_group_arns"); ok && len(v.(*schema.Set).List()) > 0 {
createInput.TargetGroupARNs = flex.ExpandStringSet(v.(*schema.Set))
}
Expand Down Expand Up @@ -1177,31 +1127,8 @@ func resourceGroupRead(ctx context.Context, d *schema.ResourceData, meta interfa
d.Set("warm_pool", nil)
}

var tagOk, tagsOk bool
var v interface{}

// Deprecated: In a future major version, this should always set all tags except those ignored.
// Remove d.GetOk() and Only() handling.
if v, tagOk = d.GetOk("tag"); tagOk {
proposedStateTags := KeyValueTags(ctx, v, d.Id(), TagResourceTypeGroup)

if err := d.Set("tag", ListOfMap(KeyValueTags(ctx, g.Tags, d.Id(), TagResourceTypeGroup).IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Only(proposedStateTags))); err != nil {
return sdkdiag.AppendErrorf(diags, "setting tag: %s", err)
}
}

if v, tagsOk = d.GetOk("tags"); tagsOk {
proposedStateTags := KeyValueTags(ctx, v, d.Id(), TagResourceTypeGroup)

if err := d.Set("tags", ListOfStringMap(KeyValueTags(ctx, g.Tags, d.Id(), TagResourceTypeGroup).IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Only(proposedStateTags))); err != nil {
return sdkdiag.AppendErrorf(diags, "setting tags: %s", err)
}
}

if !tagOk && !tagsOk {
if err := d.Set("tag", ListOfMap(KeyValueTags(ctx, g.Tags, d.Id(), TagResourceTypeGroup).IgnoreAWS().IgnoreConfig(ignoreTagsConfig))); err != nil {
return sdkdiag.AppendErrorf(diags, "setting tag: %s", err)
}
if err := d.Set("tag", ListOfMap(KeyValueTags(ctx, g.Tags, d.Id(), TagResourceTypeGroup).IgnoreAWS().IgnoreConfig(ignoreTagsConfig))); err != nil {
return sdkdiag.AppendErrorf(diags, "setting tag: %s", err)
}

return diags
Expand All @@ -1219,7 +1146,6 @@ func resourceGroupUpdate(ctx context.Context, d *schema.ResourceData, meta inter
"load_balancers",
"suspended_processes",
"tag",
"tags",
"target_group_arns",
"warm_pool",
) {
Expand Down Expand Up @@ -1339,17 +1265,11 @@ func resourceGroupUpdate(ctx context.Context, d *schema.ResourceData, meta inter
}
}

if d.HasChanges("tag", "tags") {
if d.HasChanges("tag") {
oTagRaw, nTagRaw := d.GetChange("tag")
oTagsRaw, nTagsRaw := d.GetChange("tags")

oTag := KeyValueTags(ctx, oTagRaw, d.Id(), TagResourceTypeGroup)
oTags := KeyValueTags(ctx, oTagsRaw, d.Id(), TagResourceTypeGroup)
oldTags := Tags(oTag.Merge(oTags))

nTag := KeyValueTags(ctx, nTagRaw, d.Id(), TagResourceTypeGroup)
nTags := KeyValueTags(ctx, nTagsRaw, d.Id(), TagResourceTypeGroup)
newTags := Tags(nTag.Merge(nTags))
oldTags := Tags(KeyValueTags(ctx, oTagRaw, d.Id(), TagResourceTypeGroup))
newTags := Tags(KeyValueTags(ctx, nTagRaw, d.Id(), TagResourceTypeGroup))

if err := UpdateTags(ctx, conn, d.Id(), TagResourceTypeGroup, oldTags, newTags); err != nil {
return sdkdiag.AppendErrorf(diags, "updating tags for Auto Scaling Group (%s): %s", d.Id(), err)
Expand Down Expand Up @@ -1501,12 +1421,6 @@ func resourceGroupUpdate(ctx context.Context, d *schema.ResourceData, meta inter
}
}

if v.Contains("tag") && !v.Contains("tags") {
triggers = append(triggers, "tags") // nozero
} else if !v.Contains("tag") && v.Contains("tags") {
triggers = append(triggers, "tag") // nozero
}

shouldRefreshInstances = d.HasChanges(triggers...)
}
}
Expand Down
63 changes: 8 additions & 55 deletions internal/service/autoscaling/group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,36 +274,6 @@ func TestAccAutoScalingGroup_tags(t *testing.T) {
})
}

func TestAccAutoScalingGroup_deprecatedTags(t *testing.T) {
ctx := acctest.Context(t)
var group autoscaling.Group
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, autoscaling.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckGroupDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccGroupConfig_deprecatedTags1(rName, "key1", "value1", true),
Check: resource.ComposeTestCheckFunc(
testAccCheckGroupExists(ctx, resourceName, &group),
resource.TestCheckResourceAttr(resourceName, "tag.#", "0"),
resource.TestCheckResourceAttr(resourceName, "tags.#", "1"),
resource.TestCheckTypeSetElemNestedAttrs(resourceName, "tags.*", map[string]string{
"key": "key1",
"value": "value1",
"propagate_at_launch": "true",
}),
),
},
testAccGroupImportStep(resourceName),
},
})
}

func TestAccAutoScalingGroup_simple(t *testing.T) {
ctx := acctest.Context(t)
var group autoscaling.Group
Expand Down Expand Up @@ -1165,7 +1135,7 @@ func TestAccAutoScalingGroup_InstanceRefresh_triggers(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.preferences.#", "0"),
resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.strategy", "Rolling"),
resource.TestCheckResourceAttr(resourceName, "instance_refresh.0.triggers.#", "1"),
resource.TestCheckTypeSetElemAttr(resourceName, "instance_refresh.0.triggers.*", "tags"),
resource.TestCheckTypeSetElemAttr(resourceName, "instance_refresh.0.triggers.*", "tag"),
testAccCheckInstanceRefreshCount(ctx, &group, 1),
testAccCheckInstanceRefreshStatus(ctx, &group, 0, autoscaling.InstanceRefreshStatusPending, autoscaling.InstanceRefreshStatusInProgress),
),
Expand Down Expand Up @@ -1256,6 +1226,7 @@ func TestAccAutoScalingGroup_ALBTargetGroups_elbCapacity(t *testing.T) {
var group autoscaling.Group
resourceName := "aws_autoscaling_group.test"
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
subnetCount := 2
var tg elbv2.TargetGroup

resource.ParallelTest(t, resource.TestCase{
Expand All @@ -1265,7 +1236,7 @@ func TestAccAutoScalingGroup_ALBTargetGroups_elbCapacity(t *testing.T) {
CheckDestroy: testAccCheckGroupDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccGroupConfig_targetELBCapacity(rName),
Config: testAccGroupConfig_targetELBCapacity(rName, subnetCount),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckGroupExists(ctx, resourceName, &group),
testAccCheckLBTargetGroupExists(ctx, "aws_lb_target_group.test", &tg),
Expand Down Expand Up @@ -3738,24 +3709,6 @@ resource "aws_autoscaling_group" "test" {
`, rName, tagKey1, tagValue1, tagPropagateAtLaunch1, tagKey2, tagValue2, tagPropagateAtLaunch2))
}

func testAccGroupConfig_deprecatedTags1(rName, tagKey1, tagValue1 string, tagPropagateAtLaunch1 bool) string {
return acctest.ConfigCompose(testAccGroupConfig_launchConfigurationBase(rName, "t2.micro"), fmt.Sprintf(`
resource "aws_autoscaling_group" "test" {
availability_zones = [data.aws_availability_zones.available.names[0]]
max_size = 0
min_size = 0
name = %[1]q
launch_configuration = aws_launch_configuration.test.name

tags = [{
"key" = %[2]q
"value" = %[3]q
"propagate_at_launch" = %[4]t
}]
}
`, rName, tagKey1, tagValue1, tagPropagateAtLaunch1))
}

func testAccGroupConfig_simple(rName string) string {
return acctest.ConfigCompose(testAccGroupConfig_launchConfigurationBase(rName, "t2.micro"), fmt.Sprintf(`
resource "aws_autoscaling_group" "test" {
Expand Down Expand Up @@ -4519,7 +4472,7 @@ resource "aws_autoscaling_group" "test" {

instance_refresh {
strategy = "Rolling"
triggers = ["tags"]
triggers = ["tag"]
}

tag {
Expand Down Expand Up @@ -4622,10 +4575,10 @@ resource "aws_autoscaling_group" "test" {
`, rName, targetGroupCount))
}

func testAccGroupConfig_targetELBCapacity(rName string) string {
func testAccGroupConfig_targetELBCapacity(rName string, subnetCount int) string {
return acctest.ConfigCompose(
acctest.ConfigLatestAmazonLinuxHVMEBSAMI(),
acctest.ConfigVPCWithSubnets(rName, 2),
acctest.ConfigVPCWithSubnets(rName, subnetCount),
fmt.Sprintf(`
resource "aws_internet_gateway" "test" {
vpc_id = aws_vpc.test.id
Expand Down Expand Up @@ -4686,7 +4639,7 @@ resource "aws_route_table" "test" {
}

resource "aws_route_table_association" "test" {
count = length(aws_subnet.test[*])
count = %[2]d

subnet_id = aws_subnet.test[count.index].id
route_table_id = aws_route_table.test.id
Expand Down Expand Up @@ -4737,7 +4690,7 @@ resource "aws_autoscaling_group" "test" {
propagate_at_launch = true
}
}
`, rName))
`, rName, subnetCount))
}

func testAccGroupConfig_warmPoolEmpty(rName string) string {
Expand Down
48 changes: 24 additions & 24 deletions website/docs/r/autoscaling_group.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ resource "aws_autoscaling_group" "example" {
}
```

### Interpolated tags
### Dynamic tagging

```terraform
variable "extra_tags" {
Expand All @@ -276,28 +276,32 @@ variable "extra_tags" {
]
}

resource "aws_autoscaling_group" "bar" {
resource "aws_autoscaling_group" "test" {
name = "foobar3-terraform-test"
max_size = 5
min_size = 2
launch_configuration = aws_launch_configuration.foobar.name
vpc_zone_identifier = [aws_subnet.example1.id, aws_subnet.example2.id]

tags = concat(
[
{
"key" = "interpolation1"
"value" = "value3"
"propagate_at_launch" = true
},
{
"key" = "interpolation2"
"value" = "value4"
"propagate_at_launch" = true
},
],
var.extra_tags,
)
tag {
key = "explicit1"
value = "value1"
propagate_at_launch = true
}
tag {
key = "explicit2"
value = "value2"
propagate_at_launch = true
}

dynamic "tag" {
for_each = var.extra_tags
content {
key = tag.value.key
propagate_at_launch = tag.value.propagate_at_launch
value = tag.value.value
}
}
}
```

Expand Down Expand Up @@ -416,8 +420,7 @@ The following arguments are supported:
* `termination_policies` (Optional) List of policies to decide how the instances in the Auto Scaling Group should be terminated. The allowed values are `OldestInstance`, `NewestInstance`, `OldestLaunchConfiguration`, `ClosestToNextInstanceHour`, `OldestLaunchTemplate`, `AllocationStrategy`, `Default`. Additionally, the ARN of a Lambda function can be specified for custom termination policies.
* `suspended_processes` - (Optional) List of processes to suspend for the Auto Scaling Group. The allowed values are `Launch`, `Terminate`, `HealthCheck`, `ReplaceUnhealthy`, `AZRebalance`, `AlarmNotification`, `ScheduledActions`, `AddToLoadBalancer`, `InstanceRefresh`.
Note that if you suspend either the `Launch` or `Terminate` process types, it can prevent your Auto Scaling Group from functioning properly.
* `tag` (Optional) Configuration block(s) containing resource tags. Conflicts with `tags`. See [Tag](#tag-and-tags) below for more details.
* `tags` (Optional, **Deprecated** use `tag` instead) Set of maps containing resource tags. Conflicts with `tag`. See [Tags](#tag-and-tags) below for more details.
* `tag` (Optional) Configuration block(s) containing resource tags. See [Tag](#tag) below for more details.
* `placement_group` (Optional) Name of the placement group into which you'll launch your instances, if any.
* `metrics_granularity` - (Optional) Granularity to associate with the metrics to collect. The only valid value is `1Minute`. Default is `1Minute`.
* `enabled_metrics` - (Optional) List of metrics to collect. The allowed values are defined by the [underlying AWS API](https://docs.aws.amazon.com/autoscaling/ec2/APIReference/API_EnableMetricsCollection.html).
Expand Down Expand Up @@ -611,7 +614,7 @@ This configuration block supports the following:
* `min` - (Required) Minimum.
* `max` - (Optional) Maximum.

### tag and tags
### tag

The `tag` attribute accepts exactly one tag declaration with the following fields:

Expand All @@ -620,10 +623,7 @@ The `tag` attribute accepts exactly one tag declaration with the following field
* `propagate_at_launch` - (Required) Enables propagation of the tag to
Amazon EC2 instances launched via this ASG

To declare multiple tags additional `tag` blocks can be specified.
Alternatively the `tags` attributes can be used, which accepts a list of maps containing the above field names as keys and their respective values.
This allows the construction of dynamic lists of tags which is not possible using the single `tag` attribute.
`tag` and `tags` are mutually exclusive, only one of them can be specified.
To declare multiple tags, additional `tag` blocks can be specified.

~> **NOTE:** Other AWS APIs may automatically add special tags to their associated Auto Scaling Group for management purposes, such as ECS Capacity Providers adding the `AmazonECSManaged` tag. These generally should be included in the configuration so Terraform does not attempt to remove them and so if the `min_size` was greater than zero on creation, that these tag(s) are applied to any initial EC2 Instances in the Auto Scaling Group. If these tag(s) were missing in the Auto Scaling Group configuration on creation, affected EC2 Instances missing the tags may require manual intervention of adding the tags to ensure they work properly with the other AWS service.

Expand Down