Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Cannot use subnet ids created through the same terraform configuration with aws_route_table_association

I am trying to use subnet IDs, created by the resource "aws_subnet" "public" {...} block, in to the resource "aws_route_table_association" "public" {...} block, but it is giving the error:

Error: Invalid for_each argument
 
   on main.tf line 69, in resource "aws_route_table_association" "public":
   69:   for_each       = toset(tolist([for subnet in aws_subnet.public : subnet.id]))
     ├────────────────
     │ aws_subnet.public is object with 3 attributes
 
 The "for_each" set includes values derived from resource attributes
 that cannot be determined until apply, and so Terraform cannot determine
 the full set of keys that will identify the instances of this resource.
 
 When working with unknown values in for_each, it's better to use a map
 value where the keys are defined statically in your configuration and 
 where only the values contain   apply-time results.

 Alternatively, you could use the -target planning option to first apply
 only the resources that the for_each value depends on, and then apply a
 second time to fully converge.

As showing in my terraform configuration file below, I used depends_on = [aws_subnet.public] in the resource "aws_route_table_association" "public", expecting that the subnet IDs will be created before associations trigger.

It works, as suggested in the error message, if I run in two steps like:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

terraform apply -target=aws_subnet.public -target=aws_subnet.private -auto-approve
terraform apply -auto-approve

The mapping suggestions, I’m not clear about, but I think will require to map using the AWS region name, which I do not want to use, as I need to run this on any region. If I can use the mapping with the aws_region variable, I am OK with this.

How can I accomplish this with one run?

Configuration file main.tf:

// provider
provider "aws" {
  region                   = var.aws_region
  shared_credentials_files = ["~/.aws/credentials"]
  #profile                  = var.aws_profile # using `default` profile
}

// data
data "aws_availability_zones" "available" {
  state = "available"

  filter {
    name   = "zone-type"
    values = ["availability-zone"]
  }
}

//variables
variable "aws_region" {
  type    = string
  default = "us-east-1"
}

variable "environment" {
  type        = string
  description = "Deployment Environment (e.g. dev, prod, etc.)"
  default     = "dev"
}

variable "vpc_cidr" {
  type        = string
  description = "AWS VPC CIDR"
  default     = "10.0.0.0/16"
}

variable "public_subnet_cidrs" {
  type    = list(string)
  default = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
}

// vpc
resource "aws_vpc" "this" {
  cidr_block           = var.vpc_cidr
  enable_dns_hostnames = true
  tags = {
    Name = "${var.environment}-vpc"
  }
}

// public subnets, public route table, public subnet associations
resource "aws_subnet" "public" {
  for_each          = toset(var.public_subnet_cidrs)
  cidr_block        = each.value
  vpc_id            = aws_vpc.this.id
  availability_zone = data.aws_availability_zones.available.names[index(var.public_subnet_cidrs, each.value)]
  tags = {
    Name = "Public-Subnet-${index(var.public_subnet_cidrs, each.value) + 1}"
  }
}

resource "aws_route_table" "public" {
  vpc_id = aws_vpc.this.id
  tags = {
    Name = "Public-RouteTable"
  }
}

resource "aws_route_table_association" "public" {
  for_each       = toset(tolist([for subnet in aws_subnet.public : subnet.id])) # touples --> list --> set
  route_table_id = aws_route_table.public.id
  subnet_id      = each.value
  depends_on     = [aws_subnet.public]
}

>Solution :

You can just use for_each = aws_subnet.public:

resource "aws_route_table_association" "public" {
  for_each       = aws_subnet.public
  route_table_id = aws_route_table.public.id
  subnet_id      = each.value.id
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading