More examples with terraform for and for_each loops
Loops in terraform is not something new. There is a bunch of articles with examples in the internet. However I had a number of cases when I could not find the example of my particular case so “d like to add my own article with my own examples.
Loop over list.
Let’s sasy we have a list and want to build the dynamic block for some resources using the list of values. Hoever for_each is applicable to the map or set only. If you are going to ship the list to foreach, than terraform will fail with the following error
is a tuple with X elements
Convert your list tolist()
to fix it. Here is an example where I build the dynamic block of rules in gcp firewall using the list of protocols:
locals {
protocols = tolist(["tcp","udp"])
}
resource "google_compute_firewall" "foo" {
name = "example"
network = "default"
dynamic "allow" {
for_each = local.protocols
content {
protocol = allow.value
}
}
source_ranges = "0.0.0.0/0"
}
Here is another example with ports
locals {
ports = tolist(["22","80","443"])
}
resource "google_compute_firewall" "foo" {
name = "example"
network = "default"
allow {
protocol = var.gcp_firewall_protocol
ports = [for port in local.ports : port.value]
}
source_ranges = "0.0.0.0/0"
}
More complicated example. Here I loop over the map of string values and build dynamic block:
locals {
firewall_rules = {
ssh = {
port = "22",
protocol = "tcp"
},
http = {
port = "80",
protocol = "tcp"
},
https = {
port = "443",
protocol = "tcp"
},
dns = {
port = "53",
protocol = "udp"
}
}
}
resource "google_compute_firewall" "foo" {
name = "example"
network = "default"
dynamic "allow" {
for_each = local.firewall_rules
content {
protocol = allow.value.protocol
ports = [allow.value.port]
}
}
source_ranges = ["0.0.0.0/0"]
}
And even more complicated example. Here I loop over the map of strings and lists and build the dinamic block:
locals {
firewall_rules = {
tcp = {
ports = ["22", "80", "443"]
protocol = "tcp"
},
udp = {
ports = ["53"],
protocol = "udp"
}
}
}
resource "google_compute_firewall" "foo" {
name = "example"
network = "default"
dynamic "allow" {
for_each = local.firewall_rules
content {
protocol = allow.value.protocol
ports = [for port in allow.value.ports : port]
}
}
source_ranges = ["0.0.0.0/0"]
}
Create list from map indexes
locals {
test_map = {
"key1" = {
"var1" = "val1"
},
"key2" = {
"var2" = "val2"
},
"key3" = {
"var3" = "val3"
}
}
test_map_keys = [for k, v in local.test_map : k]
}
output "test_map_keys" {
value = local.test_map_keys
}
Output instance ids
Let’s say you created the list of instances with for_each loop
resource "aws_instance" "ec2" {
for_each = local.map_of_instances
....
}
Possible output options are the following:
key=>value map
output instance_ids {
value = { for key, value in aws_instance.ec2 : key => value.id }
}
list of IDs
output instance_ids {
value = [ for instance in aws_instance.ec2 : instance.id ]
}
External links: