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.