Here's a code snippet I'm trying to fix:
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
# Find the corresponding routing table
data "aws_route_tables" "rts" {
vpc_id = aws_vpc.main.id
depends_on = [ aws_vpc.main ]
}
resource "aws_route" "rs" {
for_each = { for index, entry in local.bar : "${entry.route_table_id}.${entry.zone_cidr}" => entry }
route_table_id = each.value.route_table_id
destination_cidr_block = each.value.zone_cidr
vpc_peering_connection_id = data.aws_vpc_peering_connection.accepter.id
}
locals {
bar = flatten([
for route_table_id in toset(data.aws_route_tables.rts.ids) : [
for zone_info in foo.main.zone_info : {
route_table_id = route_table_id
zone_cidr = zone_info.cidr
}
]
])
}
In short, it creates a VPC and then it loads its routing table and then tries to add new entries to it using for_each
but since TF can't infer the size of data.aws_route_tables.rts.ids
during terraform plan
(since VPC is not created yet) it complains that local.bar
will only be known after apply. It seems to be a well-known limitation of for_each
but I'm wondering is there an easy way to fix it since it looks like a popular workflow / sequence of steps.
Here's a full error message:
Error: Invalid for_each argument
on .terraform/modules/abcde/main.tf line 88, in resource "aws_route" “
80: for_each = { for index, entry in local.bar :
${entry.route_table_id}.${e
| local.bar will be known only after apply
The "for_each" map includes keys 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 define the map
keys statically in your configuration and place apply-time results only in
the map values.
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.
Initializing: .. Done
Here's a related question I found but I'm not sure it helps since routing tables can't be defined statically beforehand.
A newly create VPC has only one route table - main route table. You do not need to use any data sources to get its ID. The main table has only local route, nothing else.
Also you get its ID using main_route_table_id
attribute of aws_vpc
, not aws_route_tables
data source:
aws_vpc.main.main_route_table_id