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.