validationvariablesterraformlocal-variables

Terraform - Adding Validation for type = map(object()) in variables.tf


First thanks for this post Adding a default field for type = map(object()) in variavles.tf, this answered the first part of the struggle that I had in getting default values to work with type map(object()). The last part that I am trying to get working is how to do validation of the input values.

terraform {
  experiments = [module_variable_optional_attrs]
}

variable "dns_server" {
  description = "Add DNS Servers for domain resolution.  You can configure a maximum of two servers.  Only one can be preferred 'true'."
  type = map(object({
    preferred = optional(bool)
    server    = optional(string)
  }))
  default = {
    default = {
      preferred = false
      server    = "198.18.1.1"
    }
  }
  validation {
    condition = (
      can(regexall("^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$", var.dns_server["server"]))
    )
    error_message = "The DNS Server is not a valid IPv4 Address."
  }
}

locals {
  dns_server = {
    for k, v in var.dns_server : k => {
      preferred = coalesce(v.preferred, false)
      server = coalesce(v.server, "198.18.1.1")
    }
  }
}

The defaults value in the variable field I know isn't used but I am using it as a placeholder for the terraform docs output.

I also know what I have above for validation is not correct because if the user used the default server IPv4 that wouldn't be set until the locals definition. I just don't know of a way to do the validation because I my trusty google search hasn't pulled up any similar examples.

The code is located here if you need more details about how it is being used:

https://github.com/scotttyso/terraform-aci-fabric/tree/main/test

If I comment out the validation everything else is working fine. Thanks in advance.


Solution

  • Is this what you are after?

    variable "mapobject" {
      type = map(object({
        cidr_block       = string
        destination_type = string
        }
      ))
    
      validation {
        condition     = alltrue([for o in var.mapobject : contains(["CIDR_BLOCK", "NETWORK_SECURITY_GROUP", "SERVICE_CIDR_BLOCK"], o.destination_type)])
        error_message = "All destination_types must be one of CIDR_BLOCK, NETWORK_SECURITY_GROUP or SERVICE_CIDR_BLOCK!"
      }
    }
    

    With a variable assignment of:

    mapobject = {
      "r0" = {
        cidr_block = "10.1.1.0/24",
        destination_type = "CIDR_BLOCK"
      }
    }
    

    The validation succeeds, whereas the following fails (as intended):

    mapobject = {
      "r0" = {
        cidr_block = "10.1.1.0/24",
        destination_type = "**CIRD_BLOCK**"
      }
    }
    

    Associated error text with the previous usage:

    Error: Invalid value for variable
      on main.tf line 86:
      86: variable "mapobject" {
    
    All destination_types must be one of CIDR_BLOCK, NETWORK_SECURITY_GROUP or
    SERVICE_CIDR_BLOCK!
    
    This was checked by the validation rule at main.tf:93,2-12.
    

    If it is, then kudos goes here: https://discuss.hashicorp.com/t/validate-list-object-variables/18291/2