-
Notifications
You must be signed in to change notification settings - Fork 10.1k
Description
Terraform Version
1.13.3
Use Cases
- Clear validation messages to help consumers of modules
- Code that is easier to read
- Reporting each instance of a failure concisely to direct the course of action rather than users having to manually pull modules apart or add other hacks to calculate the incorrect value to fix.
- Alignment with features on
resource
blocks for iterative block declaration.
Proposal
I write a number of reusable modules within my organization that target consumers in other teams.
Part of this process involves providing sensible and meaningful validation constraints to allow inputs to fail during validation rather than leaking through to apply time.
I can currently do this using the validation
blocks on variables, but this becomes incredibly clunky when you deal with nested data, and almost impossible to provide informative messages regarding the exact location/nature of the issue.
In the example above, say I have half a dozen entries; it would be useful to inform the user which one of those entries was invalid. Right now that is not possible consistently as there is no way to convey specific contextual information to the error_message
from the condition
.
What I would propose is the addition of some kind of new dynamic_validation
block that consumes an iterable object such as a set, map, object, or list, and has an inner repeatable validation { }
block that can take the rules to evaluate, within the context of each item in the loop.
variable "networks" {
type = set(object({
cidr_blocks = set(string)
description = string
name = string
...
}))
...
validation {
condition = length(var.networks) > 0
error_message = "At least one network is required."
}
dynamic_validation {
for_each = var.networks
validation {
condition = length(each.value.name) > 0
error_message = "Network at ${each.index} has an invalid name."
}
validation {
condition = length(each.value.description) > 0
error_message = "Network at ${each.index} has an invalid description."
}
}
dynamic_validation {
for_each = flatten([
for network in var.networks : [
for cidr_block in network.cidr_block :
{ network = network.name, cidr_block = cidr_block }
]
])
validation {
condition = can(cidrnetmask(each.value.cidr_block))
error_message = "Network \"each.value.network\" has an invalid CIDR \"${each.value.cidr_block}\". This must be a valid IPv4 CIDR block."
}
}
}
Attempted Solutions
variable "networks" {
type = list(object({
cidr_blocks = set(string)
name = string
...
}))
...
validation {
condition = alltrue([
for network in var.networks : alltrue([
for cidr_block in network.cidr_blocks :
can(cidrnetmask(cidr_block))
])
))
error_message = "Each CIDR block must be a valid IPv4 CIDR block."
}
}
Another workaround could be to hack around with multiple instances of terraform_data
to extract sensible messages, but this then pollutes the plan unnecessarily.