Terraform:合并列表的地图并合并重复键中的列表

时间:2020-05-27 17:45:45

标签: terraform

我有类似的东西

locals {
  roles = [
    {
      role = "roles/admin"
      members = ["user:user@example.com"]
    },
    {
      role = "roles/viewer"
      members = ["user:user2@example.com"]
    }
  ]
}

我希望我的模块能够导出自己的角色列表,例如

roles = [
    {
      role = "roles/viewer"
      members = ["user:newperson@example.com"]
    }
]

然后可以将这些东西合并在一起

locals {
  roles = [
    {
      role = "roles/admin"
      members = ["user:user@example.com"]
    },
    {
      role = "roles/viewer"
      members = ["user:user2@example.com", "user:newperson@example.com"]
    }
  ]
}

我知道如果我将所有内容都存储为地图,则可以合并地图,只要没有重复的键,它就可以正常工作。但是在这种情况下,我明确希望能够拥有重复的键,以便一个模块不需要关心其他模块。

更新,我可以通过执行以下操作来实现此目的:

roles = distinct(flatten([
    for rm in local.role_maps : [
      for role, members in rm :
      {
        role = role
        members = sort(distinct(flatten([
          for m in local.role_maps :
          m[role] if lookup(m, role, null) != null
        ])))
      }
    ]
  ]))

1 个答案:

答案 0 :(得分:1)

对于使用...分组修饰符的for expression来说,这似乎是一个很好的应用程序,该修饰符可以通过按键分组来生成列表列表。

variable "custom_roles" {
  type = list(object({
    role    = string
    members = list(string)
  })
}

locals {
  default_roles = [
    {
      role    = "roles/admin"
      members = ["user:user@example.com"]
    },
    {
      role    = "roles/viewer"
      members = ["user:user2@example.com"]
    }
  ]
  all_roles = concat(
    local.default_roles,
    var.custom_roles,
  )

  # First we'll project the inputs so that we have one
  # role/member pair per element.
  flat_roles = flatten([
    for r in locals.all_roles : [
      for m in r.members : {
        role   = r.role
        member = m
      }
    ]
  ])

  # Then we can use that flattened list to produce a map
  # grouped by unique role key.
  merged_roles = {
    for k, v in local.all_roles : k => v...
  }

  # Finally, if the list-of-objects representation was
  # important then we can recover it by projecting that
  # merged_roles map back into the list shape.
  merged_roles_list = tolist([
    for role, members in local.merged_roles : {
      role    = role
      members = tolist(members)
    }
  ])
}

在上面,local.merged_roles是列表的映射,如下所示:

{
  "roles/admin"  = ["user:user@example.com"]
  "roles/viewer" = ["user:user2@example.com", "user:newperson@example.com"]
}

您可能会直接使用该地图,但以防万一对象列表形式很重要,我附上了local.merged_roles_list,它应该与您要提问的结构相匹配。