Sometimes when you are defining infrastructure with Terraform you run into issues that start to require conditional resources. Consider the following problem:
You have a virtual machine cluster running in 3 environments in Azure,
- Test
- Staging
- Production
These 3 environments are made up of the following resources —
- Azure Virtual Machine Resource
- Azure Availability Set
- Azure Load balancer
When running these virtual machine resources on Azure – We will be adding each to a availability set. Normally we define an availability set resource using the AzureRM Terraform provider we create a resource block like –
resource "azurerm_availability_set" "docker-aset" {
name = var.aset_name
location = azurerm_resource_group.dockerswarm-rg.location
resource_group_name = azurerm_resource_group.dockerswarm-rg.name
}
Then we add our resources to that availability set.
resource "azurerm_linux_virtual_machine" "dswarm" {
for_each = var.docker_swarm
name = each.key
resource_group_name = azurerm_resource_group.dockerswarm-rg.name
location = azurerm_resource_group.dockerswarm-rg.location
size = each.value.vm_size
admin_username = "automation-user"
availability_set_id = azurerm_availability_set.docker-aset.id
network_interface_ids = [
azurerm_network_interface.dswarm[each.key].id,
]
By populating the availability_set_id
argument we can add that resource to our previously created availability set.
That’s going to work great for us, but what if we only want to create an availability set resource in our staging and production environments? To do that, we will use the count meta argument with a conditional expression.
First – We define a bool
type variable that will use as our check for whether or not we want to create the resource.
variable "aset_create" {
type = bool
default = true
description = "Boolean to determine whether or not we want to create a availabilty set."
}
We will set aset_create
to true when we want to create the resource it, false when we don’t. This will live in a tfvar
that is specific to our environment we are provisioning.
Next – We modify our original resource to include the count
meta-argument, and use a condition to check for the state of the variable.
resource "azurerm_availability_set" "docker-aset" {
count = var.aset_create ? 1: 0
name = var.aset_name
location = azurerm_resource_group.dockerswarm-rg.location
resource_group_name = azurerm_resource_group.dockerswarm-rg.name
}
Now, that resource is only created if the aset_create
variable is set to false. Otherwise, the count of resource to create will be 0.
Next – we need to modify our availability_set_id argument to include a similar check. We will update it to also include a conditonal statement, that checks the same variable – aset_create – and if it’s true it will popular the argument with the id of the availability set, and set it to null otherwise.
availability_set_id = var.aset_create ? azurerm_availability_set.docker-aset[0].id : null
Full Block:
resource "azurerm_linux_virtual_machine" "dswarm" {
for_each = var.docker_swarm
name = each.key
resource_group_name = azurerm_resource_group.dockerswarm-rg.name
location = azurerm_resource_group.dockerswarm-rg.location
size = each.value.vm_size
admin_username = "automation-user"
availability_set_id = var.aset_create ? azurerm_availability_set.docker-aset[0].id : null
network_interface_ids = [
azurerm_network_interface.dswarm[each.key].id,
]
So between the count meta-argument, an additional var and conditional expressions we now have a flexible way to determine whether or not to create a resource based on a per-existing variable. Full Code:
#test.tfvars
#Variable to make a avset or not
aset_create = false
#vars.tf
variable "aset_create" {
type = bool
default = true
description = "Boolean to determine whether or not we want to create a availabilty set."
}
#vm.tf
resource "azurerm_availability_set" "docker-aset" {
count = var.aset_create ? 1: 0
name = var.aset_name
location = azurerm_resource_group.dockerswarm-rg.location
resource_group_name = azurerm_resource_group.dockerswarm-rg.name
}
resource "azurerm_linux_virtual_machine" "dswarm" {
for_each = var.docker_swarm
name = each.key
resource_group_name = azurerm_resource_group.dockerswarm-rg.name
location = azurerm_resource_group.dockerswarm-rg.location
size = each.value.vm_size
admin_username = "automation-user"
availability_set_id = var.aset_create ? azurerm_availability_set.docker-aset[0].id : null
network_interface_ids = [
azurerm_network_interface.dswarm[each.key].id,
]