Terraform条件表达式类型不一致问题求助:动态生成Map/对象
Terraform类型不一致错误解决:动态生成单对象/Map存储账户配置
问题概述
根据optional_descr变量动态设置storage_account配置:
- 设置
optional_descr时,返回Map类型的配置(包含多个存储账户条目) - 未设置时,返回单个对象类型的配置
但运行时报错:
The true and false result expressions must have consistent types. The 'true' value includes object attribute "am", which is absent in the 'false' value
模块调用示例
# 多存储账户场景:设置optional_descr module "many_names" { # ... 其他配置 ... optional_descr = { storage_account = ["am", "sn"] } } # 单存储账户场景:未设置optional_descr module "one_name" { # ... 其他配置 ... }
现有核心代码
locals { prefix = join("-", var.prefix) suffix = join("-", var.suffix) az = { # ... 其他配置 ... storage_account = merge( var.optional_descr.storage_account != null ? { for key in var.optional_descr.storage_account : "${key}" => { name = substr(join("-", compact([local.prefix, "${key}", "stct", local.suffix])), 0, 63) name_unique = substr(join("-", compact([local.prefix, "${key}", "stct", local.suffix_unique])), 0, 63) dashes = true slug = "stct" min_length = 3 max_length = 63 scope = "parent" regex = "^[a-z0-9][a-z0-9-]+$" } } : { name = substr(join("-", compact([local.prefix, "stct", local.suffix])), 0, 63) name_unique = substr(join("-", compact([local.prefix, "stct", local.suffix_unique])), 0, 63) dashes = true slug = "stct" min_length = 3 max_length = 63 scope = "parent" regex = "^[a-z0-9][a-z0-9-]+$" } ) # ... 其他配置 ... } }
期望引用方式
# 未设置变量时 resource "azurerm_storage_account" "this" { name = module.one_name.az.storage_account.name # ... 其他配置 ... } # 设置变量时 resource "azurerm_storage_account" "am" { name = module.many_names.az.storage_account["am"].name # ... 其他配置 ... } resource "azurerm_storage_account" "sn" { name = module.many_names.az.storage_account["sn"].name # ... 其他配置 ... }
问题原因
Terraform条件表达式要求两个分支返回完全一致的数据类型:
true分支返回map(object)类型(如{"am": {...}, "sn": {...}})false分支返回单个object类型
类型不匹配导致报错。
解决方案
方案1:统一返回Map类型,添加专属输出简化引用
步骤1:修改local逻辑,统一返回Map
将无optional_descr时的单个对象包装为带默认键的Map:
locals { prefix = join("-", var.prefix) suffix = join("-", var.suffix) az = { # ... 其他配置 ... storage_account = var.optional_descr.storage_account != null ? { for key in var.optional_descr.storage_account : "${key}" => { name = substr(join("-", compact([local.prefix, "${key}", "stct", local.suffix])), 0, 63) name_unique = substr(join("-", compact([local.prefix, "${key}", "stct", local.suffix_unique])), 0, 63) dashes = true slug = "stct" min_length = 3 max_length = 63 scope = "parent" regex = "^[a-z0-9][a-z0-9-]+$" } } : { default = { name = substr(join("-", compact([local.prefix, "stct", local.suffix])), 0, 63) name_unique = substr(join("-", compact([local.prefix, "stct", local.suffix_unique])), 0, 63) dashes = true slug = "stct" min_length = 3 max_length = 63 scope = "parent" regex = "^[a-z0-9][a-z0-9-]+$" } } # ... 其他配置 ... } }
步骤2:添加模块输出
在模块的outputs.tf中添加两个输出,分别适配单/多实例场景:
# 多实例场景:返回完整Map output "storage_accounts" { type = map(object({ name = string name_unique = string dashes = bool slug = string min_length = number max_length = number scope = string regex = string })) value = local.az.storage_account description = "Map of storage account configurations (for multiple instances)" } # 单实例场景:返回默认配置对象 output "storage_account" { type = object({ name = string name_unique = string dashes = bool slug = string min_length = number max_length = number scope = string regex = string }) value = local.az.storage_account["default"] description = "Single storage account configuration (for single instance)" condition = var.optional_descr.storage_account == null }
步骤3:调整引用方式
- 单实例场景:
resource "azurerm_storage_account" "this" { name = module.one_name.storage_account.name # ... 其他配置 ... }
- 多实例场景:
resource "azurerm_storage_account" "am" { name = module.many_names.storage_accounts["am"].name # ... 其他配置 ... } resource "azurerm_storage_account" "sn" { name = module.many_names.storage_accounts["sn"].name # ... 其他配置 ... }
方案2:用for_each统一创建资源
如果不想区分输出,可统一用for_each处理单/多实例:
# 调用模块时,将单实例转为单元素列表 module "storage_accounts" { source = "./path/to/module" # ... 其他变量 ... optional_descr = { storage_account = var.create_multiple ? ["am", "sn"] : ["default"] } } # 统一用for_each创建资源 resource "azurerm_storage_account" "this" { for_each = module.storage_accounts.storage_accounts name = each.value.name # ... 其他配置 ... }
内容的提问来源于stack exchange,提问作者Anton Teterine
相关产品推荐
相关产品推荐

