Home > Enterprise >  Terraform nested loop of objects to create multiple subnets
Terraform nested loop of objects to create multiple subnets

Time:06-16

Been trying to create multiple subnet resources and got stuck at some point. So here is the code:

# variables.tf

variable "vpcs" {
    type = map(object({
        cidr = string
        tags = map(string)
        tenancy = string
    }))
    default = {
      "RU" = {
        cidr = "10.0.0.0/16"
        tags = {
          "Name" = "RU-VPC"
        }
        tenancy = "default"
      }
      "UZ" = {
        cidr = "192.168.0.0/16"
        tags = {
          "Name" = "UZ-VPC"
        }
        tenancy = "default"
      }
    }
  
}

variable "subnets" {
    type = map(object({
        cidr = string
        az = string
        tags = map(string)
    }))
    default = {
      "RU-Public-A" = {
        az = "us-east-1a"
        cidr = "10.0.1.0/24"
        tags = {
          "Name" = "RU-Public-A"
        }
      }
      "RU-Public-B" = {
        az = "us-east-1b"
        cidr = "10.0.2.0/24"
        tags = {
          "Name" = "RU-Public-B"
        }
      }
      "UZ-Public-A" = {
        az = "us-east-1a"
        cidr = "192.168.1.0/24"
        tags = {
          "Name" = "UZ-Public-A"
        }
      }
      "RU-Public-B" = {
        az = "us-east-1b"
        cidr = "192.168.1.0/24"
        tags = {
          "Name" = "UZ-Public-B"
        }
      }
    }
  
}
# main.tf

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }

  required_version = ">= 1.2.0"
}

data "aws_availability_zones" "available" {
  state = "available"
}


resource "aws_vpc" "main" {
    for_each = var.vpcs
    cidr_block = each.value["cidr"]
    instance_tenancy = each.value["tenancy"]
    tags = each.value["tags"]
  
}

resource "aws_internet_gateway" "main" {
    for_each = aws_vpc.main
    vpc_id = each.value.id
    tags = {
      "Name" = "${each.key}-IGW"
    }
  
}

resource "aws_subnet" "public" {

  
}

So I was able to create multiple VPCs and attach Internet Gateways to them using a loop. But with the subnets I'm having a problem as I can't figure out how to implement nested looping of objects. Googled for it, but couldn't find a similar problem.

Any help or hint would be aprecciated. Thank you.

CodePudding user response:

Your subnets has sub-optimal design leading to your issues. It would be much better and easier to make it in the following form:

variable "subnets" {
    type = map(map(object({
        cidr = string
        az = string
        tags = map(string)
    })))
    default = {
      
     RU = {      
      "Public-A" = {
        az = "ap-southeast-2a"
        cidr = "10.0.1.0/24"
        tags = {
          "Name" = "RU-Public-A"
        }
        }
        "Public-B" = {
          az = "ap-southeast-2b"
          cidr = "10.0.2.0/24"
          tags = {
            "Name" = "ap-southeast-2b"
          }
        }
      },
      UZ = {
        "Public-A" = {
          az = "ap-southeast-2a"
          cidr = "192.168.1.0/24"
          tags = {
            "Name" = "UZ-Public-A"
          }
        }
        "Public-B" = {
          az = "ap-southeast-2b"
          cidr = "192.168.2.0/24"
          tags = {
            "Name" = "UZ-Public-B"
          }
        }
      }
    }  
}

then you flatten it:

locals {

  flat_subnets = merge([
        for vpck, vpcv in var.vpcs: {
          for subnetk, subnetv in var.subnets[vpck]: 
            "${vpck}-${subnetk}" => {
                vpc_key = vpck
                subnet = subnetv
            }
          }
      ]...)

}

and use as:

resource "aws_subnet" "public" {
    for_each = local.flat_subnets
    
    vpc_id     = aws_vpc.main[each.value.vpc_key].id
    cidr_block = each.value.subnet.cidr
    availability_zone = each.value.subnet.az
    
    tags = each.value.subnet.tags
}
  • Related