在 Terraform Provider 中处理重新排序的列表属性

问题描述 投票:0回答:1

我正在使用 Terraform Plugin Framewok 实现 Terraform 提供程序。

我有这个资源

my_resource
,它将对象列表作为属性。

resource "my_resource" "dummy" {
  objects = [
    {
      field_1 = false
      field_2 = "value_1"
    },
    {
      field_1 = true
      field_2 = "value_2"
    },
    {
      field_1 = false
      field_2 = "value_3"
    }
  ]
}

我的问题是,读取资源的 API 会对

objects
列表进行重新排序(带有
field_1 = true
的对象在响应中被放置在第一位)。

因此,当应用给定的计划时,提供商将产生以下错误:

Error: Provider produced inconsistent result after apply

When applying changes to my_resource.dummy, provider
"provider[\"registry.terraform.io/hashicorp/my_resource\"]" produced an
unexpected new value: .objects[0].field_1: was cty.True, but now
cty.False.

This is a bug in the provider, which should be reported in the provider's own
issue tracker.

我怎样才能做到这一点? (我希望无论对象的顺序如何,该计划都能发挥作用)

terraform terraform-provider
1个回答
0
投票

如果您的远程 API 不将项目的顺序视为有意义/持久,那么 Terraform 的

list
数据类型可能不是用于建模此数据的正确类型。

还有其他两个选项可能效果更好。

  1. 如果远程系统将您显示的两个属性之一视为项目的唯一标识符,那么您可以使用对象映射,其中该唯一标识符用作键而不是值的一部分。

    例如,如果您的

    field_2
    预计在所有项目中都是唯一的,那么您可以从映射键中获取其值,然后用户将指定如下参数:

    objects = {
      value_1 = {
        field_1 = false
      }
      value_2 = {
        field_1 = false
      }
      value_3 = {
        field_1 = false
      }
    }
    

    如果远程系统不认为您的任何属性是对象的唯一标识符,则此方法不合适,因为两个对象不可能具有相同的

    field_2
    值。

  2. 如果没有一个属性alone是唯一标识符,但远程API要求所有对象作为一个整体是唯一的,那么你可以将其声明为对象的set,这是Terraform的数据唯一值的无序集合的类型。

    在配置中声明它的语法与本例中的示例相同,因为 Terraform 可以自动从元组(这是

    [ ... ]
    语法生成的)转换为集合。


如果您的远程 API 不保留顺序,但它不需要对象之间有任何唯一性,那么不幸的是,实际上并没有将该 API 设计很好地映射到 Terraform 中。 Terraform 希望能够区分就地编辑的对象与被删除的对象和添加的对象,因此它至少需要一些一些的方法来跟踪每个对象从一个计划/应用到整个计划的身份下一个。

但是,您可以使用一个更复杂的答案作为 Terraform 的其他数据类型都不适合您的 API 的最后手段:您可以编写自定义逻辑来检查结果是否一致,而不是返回最终数据到 Terraform 并让 Terraform 检查它是否一致(这不是你的情况,所以你得到了一个错误。)

我假设在您的“创建”和“更新”实现中,当前您有一些逻辑从 API 调用中获取响应来创建或更新对象,并使用它来构造您返回到 Terraform 的

objects
的值。这是一种典型的设计,当 API 的行为与 Terraform 对用于建模 API 的数据类型的期望一致时,该设计可以发挥作用,但如果 API 不符合 Terraform 的假设,则该设计不起作用。

相反,您可以编写一个函数,该函数接受

objects
的两个值并返回
true
(如果远程 API 认为它们等效)。为了这个回复,我们称其为
objectsAreEquivalent

在进行 API 调用来创建或更新后,您将像当前一样构造一个新的

objects
值,但不是立即将其返回到 Terraform,而是将其传递给您的
objectsAreEquivalent
函数以及Terraform 在
req.Plan
中提供的值。

如果

objectsAreEquivalent
返回
true
那么你可以丢弃你构造的新对象,只逐字返回
req.Plan
的值。然后 Terraform 会发现它与原始值匹配,因此由于顺序被保留,它将通过一致性检查。

如果

objectsAreEquivalent
返回
false
那么你的 API 可能有错误,因为它返回的内容与模块作者声明的内容不同。在这种情况下,您可以选择返回自己的错误消息,指出 API 返回了无效结果。

如果远程 API 执行的操作与告知的不同,那么您的提供程序实际上无法做任何有用的事情……这正是您看到的 Terraform 错误消息试图捕获的那种一致性问题。但是,如果您返回“自己的”错误消息,那么您至少可以将问题归咎于远程 API,而不是 Terraform 归咎于您的提供商,这将有望导致错误报告发送到更有用的地方。

© www.soinside.com 2019 - 2024. All rights reserved.