Home > Software design >  Terraform map, return null if key is not found
Terraform map, return null if key is not found

Time:12-23

Is it possible to return null by default from a terraform map?

Example:

variable "MY_VAR" {
   type = map(number)
   default = {}
}

And referenced in a resource:

var.MY_VAR["someKey"]

If there is no entry for someKey I would like to just return null, and not throw the 'The given key does not identify an element in this collection' error. Is there anyway to configure the terraform map to behave this way? Is there some kind of default functionality that can be leveraged?

CodePudding user response:

You can use loolkup

lookup(var.MY_VAR, "someKey", null)

CodePudding user response:

There are a few different ways to approach this.

In many cases if you are hard-coding particular keys that your module expects then that's an indication that you should be using an object type instead of a map type. A map type is intended for situations where the keys are totally under the control of the caller of the module, such as for specifying names of objects to be declared. An object type is for situations where your module is expecting a specific predefined set of attributes.

If you declare an object type with an attribute whose value is marked as optional then Terraform will automatically set it to null in any case where the caller doesn't set it:

variable "example_object" {
  type = object({
    required_thing = string
    optional_thing = optional(string)
  })
}

With the above declaration, the caller can provide any object that at least has a required_thing attribute that can convert to a string:

module "example" {
  # ...

  example_object = {
    required_thing = "Hello!"
  }
}

With the above value for this variable:

  • var.example_object.required_thing will be "Hello!"
  • var.example_object.optional_thing will be a null value

When converting between object types Terraform guarantees that the result will have all of the attributes mentioned in the type constraint, with the types specified. If the source value is not sufficient to keep that promise then Terraform will report an error with the caller's given value.


In rarer situations where you do intend for the caller to be in control of the keys but want to treat certain keys a special for some reason only if they are set then there are some different strategies to achieve that.

For the following examples I'll assume the following declaration:

# NOTE: Terraform variable names are conventionally
# written in lowercase, not in uppercase.
variable "example_map" {
  type = map(string)
}

One way is to make each separate use of the variable provide a fallback value to use if the key isn't defined. There are two ways to do that in Terraform, both of which are equivalent but the first is the newer and more general one while the second is a previous design from older versions of Terraform:

  1. try(var.example_map["specific_key"], null)
  2. lookup(var.example_map, "specific_key", null)

If you will be relying on this value in many different places then it might be easier to understand and maintain if you instead factor out the step of inserting the default values into a local value:

locals {
  example_map = tomap(merge(
    {
      specific_key = null
    },
    var.example_map,
  ))
}

With that declaration you can now use local.example_map instead of var.example_map elsewhere in your module. By merging the caller's provided map with a map of default values you can guarantee that specific_key will always be present in the map, and so you can safely refer to local.example_map["specific_key"] elsewhere.

I want to reinforce that using a map type where certain keys are "special" is a pretty unusual design, and while I can imagine some situations where it could be reasonable I would encourage using object type constraints instead if possible because then it will be easier for future users of your module to understand how it is supposed to be used just by reading the type constraints.

  • Related