4

is it possible to use validation of a variable type equals list(string)?

My example:

main.tf

  name            = "tf-prd-sg-foo"
  image_id        = "ami-00e788542ee66c64f"
  instance_type   = "m5.xlarge"
  security_groups = ["sg-000000", "sg-00000000"] # Example of SG only to contextualize
}

vars.tf

variable "security_groups"  {
    type        = list(string)
    default     = [] 
    description = "(Optional) A list of associated security group IDS."

    validation {
      condition = can(regex("^sg-", var.security_groups))
      error_message = "The Security Groups need starts to \"sg-\"."
    }
}

When I try execute returns the following error:

[terragrunt] 2021/01/05 17:12:10 Running command: terraform plan

Error: Invalid value for variable

  on vars.tf line 21:
  21: variable "security_groups"  {

The Security Groups need starts to "sg-".

This was checked by the validation rule at vars.tf:26,5-15.

[terragrunt] 2021/01/05 17:12:12 Hit multiple errors:
exit status 1


4

When validating an input variable of a collection type, we typically want to write a validation rule that tests if something is true for each value within the collection, rather than true of the collection as a whole.

You can write a "for each" sort of condition using Terraform's for expressions. If you are using Terraform v0.14 or later then you can write it concisely using the alltrue function along with a for expression that produces a true or false result for each of the items, like this:

  validation {
    condition = alltrue([
      for id in var.security_groups : can(regex("^sg-", id))
    ])
    error_message = "All security group ids must start with \"sg-\"."
  }

If you are using Terraform v0.13 then you won't have the alltrue function available to you yet, but you can get a similar result in a clunkier way by using the optional if clause of a for expression to filter out all of the valid ids and then checking whether the resulting list is empty -- that is, whether there are any remaining items that were not valid:

  validation {
    condition = length([
      for id in var.security_groups : id
      if !can(regex("^sg-", id))
    ]) == 0
    error_message = "All security group ids must start with \"sg-\"."
  }

This second example is a bit more cryptic to understand because it's using some language features in an atypical way, so I'll break it down into smaller parts to explain:

  • [for id in var.security_groups : id if !can(regex("^sg-", id))] filters the elements of var.security_groups to keep only the ones where the expression is true.
  • !can(regex("^sg-", id)) uses the ! operator to turn your original expression that decides if the value is valid into an expression which decides if the value is invalid. Consequently the result of the for expression will be empty unless there's at least one invalid value.
  • Finally, the length( ... ) == 0 around the for expression says that the value is only valid if filtering out all of the valid values produces an empty list, which conversely means that the list didn't contain any invalid values.
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.