Interpolate boot_command when defined by user variable (#8640)

This commit is contained in:
Sylvia Moss 2020-01-27 19:10:16 +01:00 committed by GitHub
parent 63cba2dc00
commit 328eb8ee96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 88 additions and 3 deletions

View File

@ -397,12 +397,17 @@ func (c *Core) init() error {
allVariables[k] = v allVariables[k] = v
} }
// Regex to exclude any build function variable or template variable
// from interpolating earlier
// E.g.: {{ .HTTPIP }} won't interpolate now
renderFilter := "{{(\\s|)\\.(.*?)(\\s|)}}"
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
shouldRetry = false shouldRetry = false
// First, loop over the variables in the template // First, loop over the variables in the template
for k, v := range allVariables { for k, v := range allVariables {
// Interpolate the default // Interpolate the default
renderedV, err := interpolate.Render(v, ctx) renderedV, err := interpolate.RenderRegex(v, ctx, renderFilter)
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

View File

@ -143,6 +143,36 @@ func TestCoreBuild_env(t *testing.T) {
} }
} }
func TestCoreBuild_IgnoreTemplateVariables(t *testing.T) {
os.Setenv("PACKER_TEST_ENV", "test")
defer os.Setenv("PACKER_TEST_ENV", "")
config := TestCoreConfig(t)
testCoreTemplate(t, config, fixtureDir("build-ignore-template-variable.json"))
core := TestCore(t, config)
if core.variables["http_ip"] != "{{ .HTTPIP }}" {
t.Fatalf("bad: User variable http_ip={{ .HTTPIP }} should not be interpolated")
}
if core.variables["var"] != "test_{{ .PACKER_TEST_TEMP }}" {
t.Fatalf("bad: User variable var should be half interpolated to var=test_{{ .PACKER_TEST_TEMP }} but was var=%s", core.variables["var"])
}
if core.variables["array_var"] != "us-west-1,us-west-2" {
t.Fatalf("bad: User variable array_var should be \"us-west-1,us-west-2\" but was %s", core.variables["var"])
}
build, err := core.Build("test")
if err != nil {
t.Fatalf("err: %s", err)
}
if _, err := build.Prepare(); err != nil {
t.Fatalf("err: %s", err)
}
}
func TestCoreBuild_buildNameVar(t *testing.T) { func TestCoreBuild_buildNameVar(t *testing.T) {
config := TestCoreConfig(t) config := TestCoreConfig(t)
testCoreTemplate(t, config, fixtureDir("build-var-build-name.json")) testCoreTemplate(t, config, fixtureDir("build-var-build-name.json"))

View File

@ -0,0 +1,11 @@
{
"variables": {
"var": "{{env `PACKER_TEST_ENV`}}_{{ .PACKER_TEST_TEMP }}",
"http_ip": "{{ .HTTPIP }}",
"array_var": "us-west-1,us-west-2"
},
"builders": [{
"type": "test"
}]
}

View File

@ -2,6 +2,9 @@ package interpolate
import ( import (
"bytes" "bytes"
"github.com/google/uuid"
"regexp"
"strings"
"text/template" "text/template"
) )
@ -42,8 +45,44 @@ func NewContext() *Context {
} }
// Render is shorthand for constructing an I and calling Render. // Render is shorthand for constructing an I and calling Render.
func Render(v string, ctx *Context) (string, error) { func Render(v string, ctx *Context) (rendered string, err error) {
return (&I{Value: v}).Render(ctx) // Keep interpolating until all variables are done
// Sometimes a variable can been inside another one
for {
rendered, err = (&I{Value: v}).Render(ctx)
if err != nil || rendered == v {
break
}
v = rendered
}
return
}
// Render is shorthand for constructing an I and calling Render.
// Use regex to filter variables that are not supposed to be interpolated now
func RenderRegex(v string, ctx *Context, regex string) (string, error) {
re := regexp.MustCompile(regex)
matches := re.FindAllStringSubmatch(v, -1)
// Replace variables to be excluded with a unique UUID
excluded := make(map[string]string)
for _, value := range matches {
id := uuid.New().String()
excluded[id] = value[0]
v = strings.ReplaceAll(v, value[0], id)
}
rendered, err := (&I{Value: v}).Render(ctx)
if err != nil {
return rendered, err
}
// Replace back by the UUID the previously excluded values
for id, value := range excluded {
rendered = strings.ReplaceAll(rendered, id, value)
}
return rendered, nil
} }
// Validate is shorthand for constructing an I and calling Validate. // Validate is shorthand for constructing an I and calling Validate.