fix interpolation when env vars interpolate before user vars
This commit is contained in:
parent
7873cabf63
commit
063dd5c133
|
@ -2,6 +2,7 @@ package packer
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
|
@ -346,13 +347,24 @@ func (c *Core) validate() error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (c *Core) init() error {
|
||||
if c.variables == nil {
|
||||
c.variables = make(map[string]string)
|
||||
func isDoneInterpolating(v string) (bool, error) {
|
||||
// Check for whether the var contains any more references to `user`, wrapped
|
||||
// in interpolation syntax.
|
||||
filter := "{{\\s*|user\\s*|\\x60?.*\\x60?}}"
|
||||
matched, err := regexp.MatchString(filter, v)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Can't tell if interpolation is done: %s", err)
|
||||
}
|
||||
// Go through the variables and interpolate the environment and
|
||||
// user variables
|
||||
if matched {
|
||||
// not done interpolating; there's still a call to "user" in a template
|
||||
// engine
|
||||
return false, nil
|
||||
}
|
||||
// No more calls to "user" as a template engine, so we're done.
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (c *Core) renderVarsRecursively() (*interpolate.Context, error) {
|
||||
ctx := c.Context()
|
||||
ctx.EnableEnv = true
|
||||
ctx.UserVariables = make(map[string]string)
|
||||
|
@ -386,15 +398,15 @@ func (c *Core) init() error {
|
|||
// 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)
|
||||
repeatMap := make(map[string]string)
|
||||
// load in template variables
|
||||
for k, v := range c.Template.Variables {
|
||||
allVariables[k] = v.Default
|
||||
repeatMap[k] = v.Default
|
||||
}
|
||||
|
||||
// overwrite template variables with command-line-read variables
|
||||
for k, v := range c.variables {
|
||||
allVariables[k] = v
|
||||
repeatMap[k] = v
|
||||
}
|
||||
|
||||
// Regex to exclude any build function variable or template variable
|
||||
|
@ -405,7 +417,7 @@ func (c *Core) init() error {
|
|||
for i := 0; i < 100; i++ {
|
||||
shouldRetry = false
|
||||
// First, loop over the variables in the template
|
||||
for k, v := range allVariables {
|
||||
for k, v := range repeatMap {
|
||||
// Interpolate the default
|
||||
renderedV, err := interpolate.RenderRegex(v, ctx, renderFilter)
|
||||
switch err.(type) {
|
||||
|
@ -415,16 +427,27 @@ func (c *Core) init() error {
|
|||
changed = true
|
||||
c.variables[k] = renderedV
|
||||
ctx.UserVariables = c.variables
|
||||
// Remove fully-interpolated variables from the map, and flag
|
||||
// variables that still need interpolating for a repeat.
|
||||
done, err := isDoneInterpolating(v)
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
if done {
|
||||
delete(repeatMap, k)
|
||||
} else {
|
||||
shouldRetry = true
|
||||
}
|
||||
case ttmp.ExecError:
|
||||
castError := err.(ttmp.ExecError)
|
||||
if strings.Contains(castError.Error(), interpolate.ErrVariableNotSetString) {
|
||||
shouldRetry = true
|
||||
failedInterpolation = fmt.Sprintf(`"%s": "%s"; error: %s`, k, v, err)
|
||||
} else {
|
||||
return err
|
||||
return ctx, err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf(
|
||||
return ctx, fmt.Errorf(
|
||||
// unexpected interpolation error: abort the run
|
||||
"error interpolating default value for '%s': %s",
|
||||
k, err)
|
||||
|
@ -436,12 +459,25 @@ func (c *Core) init() error {
|
|||
}
|
||||
|
||||
if !changed && shouldRetry {
|
||||
return fmt.Errorf("Failed to interpolate %s: Please make sure that "+
|
||||
return ctx, fmt.Errorf("Failed to interpolate %s: Please make sure that "+
|
||||
"the variable you're referencing has been defined; Packer treats "+
|
||||
"all variables used to interpolate other user varaibles as "+
|
||||
"required.", failedInterpolation)
|
||||
}
|
||||
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
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
|
||||
ctx, err := c.renderVarsRecursively()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range c.Template.SensitiveVariables {
|
||||
secret := ctx.UserVariables[v.Key]
|
||||
c.secrets = append(c.secrets, secret)
|
||||
|
|
Loading…
Reference in New Issue