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

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 必须是一个字符串,除非有其他限制它。我没有看到我在这里建议的任何会产生这种约束的东西,但也许你的模块中的其他地方有一些东西。

以上是关于具有动态类型元素的对象列表的主要内容,如果未能解决你的问题,请参考以下文章

如何从QML基本类型列表中动态删除元素?

vector

在 thymeleaf 中添加和删除具有多个元素的动态行并与列表绑定

具有动态键的对象的 Apollo/GraphQL 字段类型

具有动态键的对象的 Apollo/GraphQL 字段类型

具有动态键的对象的 Apollo/GraphQL 字段类型