Skip to content

Commit

Permalink
hcl2template: fix func to get vars from a config
Browse files Browse the repository at this point in the history
The previous implementation of the GetVarsByType function worked only on
top-level attributes, ignoring the nested blocks in the structure.

This implies that if a datasource depends on another through an
expression within a nested block, we may not execute it first, and then
executing this datasource before its dependent is possible, resulting in
an error in the end.

This commit is an attempt at making this more reliable for HCL configs,
but only works on configs lifted from HCL files for now. We need to make
this more reliable for later iterations.
  • Loading branch information
lbajolet-hashicorp committed Aug 25, 2023
1 parent 87dbdb1 commit 70983d1
Showing 1 changed file with 34 additions and 9 deletions.
43 changes: 34 additions & 9 deletions hcl2template/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ package hcl2template
import (
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"reflect"
"strings"

"github.com/gobwas/glob"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/hashicorp/packer/hcl2template/repl"
hcl2shim "github.com/hashicorp/packer/hcl2template/shim"
"github.com/zclconf/go-cty/cty"
Expand Down Expand Up @@ -188,22 +191,44 @@ func ConvertPluginConfigValueToHCLValue(v interface{}) (cty.Value, error) {
return buildValue, nil
}

// GetVarsByType walks through a hcl body, and gathers all the Traversals that
// have a root type matching one of the specified top-level labels.
//
// This will only work on finite, expanded, HCL bodies.
//
// TODO: make it work on JSON serialised HCL2 templates.
func GetVarsByType(block *hcl.Block, topLevelLabels ...string) []hcl.Traversal {
attributes, _ := block.Body.JustAttributes()
var rets []hcl.Traversal

var vars []hcl.Traversal
switch body := block.Body.(type) {
case *hclsyntax.Body:
rets = getVarsByTypeForHCLSyntaxBody(body, topLevelLabels...)
default:
log.Printf("[ERROR] - GetVarsByType cannot work on objects of type %q", reflect.TypeOf(block))
}

for _, attr := range attributes {
for _, variable := range attr.Expr.Variables() {
rootLabel := variable.RootName()
for _, label := range topLevelLabels {
if label == rootLabel {
vars = append(vars, variable)
return rets
}

func getVarsByTypeForHCLSyntaxBody(body *hclsyntax.Body, topLevelLabels ...string) []hcl.Traversal {
var rets []hcl.Traversal

for _, attr := range body.Attributes {
ts := attr.Expr.Variables()
for _, t := range ts {
varRootname := t.RootName()
for _, lbl := range topLevelLabels {
if varRootname == lbl {
rets = append(rets, t)
break
}
}
}
}

return vars
for _, block := range body.Blocks {
rets = append(rets, getVarsByTypeForHCLSyntaxBody(block.Body, topLevelLabels...)...)
}

return rets
}

0 comments on commit 70983d1

Please sign in to comment.