diff --git a/packer/build.go b/packer/build.go index 475f34718..f88044a6c 100644 --- a/packer/build.go +++ b/packer/build.go @@ -73,6 +73,7 @@ type coreBuild struct { hooks map[string][]Hook postProcessors [][]coreBuildPostProcessor provisioners []coreBuildProvisioner + variables map[string]string debug bool force bool diff --git a/packer/template.go b/packer/template.go index 995d66342..0bef1e6c3 100644 --- a/packer/template.go +++ b/packer/template.go @@ -13,6 +13,7 @@ import ( // "interface{}" pointers since we actually don't know what their contents // are until we read the "type" field. type rawTemplate struct { + Variables map[string]string Builders []map[string]interface{} Hooks map[string][]string Provisioners []map[string]interface{} @@ -22,6 +23,7 @@ type rawTemplate struct { // The Template struct represents a parsed template, parsed into the most // completed form it can be without additional processing by the caller. type Template struct { + Variables map[string]string Builders map[string]rawBuilderConfig Hooks map[string][]string PostProcessors [][]rawPostProcessorConfig @@ -123,11 +125,17 @@ func ParseTemplate(data []byte) (t *Template, err error) { } t = &Template{} + t.Variables = make(map[string]string) t.Builders = make(map[string]rawBuilderConfig) t.Hooks = rawTpl.Hooks t.PostProcessors = make([][]rawPostProcessorConfig, len(rawTpl.PostProcessors)) t.Provisioners = make([]rawProvisionerConfig, len(rawTpl.Provisioners)) + // Gather all the variables + for k, v := range rawTpl.Variables { + t.Variables[k] = v + } + // Gather all the builders for i, v := range rawTpl.Builders { var raw rawBuilderConfig @@ -412,6 +420,7 @@ func (t *Template) Build(name string, components *ComponentFinder) (b Build, err hooks: hooks, postProcessors: postProcessors, provisioners: provisioners, + variables: t.Variables, } return diff --git a/packer/template_test.go b/packer/template_test.go index c2f133634..2e9cff079 100644 --- a/packer/template_test.go +++ b/packer/template_test.go @@ -7,6 +7,17 @@ import ( "testing" ) +func testComponentFinder() *ComponentFinder { + builderFactory := func(n string) (Builder, error) { return testBuilder(), nil } + ppFactory := func(n string) (PostProcessor, error) { return new(TestPostProcessor), nil } + provFactory := func(n string) (Provisioner, error) { return new(TestProvisioner), nil } + return &ComponentFinder{ + Builder: builderFactory, + PostProcessor: ppFactory, + Provisioner: provFactory, + } +} + func TestParseTemplate_Basic(t *testing.T) { assert := asserts.NewTestingAsserts(t, true) @@ -300,6 +311,28 @@ func TestParseTemplate_Provisioners(t *testing.T) { assert.NotNil(result.Provisioners[0].rawConfig, "should have raw config") } +func TestParseTemplate_Variables(t *testing.T) { + data := ` + { + "variables": { + "foo": "bar", + "bar": "" + }, + + "builders": [{"type": "something"}] + } + ` + + result, err := ParseTemplate([]byte(data)) + if err != nil { + t.Fatalf("err: %s", err) + } + + if result.Variables == nil || len(result.Variables) != 2 { + t.Fatalf("bad vars: %#v", result.Variables) + } +} + func TestTemplate_BuildNames(t *testing.T) { assert := asserts.NewTestingAsserts(t, true) @@ -613,3 +646,39 @@ func TestTemplate_Build_ProvisionerOverride(t *testing.T) { assert.Equal(len(coreBuild.provisioners), 1, "should have one provisioner") assert.Equal(len(coreBuild.provisioners[0].config), 2, "should have two configs on the provisioner") } + +func TestTemplateBuild_variables(t *testing.T) { + data := ` + { + "variables": { + "foo": "bar" + }, + + "builders": [ + { + "name": "test1", + "type": "test-builder" + } + ] + } + ` + + template, err := ParseTemplate([]byte(data)) + if err != nil { + t.Fatalf("err: %s", err) + } + + build, err := template.Build("test1", testComponentFinder()) + if err != nil { + t.Fatalf("err: %s", err) + } + + coreBuild, ok := build.(*coreBuild) + if !ok { + t.Fatalf("couldn't convert!") + } + + if len(coreBuild.variables) != 1 { + t.Fatalf("bad vars: %#v", coreBuild.variables) + } +}