For Loops

Terraform provides for-loops and for-each loops. These can be used to loop over variables, transform those, and output in different formats.

For example,

  • [for s in ["this is a ", "list"] : upper(s)] : this loop over the list and make all strings uppercase.

  • We can loop over a list or maps

  • We can even perform calculations or manipulations on values

  • And it's possible to output them as a list or map

For loops

In order to further explore this, let's first create a file with the name vars.tf,

variable "list1" {
  type = list(string)
  default = [1, 10, 9, 101, 3]
}

variable "list2" {
  type = list(string)
  default = ["apple", "pear", "banana", "mango"]
}

variable "map1" {
  type = map(number)
  default = {
   "apple" = 5
   "pear" = 3
   "banana" = 10
   "mango" = 0
  }
}

Let's start the Terraform console and experiment with this file,

$ terraform console
> [for s in ["a", "b", "c"]: s]
[
  "a",
  "b",
  "c",
]
> [for s in ["a", "b", "c"]: upper(s)]
[
  "A",
  "B",
  "C",
]
> [for s in var.list1: s ]
[
  "1",
  "10",
  "9",
  "101",
  "3",
]
> [for s in var.list1: s + 1]
[
  2,
  11,
  10,
  102,
  4,
]
> [for s in var.list2: upper(s)]
[
  "APPLE",
  "PEAR",
  "BANANA",
  "MANGO",
]
> [for k, v in var.map1: k]
[
  "apple",
  "banana",
  "mango",
  "pear",
]
> [for k, v in var.map1: v]
[
  5,
  10,
  0,
  3,
]
> {for k, v in var.map1: k => v}
{
  "apple" = 5
  "banana" = 10
  "mango" = 0
  "pear" = 3
}
> {for k, v in var.map1: v => k}
{
  "0" = "mango"
  "10" = "banana"
  "3" = "pear"
  "5" = "apple"
}
>

To make things more interesting let's create a file with the name provider.tf,

provider "aws" {
  region = var.AWS_REGION
}

Then replace the content of the vars.tf file,

variable "AWS_REGION" {
  type    = string
  default = "eu-west-1"
}
variable "project_tags" {
  type          = map(string)
  default       = {
    Component   = "Frontend"
    Environment = "Production"
  }
}

Finally a file with the name ebs.tf,

resource "aws_ebs_volume" "example" {
  availability_zone = "eu-west-1a"
  size              = 8

  tags = {for k, v in merge({ Name = "Myvolume" }, var.project_tags): k => lower(v)}
}

Init the modules,

$ terraform init

Let's examine the output,

$ terraform plan
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:

  # aws_ebs_volume.example will be created
  + resource "aws_ebs_volume" "example" {
      + arn               = (known after apply)
      + availability_zone = "eu-west-1a"
      + encrypted         = (known after apply)
      + id                = (known after apply)
      + iops              = (known after apply)
      + kms_key_id        = (known after apply)
      + size              = 8
      + snapshot_id       = (known after apply)
      + tags              = {
          + "Component"   = "frontend"
          + "Environment" = "production"
          + "Name"        = "myvolume"
        }
      + tags_all          = {
          + "Component"   = "frontend"
          + "Environment" = "production"
          + "Name"        = "myvolume"
        }
      + throughput        = (known after apply)
      + type              = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run
"terraform apply" now.

For-Each loops

Let's start this by creating a file with the name provider.tf,

provider "aws" {
  region = var.AWS_REGION
}

Then let's create a file with the name vars.tf,

variable "AWS_REGION" {
  type    = string
  default = "eu-west-1"
}

variable "ports" {
  type = map(list(string))
  default = {
    "22" = [ "127.0.0.1/32", "192.168.0.0/24" ]
    "443" = [ "0.0.0.0/0" ]
  }
}

Finally a file with the name securitygroup.tf,

resource "aws_security_group" "example" {
  name = "example" # can use expressions here

  dynamic "ingress" {
    for_each = var.ports
    content {
      from_port   = ingress.key
      to_port     = ingress.key
      cidr_blocks = ingress.value
      protocol    = "tcp"
    }
  }
}

Init the modules,

$ terraform init

Let's examine the output,

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:

  # aws_security_group.example will be created
  + resource "aws_security_group" "example" {
      + arn                    = (known after apply)
      + description            = "Managed by Terraform"
      + egress                 = (known after apply)
      + id                     = (known after apply)
      + ingress                = [
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = ""
              + from_port        = 443
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 443
            },
          + {
              + cidr_blocks      = [
                  + "127.0.0.1/32",
                  + "192.168.0.0/24",
                ]
              + description      = ""
              + from_port        = 22
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 22
            },
        ]
      + name                   = "example"
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = false
      + tags_all               = (known after apply)
      + vpc_id                 = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run
"terraform apply" now.

Last updated