使用hclwrite中的cty获取值的类型。

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

Get the type of value using cty in hclwrite

问题

我正在寻找一种使用go-cty包在hclwrite中找到变量类型的方法。

我的目标是生成一个如下所示的变量文件:

variable "test_var" {
  val1 = bool
  val2 = string
  val3 = number
}

参考链接:https://developer.hashicorp.com/terraform/language/values/variables

我正在使用以下代码生成这个文件。

    vars := hclwrite.NewEmptyFile()
    vars_root_body := vars.Body()
    vars_file, vars_create_err := os.Create("variables.tf")
    logErrors(vars_create_err)
    vars_block := vars_root_body.AppendNewBlock("variable",[]string{"test_var"})
    vars_block_body := vars_block.Body()

    vars_block_body.SetAttributeValue("val", cty.Value{})

    _, vars_write_err := vars_file.Write(vars.Bytes())
    logErrors(vars_write_err)
    defer vars_file.Close()

上述代码生成的结果是:

variable "test_var" {
  val = null
}

我想获取该变量的类型,并根据该类型设置属性值,就像上面的参考链接中所示。我尝试了很多方法,但没有得到任何结果。有人可以帮助我吗?

我尝试了上述代码和其他很多方法,例如:

cty.SetValEmpty(cty.Bool)

但都没有成功。

英文:

am looking for a way to find the type of variable using go-cty package in hclwrite.

My aim is to generate a variables file like below

variable "test_var" {
  val1 = bool
  val2 = string
  val3 = number
}

reference: https://developer.hashicorp.com/terraform/language/values/variables

I am using the below code to generate this.

    vars := hclwrite.NewEmptyFile()
    vars_root_body := vars.Body()
    vars_file, vars_create_err := os.Create("variables.tf")
    logErrors(vars_create_err)
    vars_block := vars_root_body.AppendNewBlock("variable",[]string{"test_var"})
    vars_block_body := vars_block.Body()

    vars_block_body.SetAttributeValue("val", cty.Value{})

    _, vars_write_err := vars_file.Write(vars.Bytes())
    logErrors(vars_write_err)
    defer vars_file.Close()

the above code generates this

variable "test_var" {
  val = null
}

I want to fetch the type of that variable and set the attribute value based on that type, as show in the reference link above. I tried lot of ways but didn't get anything. Can someone please help me on this?

I tried the above code and lot of other ways like

cty.SetValEmpty(cty.Bool)

but it didn't work.

答案1

得分: 3

在Terraform中,variable块的预期语法包括一个名为type的参数,而不是一个名为val的参数。根据你的示例,我假设你想要填充type

Terraform使用的类型约束语法不是HCL的直接部分,因此没有内置的方法可以在一步中生成该语法。然而,类型约束是由HCL的标识符和函数调用语法构建的,而hclwrite确实有一些函数可以帮助生成这些作为单独部分:

	f := hclwrite.NewEmptyFile()
	rootBody := f.Body()
	varBlock := rootBody.AppendNewBlock("variable", []string{"example"})
	varBody := varBlock.Body()
	varBody.SetAttributeRaw(
		"type",
		hclwrite.TokensForFunctionCall(
			"set",
			hclwrite.TokensForIdentifier("string"),
		),
	)
	fmt.Printf("%s", f.Bytes())

以上代码将生成以下内容:

variable "example" {
  type = set(string)
}

如果你已经有一个cty.Value值,你可以使用Type方法获取其类型。然而,如上所述,没有现成的函数可以将类型转换为类型表达式,因此如果你想能够为任何值生成类型约束,你需要自己编写一个函数,包装TokensForFunctionCallTokensForIdentifier函数。例如:

package main

import (
	"fmt"
	"sort"

	"github.com/hashicorp/hcl/v2/hclwrite"
	"github.com/zclconf/go-cty/cty"
)

func main() {
	f := hclwrite.NewEmptyFile()
	rootBody := f.Body()
	varBlock := rootBody.AppendNewBlock("variable", []string{"example"})
	varBody := varBlock.Body()
	varBody.SetAttributeRaw(
		"type",
		typeExprTokens(cty.Set(cty.String)),
	)
	fmt.Printf("%s", f.Bytes())
}

func typeExprTokens(ty cty.Type) hclwrite.Tokens {
	switch ty {
	case cty.String:
		return hclwrite.TokensForIdentifier("string")
	case cty.Bool:
		return hclwrite.TokensForIdentifier("bool")
	case cty.Number:
		return hclwrite.TokensForIdentifier("number")
	case cty.DynamicPseudoType:
		return hclwrite.TokensForIdentifier("any")
	}

	if ty.IsCollectionType() {
		etyTokens := typeExprTokens(ty.ElementType())
		switch {
		case ty.IsListType():
			return hclwrite.TokensForFunctionCall("list", etyTokens)
		case ty.IsSetType():
			return hclwrite.TokensForFunctionCall("set", etyTokens)
		case ty.IsMapType():
			return hclwrite.TokensForFunctionCall("map", etyTokens)
		default:
			// Should never happen because the above is exhaustive
			panic("unsupported collection type")
		}
	}

	if ty.IsObjectType() {
		atys := ty.AttributeTypes()
		names := make([]string, 0, len(atys))
		for name := range atys {
			names = append(names, name)
		}
		sort.Strings(names)

		items := make([]hclwrite.ObjectAttrTokens, len(names))
		for i, name := range names {
			items[i] = hclwrite.ObjectAttrTokens{
				Name:  hclwrite.TokensForIdentifier(name),
				Value: typeExprTokens(atys[name]),
			}
		}

		return hclwrite.TokensForObject(items)
	}

	if ty.IsTupleType() {
		etys := ty.TupleElementTypes()
		items := make([]hclwrite.Tokens, len(etys))
		for i, ety := range etys {
			items[i] = typeExprTokens(ety)
		}
		return hclwrite.TokensForTuple(items)
	}

	panic(fmt.Errorf("unsupported type %#v", ty))
}

该程序将生成与前面示例相同的输出。你可以更改func main以将不同的类型传递给typeExprTokens,以查看它在一些不同类型上的行为。

英文:

The expected syntax for a variable block in Terraform includes an argument named type, not an argument named val. From your example I assume that you are intending to populate type.

The type constraint syntax that Terraform uses is not directly part of HCL and so there isn't any built-in way to generate that syntax in only one step. However, type constraint are built from HCL's identifier and function call syntaxes, and hclwrite does have some functions for helping to generate those as individual parts:

	f := hclwrite.NewEmptyFile()
rootBody := f.Body()
varBlock := rootBody.AppendNewBlock("variable", []string{"example"})
varBody := varBlock.Body()
varBody.SetAttributeRaw(
"type",
hclwrite.TokensForFunctionCall(
"set",
hclwrite.TokensForIdentifier("string"),
),
)
fmt.Printf("%s", f.Bytes())

The above will generate the following:

variable "example" {
type = set(string)
}

If you already have a cty.Value value then you can obtain its type using the Type method. However, as mentioned above there isn't any ready-to-use function for converting a type into a type expression, so if you want to be able to generate a type constraint for any value then you'd need to write a function for this yourself, wrapping the TokensForFunctionCall and TokensForIdentifier functions. For example:

package main
import (
"fmt"
"sort"
"github.com/hashicorp/hcl/v2/hclwrite"
"github.com/zclconf/go-cty/cty"
)
func main() {
f := hclwrite.NewEmptyFile()
rootBody := f.Body()
varBlock := rootBody.AppendNewBlock("variable", []string{"example"})
varBody := varBlock.Body()
varBody.SetAttributeRaw(
"type",
typeExprTokens(cty.Set(cty.String)),
)
fmt.Printf("%s", f.Bytes())
}
func typeExprTokens(ty cty.Type) hclwrite.Tokens {
switch ty {
case cty.String:
return hclwrite.TokensForIdentifier("string")
case cty.Bool:
return hclwrite.TokensForIdentifier("bool")
case cty.Number:
return hclwrite.TokensForIdentifier("number")
case cty.DynamicPseudoType:
return hclwrite.TokensForIdentifier("any")
}
if ty.IsCollectionType() {
etyTokens := typeExprTokens(ty.ElementType())
switch {
case ty.IsListType():
return hclwrite.TokensForFunctionCall("list", etyTokens)
case ty.IsSetType():
return hclwrite.TokensForFunctionCall("set", etyTokens)
case ty.IsMapType():
return hclwrite.TokensForFunctionCall("map", etyTokens)
default:
// Should never happen because the above is exhaustive
panic("unsupported collection type")
}
}
if ty.IsObjectType() {
atys := ty.AttributeTypes()
names := make([]string, 0, len(atys))
for name := range atys {
names = append(names, name)
}
sort.Strings(names)
items := make([]hclwrite.ObjectAttrTokens, len(names))
for i, name := range names {
items[i] = hclwrite.ObjectAttrTokens{
Name:  hclwrite.TokensForIdentifier(name),
Value: typeExprTokens(atys[name]),
}
}
return hclwrite.TokensForObject(items)
}
if ty.IsTupleType() {
etys := ty.TupleElementTypes()
items := make([]hclwrite.Tokens, len(etys))
for i, ety := range etys {
items[i] = typeExprTokens(ety)
}
return hclwrite.TokensForTuple(items)
}
panic(fmt.Errorf("unsupported type %#v", ty))
}

This program will generate the same output as the previous example. You can change func main to pass a different type to typeExprTokens to see how it behaves with some different types.

huangapple
  • 本文由 发表于 2022年11月8日 02:00:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/74350957.html
匿名

发表评论

匿名网友

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

确定