Dealing with conditional Terraform Resources on Azure using Availability Sets

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,
  ]


Leave a Reply

Your email address will not be published. Required fields are marked *