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