Я пытаюсь использовать идентификаторы подсети, созданные блоком resource "aws_subnet" "public" {...}
, в блоке resource "aws_route_table_association" "public" {...}
, но выдает ошибку:
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.
Как показано в моем файле конфигурации terraform ниже, я использовал depends_on = [aws_subnet.public]
в resource "aws_route_table_association" "public"
, ожидая, что идентификаторы подсети будут созданы до запуска ассоциаций.
Это работает, как предлагается в сообщении об ошибке, если я выполняю два шага, например:
terraform apply -target=aws_subnet.public -target=aws_subnet.private -auto-approve
terraform apply -auto-approve
Предложения по сопоставлению мне не совсем понятны, но я думаю, что потребуется сопоставить с использованием имени региона AWS, которое я не хочу использовать, так как мне нужно запускать это в любом регионе. Если я могу использовать сопоставление с переменной aws_region
, я согласен с этим.
Как я могу сделать это за один прогон?
Файл конфигурации 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]
}
Вы можете просто использовать 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
}
@ Рафик Нет проблем. Рад, что ответ помог.