Terraform多层Map遍历优化:层级项目资源创建方案问询
问题描述
我在Terraform中定义了一个多层Map类型的变量blueprint_contents,将其视为文件夹结构,需要为每一层的每个条目创建对应的cloud_project资源,且必须保证层级创建顺序:L1项目先于L2创建,L1作为L2的父级,以此类推。当前已通过以下方式实现需求,现咨询是否有更优实现方案,可按需调整变量数据类型。
现有实现代码
本地列表定义
l1_projects_list = flatten([ for l1_project, l2_project in var.blueprint_contents : { project_name = l1_project parent = "top_level" } ]) l2_projects_list = flatten([ for l1_project_name, l2_project in var.blueprint_contents : [ for l2_project_name, l3_project in l2_project : { project_name = l2_project_name parent = l1_project_name } ] ]) l3_projects_list = flatten([ for l1_project_name, l2_project in var.blueprint_contents : [ for l2_project_name, l3_project in l2_project : [ for l3_project_name, l4_project in l3_project : { project_name = l3_project_name parent = l2_project_name } ] ] ]) l4_projects_list = flatten([ for l1_project_name, l2_project in var.blueprint_contents : [ for l2_project_name, l3_project in l2_project : [ for l3_project_name, l4_project in l3_project : [ for l4_project_name, l5_project in l4_project : { project_name = l4_project_name parent = l3_project_name } ] ] ] ])
资源创建代码
resource "cloud_project" "l1_projects" { for_each = { for project in local.l1_projects_list : project.project_name => project } name = each.key } resource "cloud_project" "l2_projects" { for_each = { for project in local.l2_projects_list : project.project_name => project } name = each.key parent_project_id = cloud_project.l1_projects[each.value.parent].id depends_on = [cloud_project.l1_projects] } resource "cloud_project" "l3_projects" { for_each = { for project in local.l3_projects_list : project.project_name => project } name = each.key parent_project_id = cloud_project.l2_projects[each.value.parent].id depends_on = [cloud_project.l2_projects] } resource "cloud_project" "l4_projects" { for_each = { for project in local.l4_projects_list : project.project_name => project } name = each.key parent_project_id = cloud_project.l3_projects[each.value.parent].id depends_on = [cloud_project.l3_projects] }
变量定义
variable "blueprint_contents" { type = map(any) default = { "0. Templates" = {} "1. Highway" = { "Data" = { "External" = { "One" = {} "TWO" = {} "Three" = {} "Four" = {} "Five" = {} "Six" = {} } "Internal" = {} } "Color" = { "Red" = {} } "Shape" = {} "Dimensions" = {} } "2. Adhoc" = {} "3. Archive" = {} "4. Quarantine" = {} } }
优化方案
现有方案硬编码了层级上限(仅支持4层),后续层级扩展需重复修改代码。可以通过递归展开层级结构+单一资源块的方式实现,支持任意层级,同时自动维护依赖关系。
步骤1:递归展开所有项目层级
定义递归本地值,将多层Map结构展开为包含project_name和parent的结构化列表:
locals { # 递归函数:展开任意层级的项目结构 flatten_projects = func(projects map(any), parent_name string) { return flatten([ for name, children in projects : concat( [ { project_name = name parent = parent_name } ], # 若当前项目有子项目,递归展开下一层 length(children) > 0 ? local.flatten_projects(children, name) : [] ) ]) } # 调用递归函数,顶层项目父级设为"top_level" all_projects = local.flatten_projects(var.blueprint_contents, "top_level") # 转换为map,适配资源for_each要求(需保证项目名全局唯一) all_projects_map = { for p in local.all_projects : p.project_name => p } }
步骤2:单一资源块创建所有项目
利用Terraform的隐式依赖推断,通过父项目ID的引用自动保证创建顺序,无需手动添加depends_on:
resource "cloud_project" "all" { for_each = local.all_projects_map name = each.key # 顶层项目无父ID,非顶层项目引用对应父项目的ID parent_project_id = each.value.parent == "top_level" ? null : cloud_project.all[each.value.parent].id }
关键优势
- 支持任意层级:无需修改代码即可适配项目结构的层级扩展
- 自动维护依赖:Terraform会自动识别父项目ID的引用关系,确保父项目优先创建
- 代码简洁易维护:消除重复的层级处理逻辑,降低后续维护成本
注意事项
如果存在同名项目(不同层级下的项目名称重复),for_each会因为键冲突报错。可通过添加full_path字段保证唯一性:
locals { flatten_projects = func(projects map(any), parent_name string, parent_path string) { return flatten([ for name, children in projects : let full_path = parent_path != "" ? "${parent_path}/${name}" : name concat( [ { project_name = name parent = parent_name full_path = full_path } ], length(children) > 0 ? local.flatten_projects(children, name, full_path) : [] ) ]) } all_projects = local.flatten_projects(var.blueprint_contents, "top_level", "") all_projects_map = { for p in local.all_projects : p.full_path => p } } resource "cloud_project" "all" { for_each = local.all_projects_map name = each.value.project_name parent_project_id = each.value.parent == "top_level" ? null : cloud_project.all[ [for p in local.all_projects : p.full_path if p.project_name == each.value.parent][0] ].id }
内容的提问来源于stack exchange,提问作者14578446
相关产品推荐
相关产品推荐

