Menu

Virtual Geek

Tales from real IT system administrators world and non-production environment

Terraform count vs for_each for examples with map of objects

In this Terraform article I have two examples for loop and count loop. I have one map of object. Where I will use both the loops on map to show how to use them in different way. You can check my earlier articles for different loops examples - Terraform for_each loop on map example and Terraform one module deploy null or multiple resources based on input (nested for loop).

Download this Terraform for_each and count configuration here or it is also available on github.com.

In the below example I have terraform configuration provider.tf for azurerm and variables.tf file which has information of map of objects and mentioned default configuration.

provider.tf
terraform {
  required_version = ">=1.0"
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = ">=3.0"
    }
  }
}
provider "azurerm" {
  features {}
}

variables.tf
variable "foreach_records" {
  type = map(object({
    name     = string
    location = string
  }))
  default = {
    "rg01" = {
      name     = "rg01"
      location = "EastUS"
    }
    "rg02" = {
      name     = "rg02"
      location = "EastUS"
    }
  }
}

variable "count_records" {
  type = map(object({
    name     = string
    location = string
  }))
  default = {
    "rg01" = {
      name     = "rg03"
      location = "EastUS"
    }
    "rg02" = {
      name     = "rg04"
      location = "EastUS"
    }
  }
}

In the first example, to use first variable foreach_records, I am using for_each and for loop on the map. Then I am using each.value of object properties to create resources on azure.

for_each_example.tf
resource "azurerm_resource_group" "rg_foreach" {
  for_each = { for r in var.foreach_records : r.name => r }
  name     = each.value.name
  location = each.value.location
}

In my second example, Incase if I want to use count loop, first I am manipulating count_records variable and creating locals variable to create custom list of objects. Next using the local variable with count loop using function length() of newly created local variable. Next to determine the correct values from list I am using count.index of local variable as in the given example below.

count_example.tf
locals {
  count_records_list = [
    for key, value in var.count_records : {
      name     = value.name
      location = value.location
    }
  ]
}

resource "azurerm_resource_group" "rg_count" {
  count    = length(local.count_records_list)
  name     = local.count_records_list[count.index].name
  location = local.count_records_list[count.index].location
}

This is the screenshot of terraform apply of the configuration code.

Hashicorp terraform azure microsoft cloud automation devops format apply --auto-approve azurerm_resource_group for for_each foreach count loop with_items examples map hashtable.png

This is the output of applied and destroyed terraform configuration on Microsoft Azure.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
PS D:\Projects\Terraform\Testings\Terraform_Count_Vs_Foreach> terraform apply --auto-approve  

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_resource_group.rg_count[0] will be created
  + resource "azurerm_resource_group" "rg_count" {
      + id       = (known after apply)
      + location = "eastus"
      + name     = "rg03"
    }

  # azurerm_resource_group.rg_count[1] will be created
  + resource "azurerm_resource_group" "rg_count" {
      + id       = (known after apply)
      + location = "eastus"
      + name     = "rg04"
    }

  # azurerm_resource_group.rg_foreach["rg01"] will be created
  + resource "azurerm_resource_group" "rg_foreach" {
      + id       = (known after apply)
      + location = "eastus"
      + name     = "rg01"
    }

  # azurerm_resource_group.rg_foreach["rg02"] will be created
  + resource "azurerm_resource_group" "rg_foreach" {
      + id       = (known after apply)
      + location = "eastus"
      + name     = "rg02"
    }

Plan: 4 to add, 0 to change, 0 to destroy.
azurerm_resource_group.rg_foreach["rg01"]: Creating...
azurerm_resource_group.rg_count[1]: Creating...
azurerm_resource_group.rg_foreach["rg02"]: Creating...
azurerm_resource_group.rg_count[0]: Creating...
azurerm_resource_group.rg_count[0]: Creation complete after 4s [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg03]
azurerm_resource_group.rg_foreach["rg01"]: Creation complete after 4s [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg01]
azurerm_resource_group.rg_count[1]: Creation complete after 4s [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg04]
azurerm_resource_group.rg_foreach["rg02"]: Creation complete after 4s [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg02]

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
PS D:\Projects\Terraform\Testings\Terraform_Count_Vs_Foreach>
PS D:\Projects\Terraform\Testings\Terraform_Count_Vs_Foreach> terraform destroy --auto-approve
azurerm_resource_group.rg_count[0]: Refreshing state... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg03]
azurerm_resource_group.rg_foreach["rg02"]: Refreshing state... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg02]
azurerm_resource_group.rg_foreach["rg01"]: Refreshing state... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg01]
azurerm_resource_group.rg_count[1]: Refreshing state... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg04]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # azurerm_resource_group.rg_count[0] will be destroyed
  - resource "azurerm_resource_group" "rg_count" {
      - id       = "/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg03" -> null
      - location = "eastus" -> null
      - name     = "rg03" -> null
      - tags     = {} -> null
    }

  # azurerm_resource_group.rg_count[1] will be destroyed
  - resource "azurerm_resource_group" "rg_count" {
      - id       = "/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg04" -> null
      - location = "eastus" -> null
      - name     = "rg04" -> null
      - tags     = {} -> null
    }

  # azurerm_resource_group.rg_foreach["rg01"] will be destroyed
  - resource "azurerm_resource_group" "rg_foreach" {
      - id       = "/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg01" -> null
      - location = "eastus" -> null
      - name     = "rg01" -> null
      - tags     = {} -> null
    }

  # azurerm_resource_group.rg_foreach["rg02"] will be destroyed
  - resource "azurerm_resource_group" "rg_foreach" {
      - id       = "/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg02" -> null
      - location = "eastus" -> null
      - name     = "rg02" -> null
      - tags     = {} -> null
    }

Plan: 0 to add, 0 to change, 4 to destroy.
azurerm_resource_group.rg_foreach["rg02"]: Destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg02]
azurerm_resource_group.rg_foreach["rg01"]: Destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg01]
azurerm_resource_group.rg_count[0]: Destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg03]
azurerm_resource_group.rg_count[1]: Destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg04]
azurerm_resource_group.rg_count[0]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg03, 10s elapsed]
azurerm_resource_group.rg_foreach["rg02"]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg02, 10s elapsed]
azurerm_resource_group.rg_count[1]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg04, 10s elapsed]
azurerm_resource_group.rg_foreach["rg01"]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg01, 10s elapsed]
azurerm_resource_group.rg_foreach["rg02"]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg02, 20s elapsed]
azurerm_resource_group.rg_foreach["rg01"]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg01, 20s elapsed]
azurerm_resource_group.rg_count[1]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg04, 20s elapsed]
azurerm_resource_group.rg_count[0]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg03, 20s elapsed]
azurerm_resource_group.rg_foreach["rg01"]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg01, 30s elapsed]
azurerm_resource_group.rg_count[0]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg03, 30s elapsed]
azurerm_resource_group.rg_count[1]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg04, 30s elapsed]
azurerm_resource_group.rg_foreach["rg02"]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg02, 30s elapsed]
azurerm_resource_group.rg_foreach["rg02"]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg02, 40s elapsed]
azurerm_resource_group.rg_count[0]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg03, 40s elapsed]
azurerm_resource_group.rg_foreach["rg01"]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg01, 40s elapsed]
azurerm_resource_group.rg_count[1]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg04, 40s elapsed]
azurerm_resource_group.rg_count[1]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg04, 50s elapsed]
azurerm_resource_group.rg_count[0]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg03, 50s elapsed]
azurerm_resource_group.rg_foreach["rg02"]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg02, 50s elapsed]
azurerm_resource_group.rg_foreach["rg01"]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg01, 50s elapsed]
azurerm_resource_group.rg_foreach["rg01"]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg01, 1m0s elapsed]
azurerm_resource_group.rg_count[1]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg04, 1m0s elapsed]
azurerm_resource_group.rg_count[0]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg03, 1m0s elapsed]
azurerm_resource_group.rg_foreach["rg02"]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg02, 1m0s elapsed]
azurerm_resource_group.rg_count[0]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg03, 1m10s elapsed]
azurerm_resource_group.rg_count[1]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg04, 1m10s elapsed]
azurerm_resource_group.rg_foreach["rg01"]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg01, 1m10s elapsed]
azurerm_resource_group.rg_foreach["rg02"]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg02, 1m10s elapsed]
azurerm_resource_group.rg_foreach["rg01"]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg01, 1m20s elapsed]
azurerm_resource_group.rg_count[1]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg04, 1m20s elapsed]
azurerm_resource_group.rg_count[0]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg03, 1m20s elapsed]
azurerm_resource_group.rg_foreach["rg02"]: Still destroying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/rg02, 1m20s elapsed]
azurerm_resource_group.rg_foreach["rg01"]: Destruction complete after 1m24s
azurerm_resource_group.rg_count[1]: Destruction complete after 1m24s
azurerm_resource_group.rg_foreach["rg02"]: Destruction complete after 1m25s
azurerm_resource_group.rg_count[0]: Destruction complete after 1m25s

Destroy complete! Resources: 4 destroyed.
PS D:\Projects\Terraform\Testings\Terraform_Count_Vs_Foreach>

Useful Articles
Terraform remote-exec provisioner with ssh connection in null_resource
Terraform fore_each for loop filter with if condition example
Terraform testing local variables and output csv file without resource Part 1
Terraform testing variable map object values without resource configuration part 2
Terraform foreach module output to show only required results
Hashicorp Terraform map and object inside module and variable example
Terraform one module deploy null or multiple resources based on input
Terraform A reference to a resource type must be followed by at least one attribute access, specifying the resource name
Create an Azure virtual machine scale set and load balancer using Terraform
Azure Terraform fixed Availibility Zones on Virtual Machine Scale Set
Writing and Using Terraform modules
Terraform Using one module variable in another module
Hashicorp Terraform dynamic block with example
Terraform for_each loop on map example

Go Back

Comment

Blog Search

Page Views

11389364

Follow me on Blogarama