Complex type variable validation

Are there any examples of variable validation rules for more complex types? In particular, my use case is to ensure AWS resources have a set of required tags with correct case/spelling. Is it possible to validate each key in a map individually?

tags = {
  Name = "foo"
  Description = "foo bar baz"
  Environment = "test"
}

example

variable "tags" {
  default = {}
  type = map(string)
}

Hi @mlehner616,

You can have as many validation blocks for your variable as you want, and in this case I think I’d be inclined to write a separate one for each of the tag names, like this:

variable "tags" {
  type    = map(string)

  validation {
    condition = (
      can(var.tags["Name"]) &&
      var.tags["Name"] == lower(var.tags["Name"])
    )
    error_message = "A Name tag is required and it must be all-lowercase."
  }

  validation {
    condition     = can(var.tags["Description"])
    error_message = "A Description tag is required."
  }


  validation {
    condition = (
      can(var.tags["Environment"]) &&
      contains(["test", "production"], var.tags["Environment"])
    )
    error_message = "An Environment tag is required and it must be set to either \"test\" or \"production\"."
  }
}
3 Likes

@apparentlymart

I greatly appreciate the hint. This was exactly what I needed and gets me a lot closer to what I need to do. The docs could use an example like this with something more than just “string.”

I’m not sure if I’m encountering a bug here or not but your example for “Name” generates the following vague error if the map doesn’t contain the key “Name” at all. Shouldn’t it return error_message?

|----------------
| var.tags is map of string with 1 element

The given key does not identify an element in this collection value.

If I wrap the condition below in can() it fixes that problem but then it doesn’t properly validate the value and incorrectly succeeds even if the value has upper case characters. Am I missing something?

      ...
      can(var.tags["Name"]) &&
      can(var.tags["Name"] == lower(var.tags["Name"]))
      ...

Because the first condition would fail if the key “Name” were missing, why is the second condition even being evaluated at all?

I believe I fixed it with the following by wrapping the second condition in a try(), although it seems like I shouldn’t have to do this.

  validation {
    condition = (
      can(var.tags["Name"]) &&
      try(var.tags["Name"] == lower(var.tags["Name"]), false)
    )
    error_message = "A Name tag is required and it must be all-lowercase."
  }

Hi @mlehner616,

I think what you ran into here is the behavior discussed in the following issue:

Indeed, right now you need to make sure both sides of && can evaluate without error, which is inconvenient. Hopefully we’ll improve on that in a future Terraform release.

1 Like