Merge pull request #7733 from hashicorp/fix_var_recurisve_itnerpolation
fixing interpolation
This commit is contained in:
commit
9d00173b96
|
@ -306,7 +306,6 @@ func (c *Core) init() error {
|
||||||
if c.variables == nil {
|
if c.variables == nil {
|
||||||
c.variables = make(map[string]string)
|
c.variables = make(map[string]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go through the variables and interpolate the environment and
|
// Go through the variables and interpolate the environment and
|
||||||
// user variables
|
// user variables
|
||||||
|
|
||||||
|
@ -314,7 +313,6 @@ func (c *Core) init() error {
|
||||||
ctx.EnableEnv = true
|
ctx.EnableEnv = true
|
||||||
ctx.UserVariables = make(map[string]string)
|
ctx.UserVariables = make(map[string]string)
|
||||||
shouldRetry := true
|
shouldRetry := true
|
||||||
tryCount := 0
|
|
||||||
changed := false
|
changed := false
|
||||||
failedInterpolation := ""
|
failedInterpolation := ""
|
||||||
|
|
||||||
|
@ -337,32 +335,40 @@ func (c *Core) init() error {
|
||||||
// interpolating them. Please don't actually nest your variables in 100
|
// interpolating them. Please don't actually nest your variables in 100
|
||||||
// layers of other variables. Please.
|
// 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
|
shouldRetry = false
|
||||||
for k, v := range c.Template.Variables {
|
// First, loop over the variables in the template
|
||||||
// Ignore variables that are required
|
for k, v := range allVariables {
|
||||||
if v.Required {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignore variables that have a value already
|
|
||||||
if _, ok := c.variables[k]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interpolate the default
|
// Interpolate the default
|
||||||
def, err := interpolate.Render(v.Default, ctx)
|
renderedV, err := interpolate.Render(v, ctx)
|
||||||
switch err.(type) {
|
switch err.(type) {
|
||||||
case nil:
|
case nil:
|
||||||
// We only get here if interpolation has succeeded, so something is
|
// We only get here if interpolation has succeeded, so something is
|
||||||
// different in this loop than in the last one.
|
// different in this loop than in the last one.
|
||||||
changed = true
|
changed = true
|
||||||
c.variables[k] = def
|
c.variables[k] = renderedV
|
||||||
ctx.UserVariables = c.variables
|
ctx.UserVariables = c.variables
|
||||||
case ttmp.ExecError:
|
case ttmp.ExecError:
|
||||||
shouldRetry = true
|
shouldRetry = true
|
||||||
tryCount++
|
failedInterpolation = fmt.Sprintf(`"%s": "%s"`, k, v)
|
||||||
failedInterpolation = fmt.Sprintf(`"%s": "%s"`, k, v.Default)
|
|
||||||
continue
|
continue
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
|
@ -371,10 +377,9 @@ func (c *Core) init() error {
|
||||||
k, err)
|
k, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if tryCount >= 100 {
|
if !shouldRetry {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed == false) && (shouldRetry == true) {
|
if (changed == false) && (shouldRetry == true) {
|
||||||
|
@ -385,13 +390,8 @@ func (c *Core) init() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range c.Template.SensitiveVariables {
|
for _, v := range c.Template.SensitiveVariables {
|
||||||
def, err := interpolate.Render(v.Default, ctx)
|
secret := ctx.UserVariables[v.Key]
|
||||||
if err != nil {
|
c.secrets = append(c.secrets, secret)
|
||||||
return fmt.Errorf(
|
|
||||||
"error interpolating default value for '%#v': %s",
|
|
||||||
v, err)
|
|
||||||
}
|
|
||||||
c.secrets = append(c.secrets, def)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpolate the push configuration
|
// Interpolate the push configuration
|
||||||
|
|
|
@ -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) {
|
func TestCore_InterpolateUserVars(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
File string
|
File string
|
||||||
|
@ -531,7 +533,7 @@ func TestCore_InterpolateUserVars(t *testing.T) {
|
||||||
Err bool
|
Err bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"variables.json",
|
"build-variables-interpolate.json",
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
"bar": "bar",
|
"bar": "bar",
|
||||||
|
@ -541,7 +543,7 @@ func TestCore_InterpolateUserVars(t *testing.T) {
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"variables2.json",
|
"build-variables-interpolate2.json",
|
||||||
map[string]string{},
|
map[string]string{},
|
||||||
true,
|
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) {
|
func TestSensitiveVars(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
File string
|
File string
|
||||||
|
@ -595,9 +665,10 @@ func TestSensitiveVars(t *testing.T) {
|
||||||
// interpolated
|
// interpolated
|
||||||
{
|
{
|
||||||
"sensitive-variables.json",
|
"sensitive-variables.json",
|
||||||
map[string]string{"foo": "{{build_name}}"},
|
map[string]string{"foo": "bar",
|
||||||
[]string{"foo"},
|
"bang": "{{ user `foo`}}"},
|
||||||
"test",
|
[]string{"bang"},
|
||||||
|
"bar",
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"variables": {
|
||||||
|
"name": null
|
||||||
|
},
|
||||||
|
"builders": [{
|
||||||
|
"name": "{{upper `name`}}",
|
||||||
|
"type": "test"
|
||||||
|
}]
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"name": "{{ user `my_var` }}"
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"my_var": "interpolate this, yall"
|
||||||
|
}
|
Loading…
Reference in New Issue