Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modify resolution of global variables to avoid errors on plain strings #208

Merged
merged 2 commits into from
Apr 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 5 additions & 8 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,12 +454,10 @@ func ConvertMapToCty(iMap map[string]interface{}) (map[string]cty.Value, error)

// ResolveGlobalVariables given a map of strings to cty.Value types, will examine
// all cty.Values that are of type cty.String. If they are literal global variables,
// then they are replaces by the cty.Value of the corresponding entry in yc.Vars
// the cty.Value types that are string literal global variables to their value
// then they are replaced by the cty.Value of the corresponding entry in
// yc.Vars. All other cty.Values are unmodified.
// ERROR: if conversion from yc.Vars to map[string]cty.Value fails
// ERROR: if (somehow) the cty.String cannot be covnerted to a Go string
// ERROR: if there are literal variables which are not globals
// (this will be a use case we should consider)
// ERROR: if (somehow) the cty.String cannot be converted to a Go string
// ERROR: rely on HCL TraverseAbs to bubble up "diagnostics" when the global variable
// being resolved does not exist in yc.Vars
func (yc *YamlConfig) ResolveGlobalVariables(ctyMap map[string]cty.Value) error {
Expand All @@ -477,7 +475,8 @@ func (yc *YamlConfig) ResolveGlobalVariables(ctyMap map[string]cty.Value) error
return err
}
ctx, varName, found := IdentifyLiteralVariable(valString)
// confirm literal and that it is global
// only attempt resolution on global literal variables
// leave all other strings alone (including non-global)
if found && ctx == "var" {
varTraversal := hcl.Traversal{
hcl.TraverseRoot{Name: ctx},
Expand All @@ -488,8 +487,6 @@ func (yc *YamlConfig) ResolveGlobalVariables(ctyMap map[string]cty.Value) error
return diags
}
ctyMap[key] = newVal
} else {
return fmt.Errorf("%s was not a literal global variable ((var.name))", valString)
}
}
}
Expand Down
56 changes: 29 additions & 27 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -505,49 +505,51 @@ func (s *MySuite) TestConvertMapToCty(c *C) {

func (s *MySuite) TestResolveGlobalVariables(c *C) {
var err error
var testkey = "testkey"
var testkey1 = "testkey1"
var testkey2 = "testkey2"
var testkey3 = "testkey3"
bc := getBlueprintConfigForTest()
ctyMap := make(map[string]cty.Value)
err = bc.Config.ResolveGlobalVariables(ctyMap)
c.Assert(err, IsNil)

// confirm that a plain string (non-variable) is unchanged and errors
// confirm plain string is unchanged and does not error
testCtyString := cty.StringVal("testval")
ctyMap[testkey] = testCtyString
ctyMap[testkey1] = testCtyString
err = bc.Config.ResolveGlobalVariables(ctyMap)
c.Assert(err, NotNil)
c.Assert(ctyMap[testkey], Equals, testCtyString)
c.Assert(err, IsNil)
c.Assert(ctyMap[testkey1], Equals, testCtyString)

// confirm that a literal, but not global, variable is unchanged and errors
// confirm literal, non-global, variable is unchanged and does not error
testCtyString = cty.StringVal("((module.testval))")
ctyMap[testkey] = testCtyString
ctyMap[testkey1] = testCtyString
err = bc.Config.ResolveGlobalVariables(ctyMap)
c.Assert(err, NotNil)
c.Assert(ctyMap[testkey], Equals, testCtyString)
c.Assert(err, IsNil)
c.Assert(ctyMap[testkey1], Equals, testCtyString)

// confirm failed resolution of a literal global
testCtyString = cty.StringVal("((var.test_global_var))")
ctyMap[testkey] = testCtyString
ctyMap[testkey1] = testCtyString
err = bc.Config.ResolveGlobalVariables(ctyMap)
c.Assert(err, NotNil)
c.Assert(err.Error(), Matches, ".*Unsupported attribute;.*")

// confirm successful resolution a literal global string
testGlobalVar := "test_global_var"
testGlobalVarString := "testval"
bc.Config.Vars[testGlobalVar] = testGlobalVarString
testCtyString = cty.StringVal(fmt.Sprintf("((var.%s))", testGlobalVar))
ctyMap[testkey] = testCtyString
err = bc.Config.ResolveGlobalVariables(ctyMap)
c.Assert(err, IsNil)
c.Assert(ctyMap[testkey], Equals, cty.StringVal(testGlobalVarString))

// confirm successful resolution a literal global boolean
testGlobalVar = "test_global_var"
testGlobalVarBool := true
bc.Config.Vars[testGlobalVar] = testGlobalVarBool
testCtyString = cty.StringVal(fmt.Sprintf("((var.%s))", testGlobalVar))
ctyMap[testkey] = testCtyString
// confirm successful resolution of literal globals in presence of other strings
testGlobalVarString := "test_global_string"
testGlobalValString := "testval"
testGlobalVarBool := "test_global_bool"
testGlobalValBool := "testval"
testPlainString := "plain-string"
bc.Config.Vars[testGlobalVarString] = testGlobalValString
bc.Config.Vars[testGlobalVarBool] = testGlobalValBool
testCtyString = cty.StringVal(fmt.Sprintf("((var.%s))", testGlobalVarString))
testCtyBool := cty.StringVal(fmt.Sprintf("((var.%s))", testGlobalVarBool))
ctyMap[testkey1] = testCtyString
ctyMap[testkey2] = testCtyBool
ctyMap[testkey3] = cty.StringVal(testPlainString)
err = bc.Config.ResolveGlobalVariables(ctyMap)
c.Assert(err, IsNil)
c.Assert(ctyMap[testkey], Equals, cty.BoolVal(testGlobalVarBool))
c.Assert(ctyMap[testkey1], Equals, cty.StringVal(testGlobalValString))
c.Assert(ctyMap[testkey2], Equals, cty.StringVal(testGlobalValBool))
c.Assert(ctyMap[testkey3], Equals, cty.StringVal(testPlainString))
}
5 changes: 4 additions & 1 deletion pkg/reswriter/packerwriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ func (w PackerWriter) writeResourceLevel(yamlConfig *config.YamlConfig, bpDirect
return fmt.Errorf(
"error converting global vars to cty for writing: %v", err)
}
yamlConfig.ResolveGlobalVariables(ctySettings)
err = yamlConfig.ResolveGlobalVariables(ctySettings)
if err != nil {
return err
}
resPath := filepath.Join(groupPath, res.ID)
err = writePackerAutovars(ctySettings, resPath)
if err != nil {
Expand Down
14 changes: 13 additions & 1 deletion tools/validate_configs/validate_configs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ run_test() {
}
for folder in ./*; do
cd "$folder"
pkrdirs=()
while IFS= read -r -d $'\n'; do
pkrdirs+=("$REPLY")
done < <(find . -name "*.pkr.hcl" -printf '%h\n' | sort -u)
if [ -f 'main.tf' ]; then
tfpw=$(pwd)
terraform init -no-color -backend=false >"${exampleFile}.init" ||
Expand All @@ -62,8 +66,16 @@ run_test() {
echo "*** ERROR: terraform validate failed for ${example}, logs in ${tfpw}"
exit 1
}
elif [ ${#pkrdirs[@]} -gt 0 ]; then
for pkrdir in "${pkrdirs[@]}"; do
packer validate -syntax-only "${pkrdir}" >/dev/null ||
{
echo "*** ERROR: packer validate failed for ${example}"
exit 1
}
done
else
echo "terraform not found in folder ${BLUEPRINT}/${folder}. Skipping."
echo "neither packer nor terraform found in folder ${BLUEPRINT}/${folder}. Skipping."
fi
cd .. # back to blueprint folder
done
Expand Down