Skip to content

[Feature Request]: support for iterative assertions in validation #37749

@ascopes

Description

@ascopes

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions