Dynamic validation in locals or validation

Right now i dont see an option to validate variables in locals block…is there a provision to add dynamic in locals too
for example i have a list of comma seperated container names used while storage account creation… i wanted to validate each container name… how do i do it now…
var.othercontainer_name for example is “abc,cfr,ggg,ddd” is a comma separated list of strings

locals {
containers = “${var.othercontainer_name!=” " ? split(",", trimspace(var.othercontainer_name)) : }"

dynamic “validation”{
for_each = local.containers
content{
condition = (
length(containers.value) >= 3 &&
length(containers.value) <= 24 &&
can(regex("[1]+$", containers.value))
)
error_message = “Storage account names must be between 3 and 24 characters in length and may contain numbers and lowercase letters only.”
}
}
}


  1. 0-9a-z ↩︎

Hi @venrass!

Your example seems to combine the syntax from at least three separate features in a way where I’m not sure how to understand what effect you intended.

Can you also explain your goal in natural language so that I can hopefully understand better what your intent was? Thanks!

basically i have a variable var.othercontainer_name.

Value in this variable is comma separated string example

“abc,xyz,jkl”

now i am going to split this string to array
so i have string array now [“abc”,“xyz”,“kjl”]

for each string in this array i want to run a validation… to see if the length of each string is <3 and >24 charachers… if any string didnt pass the validation, i need to fail the validation with error message

Thanks for the extra context, @venrass!

Terraform expects validation rules and other custom conditions to be associated with the object that relies on them, rather than with the value itself, and so I think the best answer for your problem with today’s Terraform is to write this as a validation rule in your variable "othercontainer_name" block.

You can use the alltrue function as part of a condition that checks whether some role holds for every element of a collection. In your case, I think the structure would be something like this:

  validation {
    condition = alltrue([
      for s in split(",", trimspace(var.othercontainer_name)) :
      can(regex("[a-z0-9]+$", containers.value))
    ])
    # ...
  }

You can also write a separate validation block to check that the length of the list is within the required range. Terraform will not consider the value valid unless all validation rules pass, so multiple validation blocks is equivalent to a single one with && combining several conditions, except that separate blocks means you can specify a different error message for each situation.

Tangentially, it feels a bit strange to me for a module to take a string with comma-separated tokens in it rather than just declaring the variable as a list or set of strings directly and having the caller be the one to split a string if that is applicable to a particular situation. I would typically recommend using the most relevant type for any given situation and then converting data in the caller if necessary, so that the interface to your module is easy to understand from the type constraints. That doesn’t significantly change my answer above, except that you would no longer need to keep writing the split function call in each separate location where you make use of the variable; it would only be done once in the calling module instead.

Thank you that works

Hi @apparentlymart

Thanks, nicely explained. I have different scenario. I have data loaded from JSON file and wish to know if there is any mechanism to validate json object (loaded from file) before piping it to other resources.

Hello,

I know that this is a late reply. But I actually came up with a solution to validate locals, files and a lot of different things different than variables. I hope you found a solution since then, I’ll share the idea for other people looking for this kind of thing.

You can create a sub-module, define a variable in it that will receive your value. Use the validation block to set up your custom validation logic.

Per example :

# ./main.tf

local {
  external_config = yamldecode((file("my-config.yaml"))
}

module "validate-external-configuration" {
  source = "./modules/validate-external-configuration"
  external_config=local.external_config
}
# ./modules/validate-external-config/variables.tf

variable "external_config" {
  type = object({
     first_name = string
     family_name = string
     age = number
  })
  
  validation {
    condition = var.external_config.age > 0
    error_message = "You're little too young..."
  }
  validation {
    condition = var.external_config.age <= 150
    error_message = "You're little too old..."
  }
  validation {
    condition = can(regex("^[a-z0-9\\-]+$",var.external_config.first_name))
    error_message = "We only accept kebab-case people here!"
  }
}

When you run a plan or an apply, it will fail if the loaded external configuration does not pass the valiation checks.

You also can mutualize the validation with multiple variables for the validation module, or have multiple validation modules.

I’m using this idea in one of my projet. It works fine.

Have a good day