具有动态类型元素的对象列表
Posted
技术标签:
【中文标题】具有动态类型元素的对象列表【英文标题】:A list of objects with dynamic type elements 【发布时间】:2021-11-26 23:16:29 【问题描述】:我有一个对象列表,其中一个元素operand
可以是动态类型的字符串、数字或映射。
我将变量定义如下:
variable "settings"
type = list(object(
type=string
operator=string
operand=any
...
))
并且从调用模块,分配如下值:
settings = [
"operator" = "lessThan", "type" = "responseTime", "operand" = 10000 ,
"operator" = "is", "type" = "statusCode", "operand" = 200 ,
"operator" = "is", "property" = "content-type", "type" = "header", "operand" = "abc" ,
"operator" = "validatesJSONPath", "type" = "body", "operand" = "operator" = "contains", "operandValue" = "google", "jsonPath" = "id"
]
但是,这会引发以下错误:
The given value is not suitable for child module variable "settings" defined at operator\variables.tf:64,1-21: cannot find a common base type for all elements.
我怎样才能最好地解决这个问题?
【问题讨论】:
有趣的是,这个配置会导致 0.12 版本出现段错误。无论如何,any
对类型的名称有点误导,我之前也犯过同样的错误。 any
并不意味着它可以是“任何”不同的类型,而是当您声明它时,该类型可以是“任何”一种未知类型。我相信由于 Golang map
合并、反序列化、编组或类似这些方面的某些行为,您确切想做的事情是不可能的。您可能必须将 type
指定为仅 list
。
【参考方案1】:
在考虑 Terraform 类型约束时,您应该将 any
理解为要求 Terraform 自动推断出一个具体类型来替换它。 any
本身不是一个类型,而是一个占位符。
在您的情况下,您有效地要求 Terraform 推断与约束匹配的列表的元素类型。这与list(any)
的简单情况略有不同,但仍然有相同的约束:Terraform 需要找到一个具体类型来替换any
,然后将所有列表元素转换为该类型.
您所描述的情况似乎您更喜欢 Terraform 表现得像一种动态类型的语言而不是静态类型的语言,它只取您给它的任何值,然后动态检查它是否以合适的方式,如duck typing。
您可以在 Terraform 中通过设置 type = any
来实现这一点,这会要求 Terraform 自动推断 整个值的类型,这实际上根本不应用任何约束,因为该值已经具有具体类型所以any
将直接替换为该类型。
如果您希望可以在模块中的其他位置使用该值,例如 var.settings[0].operand.operator
,Terraform 将成功评估结构是否匹配,如果不匹配,则会引发动态操作错误,就像我们通常在动态中看到的那样像 Python 这样的编程语言。
您还可以通过对变量本身进行一些验证检查来找到中间立场,这大致相当于启动一个 Python 函数,对每个参数进行一些显式验证,如果它们不“嘎嘎”,则返回错误像鸭子一样”:
variable "settings"
type = any
validation
condition = alltrue([for o in var.settings : can(tostring(o.operator))])
error_message = "Each element must be an object with a string attribute named \"operator\"."
# ... and any other similar validation rules you want
像这样使用显式 validation
块的一个很好的好处是,Terraform 会将这些验证失败归因于调用 module
块内的参数,而不是仅仅让表达式内联失败。模块内部的实现细节。因此,在调用者看来,这是他们的模块 call 的问题,而不是模块本身的错误。
【讨论】:
这可能应该作为注释添加到文档中,因为该用例出现的频率很高,并且文档中目前没有明确的解决方案。类似动机的文档 sn-p 解释原理:terraform.io/docs/language/functions/… @Martin 即使我创建了settings
类型为any
的变量,我也会得到Inappropriate value for attribute "operand": string required.
。假设那是因为从上面的 3 个实例推断类型是字符串,但最后当它找到一个映射时,它抛出了这个错误。
如果 type = any
则 Terraform 没有理由认为 operand
必须是一个字符串,除非有其他限制它。我没有看到我在这里建议的任何会产生这种约束的东西,但也许你的模块中的其他地方有一些东西。以上是关于具有动态类型元素的对象列表的主要内容,如果未能解决你的问题,请参考以下文章