如何合并多个for_each资源输出以用于另一for_each资源
问题描述
我有一个用于配置Gitlab仓库的Terraform项目:
variable "backend_repos" { type = list(string) default = ["backend-1", "backend-2"] } variable "web_repos" { type = list(string) default = ["web-1", "web-2"] } resource "gitlab_project" "backend" { for_each = var.backend_repos name = each.key ... } resource "gitlab_project" "web" { for_each = var.web_repos name = each.key ... }
我需要为backend和web仓库配置完全相同的分支保护,但找不到合并这两个资源集合的方法。尝试过多种写法均无效:
{ for project in concat(gitlab_project.backend, gitlab_project.web) : project.name -> project.id }{ for project in concat(gitlab_project.backend[*], gitlab_project.web[*]) : project.name -> project.id }{ for project in setunion(gitlab_project.backend, gitlab_project.web) : project.name -> project.id }{ for project in setunion(gitlab_project.backend[*], gitlab_project.web[*]) : project.name -> project.id }
但单独针对其中一个资源配置时可以正常工作:
resource "gitlab_branch_protection" "develop" { for_each = { for project in gitlab_project.backend : project.name -> project.id } project = each.value branch = "develop" ... }
解决方案
方法一:用merge合并映射(推荐)
直接合并两个for_each生成的资源映射,是最简洁的方式:
resource "gitlab_branch_protection" "develop" { for_each = merge( { for k, p in gitlab_project.backend : p.name => p.id }, { for k, p in gitlab_project.web : p.name => p.id } ) project = each.value branch = "develop" # 补充你的分支保护规则,比如: # push_access_level = "maintainer" # merge_access_level = "developer" }
如果存在backend和web仓库同名的情况,为避免键冲突,可以给键加上前缀区分:
resource "gitlab_branch_protection" "develop" { for_each = merge( { for k, p in gitlab_project.backend : "backend-${k}" => p.id }, { for k, p in gitlab_project.web : "web-${k}" => p.id } ) project = each.value branch = "develop" # 分支保护配置... }
方法二:转换为列表后合并
先通过values()将映射转为资源对象列表,再用concat合并,最后重新构建映射:
resource "gitlab_branch_protection" "develop" { for_each = { for p in concat(values(gitlab_project.backend), values(gitlab_project.web)) : p.name => p.id } project = each.value branch = "develop" # 分支保护配置... }
原因解析
- 用
for_each创建的资源(如gitlab_project.backend)本质是映射(map)类型,而concat、setunion仅支持列表类型,直接传入映射会导致类型不匹配错误。 merge函数专门用于合并多个映射,完美适配for_each对映射输入的要求;而values()可以把映射的所有值提取为列表,让concat能正常处理。
内容的提问来源于stack exchange,提问作者rj93
相关产品推荐
相关产品推荐

