具有动态类型元素的对象列表



我有一个对象列表,其中一个元素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 operatorvariables.tf:64,1-21: cannot find a common base type for all elements.

我怎样才能最好地解决这个问题?

在考虑Terraform类型约束时,您应该将any理解为要求Terraform自动推断一个具体类型来替换它。any本身不是一个类型,而是一个占位符。

在您的例子中,您已经有效地要求Terraform推断出与约束匹配的列表的元素类型。这与list(any)的简单情况略有不同,但仍然具有相同的约束:Terraform需要找到一个具体类型来替换any,然后将所有列表元素转换为该类型。


你所描述的情况似乎你更喜欢Terraform表现得像一个动态类型的语言,而不是静态类型的语言,它只是接受你给它的任何值,然后动态检查它是否以合适的方式形成,就像鸭子类型一样。

您可以通过设置type = any在Terraform中实现这一点,它要求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块中的参数,而不是模块内的一些实现细节。因此,对于调用者来说,这将是他们的模块调用的问题,而不是模块本身的错误。

最新更新