Writting Grafana Terraform data source definition, stuk on Json encode

Hello all,

I’m trying to generate a working HCL configuration as explained here
.

The HCL syntax is not overly complex and I’m using HashiCorp hclwrite for the task:

resource "grafana_data_source" "prometheus" {
  type                = "prometheus"
  name                = "mimir"
  url                 = "https://my-instances.com"
  basic_auth_enabled  = true
  basic_auth_username = "username"

  json_data_encoded = jsonencode({
    httpMethod        = "POST"
    prometheusType    = "Mimir"
    prometheusVersion = "2.4.0"
  })

  secure_json_data_encoded = jsonencode({
    basicAuthPassword = "password"
  })
}

But I’m stuck on how to generate the sections for json_data_encoded and secure_json_data_encoded as they are dictionaries but they are embedded into the jsonencode() function call.

My data comes from an existing JSON file which I got using the REST API and my Golang code looks like this:

func WriteHcl(hclFile string, jsonPayload []map[string]interface{}, verbose bool, dryRun bool) error {
	// https://grafana.com/docs/grafana-cloud/infrastructure-as-code/terraform/terraform-cloud-stack/
	// https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/data_source
	hcl := hclwrite.NewEmptyFile()
	rootBody := hcl.Body()
	encodedRegexp, _ := regexp.Compile(`jsonData|secureJsonData`)
	for _, dataSource := range jsonPayload {
		dsName := dataSource["name"]
		resourceBlock := rootBody.AppendNewBlock("resource", []string{"grafana_data_source", dsName.(string)})
		resourceBody := resourceBlock.Body()
		resourceBody.AppendNewline()
		resourceBody.SetAttributeValue("provider", cty.StringVal("grafana"))
		resourceBody.SetAttributeValue("is_default", cty.BoolVal(false))
		for key, value := range dataSource {
			str, check := value.(string)
			if check {
				resourceBody.SetAttributeValue(key, cty.StringVal(str))
			}
			bol, check := value.(bool)
			if check {
				resourceBody.SetAttributeValue(key, cty.BoolVal(bol))

			}
			itg, check := value.(int64)
			if check {
				resourceBody.SetAttributeValue(key, cty.NumberIntVal(itg))

			}
			flt, check := value.(float64)
			if check {
				resourceBody.SetAttributeValue(key, cty.NumberFloatVal(flt))
			}
			match := encodedRegexp.MatchString(key)
			if match {
                               // This is where I need to embed JSON encoded extra DATA
				fmt.Println("DEBUG: ", key, "->", value)
			}

		}
		resourceBody.AppendNewline()
	}
	rootBody.AppendNewline()
	if verbose {
		fmt.Printf("HCL payload: %s", hcl.Bytes())
	}
	if !dryRun {
		return os.WriteFile(hclFile, hcl.Bytes(), 0644)
	}
	return nil
}

I’m fairly new to Golang, please apologize if there is an obvious way to do this which I missed.

Thanks,

I found a way to acomplish what I need, pretty sure there is a more efficient way:

			// https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/encoding/jsonencode
			if key == "jsonData" || key == "secureJsonData" {
				var configMap map[string]cty.Value = make(map[string]cty.Value)
				if verbose {
					fmt.Printf("DEBUG: %s\n", key)
					for jsonKey, jsonValue := range value.(map[string]interface{}) {
						fmt.Printf("\tDEBUG: %s -> %s\n", jsonKey, jsonValue)
						str, check := jsonValue.(string)
						if check {
							configMap[jsonKey] = cty.StringVal(str)
						}
						bol, check := jsonValue.(bool)
						if check {
							configMap[jsonKey] = cty.BoolVal(bol)
						}
						itg, check := jsonValue.(int64)
						if check {
							configMap[jsonKey] = cty.NumberIntVal(itg)
						}
						flt, check := jsonValue.(float64)
						if check {
							configMap[jsonKey] = cty.NumberFloatVal(flt)
						}
						if jsonValue == nil {
							configMap[jsonKey] = cty.NilVal
						}
					}
				}
				resourceBody.SetAttributeRaw(equivalentKey,
					hclwrite.TokensForFunctionCall("jsonencode",
						hclwrite.TokensForValue(cty.ObjectVal(configMap)),
					))