Terraform中for循环处理映射列表的问题排查求助
Terraform AWS OU 创建的 for_each 配置错误分析与修正
初始配置的错误点
初始locals结构
locals { l3_crm = [ { parent: "crm", child: ["crm-sap", "crm-sf"] }, { parent: "fin", child: ["fin-mon"] }, ] }
模块调用的错误
module "l3_crm" { source = "./modules/ou" for_each = { for idx, val in local.l3_crm : idx => val } ou_name = [each.value.child] parent_id = module.l2[each.key.parent].ou_ids[0] depends_on = [module.l2] ou_tags = var.l2_ou_tags }
报错原因
each.key是数组循环的索引(字符串类型的"0"、"1"),并非包含parent属性的对象,each.key.parent属于错误的属性调用,正确应使用each.value.parent获取父OU名称。ou_name = [each.value.child]会将子OU数组嵌套为二维数组(如[["crm-sap", "crm-sf"]]),但模块的ou_name变量要求单个字符串类型值,此处未遍历单个子OU,而是传递了整组子OU的数组。
第二种尝试配置的错误点
第二种locals结构
locals { l3_crm = [ { "rnd" : ["crm-sap", "crm-sf"] }, { "trade" : ["fin-mon"] } ] }
模块调用的错误
module "l3_rnd" { source = "./modules/ou" for_each = { for parent, child in local.l3_crm : parent => child } ou_name = [each.value] parent_id = module.l2[each.key].ou_ids[0] depends_on = [module.l2] ou_tags = var.l2_ou_tags }
报错原因
- 遍历数组
local.l3_crm时,parent会被赋值为数组索引("0"、"1"),而非对象中的键名("rnd"、"trade"),导致each.key与module.l2的有效键不匹配,触发索引错误。 each.value是数组中的单个对象(如{"rnd": ["crm-sap", "crm-sf"]}),ou_name = [each.value]传递的是对象而非字符串,完全不符合模块变量的类型要求。
正确配置方案
第一步:扁平化数据结构
先将嵌套的子OU数组展开,生成每个子OU对应的父-子关系条目,确保每个模块实例对应一个单独的AWS OU:
locals { l3_crm = [ { parent: "crm", child: ["crm-sap", "crm-sf"] }, { parent: "fin", child: ["fin-mon"] }, ] # 扁平化数据,拆分出每个子OU的独立条目 flattened_l3_ous = flatten([ for item in local.l3_crm : [ for child_ou in item.child : { parent_name = item.parent ou_name = child_ou } ] ]) # 转换为for_each所需的映射结构,用"父OU-子OU"作为唯一键 l3_ous_map = { for ou in local.flattened_l3_ous : "${ou.parent_name}-${ou.ou_name}" => ou } }
第二步:正确调用模块
module "l3_crm" { source = "./modules/ou" # 使用扁平化后的映射,每个实例对应一个子OU for_each = local.l3_ous_map # 直接传递字符串类型的子OU名称 ou_name = each.value.ou_name # 通过parent_name匹配module.l2中的父OU ID parent_id = module.l2[each.value.parent_name].ou_ids[0] depends_on = [module.l2] ou_tags = var.l2_ou_tags }
关键修正点
- 扁平化数据:将一组子OU拆分为单个条目,符合Terraform每个模块实例对应一个资源的最佳实践。
- for_each键:采用
父OU-子OU的组合键,确保键在apply前可预测,避免索引导致的歧义。 - 属性调用:用
each.value.parent_name正确获取父OU名称,替代错误的索引属性调用。 - 变量传递:直接传递字符串类型的子OU名称,匹配模块变量的类型要求。
内容的提问来源于stack exchange,提问作者Felixrobin antony
相关产品推荐
相关产品推荐

