使用 tostring() 来确保 Terraform 中的功能条件?
Using tostring() to ensure functional conditionals in Terraform?
tl;dr:使用 tostring()
来转换用于 Terraform >= 0.13 的条件的值以处理一组严格定义的输入类型是否是一种可接受的做法?
昨天我问了一个问题,今天我又想到了一个新问题:
我了解到,在 Terraform 中对某些原语应用了一些自动类型转换(主要是从字符串到其他数据类型),但是这些原语不能用于推断不同的数据类型(例如 bool
不能作为输入传递给 count
参数,因为 count 只接受 number
类型。
对该问题的一个评论有一个使用 bool
作为条件的非常简单的方法:
count = var.my_var ? 1 : 0
唯一的潜在问题是 my_var
是否可以有不同的输入类型。在我的用例中,它将被添加到 Terraform 模块中,用户将在其中决定为该参数提供什么;之前我们只传递了 string
或 number
,但我发现它比我希望的要不那么具体,因为 Terraform 可以将 count
解释为 > 1 个副本资源的(我想要一个离散的 0 或 1 [特别是像 var.create_this_resource
这样的值可以是 true 或 false 的东西]); "1"
与 true
IMO 相比,这看起来也不太好。所以我想 start 使用 bool
代替,但是 也 能够处理用户输入 number
.我发现我可以使用以下方法来完成此操作:
count = tostring(var.my_var) ? 1 : 0
在这里,tostring()
将接受输入中的任何内容,并可能将其转换为字符串。它仅适用于 string
、number
和 boolean
,实际上,我只是用它来获得 number
到 string
,因为那是唯一传递给三元运算符当前失败的情况。
所以我的问题是这样做是否可以接受?我用 string
、bool
和 number
以及不受支持的类型(即空列表或 null
)对其进行了测试;它似乎在代码中运行良好,但以下内容让我认为我不应该使用它:
来自docs:
Explicit type conversions are rarely necessary in Terraform because it will convert types automatically where required. Use the explicit type conversion functions only to normalize types returned in module outputs.
在大多数情况下,我建议避免设计特定变量在不同情况下可能具有不同类型的设计,除非您的模块将值视为完全不透明,并且只是将其传递给具有更广泛验证规则的其他对象。
因为你的模块 是 直接使用这个值,通常最好为变量指定一个确切的类型约束,并让模块的调用者编写表达式来转换自动转换不足时的值。这样,调用者可以获得关于您的模块期望什么样的值的更好反馈,并且可以自己决定如何转换他们的不同类型的值。
转成字符串只能在以下情况下产生一个可以自动转成bool
的值:
- 该值已经是一个字符串,并且是
"true"
或 "false"
。
- 该值为 bool 值,在这种情况下
tostring
会将其转换为字符串,然后条件运算符会立即将其再次转换回 bool,这将是多余的。
如果您将变量声明为 bool
本身,则将应用相同的规则,但转换将在调用 module
块内而不是在 count
表达式中发生:
variable "my_var" {
type = bool
}
module "example" {
# ...
# This will automatically convert to bool true,
# just as it would've in the conditional operator.
my_var = "true"
}
如果您真的无法避免支持各种不寻常的布尔值编写方式,那么您可以编写自己的转换 table, 将基于字符串,并且指定转换后每个可能的字符串的布尔值:
locals {
sloppy_bool = tomap({
"1" = true
"true" = true
"0" = false
"false" = false
})
my_var = local.sloppy_bool[var.my_var]
}
因为映射类型(映射类型和对象类型)只支持字符串作为键,local.sloppy_bool[var.my_var]
会自动将var.my_var
转换为字符串,就像你写tostring(var.my_var)
一样。然后它将在 table 和 return 中查找相应的布尔值的结果,这意味着您可以在模块的其他地方使用 local.my_var
而不是 var.my_var
并依赖它始终是一个真正的布尔值。
我建议只有当您的模块的先前版本可以容忍这种类型的奇怪输入并且您需要与其保持兼容时才这样做。对于一个全新的模块,我认为这是 non-idiomatic 并且可能会让任何已经熟悉 Terraform 并尝试使用该模块的人感到困惑,因为他们需要熟悉您对类型转换的不寻常定义,而不是而不是依赖他们对 built-in 转换规则的了解。
tl;dr:使用 tostring()
来转换用于 Terraform >= 0.13 的条件的值以处理一组严格定义的输入类型是否是一种可接受的做法?
昨天我问了一个问题,今天我又想到了一个新问题:
我了解到,在 Terraform 中对某些原语应用了一些自动类型转换(主要是从字符串到其他数据类型),但是这些原语不能用于推断不同的数据类型(例如 bool
不能作为输入传递给 count
参数,因为 count 只接受 number
类型。
对该问题的一个评论有一个使用 bool
作为条件的非常简单的方法:
count = var.my_var ? 1 : 0
唯一的潜在问题是 my_var
是否可以有不同的输入类型。在我的用例中,它将被添加到 Terraform 模块中,用户将在其中决定为该参数提供什么;之前我们只传递了 string
或 number
,但我发现它比我希望的要不那么具体,因为 Terraform 可以将 count
解释为 > 1 个副本资源的(我想要一个离散的 0 或 1 [特别是像 var.create_this_resource
这样的值可以是 true 或 false 的东西]); "1"
与 true
IMO 相比,这看起来也不太好。所以我想 start 使用 bool
代替,但是 也 能够处理用户输入 number
.我发现我可以使用以下方法来完成此操作:
count = tostring(var.my_var) ? 1 : 0
在这里,tostring()
将接受输入中的任何内容,并可能将其转换为字符串。它仅适用于 string
、number
和 boolean
,实际上,我只是用它来获得 number
到 string
,因为那是唯一传递给三元运算符当前失败的情况。
所以我的问题是这样做是否可以接受?我用 string
、bool
和 number
以及不受支持的类型(即空列表或 null
)对其进行了测试;它似乎在代码中运行良好,但以下内容让我认为我不应该使用它:
来自docs:
Explicit type conversions are rarely necessary in Terraform because it will convert types automatically where required. Use the explicit type conversion functions only to normalize types returned in module outputs.
在大多数情况下,我建议避免设计特定变量在不同情况下可能具有不同类型的设计,除非您的模块将值视为完全不透明,并且只是将其传递给具有更广泛验证规则的其他对象。
因为你的模块 是 直接使用这个值,通常最好为变量指定一个确切的类型约束,并让模块的调用者编写表达式来转换自动转换不足时的值。这样,调用者可以获得关于您的模块期望什么样的值的更好反馈,并且可以自己决定如何转换他们的不同类型的值。
转成字符串只能在以下情况下产生一个可以自动转成bool
的值:
- 该值已经是一个字符串,并且是
"true"
或"false"
。 - 该值为 bool 值,在这种情况下
tostring
会将其转换为字符串,然后条件运算符会立即将其再次转换回 bool,这将是多余的。
如果您将变量声明为 bool
本身,则将应用相同的规则,但转换将在调用 module
块内而不是在 count
表达式中发生:
variable "my_var" {
type = bool
}
module "example" {
# ...
# This will automatically convert to bool true,
# just as it would've in the conditional operator.
my_var = "true"
}
如果您真的无法避免支持各种不寻常的布尔值编写方式,那么您可以编写自己的转换 table, 将基于字符串,并且指定转换后每个可能的字符串的布尔值:
locals {
sloppy_bool = tomap({
"1" = true
"true" = true
"0" = false
"false" = false
})
my_var = local.sloppy_bool[var.my_var]
}
因为映射类型(映射类型和对象类型)只支持字符串作为键,local.sloppy_bool[var.my_var]
会自动将var.my_var
转换为字符串,就像你写tostring(var.my_var)
一样。然后它将在 table 和 return 中查找相应的布尔值的结果,这意味着您可以在模块的其他地方使用 local.my_var
而不是 var.my_var
并依赖它始终是一个真正的布尔值。
我建议只有当您的模块的先前版本可以容忍这种类型的奇怪输入并且您需要与其保持兼容时才这样做。对于一个全新的模块,我认为这是 non-idiomatic 并且可能会让任何已经熟悉 Terraform 并尝试使用该模块的人感到困惑,因为他们需要熟悉您对类型转换的不寻常定义,而不是而不是依赖他们对 built-in 转换规则的了解。