DevOps | Scripts | Automation

Terraform

How to use for_each in terraform?

Use of for_each in Terraform

In Terraform, for_each is used to create multiple instances of the resources. It works with both resource and module blocks.

for_each works with the below variables.

  • Set
  • Map

You can also use the list with Terraform but first, they need to be converted to the set using the toSet() function.

Terraform also uses the count meta-argument to create multiple resources, we will cover that in a separate article.


for_each with map

In the previous article, we have covered how to use the terraform map variable, now using that map variable we will create multiple resources with the for_each.

Syntax,

for_each = {
   key1 = value2
   key2 = value2
}

For example, we need two storage accounts created in the same resource group.

resource "azurerm_storage_account" "StorageAccount" {
    for_each = {
        "storageaccount1" = "LRS"
        "storageaccount2" = "GRS"
    }

  name                     = each.key
  resource_group_name      = "testRG"
  location                 = "eastUS"
  account_tier             = "Standard"
  account_replication_type = each.value
} 

In the above example, left-side values (storage account name) are referenced using “each.key” while right-side values (replication type) are referenced with “each.value“.

The above example with variable

variables.tf:

variable "storageAccounts" {
    type = map
    default = {
        "storageaccount1" = "LRS"
        "storageaccount2" = "GRS"
    }
}

main.tf:


resource "azurerm_storage_account" "StorageAccount" {
  for_each = var.storageAccounts
  name                     = each.key
  resource_group_name      = "testRG"
  location                 = "eastUS"
  account_tier             = "Standard"
  account_replication_type = each.value
} 

The output will remain the same. Now let’s check how we can use for_each with the Set variable.

for_each with Set

You can use the for_each loop with set values, a list of values shown in the example below.

main.tf

resource "azurerm_storage_account" "StorageAccount" {
   
  for_each = toset(["storage1","storage2"])

  name                     = each.key
  resource_group_name      = "testRG"
  location                 = "eastUS"
  account_tier             = "Standard"
  account_replication_type = "LRS"
} 

In the above example, you might have noticed, we are using a list and converting it to a set using the toset() function because for_each works only with set variables.

Each value in a Set variable is referred to each.key

Set with Variables.tf file:

variables.tf:

variable "storageAccounts" {
    type = list
    default = ["storage1","storage2"]
}

main.tf:

resource "azurerm_storage_account" "StorageAccount" {
   
  for_each = toset(var.storageAccounts)

  name                     = each.key
  resource_group_name      = "testRG"
  location                 = "eastUS"
  account_tier             = "Standard"
  account_replication_type = "LRS"
} 

You must have noticed that we declared a list variable and later in the main.tf file it is converted to set using the toset() function.


for_each with Modules

Let’s say you want to use for_each with the modules. We will take the same above example and consider that the above values are stored in a module. To call out the module that has a for_each meta-argument, we just need to pass the list.

For example,

module name {
  source = "../../Modules/StorageAccounts"
  storageAccounts = toset(["storage1","storage2"])
}


for_each with data block

In the below example, we are going to enable LAWS (Log Analytics WorkSpace) for the existing storage accounts.

data "azurerm_storage_account" "StorageAccount" {
   
  for_each = toset(var.storageAccounts)
  name                     = each.key
  resource_group_name      = "StorageAccountTest"
} 

# Enable Diag setting for storage account.
resource "azurerm_monitor_diagnostic_setting" "storage_diag_setting" {
  for_each = toset(var.storageAccounts)
  name               = "${each.key}-diagSetting" 
  target_resource_id = data.azurerm_storage_account.StorageAccount[each.key].id
  log_analytics_workspace_id = "/subscriptions/abcd-efg-hikjl-mnop/resourceGroups/StorageAccountTest/providers/Microsoft.OperationalInsights/workspaces/logAnalyticsWSName"

  metric {
    category = "Transaction"

    retention_policy {
      enabled = false
    }
  }

  depends_on = [data.azurerm_storage_account.StorageAccount]
}

in the resource block to enable the diag settings for the storage accounts, we are referring to the resource id from the data block for each storage account using each.key

data.azurerm_storage_account.StorageAccount[each.key].id

for_each with output module

To retrieve the output of the resource properties used in the for_each loop, you need to use the special method shown below. Unlike, the count loop, you can’t use “[*]” or “.*”


resource "azurerm_storage_account" "StorageAccount" {
   
  for_each = toset(["storage1","storage2"])

  name                     = each.key
  resource_group_name      = "testRG"
  location                 = "eastUS"
  account_tier             = "Standard"
  account_replication_type = "LRS"
} 

output storageAccountId {
   value = {
    for k, strgId in azurerm_storage_account.StorageAccount : k => strgId.id
  }
  depends_on  = [azurerm_storage_account.StorageAccount]
}

There are also other methods, you can retrieve output with the for_each module but here this is one of them.

You can get all the above-explained examples in my GitHub repository.

https://github.com/chiragce17/MyPublicRepo/tree/main/Terraform/for_each

Loading