Clock
7
min read

Terraform Optionals On Complex Input Variables

Heading

This is some text inside of a div block.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.

With the recent release of Terraform v1.3 we were given one of the most - in my opinion - important features to come to Terraform since the v1.0 release. And that is, the optional object type attribute. To first understand why this is so powerful let's look at a variable for creating a storage account on Azure.

The variables will be at their rawest form, no validation or description.
variable "storage_account" {
type = object({
  name                = string
  resource_group_name = string
  location            = string
  kind                = string
  tier                = string
  replication_type    = string
  })
}

This above example has all the properties we need to create a storage account on Azure, however, the kind property is actually optional and given that optional on an attribute doesn't exist yet, we will need to deal with that. There were two ways that I have seen commonly used:

storage_account = {
  name                = "sablt"
  resource_group_name = "rg-blt"
  location            = "australieast"
  kind                = "" //NOTE: We don't want to set this
  tier                = "Premium"
  replication_type    = "LRS"
}

This is what we would set either in a .tfvars file or a module call. We are passing in an empty string on kind and our code would deal with the occurrence of an empty string for us, but we still have to type those four pesky characters. So lets look at the next scenario, which actually requires more typing!

variable "storage_account" {
  type = object({
    name                = string
    resource_group_name = string
    location            = string
    tier                = string
    replication_type    = string
  })
}

variable "storage_account_kind" {
  type    = string
  default = ""
}

Now we have two variables, and this could be worse and that entire storage_account variable could be split out into its individual components. And yes, I have seen that happen. We have also set a default for the variable so that we don’t ever have to pass anything in if we don’t want/need to.

On the surface I would say this doesn’t feel so bad, especially when its something rather simple like this. But, if you were to extrapolate this to more complex situations or were there are many - potentially most - optional properties you are going to end up with a mess of variables. I personally always opt for complex objects as I feel it is far easier to see and understand what’s going on and what the requirements of the code are!

Now, lets move on to the fun stuff! Lets use this awesome new feature!

variable "storage_account" {
  type = object({
    name                = string
    resource_group_name = string
    location            = string
    kind                = optional(string)
    tier                = string
    replication_type    = string
  })
}

Above we can now see the kind is of type optional(string) this means that should we desire to set a value that value will be a string. It can go a step further though. What if we wanted to set a default value just for this property, well now you can!

variable "storage_account" {
  type = object({
    name                = string
    resource_group_name = string
    location            = string
    kind                = optional(string, "StorageV2")
    tier                = string
    replication_type    = string
  })
}

We probably aren’t going to set a default value for this particular property as we more so want it to be optional, but the tier for instance we might want to default to something that is common for the business and you deviate from it on an as needs basis.

optional gives us as engineers a huge amount of power to setup our complex object variables now, set sensible defaults and fully optional for some properties. No longer will we be required to build out seperate variables for properties we want to be optional.

You can follow Brendan @BrendanLiamT on Twitter.