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

Data source reference for_each resource is 1 timestep old #24948

Closed
yorinasub17 opened this issue May 14, 2020 · 4 comments
Closed

Data source reference for_each resource is 1 timestep old #24948

yorinasub17 opened this issue May 14, 2020 · 4 comments

Comments

@yorinasub17
Copy link

Terraform Version

v0.12.25

Terraform Configuration Files

variable "names" {
  default = ["foo", "bar", "baz"]
}

provider "aws" {
  region = "us-east-2"
}

resource "random_string" "random" {
  length  = 16
  upper   = false
  special = false
}

resource "aws_s3_bucket" "test" {
  for_each = toset(var.names)
  bucket   = "test-bucket-${each.key}-${random_string.random.result}"
  acl      = "private"
}

resource "aws_iam_role" "foo" {
  name               = "foo-${random_string.random.result}"
  assume_role_policy = data.aws_iam_policy_document.ec2_assume_role_policy.json
}

resource "aws_iam_role_policy" "read_s3" {
  name   = "read_s3"
  role   = aws_iam_role.foo.id
  policy = data.aws_iam_policy_document.read_s3_bucket.json
}

data "aws_iam_policy_document" "ec2_assume_role_policy" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type        = "Service"
      identifiers = ["ec2.amazonaws.com"]
    }
  }
}

data "aws_iam_policy_document" "read_s3_bucket" {
  statement {
    actions   = ["s3:PutObject"]
    resources = [for name, bucket in aws_s3_bucket.test : bucket.arn]
  }
}

Expected Behavior

All modifications to aws_s3_bucket.test that cause changes to the policy document are handled in a single timestep when running apply.

Actual Behavior

Any changes that cause at least one of the resources in the for_each call to be removed or modified do not translate to a change of the iam policy. Here is the plan I see after removing one of the names in the list (in this case I am removing bar):

random_string.random: Refreshing state... [id=t2ycqa7vln9fzw6k]
data.aws_iam_policy_document.ec2_assume_role_policy: Refreshing state...
aws_s3_bucket.test["baz"]: Refreshing state... [id=test-bucket-baz-t2ycqa7vln9fzw6k]
aws_s3_bucket.test["foo"]: Refreshing state... [id=test-bucket-foo-t2ycqa7vln9fzw6k]
aws_s3_bucket.test["bar"]: Refreshing state... [id=test-bucket-bar-t2ycqa7vln9fzw6k]
aws_iam_role.foo: Refreshing state... [id=foo-t2ycqa7vln9fzw6k]
data.aws_iam_policy_document.read_s3_bucket: Refreshing state...
aws_iam_role_policy.read_s3: Refreshing state... [id=foo-t2ycqa7vln9fzw6k:read_s3]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # aws_s3_bucket.test["bar"] will be destroyed
  - resource "aws_s3_bucket" "test" {
      - acl                         = "private" -> null
      - arn                         = "arn:aws:s3:::test-bucket-bar-t2ycqa7vln9fzw6k" -> null
      - bucket                      = "test-bucket-bar-t2ycqa7vln9fzw6k" -> null
      - bucket_domain_name          = "test-bucket-bar-t2ycqa7vln9fzw6k.s3.amazonaws.com" -> null
      - bucket_regional_domain_name = "test-bucket-bar-t2ycqa7vln9fzw6k.s3.us-east-2.amazonaws.com" -> null
      - force_destroy               = false -> null
      - hosted_zone_id              = "XXXXXXXXXXX" -> null
      - id                          = "test-bucket-bar-t2ycqa7vln9fzw6k" -> null
      - region                      = "us-east-2" -> null
      - request_payer               = "BucketOwner" -> null
      - tags                        = {} -> null

      - versioning {
          - enabled    = false -> null
          - mfa_delete = false -> null
        }
    }

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

Note how this only updates the s3 bucket, but the data source isn't recomputed after the change happens, leaving the IAM role policy to be stale. The change is only propagated to the data source after running apply; when I run plan after applying this change, I see the data source being updated and subsequently the IAM role policy. Here is the plan from the second apply immediately after applying the above plan:

random_string.random: Refreshing state... [id=t2ycqa7vln9fzw6k]
data.aws_iam_policy_document.ec2_assume_role_policy: Refreshing state...
aws_s3_bucket.test["baz"]: Refreshing state... [id=test-bucket-baz-t2ycqa7vln9fzw6k]
aws_s3_bucket.test["foo"]: Refreshing state... [id=test-bucket-foo-t2ycqa7vln9fzw6k]
aws_iam_role.foo: Refreshing state... [id=foo-t2ycqa7vln9fzw6k]
data.aws_iam_policy_document.read_s3_bucket: Refreshing state...
aws_iam_role_policy.read_s3: Refreshing state... [id=foo-t2ycqa7vln9fzw6k:read_s3]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # aws_iam_role_policy.read_s3 will be updated in-place
  ~ resource "aws_iam_role_policy" "read_s3" {
        id     = "foo-t2ycqa7vln9fzw6k:read_s3"
        name   = "read_s3"
      ~ policy = jsonencode(
          ~ {
              ~ Statement = [
                  ~ {
                        Action   = "s3:PutObject"
                        Effect   = "Allow"
                      ~ Resource = [
                            "arn:aws:s3:::test-bucket-foo-t2ycqa7vln9fzw6k",
                            "arn:aws:s3:::test-bucket-baz-t2ycqa7vln9fzw6k",
                          - "arn:aws:s3:::test-bucket-bar-t2ycqa7vln9fzw6k",
                        ]
                        Sid      = ""
                    },
                ]
                Version   = "2012-10-17"
            }
        )
        role   = "foo-t2ycqa7vln9fzw6k"
    }

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

This doesn't appear to happen if the change is to add a new for_each resource. E.g., if you add back in bar after this the first plan includes updates to both the IAM role policy and the s3 bucket.

Steps to Reproduce

  1. terraform init
  2. terraform apply
  3. Remove one of the elements from the var.names list.
  4. terraform plan <= This should include updates to both aws_s3_bucket.test and aws_iam_role_policy.read_s3.
@danieldreier
Copy link
Contributor

@yorinasub17 I believe the issue you're running into is that data sources are currently all pulled at the very beginning of the terraform apply. In the upcoming Terraform 0.13 release, @jbardin is refactoring this so that data sources are part of the graph and participate in dependency ordering.

@jbardin does this look like it'll be within scope of the refactor you're doing? If so, I think we can close this with the expectation it'll be fixed in 0.13.

@danieldreier danieldreier added the waiting-response An issue/pull request is waiting for a response from the community label May 18, 2020
@jbardin
Copy link
Member

jbardin commented May 19, 2020

Yes, this is something that we're working on implementing for 0.13. We can close this however as a duplicate of #17034, which will be closed when the corresponding changes can be merged.

@yorinasub17
Copy link
Author

Thanks for the information! Will subscribe to the other issue, and wait patiently for 0.13.

FWIW, I found a workaround by injecting a null_resource inbetween the resources and data source that does the proper dependency ordering, so am unblocked for the time being.

@ghost ghost removed waiting-response An issue/pull request is waiting for a response from the community labels May 19, 2020
@ghost
Copy link

ghost commented Jun 19, 2020

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@ghost ghost locked and limited conversation to collaborators Jun 19, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants