Terraform嵌套for循环生成意外结果的问题排查
Terraform嵌套for循环生成意外结果的问题排查
最近我在写Terraform配置的时候踩了个坑,想跟大家聊聊我的问题和排查思路。先给大家看看我定义的核心变量:
variable "port_mapping_metadata" { type = map(object({ target_type = optional(string, "instance") ssl_policy = optional(string) listener_cert_arn = optional(string) additional_SNI_listener_cert_arns = optional(list(string), []) # 省略其他字段 })) }
我的需求很明确:要针对port_mapping_metadata里每一个非空的条目(而且不同资源之间可能存在重复的键),再逐个遍历条目里additional_SNI_listener_cert_arns列表的元素,为每个元素生成对应的资源。
举个具体的输入例子,比如我有这样的配置片段:
"bar" = { vpc_name = "foo" name = "bar" type = "application" port_mapping_metadata = { "forward" = { instance_names = ["inst"] listener_cert_arn = "arn:aws:acm:us-east-1:1234:certificate/abcd" additional_SNI_listener_cert_arns = ["arn:aws:acm:us-east-1:1234:certificate/efgh", "arn:aws:acm:us-east-1:1234:certificate/ijkl"] # 其他字段省略 } } }
按预期这里应该生成2个SNI证书相关的资源,但实际运行下来结果完全不对——要么资源数量不符合预期,要么报键冲突的错误,甚至资源关联的信息也混乱了。
我梳理的几个排查方向和解决思路
- 键重复导致的资源命名冲突:直接用
port_mapping_metadata的键作为for_each标识符肯定会出问题,得把条目键和SNI证书ARN组合成唯一标识,比如用${pm_key}-${replace(sni_arn, "/", "-")}这种方式生成唯一ID。 - 嵌套循环的逻辑漏洞:最初写的嵌套
for表达式没处理好层级关系,导致没有正确遍历每一层元素,后来改用flatten配合嵌套循环来展平集合,确保每个元素都能被单独处理。 - 空值/空列表的边界处理:如果
additional_SNI_listener_cert_arns是空列表,必须跳过生成资源,避免创建无效的空实例,这一步可以在循环里加if length(pm_val.additional_SNI_listener_cert_arns) > 0来过滤。
修正后的示例代码
给大家看看我调整后的配置片段,核心是先通过local变量整理出符合要求的资源集合:
locals { sni_cert_resources = flatten([ for pm_key, pm_val in var.port_mapping_metadata : [ for sni_arn in pm_val.additional_SNI_listener_cert_arns : { id = "${pm_key}-${replace(sni_arn, "/", "-")}" pm_key = pm_key sni_arn = sni_arn target_type = pm_val.target_type ssl_policy = pm_val.ssl_policy } ] if length(pm_val.additional_SNI_listener_cert_arns) > 0 ]) } resource "aws_lb_listener_certificate" "sni_certs" { for_each = { for res in local.sni_cert_resources : res.id => res } listener_arn = aws_lb_listener.main[each.value.pm_key].arn certificate_arn = each.value.sni_arn }
这样调整后,不仅解决了键冲突的问题,也能准确生成对应数量的资源,空列表的情况也会被自动跳过。
备注:内容来源于stack exchange,提问作者cawwot
相关产品推荐
相关产品推荐

