for_每个选项的terraform



我有以下rds的子网组代码片段:

data "aws_subnets" "example" {
filter {
name = "vpc-id"
values = [var.vpc_id]
}
filter {
name = "tag:tier"
values = ["app"]
}
}
data "aws_subnet" "my_subnet" {
for_each = toset(data.aws_subnets.example.ids)
id = each.value
}

resource "aws_db_subnet_group" "subnet_groups" {
subnet_ids = data.aws_subnets.example.ids
}

我一直在遵循terraform的文档,但是Invalid for_each argument失败了。

完整错误:

data.aws_subnets.example.ids是一个字符串列表,只有在apply

之后才知道for_each集合包括从资源属性派生的值,这些值在应用之后才能确定,因此Terraform无法确定识别该资源实例的完整键集。

当在for_each中使用未知值时,最好使用map值,其中键在配置中是静态定义的,并且只有值包含应用时结果。

或者,您可以使用-target计划选项首先只应用for_each值所依赖的资源,然后第二次应用以完全收敛

我想知道是否有人使用地图或知道如何解决这个错误的替代方法。

从你在这里分享的内容来看,var.vpc_id必须是一个Terraform还不知道的值,如果相应的VPC同时被计划创建,则会发生这种情况,因为VPC ID还没有分配,反过来VPC中还没有任何子网可以查询。

如果这是真的,那么你这里有一个resource块和data块在你的配置中引用同一个远程对象的问题的例子。如果此配置的不同模块也是负责管理 VPC和子网的模块(使用resource块),那么您通常不应该在配置中的任何地方使用data块引用该VPC或子网。

相反,您可以将有关子网的信息从声明它们的模块传递到将使用它们的模块。例如:

variable "vpc" {
type = object({
id = string
})
}
variable "subnets" {
type = map(object({
id = string
}))
}
resource "aws_db_subnet_group" "subnet_groups" {
subnet_ids = [for s in var.subnets : s.id]
}

你还没有分享调用这个模块的源代码,所以我不能展示一个具体的例子,但这里有一个人为的例子,展示了如何将VPC和子网映射传递到上述模块:

resource "aws_vpc" "example" {
# ...
}
resource "aws_subnet" "example" {
for_each = ["a", "b", "c"]
# ...
}
module "child" {
source = "../modules/child" # (this is the module I showed above)
vpc     = aws_vpc.example
subnets = aws_subnet_example
}

Terraform将确保vpc的值是一个具有ID的单个对象,而subnets的值是一个具有ID的对象的映射,这对于aws_vpcaws_subnet来说是正确的。

通过传递实际的资源对象,而不是尝试使用data块重新获取它们的数据,您可以获得一些改进的效率(不需要重新获取Terraform已经在内存中的数据),并且您给Terraform一个更好的对象之间关系的描述,因此它可以自动确定操作需要发生的顺序。


我保持上述声明最小,但如果你的模块需要使用子网的其他属性,如它们的CIDR块,那么你可以添加额外的必需属性到变量的类型约束:

variable "subnets" {
type = map(object({
id         = string
cidr_block = string
}))
}

任何aws_subnet资源实例都将匹配上面的对象类型约束,因为该资源类型同时具有idcidr_block属性,它们都是字符串类型。

最新更新