Merge pull request #7733 from hashicorp/fix_var_recurisve_itnerpolation

fixing interpolation
This commit is contained in:
Adrien Delorme 2019-06-11 11:10:08 +02:00 committed by GitHub
commit 9d00173b96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 118 additions and 32 deletions

View File

@ -306,7 +306,6 @@ func (c *Core) init() error {
if c.variables == nil {
c.variables = make(map[string]string)
}
// Go through the variables and interpolate the environment and
// user variables
@ -314,7 +313,6 @@ func (c *Core) init() error {
ctx.EnableEnv = true
ctx.UserVariables = make(map[string]string)
shouldRetry := true
tryCount := 0
changed := false
failedInterpolation := ""
@ -337,32 +335,40 @@ func (c *Core) init() error {
// interpolating them. Please don't actually nest your variables in 100
// layers of other variables. Please.
for shouldRetry == true {
// c.Template.Variables is populated by variables defined within the Template
// itself
// c.variables is populated by variables read in from the command line and
// var-files.
// We need to read the keys from both, then loop over all of them to figure
// out the appropriate interpolations.
allVariables := make(map[string]string)
// load in template variables
for k, v := range c.Template.Variables {
allVariables[k] = v.Default
}
// overwrite template variables with command-line-read variables
for k, v := range c.variables {
allVariables[k] = v
}
for i := 0; i < 100; i++ {
shouldRetry = false
for k, v := range c.Template.Variables {
// Ignore variables that are required
if v.Required {
continue
}
// Ignore variables that have a value already
if _, ok := c.variables[k]; ok {
continue
}
// First, loop over the variables in the template
for k, v := range allVariables {
// Interpolate the default
def, err := interpolate.Render(v.Default, ctx)
renderedV, err := interpolate.Render(v, ctx)
switch err.(type) {
case nil:
// We only get here if interpolation has succeeded, so something is
// different in this loop than in the last one.
changed = true
c.variables[k] = def
c.variables[k] = renderedV
ctx.UserVariables = c.variables
case ttmp.ExecError:
shouldRetry = true
tryCount++
failedInterpolation = fmt.Sprintf(`"%s": "%s"`, k, v.Default)
failedInterpolation = fmt.Sprintf(`"%s": "%s"`, k, v)
continue
default:
return fmt.Errorf(
@ -371,10 +377,9 @@ func (c *Core) init() error {
k, err)
}
}
if tryCount >= 100 {
if !shouldRetry {
break
}
}
if (changed == false) && (shouldRetry == true) {
@ -385,13 +390,8 @@ func (c *Core) init() error {
}
for _, v := range c.Template.SensitiveVariables {
def, err := interpolate.Render(v.Default, ctx)
if err != nil {
return fmt.Errorf(
"error interpolating default value for '%#v': %s",
v, err)
}
c.secrets = append(c.secrets, def)
secret := ctx.UserVariables[v.Key]
c.secrets = append(c.secrets, secret)
}
// Interpolate the push configuration

View File

@ -524,6 +524,8 @@ func TestCoreValidate(t *testing.T) {
}
}
// Tests that we can properly interpolate user variables defined within the
// packer template
func TestCore_InterpolateUserVars(t *testing.T) {
cases := []struct {
File string
@ -531,7 +533,7 @@ func TestCore_InterpolateUserVars(t *testing.T) {
Err bool
}{
{
"variables.json",
"build-variables-interpolate.json",
map[string]string{
"foo": "bar",
"bar": "bar",
@ -541,7 +543,7 @@ func TestCore_InterpolateUserVars(t *testing.T) {
false,
},
{
"variables2.json",
"build-variables-interpolate2.json",
map[string]string{},
true,
},
@ -576,6 +578,74 @@ func TestCore_InterpolateUserVars(t *testing.T) {
}
}
// Tests that we can properly interpolate user variables defined within a
// var-file provided alongside the Packer template
func TestCore_InterpolateUserVars_VarFile(t *testing.T) {
cases := []struct {
File string
Variables map[string]string
Expected map[string]string
Err bool
}{
{
// tests that we can interpolate from var files when var isn't set in
// originating template
"build-basic-interpolated.json",
map[string]string{
"name": "gotta-{{user `my_var`}}",
"my_var": "interpolate-em-all",
},
map[string]string{
"name": "gotta-interpolate-em-all",
"my_var": "interpolate-em-all"},
false,
},
{
// tests that we can interpolate from var files when var is set in
// originating template as required
"build-basic-interpolated-required.json",
map[string]string{
"name": "gotta-{{user `my_var`}}",
"my_var": "interpolate-em-all",
},
map[string]string{
"name": "gotta-interpolate-em-all",
"my_var": "interpolate-em-all"},
false,
},
}
for _, tc := range cases {
f, err := os.Open(fixtureDir(tc.File))
if err != nil {
t.Fatalf("err: %s", err)
}
tpl, err := template.Parse(f)
f.Close()
if err != nil {
t.Fatalf("err: %s\n\n%s", tc.File, err)
}
ccf, err := NewCore(&CoreConfig{
Template: tpl,
Version: "1.0.0",
Variables: tc.Variables,
})
if (err != nil) != tc.Err {
t.Fatalf("err: %s\n\n%s", tc.File, err)
}
if !tc.Err {
for k, v := range ccf.variables {
if tc.Expected[k] != v {
t.Fatalf("Expected value %s for key %s but got %s",
tc.Expected[k], k, v)
}
}
}
}
}
func TestSensitiveVars(t *testing.T) {
cases := []struct {
File string
@ -595,9 +665,10 @@ func TestSensitiveVars(t *testing.T) {
// interpolated
{
"sensitive-variables.json",
map[string]string{"foo": "{{build_name}}"},
[]string{"foo"},
"test",
map[string]string{"foo": "bar",
"bang": "{{ user `foo`}}"},
[]string{"bang"},
"bar",
false,
},
}

View File

@ -0,0 +1,9 @@
{
"variables": {
"name": null
},
"builders": [{
"name": "{{upper `name`}}",
"type": "test"
}]
}

View File

@ -0,0 +1,3 @@
{
"name": "{{ user `my_var` }}"
}

View File

@ -0,0 +1,3 @@
{
"my_var": "interpolate this, yall"
}