Working with Module For_Loop in Terraform
With 0.13 Terraform is officially supporting Module For_Each Loop.
Given the below Subnet module
Subnet Module
variable "subnets"{
default = {
"public" = {
"0" = {
"az" = 0
"cidr" = "10.1.0.0/18"
}
"1" = {
"az" = 1
"cidr" = "10.1.64.0/18"
}
}
"private" = {
"0" = {
"az" = 0
"cidr" = "10.1.128.0/19"
}
"1" = {
"az" = 1
"cidr" = "10.1.160.0/19"
}
"2" = {
"az" = 0
"cidr" = "10.1.192.0/19"
}
"3" = {
"az" = 1
"cidr" = "10.1.224.0/19"
}
}
}
}
locals {
private_subnets = lookup(var.subnet_map,"private",{})
}
resource "aws_subnet" "public_subnets" {
for_each = local.public_subnets
vpc_id = var.vpc_id
cidr_block = each.value["cidr"]
availability_zone = data.aws_availability_zones.az.names[each.value["az"]]
map_public_ip_on_launch = "false"
}
output "public_subnets" {
value = aws_subnet.public_subnets
}
We can call it multiple times via this module call
variable "subnets_map"{
default = {
"10.20.0.0/24" = {
"public" = {
"0" = {
"az" = 0
"cidr" = "10.20.0.0/26"
}
"1" = {
"az" = 1
"cidr" = "10.20.64.0/26"
}
}
"private" = {
"0" = {
"az" = 0
"cidr" = "10.20.128.0/26"
}
"1" = {
"az" = 1
"cidr" = "10.20.160.0/26"
}
}
}
"10.30.0.0/24" = {
"public" = {
"0" = {
"az" = 0
"cidr" = "10.30.0.0/26"
}
"1" = {
"az" = 1
"cidr" = "10.30.64.0/26"
}
}
"private" = {
"0" = {
"az" = 0
"cidr" = "10.30.128.0/26"
}
"1" = {
"az" = 1
"cidr" = "10.30.160.0/26"
}
}
}
}
}
module "many_subnets" {
source = "../subnets"
for_each = var.subnets_map
vpc_id = var.vpc_id
subnet_map = each.value
}
outputs "public_subnets"{
value = module.many_subnets.public_subnets
}
The content of module.many_subnets looks like this:
module.many_subnets["10.30.0.0/24"] =
private_subnets = {
0 = {
arn = "arn:aws:ec2:us-east-1:xxxx:subnet/subnet-xxx"
assign_ipv6_address_on_creation = false
availability_zone = "us-east-1a"
availability_zone_id = "use1-az2"
cidr_block = "10.30.0.0/26"
id = "subnet-xxxx"
ipv6_cidr_block = ""
ipv6_cidr_block_association_id = ""
map_public_ip_on_launch = false
outpost_arn = ""
owner_id = "xxxx"
tags = {}
timeouts = null
vpc_id = "vpc-xxx"
}
1 = {...}
}
After everything was done, I only wanted Subnet CIDR and ID, I could have gone back to the original module and updated the output, but I just did this local variable instead:
private_subnets = {
for key, value in flatten([
for item in module.many_subnets : [
for child in item.private_subnets : {
"id" = child.id
"cidr" = child.cidr_block
}
]
]) : (value["cidr"]) => (value["id"])
}