Terraform因无效的for_each参数而失败/给定的“ for_each”参数值不合适

时间:2020-06-08 14:10:17

标签: amazon-web-services foreach terraform

在运行terraform planterraform 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"
}

1 个答案:

答案 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>