如何在Terraform中对listobject变量执行嵌套的for循环

问题描述

我正在编写一个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
    }))
  }))
}

terraform输出

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接受map或set,因此必须将对象数组转换为map。常用的方法是先创建对象的平面数组,然后将其转换为地图。可以使用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
}