获取Terraform中变量的类型

获取Terraform中变量的类型,terraform,Terraform,有没有办法检测地形中变量的类型?比如说,我有一个any类型的模块输入变量,我可以根据类型进行某种切换吗 variable "details" { type = any } local { name = var.details.type == map ? var.details["name"] : var.details } 我想归档的是,能够以简写形式传递字符串,或者传递带有附加键的复杂对象 module "foo" { details = "my-name" } 或 我知

有没有办法检测地形中变量的类型?比如说,我有一个
any
类型的模块输入变量,我可以根据类型进行某种切换吗

variable "details" {
  type = any
}

local {
  name = var.details.type == map ? var.details["name"] : var.details
}

我想归档的是,能够以简写形式传递字符串,或者传递带有附加键的复杂对象

module "foo" {
  details = "my-name"
}



我知道这个例子没有多大意义,您想建议改为使用两个带有默认值的输入变量。此示例仅简化为最小(非)工作示例。最终目标是有一个IAM策略语句列表,因此它将是一个对象列表。

Terraform v0.12.20引入了一个新函数,可用于在不同的检索值方法之间进行简单选择,采用不会产生错误的第一种方法

variable "person" {
  type = any

  # Optional: add a validation rule to catch invalid types,
  # though this feature remains experimental in Terraform v0.12.20.
  # (Since this is experimental at the time of writing, it might
  # see breaking changes before final release.)
  validation {
    # If var.person.name succeeds then var.person is an object
    # which has at least the "name" attribute.
    condition     = can(var.person.name) || can(tostring(var.person))
    error_message = "The \"person\" argument must either be a person object or a string giving a person's name."
  }
}

locals {
  person = try(
    # The value of the first successful expression will be taken.

    {name = tostring(var.person)}, # If the value is just a string
    var.person,                    # If the value is not a string (directly an object)
  )
}
然后,您可以在配置的其他位置写入
local.person.name
以获取名称,而不管调用方传递的是对象还是字符串


此答案的其余部分是早期的响应,现在仅适用于v0.12.0和v0.12.20之间的地形版本

在Terraform中没有基于类型切换行为的机制。一般来说,Terraform倾向于选择特定的类型,这样模块调用者总是一致的,Terraform可以完全验证给定的值,即使这意味着在更简单的情况下会有一点额外的冗长

我建议将
details
定义为一个对象,并让调用者使用
name
属性显式写出对象,以便更加明确和一致:

variable "details" {
  type = object({
    name = string
  })
}
如果您需要支持两种不同的类型,Terraform语言中最接近的事情就是定义两个变量并检测哪个是
null

variable "details" {
  type = object({
    name = string
  })
  default = null
}

variable "name" {
  type    = string
  default = null
}

local {
  name = var.name != null ? var.name : var.details.name
}

但是,由于目前还没有一种方法来表示必须指定这两个模块中的一个,因此您编写的模块配置必须准备好处理这两个模块都将被设置(在上面的示例中,
var.name
优先)或两者都不会被设置的可能性(在上面的示例中,表达式将产生一个错误,但不是一个非常方便调用方的错误).

虽然这种可变模板/鸭子类型目前在Terraform中不可用,但这看起来确实是一个有趣的功能请求。我创建了一个功能请求:-如果得到积极反馈,我将研究实现。谢谢Martin,是的,详细的定义就是我现在拥有的。这很不幸,因为我会有数百个这样的条目,在大多数情况下,一个字符串就足够了。只有很少的条目需要额外的信息。正如fineprint中提到的,它实际上是一个对象/字符串列表。因此理想情况下,一个列表只需定义为
x=[“a”,“b”,“c”]
,而不是
x=[{name=“a”},{name=“b”},{name=“c”}
。但我知道,不幸的是,现在不可能。
module "example" {
  source = "./modules/example"

  details = { name = "example" }
}
variable "details" {
  type = object({
    name = string
  })
  default = null
}

variable "name" {
  type    = string
  default = null
}

local {
  name = var.name != null ? var.name : var.details.name
}