Terraform Modules, a little bit of repeating

James
James Cloud Architect working mainly in Azure and blogging his journey and hopefully dropping some useful bits of information on the way.

Repeatability within the Module

Repeatability is one of the key goals of Modules but you have to decide how to perform that repeatability in your module. Let me give you some examples:

Count

The count argument can be a really useful argument lets take a Virtual Machine inside of the module for example, below I have a Virtual Machine and I have a variable that allows you to stand up however many Virtual machines with exactly the same settings (in this case I’m creating Virtual Machines that will be domain controllers).

When using the count feature you need to account for uniqueness so the example below uses the format command to use a “Host Prefix” variable along with the count to make a 2 digit number my code comes with a limitation of only being able to create up to 99 virtual machines otherwise the naming convention breaks.

You can access the “number” of the virtual machine though using count.index

resource "azurerm_windows_virtual_machine" "main" {
  count = var.ad_host_count

  name                = format("%s%02d", var.ad_host_prefix, count.index + 1)
  location            = azurerm_resource_group.adds.location
  resource_group_name = azurerm_resource_group.adds.name

  network_interface_ids = [azurerm_network_interface.main[count.index].id]

  size                = var.ad_machine_sku

  admin_username = var.admin_username
  admin_password = random_password.ad_admin.result

  source_image_reference {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = var.ad_servers_os
    version   = "latest"
  }

  os_disk {
    name                 = format("%s-disk-%s-osdisk-%02d", var.customer_prefix, var.ad_host_prefix, count.index + 1)
    caching              = "ReadWrite"
    storage_account_type = var.disk_type
  }

  boot_diagnostics {
    storage_account_uri = null
  }
}

For Each Lists

You could always use a for_each list and create a bunch of resources based on a set\map. This can be used in more complicated scenarios for creating multiple resources.

The example below created Backup Policies using a Map style variable. This has a “Key” that is used in the instance reference and then multiple values in the map. The advantage of using this method is uniqueness is not so much of a problem as you can place uniqueness in the key and use that as the name.

Inside Module - main.tf

resource "azurerm_backup_policy_vm" "main" {
  for_each = var.vm_policies

  name                = each.key
  resource_group_name = azurerm_resource_group.backup.name
  recovery_vault_name = azurerm_recovery_services_vault.main.name

  instant_restore_retention_days = each.value["instant"]

  backup {
    frequency = "Daily"
    time      = each.value["time"]
  }

  retention_daily {
    count = each.value["daily"]
  }

  retention_weekly {
    count    = each.value["weekly"]
    weekdays = ["Sunday"]
  }

  retention_monthly {
    count    = each.value["monthly"]
    weekdays = ["Sunday"]
    weeks    = ["First"]
  }
}

Inside Module - terraform.tfvars

vm_policies = {
    1yr2300 = {
      instant = 5,
      time    = "23:00",
      daily   = 35,
      weekly  = 5,
      monthly = 12
    },
    3yr2300 = {
      instant = 5,
      time    = "23:00",
      daily   = 35,
      weekly  = 5,
      monthly = 36
    }
}

Repeatability of a Module

The repeatability of the module is probably the most important part, the most common example of module repeating that I can think of is when you want multiple regions (there are many other reasons but pretty sure this would be the most common). For me this discounts the possibility of using Count and only makes sense to use a for_each loop with a map as the example below.

Modules - main.tf

module "hub" {
  for_each = var.hubs

  source = "git::https://dev.azure.com/rawritscloud/TerraformModules/_git/terraform-azurerm-hub?ref=v1.0.0"

  location           = each.key
  hub_address_prefix = each.value["hub_address_prefix"]

Modules - terraform.tfvars

hubs = {
    uksouth = {
      hub_address_prefix    = "10.100.0.0/23"
    },
    ukwest = {
      hub_address_prefix    = "10.101.0.0/23",
    }
}

comments powered by Disqus