OneManITArmy

Implementing the same multiple resources in Terraform with ‘for_each’

Table of Contents

    Suppose you get an assignment where you have to deploy the same resource multiple times (in one environment and as resource local network gateway in my context). How would you do it?

    You could

    • Create each resource manually;
    • Create a module and refer to it multiple times;
    • Use a count and loop through it.

    The options above would show something like this (excluding count here):

    # Done via creating resource manually or via Modules.
    
    module "local-net-gw" {
      source              = "../../modules/local-net-gw"
        name                = var.name
        resource_group_name = var.resource-group-name 
        location            = var.location
        gateway_address     = var.gateway-address
        address_space       = var.address-space
    }
    
    module "local-net-gw2" {
      source              = "../../modules/local-net-gw"
        name                = var.name2
        resource_group_name = var.resource-group-name2 
        location            = var.location
        gateway_address     = var.gateway-address2
        address_space       = var.address-space2
    }

    While Terraform can deploy this successfully, you’ve created more duplicated code in your resource.tf file and defined more variables in your variables.tf & .tfvars’ files.
    So what can we do to mitigate this kind of coding? We can make lists for this, but we need to have to define the unique parameters in it.

    In this blog, we will discuss the solution for this with the use of for_each.

    For each

    A for_each can be seen as a loop where it will accept a map or a set of strings.
    A map is a group of values that can be identified by labeling it (this can be seen in the Python language as a dictionary).

    If we go back to the module code, we need to create a map in the input fields that this module needs to have in order to deploy:

    Main.tf
    Line 5 defines the for_each function to loop it through var.local-net-gw which is in the variables.tf a map type.
    Line 7 – 11 shows the syntax to perform the each value for each variable.

    module "local-net-gw" {
      source              = "../../modules/local-net-gw"
      
      # Process Resource List
      for_each = var.local-net-gw # Use for_each based on the variables below.
    
        name                = each.value.name
        resource_group_name = each.value.resource-group-name 
        location            = each.value.location
        gateway_address     = each.value.gateway-address
        address_space       = each.value.address-space
    }

    Variables.tf

    # Local Network Gateway
    variable "local-net-gw" {
      description = "Variable Mapping for Configuration Local Network Gateway"
      type        = map(any)
    }

    Your unique parameters will be defined in the .tfvars file as usual but with a different format of syntax since we’re using maps:

    dev.tfvars

    # Local Network Gateway
    local-net-gw = {
    
      # VPN Connections (Site-to-Site)
      
      "local-network-gateway1" = {
        name = "local-network-gateway1"
        resource-group-name = "rg-onemanitarmy"
        location = "westeurope"
        gateway-address = "100.100.100.1"
        address-space = ["192.168.1.0/24"]
      },
      
      "local-network-gateway2" = {
        name = "local-network-gateway2"
        resource-group-name = "rg-onemanitarmy"
        location = "westeurope"
        gateway-address = "100.100.100.2"
        address-space = ["192.168.2.0/24"]
      }
      
    }

    And there you have it.

    Personally, if someone asks me to create one resource, I would probably implement it via modules for future purposes and adjust the resource.tf to for_each if multiple resources are needed to deploy.

    More information (such as restrictions) can be found on the official webpage of Terraform.
    Code can be found in the repository link here.