Terraform Google Pub/Sub模块:变量未定义与设为null的差异疑问
我在用Terraform部署Google Pub/Sub模块时遇到了问题,模块里的for_each逻辑如下:
for_each = var.create_topic ? { for i in var.push_subscriptions : i.name => i if try(i.dead_letter_topic, "") != "" } : {}
当我传递包含dead_letter_topic = null的push_subscriptions变量时:
push_subscriptions = [ { name = "push" push_endpoint = "https://example.com/push" dead_letter_topic = null }, ]
出现了如下错误:
on .terraform/modules/pubsub/main.tf line 62, in resource "google_pubsub_topic_iam_member" "push_topic_binding": │ 62: topic = each.value.dead_letter_topic │ │ The argument "topic" is required, but no definition was found.
但如果完全移除dead_letter_topic字段,代码就能正常运行。我之前以为Terraform会把null视为字段不存在,为什么这两种情况结果不一样?
null和字段不存在的本质区别:
Terraform里,null是明确的空值,代表字段存在但无有效值;完全不写字段才是字段不存在。你的try(i.dead_letter_topic, "")逻辑中,字段不存在时会返回默认值"",但如果字段存在且值为null,try会直接返回null。for_each过滤逻辑失效的原因:
你的过滤条件是try(i.dead_letter_topic, "") != "",当dead_letter_topic = null时,try返回null,而null != ""的结果是true(因为null和任何非null值比较都返回true),所以这个订阅会被纳入for_each集合。但后续google_pubsub_topic_iam_member资源的topic参数要求必须有有效值,传递null就触发了必填参数缺失的错误。修复方法:
调整for_each的过滤条件,同时排除null值:for_each = var.create_topic ? { for i in var.push_subscriptions : i.name => i if try(i.dead_letter_topic, "") != "" && try(i.dead_letter_topic, null) != null } : {}或者更简洁的写法,直接检查值是否非空:
for_each = var.create_topic ? { for i in var.push_subscriptions : i.name => i if !isnull(try(i.dead_letter_topic, null)) && try(i.dead_letter_topic, "") != "" } : {}这样不管是字段不存在返回默认空字符串,还是字段存在但为
null,都会被过滤掉,避免无效的资源创建。
内容的提问来源于stack exchange,提问作者user1966723

