
Terraform v1.3 shipped what I think is one of the most useful features since v1.0: the optional object type attribute. To see why it matters, let's start with 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 let's 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 it's something rather simple like this. But, if you were to extrapolate this to more complex situations or where 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 let's see how the new feature handles the same case.
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 a much better way to set up complex object variables. We can mark some properties as optional and give others a sensible default. No longer will we be required to build out separate variables for properties we want to be optional.
You can follow Brendan @BrendanLiamT on Twitter.
