hashicorp / terraform-provider-aws

The AWS Provider enables Terraform to manage AWS resources.
https://registry.terraform.io/providers/hashicorp/aws
Mozilla Public License 2.0
9.8k stars 9.15k forks source link

[Bug]: `aws_s3_lifecycle_configuration` rules show diffs when order changes #34645

Open tjstansell opened 10 months ago

tjstansell commented 10 months ago

Terraform Core Version

1.6.4

AWS Provider Version

5.26.0

Affected Resource(s)

aws_s3_bucket_lifecycle_configuration

Expected Behavior

When I update the list of rules for a lifecycle configuration, the diff looks at the list of rules as an ordered list. There is no actual ordering to the rules, however, and should be treated as a ListSet instead. If I have 3 rules and then add a 4th rule at the top, it shows diffs for any rules moving position in the list instead of just showing that it is adding a new rule.

Actual Behavior

When the rule ordering changes, it shows diffs for all rules instead of recognizing that the rules simply got reordered. When code gets refactored and the order happens to change, it is very difficult to parse the plan output to verify that the changes are what are expected. The schema for rules uses a TypeList when it seems they should instead be a TypeSet.

Relevant Error/Panic Output Snippet

No response

Terraform Configuration Files

Original config:

resource "aws_s3_bucket" "this" {
  bucket        = "my-test-lifecycle-bucket"
  force_destroy = true
}

resource "aws_s3_bucket_lifecycle_configuration" "this" {
  bucket = aws_s3_bucket.this.id
  rule {
    id     = "rule1"
    status = "Enabled"
    filter {
      prefix = "prefix1/"
    }
    expiration {
      days = 10
    }
  }
  rule {
    id     = "rule2"
    status = "Enabled"
    filter {
      prefix = "prefix2/"
    }
    expiration {
      days = 20
    }
  }
  rule {
    id     = "rule3"
    status = "Enabled"
    filter {
      prefix = "prefix3/"
    }
    expiration {
      days = 30
    }
  }
}

Then add a 4th rule

  rule {
    id     = "rule4"
    status = "Enabled"
    filter {
      prefix = "prefix4/"
    }
    expiration {
      days = 40
    }
  }

Steps to Reproduce

If I add the 4th rule at the end of the config, the plan output looks as you'd expect:

Terraform will perform the following actions:

  # aws_s3_bucket_lifecycle_configuration.this will be updated in-place
  ~ resource "aws_s3_bucket_lifecycle_configuration" "this" {
        id     = "my-test-lifecycle-bucket"
        # (1 unchanged attribute hidden)

      + rule {
          + id     = "rule4"
          + status = "Enabled"

          + expiration {
              + days = 40
            }

          + filter {
              + prefix = "prefix4/"
            }
        }

        # (3 unchanged blocks hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

However, if the rule is added between rule1 and rule2, I get unexpected plan results:

Terraform will perform the following actions:

  # aws_s3_bucket_lifecycle_configuration.this will be updated in-place
  ~ resource "aws_s3_bucket_lifecycle_configuration" "this" {
        id     = "my-test-lifecycle-bucket"
        # (1 unchanged attribute hidden)

      ~ rule {
          ~ id     = "rule2" -> "rule4"
            # (1 unchanged attribute hidden)

          ~ expiration {
              ~ days                         = 20 -> 40
                # (1 unchanged attribute hidden)
            }

          ~ filter {
              ~ prefix = "prefix2/" -> "prefix4/"
            }
        }
      ~ rule {
          ~ id     = "rule3" -> "rule2"
            # (1 unchanged attribute hidden)

          ~ expiration {
              ~ days                         = 30 -> 20
                # (1 unchanged attribute hidden)
            }

          ~ filter {
              ~ prefix = "prefix3/" -> "prefix2/"
            }
        }
      + rule {
          + id     = "rule3"
          + status = "Enabled"

          + expiration {
              + days = 30
            }

          + filter {
              + prefix = "prefix3/"
            }
        }

        # (1 unchanged block hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Debug Output

No response

Panic Output

No response

Important Factoids

No response

References

can rules be TypeSet instead?

Would you like to implement a fix?

No

github-actions[bot] commented 10 months ago

Community Note

Voting for Prioritization

Volunteering to Work on This Issue

tmccombs commented 6 months ago

It's actually even worse than this. It appears that AWS orders the rules alphabetically by id. So if you don't have the rules in alphabetical order to begin with, then whenever you refresh the state, including with a plan without setting refresh to false, then you will always get a diff.

supergibbs commented 2 months ago

I had two environments that had different orders from my terraform code. Removing and re-importing did not help, had to apply the change.