【问题标题】:Get type of a variable in Terraform在 Terraform 中获取变量的类型
【发布时间】:2022-02-03 21:51:48
【问题描述】:

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

variable "details" {
  type = any
}

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

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

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

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

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

【问题讨论】:

  • 虽然这种可变参数模板/鸭子类型目前在 Terraform 中不可用,但这似乎是一个有趣的功能请求。
  • 我创建了一个功能请求:github.com/hashicorp/terraform/issues/23070 - 如果得到积极反馈,我将研究实施。

标签: terraform


【解决方案1】:

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)
  )
}

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


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

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

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

variable "details" {
  type = object({
    name = string
  })
}
module "example" {
  source = "./modules/example"

  details = { name = "example" }
}

如果您需要支持两种不同的类型,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优先)或者两者都不会设置(在上面的示例中,表达式会产生错误,但不是对调用者非常友好的错误)。

【讨论】:

  • 谢谢马丁,是的,详细的定义就是我现在所拥有的。不幸的是,我将有数百个这样的条目,而且在大多数情况下,一个字符串就足够了。只有极少数条目需要额外信息。如细则中所述,它实际上是对象/字符串列表的列表。所以理想情况下,列表将简单地定义为x = ["a", "b", "c"] 而不是x = [{ name = "a" }, { name = "b" }, { name = "c" }。但我明白了,不幸的是,目前不可能。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2021-02-06
    • 1970-01-01
    • 2015-07-02
    • 1970-01-01
    • 2021-09-26
    • 1970-01-01
    • 2016-08-06
    • 2022-12-15
    • 2018-07-30
    相关资源
    最近更新 更多