Hclwrite(v2) a object with a reference value

Hi,

We works on golang programm to generate terraform files and I am having difficulty generating a local of type object with a value reference, like this :

locals {
  servers = {
    "admin@server-1" = {
      hostname = "srv1"
      login    = "admin"
      password = data.vault_generic_secret.srv1.data["password"]
      port     = 22
    }
    "admin@server-2" = {
      hostname = "srv2"
      login    = "admin"
      password = data.vault_generic_secret.srv2.data["password"]
      port     = 22
    }
  }
}

An example of code to generate this file :

package main

import (
	"fmt"

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

func main() {
	f := hclwrite.NewEmptyFile()
	rootBody := f.Body()
	localsBlock := rootBody.AppendNewBlock("locals", nil).Body()
	localsBlock.SetAttributeValue("servers",
		cty.ObjectVal(map[string]cty.Value{
			"admin@server-1": cty.ObjectVal(map[string]cty.Value{
				"hostname": cty.StringVal("srv1"),
				"login":    cty.StringVal("admin"),
				"password": <?>,
				"port":     cty.NumberIntVal(22),
			}),
			"admin@server-2": cty.ObjectVal(map[string]cty.Value{
				"hostname": cty.StringVal("srv2"),
				"login":    cty.StringVal("admin"),
				"password": <?>,
				"port":     cty.NumberIntVal(22),
			}),
		}))
	fmt.Printf("%s", f.Bytes())
}

but I don’t know what to do for the reference in password

Have you an idea ?

Hi @jeremmfr,

hclwrite doesn’t currently have a helper function for generating this sort of expression with a mixture of literal and reference parts. Its existing helpers are only for setting entirely-literal values or single references.

I think therefore you’d need to use SetAttributeRaw to meet this use-case with today’s hclwrite. That’ll require constructing the necessary tokens yourself, because the AST layer doesn’t have any rule for doing that automatically.

Alternatively, you could generate this in a .tf.json file instead, which means you can use a normal JSON encoder rather than hclwrite. The JSON syntax equivalent of what you shared would be the following:

{
  "locals": {
    "servers": {
      "admin@server-1": {
        "hostname": "srv1",
        "login": "admin",
        "password": "${data.vault_generic_secret.srv1.data[\"password\"]}",
        "port": 22
      },
      "admin@server-2": {
        "hostname": "srv2",
        "login": "admin",
        "password": "${data.vault_generic_secret.srv2.data[\"password\"]}",
        "port": 22
      }
    }
  }
}

The Terraform language’s JSON mode exists specifically to make it easier to do this sort of dynamic generation. You can see more about how it works in JSON Configuration Syntax.

Thanks for your quick reply