获取 Terraform 中变量的类型

udo*_*dan 6 terraform

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

variable "details" {
  type = any
}

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

Run Code Online (Sandbox Code Playgroud)

我想要归档的是,能够传递字符串作为速记或带有附加键的复杂对象。

module "foo" {
  details = "my-name"
}
Run Code Online (Sandbox Code Playgroud)

或者

module "foo" {
  details = {
    name = "my-name"
    age = "40"
  }
}
Run Code Online (Sandbox Code Playgroud)

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

Mar*_*ins 7

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

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)
  )
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以在配置的其他位置编写local.person.name以获取名称,无论调用者传递的是对象还是字符串。


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

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

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

variable "details" {
  type = object({
    name = string
  })
}
Run Code Online (Sandbox Code Playgroud)
module "example" {
  source = "./modules/example"

  details = { name = "example" }
}
Run Code Online (Sandbox Code Playgroud)

如果您需要支持两种不同的类型,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
}
Run Code Online (Sandbox Code Playgroud)

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


Noa*_*rks 1

terraform v1.0+ 为此引入了一个新函数 type()。请参阅https://www.terraform.io/language/functions/type

  • type() 函数仅适用于 `terraform console`。不适用于该语言。 (6认同)