Terraform动态拼接模块引用获取输出报未声明模块错误如何解决
问题根因
Terraform 对模块、资源的引用是静态解析的,在terraform init初始化阶段就会完成所有引用地址的校验,不支持通过字符串拼接动态构造模块引用的写法。你写的module.node_[each.value[0]]会被Terraform直接识别为「名为node_的模块下的[each.value[0]]属性」,自然会抛出模块不存在的错误。
可行解决方案
方案1(最优:重构node模块为for_each统一声明模式)
从源头替换原来逐个声明module "node_x"的写法,基于节点和项目的映射关系用for_each统一创建所有node模块,模块实例会天然以key为索引形成map结构,可直接遍历引用,完全不需要动态拼接地址。
示例代码:
# 建议将本地映射调整为map类型,使用更便捷 locals { node_project = { "node_1" = "project_A" "node_2" = "project_B" # 其余节点与项目的映射关系 "node_N" = "project_N" } } # 统一用for_each声明所有node模块,替代原来逐个写module块的方式 module "node" { for_each = local.node_project # 此处填写原node模块的所有入参,可通过each.key获取节点名、each.value获取对应项目名 # source = "xxx" 替换为你原来使用的node模块源地址 # 其余模块参数按原有逻辑填写 } # 声明outputs_sample模块时可直接索引对应模块实例,无需动态拼接 module "outputs_sample" { for_each = local.node_project node_name = module.node[each.key].node_name project_name = each.value # 其余参数按原有逻辑填写 }
注意:如果你已经用原来逐个声明模块的方式在环境中部署过资源,重构为for_each模式前需要先做Terraform状态迁移,将原有
module.node_1、module.node_2这类实例的状态,迁移到module.node["node_1"]、module.node["node_2"]对应的新地址下,避免触发资源重建。
方案2(无重构:手动构造模块输出映射map)
如果你不想改动已经写好的node模块声明,也不想做状态迁移,可以手动构造一个存储所有node模块引用的本地map,提前把所有静态可解析的模块引用写入map,再基于这个map做遍历,绕开动态拼接的语法限制。
示例代码:
locals { node_project = [ ["node_1", "project_A"], ["node_2", "project_B"], # 其余节点与项目的映射关系 ["node_N", "project_N"] ] # 手动维护节点名到对应模块引用的映射,此处的模块引用都是静态可被Terraform解析的 node_outputs = { "node_1" = module.node_1 "node_2" = module.node_2 # 其余节点对应的模块引用 "node_N" = module.node_N } } module "outputs_sample" { for_each = { for pair in local.node_project : pair[0] => pair[1] } node_name = local.node_outputs[each.key].node_name project_name = each.value # 其余参数按原有逻辑填写 }
这个方案的缺点是后续新增节点时,需要同时在node_project和node_outputs两个本地变量中添加对应配置,维护成本略高。
内容的提问来源于stack exchange,提问作者naeroy
相关产品推荐
相关产品推荐

