在运行terraform plan
或terraform apply
并向for_each
提供列表的情况下,发生错误,提示
Error: Invalid for_each argument
on main.tf line 2, in resource "aws_ssm_parameter" "foo":
2: for_each = ["a", "b"]
The given "for_each" argument value is unsuitable: the "for_each" argument
must be a map, or set of strings, and you have provided a value of type tuple.
重现此错误的最小示例是:
resource "aws_ssm_parameter" "foo" {
for_each = ["a", "b"]
name = "foo-$each.value"
type = "String"
value = "bar-$each.value"
}
答案 0 :(得分:6)
此错误通常是由于将列表传递给for_each
引起的,但是for_each
仅适用于无序数据类型,即集合和映射。
解决方案取决于情况。
如果该列表只是一个字符串列表,最简单的解决方法是添加一个toset()
调用以将该列表转换为可由for_each处理的集合,例如
resource "aws_ssm_parameter" "foo" {
for_each = toset(["a", "b"])
name = "foo-$each.value"
type = "String"
value = "bar-$each.value"
}
如果输入是列表,但很容易重新排列为地图,则通常是最佳方法。 说我们有一个这样的列表
locals {
animals = [
{
name = "Bello"
age = 3
type = "dog"
},
{
name = "Minga"
age = 4
type = "cat"
},
]
}
然后可能是适当的重组
locals {
animals = {
Bello : {
age = 3
type = "dog"
},
Minga : {
age = 4
type = "cat"
}
}
}
然后您可以定义
resource "aws_ssm_parameter" "foo" {
for_each = local.animal
name = each.key
type = string
value = "This is a ${each.value.type}, ${each.value.age} years old."
}
有时候,有一个列表很自然,例如来自一个不受控制的模块的输出或来自count
定义的资源。在这种情况下,一个人都可以使用这样的计数
resource "aws_ssm_parameter" "foo" {
count = length(local.my_list)
name = my_list[count.index].name
type = "String"
value = my_list[count.index].value
}
适用于包含名称和值作为键的地图列表。不过,通常情况下,更合适的是将列表转换成地图而不是像这样
resource "aws_ssm_parameter" "foo" {
for_each = { for x in local.my_list: x.id => x }
name = each.value.name
type = "String"
value = each.value.value
}
在这里,应该选择任何合适的内容来代替x.id
。如果my_list
是对象列表,则通常可以使用一些公用字段,例如名称或键。这种方法有利于如上所述使用count
的优点是,从列表中插入或删除元素时,这种方法的行为更好。 count
不会原样注意到插入或删除,因此将更新插入发生位置之后的所有资源,而for_each
实际上仅添加或删除具有新ID或删除ID的资源。 / p>