Home > Mobile >  Terraform for_each loop
Terraform for_each loop

Time:10-14

So i want to specify gateway_id to the route table but i am getting this:

Error: Missing resource instance key

    on modules/vpc/main.tf line 55, in resource "aws_route_table" "RT":
    55:       gateway_id = aws_internet_gateway.igw.id
 
    Because aws_internet_gateway.igw has "for_each" set, its attributes must be accessed on
    specific instances.
 
    For example, to correlate with indices of a referring resource, use:
     aws_internet_gateway.igw[each.key]`

variables.tf

variable "vpc" {
    type = map(object({
        cidr = string
        tags = map(string)
    }))
    default = {
      "main" = {
        cidr = "10.0.0.0/16"
        tags = {
          "Name" = "Main-Vpc"
        }
      }
    }
}

# Subnets

variable "subnets" {
  type = map(object({
    cidr = string
    tags = map(string)
  }))
  # Privates
  default = {
    "Private1" = {
      cidr = "10.0.10.0/24"
      tags = {
        "Name" = "Private1"
      }
    }
    "Private2" = {
        cidr = "10.0.20.0/24"
        tags = {
            "Name" = "Private2"
        }
    }
    #Publcs 
    "Public1" = {
        cidr = "10.0.1.0/24"
        tags = {
            "Name" = "Public1"
        }
    }
    "Public2" = {
        cidr = "10.0.2.0/24"
        tags = {
            "Name" = "Public2"
        }
    }
  }
}

# Route tables

variable "route-tables" {
  type = map(object({
    cidr_block = string
    tags  = map(string)
  }))
  default = {
    "Public1" = {
      cidr_block = "0.0.0.0/0"
      tags = {
        "Name" = "Public1"
      }
    }
    "Public2" = {
      cidr_block = "0.0.0.0/0"
      tags = {
        "Name" = "Public2"
      }
    }
    "Private1" = {
      cidr_block = "0.0.0.0/0"
      tags = {
        "Name" = "Private1"
      }
    }
    "Private2" = {
      cidr_block = "0.0.0.0/0"
      tags = {
        "Name" = "Private2"
      }
    }
  }
}

main.tf

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


 
# Creting Privates and Public
resource "aws_subnet" "subnets" {
    vpc_id = aws_vpc.main["main"].id
    for_each = var.subnets
    cidr_block = each.value["cidr"]
    tags = each.value["tags"]

    depends_on = [
      aws_vpc.main
    ]
}

# Gateways and Elastic ip
resource "aws_internet_gateway" "igw" {
  for_each = aws_vpc.main
  vpc_id = aws_vpc.main["main"].id
}

resource "aws_eip" "elastic" {
  vpc = true
}

resource "aws_nat_gateway" "nat" {
  allocation_id = aws_eip.elastic.id
  subnet_id = aws_subnet.subnets["Public1"].id

  tags = {
    "Name" = "nat-gateway"
  }

  depends_on = [
    aws_internet_gateway.igw
  ]
}

# Route tables
resource "aws_route_table" "RT" {
  for_each = var.route-tables
  tags = each.value["tags"]
  vpc_id = aws_vpc.main["main"].id

  dynamic "route" {
    for_each = var.route-tables
    content {
      cidr_block = route.value.cidr_block
      gateway_id = aws_internet_gateway.igw["main"].id
    }
  }
}

I am trying to get the value of created resource igw but i dont know how to do it when im using for_each . Also i'm not sure how can i debug this to check the output of the internet_gateway resource!

Edit: I'm posting my full code if needed to analyze maybe will help!

CodePudding user response:

To debug such an issue, run Terraform console on your terminal, type aws_internet_gateway.igw and run enter,

it will show you how many items are created by this resource, and it will give you an idea how to reference your igw ID,

from your code I assume referencing your igw ID by gateway_id = aws_internet_gateway.igw.["main"].id will work, but I'm not sure,

use Terrafrom console to confirm.

UPDATE :

it worked because you didn't pass a value for the variable var.vpc, so terraform used the default value and thus create just one vpc resource with the key 'main'

if you run terraform plan, you'll see :

aws_vpc.main["main"] will be created
    resource "aws_vpc" "main" {
        arn                                  = (known after apply)
        cidr_block                           = "10.0.0.0/16"
        default_network_acl_id               = (known after apply)
        default_route_table_id               = (known after apply)
        default_security_group_id            = (known after apply)
        dhcp_options_id                      = (known after apply)

and when you did for_each = aws_vpc.main on the igw resource, for_each received a map of one element with a key "main", so it created just one igw resource with the same key of the vpc which is main so we were able to reference it by aws_internet_gateway.igw.["main"].id

if you have instead multiple items on the var.vpc variable like

variable "vpcs" {
    type = map(object({
        cidr = string
        tags = map(string)
    }))
    default = {
      "main" = {
        cidr = "10.0.0.0/16"
        tags = {
          "Name" = "Main-Vpc"
        }
      }
         "boo" = {
        cidr = "10.0.0.0/16"
        tags = {
          "Name" = "Main-Vpc"
        }
      }
    }
}

this will create two vpcs with keys main, boo, and as you're using var.vpcs as the for_each value of the igw resource, it will create two igw with the same keys main, and boo

  • Related