Terraform v1.2升级:map()迁移tomap()时动态块for_each报错排查
Terraform v1.0+ 已废弃旧版map()构造函数,要求使用tomap()做显式类型转换。替换时报错的核心原因是:Terraform对象字面量的语法规则中,未加特殊标记的键名会被直接识别为固定字符串标识符,不会解析变量值。你写的{ each.key = each.value }会被Terraform尝试创建一个键名字面量为each.key的对象,而非取each.key的运行时值作为键,因此触发Ambiguous attribute key错误。
要完全保留原有逻辑、无行为差异的完成迁移,只需要给动态键名包裹圆括号,告诉Terraform这是需要计算的表达式,而非固定字面量键名即可。将原代码中所有map( each.key, each.value )替换为tomap({ (each.key) = each.value })即可正常运行。
修正后的完整代码如下:
resource "aws_lb_listener_rule" "forward" { for_each = var.lb_listener_rules_forward listener_arn = var.listener_arn priority = each.value.priority action { type = "forward" target_group_arn = aws_lb_target_group.this[each.key].arn } dynamic "condition" { for_each = { for k, v in tomap({ (each.key) = each.value }) : k => v if length(v.host_header_values) > 0 } content { host_header { values = each.value.host_header_values } } } dynamic "condition" { for_each = { for k, v in tomap({ (each.key) = each.value }) : k => v if length(v.path_pattern_values) > 0 } content { path_pattern { values = each.value.path_pattern_values } } } }
原有代码中存在一层冗余逻辑:map(each.key, each.value)本质是构造了一个仅包含当前迭代规则的单元素map,再通过for遍历做字段长度判断,核心目的只是判断当前规则的对应字段是否非空,决定是否生成condition块。可以去掉冗余的map构造和遍历逻辑,直接用布尔判断控制dynamic块生成,代码更简洁,也不存在版本兼容问题:
resource "aws_lb_listener_rule" "forward" { for_each = var.lb_listener_rules_forward listener_arn = var.listener_arn priority = each.value.priority action { type = "forward" target_group_arn = aws_lb_target_group.this[each.key].arn } dynamic "condition" { for_each = length(each.value.host_header_values) > 0 ? [1] : [] content { host_header { values = each.value.host_header_values } } } dynamic "condition" { for_each = length(each.value.path_pattern_values) > 0 ? [1] : [] content { path_pattern { values = each.value.path_pattern_values } } } }
旧版map(k, v)的行为等价于tomap({ (k) = v }),只要记住在Terraform中用变量/表达式作为对象键名时,必须用圆括号包裹表达式,就不会再遇到这类键名歧义错误。
内容的提问来源于stack exchange,提问作者PsySkeletor

