From 0339c670a79686b7fc122edcc9b9ae370f3ce6b7 Mon Sep 17 00:00:00 2001 From: Lucas Bajolet Date: Fri, 25 Aug 2023 17:00:03 -0400 Subject: [PATCH] hcl2template: fix func to get vars from a config 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. --- hcl2template/utils.go | 52 ++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/hcl2template/utils.go b/hcl2template/utils.go index 8c3b55ed584..d3d0cb29447 100644 --- a/hcl2template/utils.go +++ b/hcl2template/utils.go @@ -11,6 +11,7 @@ import ( "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" @@ -187,22 +188,47 @@ 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. func GetVarsByType(block *hcl.Block, topLevelLabels ...string) []hcl.Traversal { - attributes, _ := block.Body.JustAttributes() - - var vars []hcl.Traversal - - for _, attr := range attributes { - for _, variable := range attr.Expr.Variables() { - rootLabel := variable.RootName() - for _, label := range topLevelLabels { - if label == rootLabel { - vars = append(vars, variable) - break - } + var travs []hcl.Traversal + + switch body := block.Body.(type) { + case *hclsyntax.Body: + travs = getVarsByTypeForHCLSyntaxBody(body) + default: + attrs, _ := body.JustAttributes() + for _, attr := range attrs { + travs = append(travs, attr.Expr.Variables()...) + } + } + + var rets []hcl.Traversal + for _, t := range travs { + varRootname := t.RootName() + for _, lbl := range topLevelLabels { + if varRootname == lbl { + rets = append(rets, t) + break } } } - return vars + return rets +} + +func getVarsByTypeForHCLSyntaxBody(body *hclsyntax.Body) []hcl.Traversal { + var rets []hcl.Traversal + + for _, attr := range body.Attributes { + rets = append(rets, attr.Expr.Variables()...) + } + + for _, block := range body.Blocks { + rets = append(rets, getVarsByTypeForHCLSyntaxBody(block.Body)...) + } + + return rets }