如何在 Terraform 中对列表(对象)变量执行嵌套循环

How perform nested for loop on list(object) variable in Terraform

我正在编写一个 terraform 模块接受 list 个实体,每个 entity 与一个别名列表相关联。我在访问别名对象并传入 each.key 时遇到问题。非常感谢任何帮助。

resource "vault_identity_entity_alias" "alias" {
  provider = vault.this

  for_each = [
    for entity in var.entities : {
      for alias in entity.aliases :
      alias.name => alias
    }
  ]

  name           = each.key
  mount_accessor = lookup(vault_auth_backend.b[each.key], "accessor", null)
  canonical_id   = vault_identity_entity.entity[each.value.entity].id
}

变量定义

variable "entities" {
  description = "A collection of entities where each entity is associated with a list aliases "
  type = list(object({
    name     = string
    policies = list(string)
    metadata = map(string)
    aliases = list(object({
      name      = string
      entity    = string
      auth_path = string
      type      = string
    }))
  }))
}

地形输出

Error: Invalid for_each argument

  on .terraform/modules/vault_dba_entity/main.tf line 9, in resource "vault_auth_backend" "b":
   9:   for_each = [
  10:     for entity in var.entities : {
  11:       for alias in entity.aliases :
  12:       alias.name => alias
  13:     }
  14:   ]

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.

如错误消息所述,for_each 接受映射或集合,因此您必须将对象数组转换为映射。常见的做法是先创建平面对象数组,然后将其转换为地图。可以使用 flatten 函数来完成。为了更好的可读性,我把它放在一个局部变量中,但它也可以内联完成:

locals {
  entities = flatten([
    for entity in var.entities: [
      for alias in entity.aliases: {
        entity_name = entity.name
        alias_name = alias.name
        alias_entity = alias.entity
      }
    ]
  ])
}

变量 local.entities 将包含对象列表,例如:

[
  {
    "alias_name" = "alias1"
    "entity_name" = "object1"
    "alias_entity" = "entity alias1"
  },
  {
    "alias_name" = "alias2"
    "entity_name" = "object1"
    "alias_entity" = "entity alias2"
  },
]

现在很容易将其转换为地图。我们只需要选择唯一键用作索引。根据你的问题,别名应该是唯一的,所以可以这样做:

resource "vault_identity_entity_alias" "alias" {
  provider = vault.this

  for_each = {
    for item in local.entities: item.alias_name => item
  }

  name           = each.key
  mount_accessor = lookup(vault_auth_backend.b[each.key], "accessor", null)
  
  # Note, we reference alias_entity, because it was defined with this name
  # in local variable.
  canonical_id   = vault_identity_entity.entity[each.value.alias_entity].id
}