有没有办法在提供者测试中避免硬编码 Terraform TypeSet 的哈希索引值?

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

Is there a way to avoid hardcoding Terraform TypeSet hashed index values in provider tests?

问题

在使用TypeSet时,Terraform指出哈希索引是基于集合的值计算的。我使用Go编写了一个Terraform提供程序,使用Terraform Provider Go SDK,我目前需要在测试中硬编码这些索引值。是否可以避免在Terraform提供程序测试中硬编码这些值?

Terraform文档中提到了以下内容,但没有提供如何计算哈希索引值或避免计算它们的信息。

TypeSet项以集合的属性的哈希值计算的索引值存储在状态中。

参考:Terraform文档:https://www.terraform.io/plugin/sdkv2/schemas/schema-types

以下是文档中提供的示例,其中1061987227493694946是自动生成的哈希索引值。

"ingress.#": "2",
"ingress.1061987227.cidr_blocks.#": "1",
"ingress.1061987227.cidr_blocks.0": "10.0.0.0/8",
"ingress.1061987227.description": "",
"ingress.1061987227.from_port": "80",
"ingress.1061987227.ipv6_cidr_blocks.#": "0",
"ingress.1061987227.protocol": "tcp",
"ingress.1061987227.security_groups.#": "0",
"ingress.1061987227.self": "false",
"ingress.1061987227.to_port": "9000",
"ingress.493694946.cidr_blocks.#": "2",
"ingress.493694946.cidr_blocks.0": "0.0.0.0/0",
"ingress.493694946.cidr_blocks.1": "10.0.0.0/8",
"ingress.493694946.description": "",
"ingress.493694946.from_port": "80",
"ingress.493694946.ipv6_cidr_blocks.#": "0",
"ingress.493694946.protocol": "tcp",
"ingress.493694946.security_groups.#": "0",
"ingress.493694946.self": "false",
"ingress.493694946.to_port": "8000",

目前,在我的Go测试中,我硬编码了哈希索引值,我希望避免这样做。以下是一个摘录,其中包含3个硬编码的索引值:36869850215520865453172309932

resource.TestCheckResourceAttr(resourceName, "workspace_configs.368698502.client_ip_header", "Fastly-Client-IP"),
resource.TestCheckResourceAttr(resourceName, "workspace_configs.368698502.instance_location", "advanced"),
resource.TestCheckResourceAttr(resourceName, "workspace_configs.368698502.listener_protocols.#", "1"),
resource.TestCheckResourceAttr(resourceName, "workspace_configs.368698502.listener_protocols.1552086545", "https"),
resource.TestCheckResourceAttr(resourceName, "workspace_configs.368698502.routes.#", "1"),
resource.TestCheckResourceAttr(resourceName, "workspace_configs.368698502.routes.3172309932.certificate_ids.#", "0"),
resource.TestCheckResourceAttr(resourceName, "workspace_configs.368698502.routes.3172309932.connection_pooling", "true"),

完整的代码在这里:https://github.com/signalsciences/terraform-provider-sigsci/blob/main/provider/resource_corp_cloudwaf_instance_test.go

有没有办法避免硬编码索引值?例如,是否可以创建一个满足TestCheckResourceAttrWith中使用的CheckResourceAttrWithFunc接口的函数?

英文:

When using TypeSet, Terraform indicates the hash indexes are calculated based on the values of the set. I have a Terraform Provider written in Go using the Terraform Provider Go SDK where I currently need to hard code these index values in the tests. Can hardcoding the values in the Terraform Provider tests be avoided?

Terraform docs say the following, but don't provide information on how to calculate the hash index values or avoid calculating them.

> TypeSet items are stored in state with an index value calculated by the hash of the attributes of the set.

Ref: Terraform docs: https://www.terraform.io/plugin/sdkv2/schemas/schema-types

Here's the example provided in the documentation where 1061987227 and 493694946 are auto-generated hash index values.

"ingress.#": "2",
"ingress.1061987227.cidr_blocks.#": "1",
"ingress.1061987227.cidr_blocks.0": "10.0.0.0/8",
"ingress.1061987227.description": "",
"ingress.1061987227.from_port": "80",
"ingress.1061987227.ipv6_cidr_blocks.#": "0",
"ingress.1061987227.protocol": "tcp",
"ingress.1061987227.security_groups.#": "0",
"ingress.1061987227.self": "false",
"ingress.1061987227.to_port": "9000",
"ingress.493694946.cidr_blocks.#": "2",
"ingress.493694946.cidr_blocks.0": "0.0.0.0/0",
"ingress.493694946.cidr_blocks.1": "10.0.0.0/8",
"ingress.493694946.description": "",
"ingress.493694946.from_port": "80",
"ingress.493694946.ipv6_cidr_blocks.#": "0",
"ingress.493694946.protocol": "tcp",
"ingress.493694946.security_groups.#": "0",
"ingress.493694946.self": "false",
"ingress.493694946.to_port": "8000",

Currently, in my Go tests, I hardcode the hash index values which I'd like to avoid. Here's an excerpt with 3 hard coded index values: 368698502, 1552086545, and 3172309932:

resource.TestCheckResourceAttr(resourceName, "workspace_configs.368698502.client_ip_header", "Fastly-Client-IP"),
resource.TestCheckResourceAttr(resourceName, "workspace_configs.368698502.instance_location", "advanced"),
resource.TestCheckResourceAttr(resourceName, "workspace_configs.368698502.listener_protocols.#", "1"),
resource.TestCheckResourceAttr(resourceName, "workspace_configs.368698502.listener_protocols.1552086545", "https"),
resource.TestCheckResourceAttr(resourceName, "workspace_configs.368698502.routes.#", "1"),
resource.TestCheckResourceAttr(resourceName, "workspace_configs.368698502.routes.3172309932.certificate_ids.#", "0"),
resource.TestCheckResourceAttr(resourceName, "workspace_configs.368698502.routes.3172309932.connection_pooling", "true"),

The full code is here: https://github.com/signalsciences/terraform-provider-sigsci/blob/main/provider/resource_corp_cloudwaf_instance_test.go

Is there a way to avoid hard coding the index values? For example, is it possible to create a function that fulfills the CheckResourceAttrWithFunc interface used with TestCheckResourceAttrWith?

答案1

得分: 1

这些哈希值是 Terraform 的旧版本遗留下来的,SDKv2 仍然使用这些哈希值,以便使用它构建的提供程序与旧版本的 Terraform 兼容。

resource.TextCheckResourceAttr 是一个辅助函数,它返回一个 resource.TestCheckFunc 值,实际上它只是一个指向具有以下签名的函数的命名类型的引用:

func(*terraform.State) error

resource 包中还有许多其他返回测试检查函数的辅助函数,其中一些特别用于描述关于集合的断言,同时避免提及特定的哈希键:

我建议首先查看每个函数的文档,看看它是否符合您想编写的断言类型。

如果发现没有符合您需要描述的规则的函数,那么可以编写一个符合上述签名的自定义函数,然后使用任意逻辑来分析给定的 *terraform.State 值中的数据。

您可以使用预定义的测试检查函数辅助程序作为使用该 API 的示例。虽然在 resource 包中实现时有一些间接性,但一般的模式是:

  1. 访问根模块(因为提供程序测试通常不使用嵌套模块)

    ms := s.RootModule()
    
  2. 在根模块中找到要针对其进行测试的特定资源实例:

    rs, ok := ms.Resources[name]
    if !ok {
    	return nil, fmt.Errorf("Not found: %s in %s", name, ms.Path)
    }
    
    is := rs.Primary
    if is == nil {
    	return nil, fmt.Errorf("No primary instance: %s in %s", name, ms.Path)
    }
    
  3. is 是一个指向 terraform.InstanceState 对象的指针,其属性位于 Attributes 映射中。

    在这里,您将找到包括您想要避免硬编码的哈希值在内的原始键,因此通常需要编写逻辑来迭代所有属性,查找与特定前缀匹配的属性,然后可能还要匹配特定后缀以确定找到的叶属性,然后仅对映射中的键与相关条件匹配的值进行断言。

英文:

These hash values are a holdover from older versions of Terraform which SDKv2 continues to use so that providers built with it can remain compatible with those older versions of Terraform.

resource.TextCheckResourceAttr is a helper function which returns a resource.TestCheckFunc value, which is really just a named type for a reference to a function with the following signature:

func(*terraform.State) error

There are many other helper functions which return test check functions in the resource package, and some of them are specifically intended for describing assertions about sets while avoiding mentioning a specific hash key:

I would suggest first reviewing the documentation for each of those to see if it matches the kind of assertion you'd like to write.

If you find that none of them matches the rule you need to describe then the fallback is to write your own function matching the above signature, which can then use arbitrary logic to analyze the data in the given *terraform.State value.

You can use the predefined test check function helpers as examples for how to work with that API. Although there's some indirection in how it's implemented in the resource package, the general pattern is:

  1. Access the root module (since provider tests don't typically use nested modules)

    ms := s.RootModule()
    
  2. Find the specific resource instance inside the root module that you want to test against:

    rs, ok := ms.Resources[name]
    if !ok {
    	return nil, fmt.Errorf("Not found: %s in %s", name, ms.Path)
    }
    
    is := rs.Primary
    if is == nil {
    	return nil, fmt.Errorf("No primary instance: %s in %s", name, ms.Path)
    }
    
  3. is is a pointer to a terraform.InstanceState object, whose attributes are in the Attributes map.

    You'll find in here the raw keys including the hash values that you want to avoid hard-coding, so you'll typically need to write logic that iterates over all of the attributes to look for ones matching a particular prefix, then possibly also match a particular suffix to determine which leaf attribute you've found, and then make assertions only for values in the map whose keys match the relevant criteria.

huangapple
  • 本文由 发表于 2022年9月12日 04:46:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/73682537.html
匿名

发表评论

匿名网友

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

确定