In Terraform, how do I apply DiffSuppressFunc on a TypeList with each element in the list being an object following a schema?

huangapple go评论61阅读模式
英文:

In Terraform, how do I apply DiffSuppressFunc on a TypeList with each element in the list being an object following a schema?

问题

简要背景

我正在编写一个Terraform提供程序(使用Terraform SDK),其中包含一个资源。资源的架构有几个属性,其中一个是

			"sample_attribute": {
				Type:        schema.TypeList,
				Optional:    true,
				Description: "A sample attribute whose details have been redacted.",
				Elem:        sampleAttributeSchemaExpanded()
			},

其中 sampleAttributeSchemaExpanded() 返回一个属性列表(*schema.Resource),其中一些是整数,一些是布尔值,一些是字符串等。

我想要在 sample_attribute 上应用 DiffSuppressFunc

我尝试解决的问题

当创建此资源(即运行 terraform apply )并读取资源(即在第一次 terraform apply 后进行 terraform plan 以检查更新时),资源中的相应方法将发送API调用来创建资源,以及读取资源。

问题是,在创建API调用的请求和响应中的元素顺序(在 sample_attribute 中)与读取API调用中的元素顺序不同。因此,即使不对Terraform配置进行任何更改,在运行 terraform plan 时,仍会显示漂移(非空更改列表),建议对属于 sample_attribute 的元素进行更改。在Terraform配置中重新排列 sample_attribute 中的元素顺序可以消除漂移,但这显然不应该是解决方案。

为了解决此问题,我想以这样的方式使用 DiffSuppressFunc,即仅当当前配置(新的)和状态(旧的)中 sample_attribute 相关的配置之间的差异仅为元素顺序时,才抑制差异。如果对 sample_attribute 中的元素进行了实际更改,则应像往常一样显示差异。


不幸的是,我还没有找到一个关于如何使用带有对象的 TypeListDiffSuppressFunc 的良好示例,这就是为什么我被阻碍的原因。如果您有关于此的见解、示例(甚至建议,如果您认为其他方法也可以工作)将不胜感激 In Terraform, how do I apply DiffSuppressFunc on a TypeList with each element in the list being an object following a schema?

P.S. 我的朋友圈中的一个建议是对读取响应中获得的 sample_attribute 的元素进行排序,以使它们与Terraform配置中 sample_attribute 的元素顺序相一致,但我不想这样做(除非无法通过其他方法(如 DiffSuppressFunc)来做到这一点)。

英文:

Brief Context

I am working on coding a Terraform Provider (using the Terraform SDK), which has a resource. The schema of the resource has a couple of attributes, of which one is

			"sample_attribute": {
				Type:        schema.TypeList,
				Optional:    true,
				Description: "A sample attribute whose details have been redacted.",
				Elem:        sampleAttributeSchemaExpanded()
			},

where sampleAttributeSchemaExpanded() returns a list of attributes (*schema.Resource) of which some are integers, some are boolean, some are strings, etc.

What I would like to achieve here, is to apply a DiffSuppressFunc on sample_attribute.

The Problem I'm Trying To Solve

When this resource is created (i.e. running terraform apply) and the resource is read (i.e. upon terraform plan after the first terraform apply to check for updates), API calls are sent from the respective methods in the resource to create the resource, and read the resource respectively.

The problem is that the order of elements (in sample_attribute) in the create API call's request and response and the order of elements in the read API call are dissimilar. Owing to this, after the first terraform apply, even if no changes are made to the Terraform Configuration, upon running terraform plan, a drift (non-null list of changes) is shown, suggesting a change to be made to elements belonging to sample_attribute. Restructuring the order of elements in sample_attribute in the Terraform Configuration eliminates the drift, but this should trivially not be the solution.

To fix this, I would like to use DiffSuppressFunc in such a way that differences are suppressed if the difference between the current configuration(new) and the configuration in the state (old) pertaining to sample_attribute is only the order of elements. If real changes are made to an element in sample_attribute, the differences are to be shown as usual.


Unfortunately, I haven't been able to find a good example on using DiffSuppressFunc with TypeList with each element as an object (following a schema), which is why I am blocked. Any insights or a sample on this (or even suggestions, if you think other methods would work) would really be appreciated In Terraform, how do I apply DiffSuppressFunc on a TypeList with each element in the list being an object following a schema?

P.S. One suggestion I've taken from my circles is to sort the elements of sample_attribute obtained in the read response to align them with the order of elements in sample_attribute in the Terraform Configuration, but I'd not want to do that (unless it is impossible to do this by any other means such as DiffSuppressFunc).

答案1

得分: 1

DiffSuppressFunc的签名是:

func(k, old, new string, d *schema.ResourceData) bool

不幸的是,这个签名意味着它只能与“类似字符串”的属性一起工作,因为其他属性类型无法作为oldnew中的单个字符串提供。这是旧的Terraform插件SDK的限制,最初设计用于早期版本的Terraform,这些版本还没有完全支持列表和映射。

对于这样的要求,通常最好使用现代插件框架而不是旧的SDK。新框架是为现代Terraform设计的,因此它支持Terraform本身支持的所有类型和数据结构,包括对象列表。

这个框架没有直接类似于DiffSuppressFunc的功能,但您可以使用更通用的计划修改功能来实现相同的效果。SDK使用DiffSupressFunc的结果将属性重置为其来自先前状态的值,您可以通过比较req.StateValuereq.PlanValue,然后将req.PlanValue设置为与req.StateValue完全相同以“抑制差异”。

或者,您可以定义一个具有语义相等规则的自定义类型,告诉框架如何比较两个您自定义类型的值,并决定它们是否等效。如果您的类型指示两个值是等效的,那么框架将自动保留先前的值,类似于旧SDK中DiffSuppressFunc的处理方式。

如果无法迁移到现代插件框架,那么旧的SDK中的替代方法是资源级CustomizeDiff函数,它在范围上类似于插件框架的“计划修改”概念。在CustomizeDiff函数中,您可以实现一个规则,用于比较属性的旧值和新值,并在适当时使用d.Set将新值覆盖回旧值。

英文:

The signature of DiffSuppressFunc is:

func(k, old, new string, d *schema.ResourceData) bool

Unfortunately this signature means that it's only able to work with "string-like" attributes, because other attribute types cannot be provided as a single string in old and new. This is a limitation of the old Terraform plugin SDK that was originally designed for much older versions of Terraform that didn't yet have full support for lists and maps.

For requirements like this it's typically better to use the modern Plugin Framework instead of the legacy SDK. The new framework was designed for modern Terraform and so it supports all of the same types and data structures that Terraform itself supports, including lists of objects.

The framework does not have a feature that's directly analogous to DiffSuppressFunc, but you can use the more general plan modification features to achieve the same effect. The SDK uses the DiffSupressFunc result to reset an attribute back to its value from the prior state, which you can implement yourself in a plan modifier by comparing req.StateValue with req.PlanValue and then setting req.PlanValue to exactly req.StateValue to "suppress the diff".

Alternatively, you can define a custom type with a semantic equality rule to tell the framework how to compare two values of your custom type and decide if they are equivalent. If your type indicates that the two values are equivalent then the framework will automatically retain the prior value, in a similar way as DiffSuppressFunc is treated in the old SDK.

If you cannot migrate to the modern Plugin Framework then an an alternative with the old SDK is the resource-level CustomizeDiff function, which is similar in scope to the plugin framework's "plan modification" concept. In a CustomizeDiff function you can implement a rule which compares the old and new values for an attribute and uses d.Set to override the new value back to the old value when appropriate.

huangapple
  • 本文由 发表于 2023年7月3日 14:47:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/76602423.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定