Merge pull request #1402 from jasonberanek/858-issue
fix build name ConfigTemplate processing [GH-858]
This commit is contained in:
commit
347f02a7f2
|
@ -66,6 +66,12 @@ func (f *BuildOptions) AllUserVars() (map[string]string, error) {
|
|||
func (f *BuildOptions) Builds(t *packer.Template, cf *packer.ComponentFinder) ([]packer.Build, error) {
|
||||
buildNames := t.BuildNames()
|
||||
|
||||
// Process the name
|
||||
tpl, _, err := t.NewConfigTemplate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
checks := make(map[string][]string)
|
||||
checks["except"] = f.Except
|
||||
checks["only"] = f.Only
|
||||
|
@ -73,7 +79,12 @@ func (f *BuildOptions) Builds(t *packer.Template, cf *packer.ComponentFinder) ([
|
|||
for _, n := range ns {
|
||||
found := false
|
||||
for _, actual := range buildNames {
|
||||
if actual == n {
|
||||
var processed string
|
||||
processed, err = tpl.Process(actual, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if actual == n || processed == n {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
@ -88,17 +99,22 @@ func (f *BuildOptions) Builds(t *packer.Template, cf *packer.ComponentFinder) ([
|
|||
|
||||
builds := make([]packer.Build, 0, len(buildNames))
|
||||
for _, buildName := range buildNames {
|
||||
var processedBuildName string
|
||||
processedBuildName, err = tpl.Process(buildName, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(f.Except) > 0 {
|
||||
found := false
|
||||
for _, except := range f.Except {
|
||||
if buildName == except {
|
||||
if buildName == except || processedBuildName == except {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
log.Printf("Skipping build '%s' because specified by -except.", buildName)
|
||||
log.Printf("Skipping build '%s' because specified by -except.", processedBuildName)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
@ -106,19 +122,19 @@ func (f *BuildOptions) Builds(t *packer.Template, cf *packer.ComponentFinder) ([
|
|||
if len(f.Only) > 0 {
|
||||
found := false
|
||||
for _, only := range f.Only {
|
||||
if buildName == only {
|
||||
if buildName == only || processedBuildName == only {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
log.Printf("Skipping build '%s' because not specified by -only.", buildName)
|
||||
log.Printf("Skipping build '%s' because not specified by -only.", processedBuildName)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("Creating build: %s", buildName)
|
||||
log.Printf("Creating build: %s", processedBuildName)
|
||||
build, err := t.Build(buildName, cf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to create build '%s': \n\n%s", buildName, err)
|
||||
|
|
|
@ -7,17 +7,23 @@ import (
|
|||
|
||||
func testTemplate() (*packer.Template, *packer.ComponentFinder) {
|
||||
tplData := `{
|
||||
"builders": [
|
||||
{
|
||||
"type": "foo"
|
||||
},
|
||||
{
|
||||
"type": "bar"
|
||||
}
|
||||
]
|
||||
}`
|
||||
"variables": {
|
||||
"foo": null
|
||||
},
|
||||
|
||||
tpl, err := packer.ParseTemplate([]byte(tplData), nil)
|
||||
"builders": [
|
||||
{
|
||||
"type": "foo"
|
||||
},
|
||||
{
|
||||
"name": "{{user \"foo\"}}",
|
||||
"type": "bar"
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
||||
|
||||
tpl, err := packer.ParseTemplate([]byte(tplData), map[string]string{"foo": "bar"})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -59,6 +65,44 @@ func TestBuildOptionsBuilds_except(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
//Test to make sure the build name pattern matches
|
||||
func TestBuildOptionsBuilds_exceptConfigTemplateRaw(t *testing.T) {
|
||||
opts := new(BuildOptions)
|
||||
opts.Except = []string{"{{user \"foo\"}}"}
|
||||
|
||||
bs, err := opts.Builds(testTemplate())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if len(bs) != 1 {
|
||||
t.Fatalf("bad: %d", len(bs))
|
||||
}
|
||||
|
||||
if bs[0].Name() != "foo" {
|
||||
t.Fatalf("bad: %s", bs[0].Name())
|
||||
}
|
||||
}
|
||||
|
||||
//Test to make sure the processed build name matches
|
||||
func TestBuildOptionsBuilds_exceptConfigTemplateProcessed(t *testing.T) {
|
||||
opts := new(BuildOptions)
|
||||
opts.Except = []string{"bar"}
|
||||
|
||||
bs, err := opts.Builds(testTemplate())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if len(bs) != 1 {
|
||||
t.Fatalf("bad: %d", len(bs))
|
||||
}
|
||||
|
||||
if bs[0].Name() != "foo" {
|
||||
t.Fatalf("bad: %s", bs[0].Name())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildOptionsBuilds_only(t *testing.T) {
|
||||
opts := new(BuildOptions)
|
||||
opts.Only = []string{"foo"}
|
||||
|
@ -77,6 +121,44 @@ func TestBuildOptionsBuilds_only(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
//Test to make sure the build name pattern matches
|
||||
func TestBuildOptionsBuilds_onlyConfigTemplateRaw(t *testing.T) {
|
||||
opts := new(BuildOptions)
|
||||
opts.Only = []string{"{{user \"foo\"}}"}
|
||||
|
||||
bs, err := opts.Builds(testTemplate())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if len(bs) != 1 {
|
||||
t.Fatalf("bad: %d", len(bs))
|
||||
}
|
||||
|
||||
if bs[0].Name() != "bar" {
|
||||
t.Fatalf("bad: %s", bs[0].Name())
|
||||
}
|
||||
}
|
||||
|
||||
//Test to make sure the processed build name matches
|
||||
func TestBuildOptionsBuilds_onlyConfigTemplateProcessed(t *testing.T) {
|
||||
opts := new(BuildOptions)
|
||||
opts.Only = []string{"bar"}
|
||||
|
||||
bs, err := opts.Builds(testTemplate())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if len(bs) != 1 {
|
||||
t.Fatalf("bad: %d", len(bs))
|
||||
}
|
||||
|
||||
if bs[0].Name() != "bar" {
|
||||
t.Fatalf("bad: %s", bs[0].Name())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildOptionsBuilds_exceptNonExistent(t *testing.T) {
|
||||
opts := new(BuildOptions)
|
||||
opts.Except = []string{"i-dont-exist"}
|
||||
|
|
|
@ -475,52 +475,13 @@ func (t *Template) Build(name string, components *ComponentFinder) (b Build, err
|
|||
return
|
||||
}
|
||||
|
||||
// Prepare the variable template processor, which is a bit unique
|
||||
// because we don't allow user variable usage and we add a function
|
||||
// to read from the environment.
|
||||
varTpl, err := NewConfigTemplate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
varTpl.Funcs(template.FuncMap{
|
||||
"env": templateEnv,
|
||||
"user": templateDisableUser,
|
||||
})
|
||||
|
||||
// Prepare the variables
|
||||
var varErrors []error
|
||||
variables := make(map[string]string)
|
||||
for k, v := range t.Variables {
|
||||
if v.Required && !v.HasValue {
|
||||
varErrors = append(varErrors,
|
||||
fmt.Errorf("Required user variable '%s' not set", k))
|
||||
}
|
||||
|
||||
var val string
|
||||
if v.HasValue {
|
||||
val = v.Value
|
||||
} else {
|
||||
val, err = varTpl.Process(v.Default, nil)
|
||||
if err != nil {
|
||||
varErrors = append(varErrors,
|
||||
fmt.Errorf("Error processing user variable '%s': %s'", k, err))
|
||||
}
|
||||
}
|
||||
|
||||
variables[k] = val
|
||||
}
|
||||
|
||||
if len(varErrors) > 0 {
|
||||
return nil, &MultiError{varErrors}
|
||||
}
|
||||
|
||||
// Process the name
|
||||
tpl, err := NewConfigTemplate()
|
||||
tpl, variables, err := t.NewConfigTemplate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tpl.UserVars = variables
|
||||
|
||||
rawName := name
|
||||
name, err = tpl.Process(name, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -554,7 +515,7 @@ func (t *Template) Build(name string, components *ComponentFinder) (b Build, err
|
|||
for _, rawPPs := range t.PostProcessors {
|
||||
current := make([]coreBuildPostProcessor, 0, len(rawPPs))
|
||||
for _, rawPP := range rawPPs {
|
||||
if rawPP.TemplateOnlyExcept.Skip(name) {
|
||||
if rawPP.TemplateOnlyExcept.Skip(rawName) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -587,7 +548,7 @@ func (t *Template) Build(name string, components *ComponentFinder) (b Build, err
|
|||
// Prepare the provisioners
|
||||
provisioners := make([]coreBuildProvisioner, 0, len(t.Provisioners))
|
||||
for _, rawProvisioner := range t.Provisioners {
|
||||
if rawProvisioner.TemplateOnlyExcept.Skip(name) {
|
||||
if rawProvisioner.TemplateOnlyExcept.Skip(rawName) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -636,6 +597,59 @@ func (t *Template) Build(name string, components *ComponentFinder) (b Build, err
|
|||
return
|
||||
}
|
||||
|
||||
//Build a ConfigTemplate object populated by the values within a
|
||||
//parsed template
|
||||
func (t *Template) NewConfigTemplate() (c *ConfigTemplate, variables map[string]string, err error) {
|
||||
|
||||
// Prepare the variable template processor, which is a bit unique
|
||||
// because we don't allow user variable usage and we add a function
|
||||
// to read from the environment.
|
||||
varTpl, err := NewConfigTemplate()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
varTpl.Funcs(template.FuncMap{
|
||||
"env": templateEnv,
|
||||
"user": templateDisableUser,
|
||||
})
|
||||
|
||||
// Prepare the variables
|
||||
var varErrors []error
|
||||
variables = make(map[string]string)
|
||||
for k, v := range t.Variables {
|
||||
if v.Required && !v.HasValue {
|
||||
varErrors = append(varErrors,
|
||||
fmt.Errorf("Required user variable '%s' not set", k))
|
||||
}
|
||||
|
||||
var val string
|
||||
if v.HasValue {
|
||||
val = v.Value
|
||||
} else {
|
||||
val, err = varTpl.Process(v.Default, nil)
|
||||
if err != nil {
|
||||
varErrors = append(varErrors,
|
||||
fmt.Errorf("Error processing user variable '%s': %s'", k, err))
|
||||
}
|
||||
}
|
||||
|
||||
variables[k] = val
|
||||
}
|
||||
|
||||
if len(varErrors) > 0 {
|
||||
return nil, variables, &MultiError{varErrors}
|
||||
}
|
||||
|
||||
// Process the name
|
||||
tpl, err := NewConfigTemplate()
|
||||
if err != nil {
|
||||
return nil, variables, err
|
||||
}
|
||||
tpl.UserVars = variables
|
||||
|
||||
return tpl, variables, nil
|
||||
}
|
||||
|
||||
// TemplateOnlyExcept contains the logic required for "only" and "except"
|
||||
// meta-parameters.
|
||||
type TemplateOnlyExcept struct {
|
||||
|
|
|
@ -1165,7 +1165,62 @@ func TestTemplateBuild_exceptPP(t *testing.T) {
|
|||
t.Fatal("should have no postProcessors")
|
||||
}
|
||||
|
||||
// Verify test2 has no post-processors
|
||||
// Verify test2 has one post-processors
|
||||
build, err = template.Build("test2", testTemplateComponentFinder())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
cbuild = build.(*coreBuild)
|
||||
if len(cbuild.postProcessors) != 1 {
|
||||
t.Fatalf("invalid: %d", len(cbuild.postProcessors))
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateBuild_exceptPPConfigTemplateName(t *testing.T) {
|
||||
data := `
|
||||
{
|
||||
"variables": {
|
||||
"foo": null
|
||||
},
|
||||
|
||||
"builders": [
|
||||
{
|
||||
"name": "test1-{{user \"foo\"}}",
|
||||
"type": "test-builder"
|
||||
},
|
||||
{
|
||||
"name": "test2",
|
||||
"type": "test-builder"
|
||||
}
|
||||
],
|
||||
|
||||
"post-processors": [
|
||||
{
|
||||
"type": "test-pp",
|
||||
"except": ["test1-{{user \"foo\"}}"]
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
||||
|
||||
template, err := ParseTemplate([]byte(data), map[string]string{"foo": "bar"})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify test1 has no post-processors
|
||||
build, err := template.Build("test1-{{user \"foo\"}}", testTemplateComponentFinder())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
cbuild := build.(*coreBuild)
|
||||
if len(cbuild.postProcessors) > 0 {
|
||||
t.Fatal("should have no postProcessors")
|
||||
}
|
||||
|
||||
// Verify test2 has one post-processors
|
||||
build, err = template.Build("test2", testTemplateComponentFinder())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
|
@ -1245,7 +1300,62 @@ func TestTemplateBuild_exceptProv(t *testing.T) {
|
|||
t.Fatal("should have no provisioners")
|
||||
}
|
||||
|
||||
// Verify test2 has no provisioners
|
||||
// Verify test2 has one provisioners
|
||||
build, err = template.Build("test2", testTemplateComponentFinder())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
cbuild = build.(*coreBuild)
|
||||
if len(cbuild.provisioners) != 1 {
|
||||
t.Fatalf("invalid: %d", len(cbuild.provisioners))
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateBuild_exceptProvConfigTemplateName(t *testing.T) {
|
||||
data := `
|
||||
{
|
||||
"variables": {
|
||||
"foo": null
|
||||
},
|
||||
|
||||
"builders": [
|
||||
{
|
||||
"name": "test1-{{user \"foo\"}}",
|
||||
"type": "test-builder"
|
||||
},
|
||||
{
|
||||
"name": "test2",
|
||||
"type": "test-builder"
|
||||
}
|
||||
],
|
||||
|
||||
"provisioners": [
|
||||
{
|
||||
"type": "test-prov",
|
||||
"except": ["test1-{{user \"foo\"}}"]
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
||||
|
||||
template, err := ParseTemplate([]byte(data), map[string]string{"foo": "bar"})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify test1 has no provisioners
|
||||
build, err := template.Build("test1-{{user \"foo\"}}", testTemplateComponentFinder())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
cbuild := build.(*coreBuild)
|
||||
if len(cbuild.provisioners) > 0 {
|
||||
t.Fatal("should have no provisioners")
|
||||
}
|
||||
|
||||
// Verify test2 has one provisioners
|
||||
build, err = template.Build("test2", testTemplateComponentFinder())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
|
@ -1325,7 +1435,7 @@ func TestTemplateBuild_onlyPP(t *testing.T) {
|
|||
t.Fatal("should have no postProcessors")
|
||||
}
|
||||
|
||||
// Verify test2 has no post-processors
|
||||
// Verify test2 has one post-processors
|
||||
build, err = template.Build("test2", testTemplateComponentFinder())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
|
@ -1337,6 +1447,61 @@ func TestTemplateBuild_onlyPP(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTemplateBuild_onlyPPConfigTemplateName(t *testing.T) {
|
||||
data := `
|
||||
{
|
||||
"variables": {
|
||||
"foo": null
|
||||
},
|
||||
|
||||
"builders": [
|
||||
{
|
||||
"name": "test1",
|
||||
"type": "test-builder"
|
||||
},
|
||||
{
|
||||
"name": "test2-{{user \"foo\"}}",
|
||||
"type": "test-builder"
|
||||
}
|
||||
],
|
||||
|
||||
"post-processors": [
|
||||
{
|
||||
"type": "test-pp",
|
||||
"only": ["test2-{{user \"foo\"}}"]
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
||||
|
||||
template, err := ParseTemplate([]byte(data), map[string]string{"foo": "bar"})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify test1 has no post-processors
|
||||
build, err := template.Build("test1", testTemplateComponentFinder())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
cbuild := build.(*coreBuild)
|
||||
if len(cbuild.postProcessors) > 0 {
|
||||
t.Fatal("should have no postProcessors")
|
||||
}
|
||||
|
||||
// Verify test2 has one post-processors
|
||||
build, err = template.Build("test2-{{user \"foo\"}}", testTemplateComponentFinder())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
cbuild = build.(*coreBuild)
|
||||
if len(cbuild.postProcessors) != 1 {
|
||||
t.Fatalf("invalid: %d", len(cbuild.postProcessors))
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateBuild_onlyProvInvalid(t *testing.T) {
|
||||
data := `
|
||||
{
|
||||
|
@ -1405,7 +1570,7 @@ func TestTemplateBuild_onlyProv(t *testing.T) {
|
|||
t.Fatal("should have no provisioners")
|
||||
}
|
||||
|
||||
// Verify test2 has no provisioners
|
||||
// Verify test2 has one provisioners
|
||||
build, err = template.Build("test2", testTemplateComponentFinder())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
|
@ -1417,6 +1582,61 @@ func TestTemplateBuild_onlyProv(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTemplateBuild_onlyProvConfigTemplateName(t *testing.T) {
|
||||
data := `
|
||||
{
|
||||
"variables": {
|
||||
"foo": null
|
||||
},
|
||||
|
||||
"builders": [
|
||||
{
|
||||
"name": "test1",
|
||||
"type": "test-builder"
|
||||
},
|
||||
{
|
||||
"name": "test2-{{user \"foo\"}}",
|
||||
"type": "test-builder"
|
||||
}
|
||||
],
|
||||
|
||||
"provisioners": [
|
||||
{
|
||||
"type": "test-prov",
|
||||
"only": ["test2-{{user \"foo\"}}"]
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
||||
|
||||
template, err := ParseTemplate([]byte(data), map[string]string{"foo": "bar"})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify test1 has no provisioners
|
||||
build, err := template.Build("test1", testTemplateComponentFinder())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
cbuild := build.(*coreBuild)
|
||||
if len(cbuild.provisioners) > 0 {
|
||||
t.Fatal("should have no provisioners")
|
||||
}
|
||||
|
||||
// Verify test2 has one provisioners
|
||||
build, err = template.Build("test2-{{user \"foo\"}}", testTemplateComponentFinder())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
cbuild = build.(*coreBuild)
|
||||
if len(cbuild.provisioners) != 1 {
|
||||
t.Fatalf("invalid: %d", len(cbuild.provisioners))
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplate_Build_ProvisionerOverride(t *testing.T) {
|
||||
data := `
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue