terraform icon indicating copy to clipboard operation
terraform copied to clipboard

Unexpected Behavior of Variable Validation Against Data Blocks and Resources on First Apply

Open konradzagozda opened this issue 1 year ago • 6 comments

Terraform Version

1.9.7

Terraform Configuration Files


variable "unused_variable" {
    description = "This variable is not used in the configuration"
    type        = string
    default     = "unused"

    validation {
        condition = var.unused_variable != null && startswith(data.aws_s3_bucket.example_bucket_data.bucket, "zzz")
        error_message = "test"
    }
}

resource "random_string" "bucket_suffix" {
  length  = 6
  special = false
  upper   = false
}

resource "aws_s3_bucket" "example_bucket" {
  bucket = "kz-${random_string.bucket_suffix.result}"
}


data "aws_s3_bucket" "example_bucket_data" {
  bucket = aws_s3_bucket.example_bucket.bucket
}

Debug Output

first apply success: https://gist.github.com/konradzagozda/cd5f98261795ece6561fac8a1f29723a second apply fails: https://gist.github.com/konradzagozda/65a77d4d6228fef75f3043bcc9a8c1ca destroy fails: https://gist.github.com/konradzagozda/d42619fe01c7536e5e4772508c9c4346

Expected Behavior

Variable validation could occur after it can reference the attributes of a resource.

Actual Behavior

  1. Validation passes every time when the resource was not present before the apply.
  2. After that, it works as expected.

Steps to Reproduce

  1. terraform init
  2. terraform apply - success
  3. terraform destroy|apply - fail

Additional Context

A relatively new feature for variable validation was released in 1.9: "Input variable validation rules can refer to other objects."

While I find this super useful for referencing other variables, it behaves strangely when I try to reference resource or data blocks.

For example, let's say I have a feature for my app that has external infrastructure dependencies. I'd like to use a data block to fetch that information to validate whether the feature can be enabled successfully.

    validation {
        condition = var.unused_variable != null && startswith(data.aws_s3_bucket.example_bucket_data.bucket, "zzz")
        error_message = "test"
    }

I would expect this to fail every time because the prefix doesn't match the expected name.

However, the behavior is as follows:

First apply: passes without issues. Second apply: actually validates against the data block and produces the error message. Destroy: blocks the destroy operation due to the validation.

I can see this being useful if validation that includes references to resources and blocks were moved to the final stage of the apply process, perhaps with the ability to roll back on failure.

References

No response

konradzagozda avatar Oct 12 '24 14:10 konradzagozda