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.
CodePudding user response:
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.