Gabrielbu
Gabrielbu

Reputation: 77

Adding a default field for type = map(object()) in variavles.tf

I have the following variable in my variables.tf file:

variable "accounts" {
   type = map(object({
       field1       = string,
       field2       = list(string),
       field3       = list(string),
       field4       = list(string),
       field5       = string
  }))
 }

I need to add a default field so that my users don't have to specify every field. For example, if field2 is an empty list, I don't want the user to have to define field2 =[]

I've tried some variations of the following but nothing seems to work.

default = {
  default = {
    "field1"   = "",
    "field2"   = [],
    "field3"   = [],
    "field4"   = [],
    "field5"   = ""
  }
}

Anyone have any idea of how to do it or know if it's even possible?

Upvotes: 6

Views: 23138

Answers (3)

Supy
Supy

Reputation: 390

It is now possible to specify a default value for Terraform's optional(...) type constraint (as of Terraform 1.3). To solve the problem in the question posed:

variable "accounts" {
   type = map(object({
       field1       = string
       field2       = optional(list(string), [])
       field3       = list(string)
       field4       = list(string)
       field5       = optional(string, "")
  }))
 }

Reference documentation: https://developer.hashicorp.com/terraform/language/expressions/type-constraints#optional-object-type-attributes

Upvotes: 8

Martin Atkins
Martin Atkins

Reputation: 74269

The closest thing in Today's Terraform is to have your callers set the attribute value to null and then handle that null somehow inside your module.

One way to do that is to combine the input variable with a local value that normalizes it, like this:

variable "example" {
  type = map(object({
    a = string
    b = string
  }))
}

locals {
  example = {
    for k, v in var.example : k => {
      a = coalesce(v.a, "default a")
      b = coalesce(v.b, "default b")
    }
  }
}

The coalesce function can be a good choice if you have a fallback value that isn't null or "", but really you can use any expression/function you like here to handle the null case in whatever way is appropriate for your needs.

You can then use local.example elsewhere in the module to get the normalized value, or var.example to get the raw value as given by the caller.

From a caller's perspective omitting those two attributes would look like this:

  example = {
    a = null
    b = null
  }

Terraform v0.14 (which is about to have its first beta release at the time I'm writing this) will include an experimental new feature to allow marking object type attributes as optional in type constraints:

terraform {
  experiments = [module_variable_optional_attrs]
}

variable "example" {
  type = map(object({
    a = optional(string)
    b = optional(string)
  }))
}

The effect of this new optional(...) annotation is that the caller can omit that attribute when passing in an object value, in which case Terraform will perform the type conversion by inserting the attribute with the value null, rather than returning an error as it would by default.

Combined with the normalization approach I showed above this would then achieve the module interface you were looking for, without the need for callers to explicitly set null in order to omit the attributes:

  example = {}

Unless this feature sees some show-stopping feedback during the Terraform 0.14 series it'll likely be stabilized in Terraform 0.15.

Upvotes: 8

T.H.
T.H.

Reputation: 859

A default can only be defined at the variable level, so with your current variable structure there's no way around forcing the users to define all fields, except perhaps by pre-processing their input before it's passed to Terraform.

Upvotes: 1

Related Questions