hcl icon indicating copy to clipboard operation
hcl copied to clipboard

How to define a struct to parse list of objects resource in hcl file. Keep getting `panic: unsuitable DecodeExpression target: no cty.Type (no cty field tags)`

Open hrdivyashree opened this issue 5 years ago • 5 comments

HCL Template

resource "test" "test-policy" {
  src_security_zone = src_sz
  dst_security_zone = dst_sz
  name              = "testpolicy"
  acl_type          = "pba"
  applied_on        = "dst"
  approval_ticket   = "20501"
  ports             = [{ approval_ticket = "23653", port_range = "9000", protocol = "tcp" }, { approval_ticket = "23653", port_range = "10504", protocol = "tcp" },]
}

I defined the structure for parsing the above HCL file as below.

type NaclPolicyPort struct {
	PortRange string `hcl:"port_range,attr"`
	Protocol string `hcl:"protocol,attr"`
	ApprovalTicket string `hcl:"approval_ticket,attr"`
}
type NaclPolicyResource struct{
	LabelNaclPolicy string `hcl:"name,label"`
	LabelNaclPolicyName string `hcl:"name,label"`

	Name string `hcl:"name,attr"`
	SrcSecurityZone string `hcl:"src_security_zone,attr"`
	DstSecurityZone string `hcl:"dst_security_zone,attr"`
	AclType string `hcl:"acl_type,attr"`
	AppliedOn string `hcl:"applied_on,attr"`
	ApprovalTicket string `hcl:"approval_ticket,attr"`
	Ports  []NaclPolicyPort `hcl:"ports"`
}

Expected behavior

What should have happened? I get an error when my program tries to parse hcl:ports as below. panic: unsuitable DecodeExpression target: no cty.Type for main.NaclPolicyPort (no cty field tags)

Actual behavior

What actually happened? I was expecting this to be parsed and I should have been able to get the ports.

hrdivyashree avatar Aug 14 '20 01:08 hrdivyashree

Hey @hrdivyashree, I am having the same issue, were you able to find a solution ?

xsaamiir avatar Oct 20 '20 06:10 xsaamiir

Not OP, but I got it to work by replacing hcl with cty in the child struct's tags, but couldn't figure out how to use optional fields. :confused:

This is a serious issue when using gohcl...

type NaclPolicyPort struct {
	PortRange string `cty:"port_range"`
	Protocol string `cty:"protocol"`
	ApprovalTicket string `cty:"approval_ticket"`
}

moqmar avatar Jan 02 '21 17:01 moqmar

Same here and this issue is worse when the list of maps contain an expression. Still have not gotten it to work, example

data = [{url=dependency.urls[0]}]

I tried decoding it with

type Net struct {
   URL hcl.Expression `hcl:"url,attr"`
}

type Config struct {
   Data []URL `hcl:"data,attr"`
}

This gives me a panic

shubhang93 avatar Jul 08 '22 17:07 shubhang93

Instread of using a Port struct you can use:

Ports    []map[string]string `hcl:"ports,attr"`

I'm assuming this is because it's an unnamed block? [ { stuff = stuff } ]. I'm not sure how you'd do it for mixed types, an interface maybe.

b0bu avatar Apr 28 '23 14:04 b0bu

Thank you for the hint @b0bu. Unfortunately, an interface doesn't work either. Here's my code example with using interface{}:

const inputBody = `module "module1" {
  source = "../../modules/pipeline"

  steps = [
    {
      name = "Step1",
      type = "manualApproval",
      params = {
        server = "one",
      },
    },
  ]
}
`

type Step struct {
	Name      string            `hcl:"name"`
	Type      string            `hcl:"type"`
	DependsOn []string          `hcl:"dependsOn,optional"`
	Params    map[string]string `hcl:"params,attr"`
	Remain    hcl.Body          `hcl:",remain"`
}

type Steps []Step

type Pipeline struct {
	Name   string                   `hcl:",label"`
	Source string                   `hcl:"source"`
	Steps  []map[string]interface{} `hcl:"steps,attr"`
	Remain hcl.Body                 `hcl:",remain"`
}

type Module struct {
	Module Pipeline `hcl:"module,block"`
}

And here's the error I get:

panic: unsuitable DecodeExpression target: no cty.Type for interface {}

goroutine 1 [running]:
github.com/hashicorp/hcl/v2/gohcl.DecodeExpression({0x14ac210, 0xc0000f4780}, 0x11d01c0?, {0xc0000fe6c0, 0xc0000f20c0})
	/Users/bilen/go/pkg/mod/github.com/hashicorp/hcl/[email protected]/gohcl/decode.go:296 +0x82c
github.com/hashicorp/hcl/v2/gohcl.decodeBodyToStruct({0x12559e8, 0xc0000d2420}, 0x1?, {0x11ec2c0?, 0xc0000f20a0?, 0x1?})
	/Users/bilen/go/pkg/mod/github.com/hashicorp/hcl/[email protected]/gohcl/decode.go:127 +0xe5f
github.com/hashicorp/hcl/v2/gohcl.decodeBodyToValue({0x12559e8, 0xc0000d2420}, 0x12?, {0x11ec2c0?, 0xc0000f20a0?, 0x1?})
	/Users/bilen/go/pkg/mod/github.com/hashicorp/hcl/[email protected]/gohcl/decode.go:46 +0xc5
github.com/hashicorp/hcl/v2/gohcl.decodeBlockToValue(0xc00009ef70, 0xc0000f20a0?, {0x11ec2c0?, 0xc0000f20a0?, 0x12578a0?})
	/Users/bilen/go/pkg/mod/github.com/hashicorp/hcl/[email protected]/gohcl/decode.go:264 +0x72
github.com/hashicorp/hcl/v2/gohcl.decodeBodyToStruct({0x12559e8, 0xc0000d24d0}, 0xc000142000?, {0x11dd7e0?, 0xc0000f20a0?, 0x9b?})
	/Users/bilen/go/pkg/mod/github.com/hashicorp/hcl/[email protected]/gohcl/decode.go:227 +0x2125
github.com/hashicorp/hcl/v2/gohcl.decodeBodyToValue({0x12559e8, 0xc0000d24d0}, 0x0?, {0x11dd7e0?, 0xc0000f20a0?, 0x0?})
	/Users/bilen/go/pkg/mod/github.com/hashicorp/hcl/[email protected]/gohcl/decode.go:46 +0xc5
github.com/hashicorp/hcl/v2/gohcl.DecodeBody({0x12559e8, 0xc0000d24d0}, 0x334?, {0x11cd840?, 0xc0000f20a0?})
	/Users/bilen/go/pkg/mod/github.com/hashicorp/hcl/[email protected]/gohcl/decode.go:39 +0x105
main.main()
	/Users/bilen/src/bilenkis/cources/hcl-parser/main.go:83 +0x18c
exit status 2

Using cty instead of hcl allows me to parse the structure properly but doesn't solve the issue with optional fields. Are there any other workarounds? I'm happy to test them out. Thanks!

bilenkis avatar May 16 '23 10:05 bilenkis