You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 18:20:56