From 28d25c718c4290317c7accb8f0a9b8743367d46c Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 20 Sep 2013 10:49:35 -0700 Subject: [PATCH] packer: `only` metaparameter for provisioners [GH-438] --- packer/template.go | 32 +++++++++++-- packer/template_test.go | 100 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 3 deletions(-) diff --git a/packer/template.go b/packer/template.go index 7c3dd0529..12d47e5a8 100644 --- a/packer/template.go +++ b/packer/template.go @@ -59,6 +59,7 @@ type RawPostProcessorConfig struct { type RawProvisionerConfig struct { Type string Override map[string]interface{} + Only []string RawConfig interface{} } @@ -237,9 +238,8 @@ func ParseTemplate(data []byte) (t *Template, err error) { continue } - // The provisioners not only don't need or want the override settings - // (as they are processed as part of the preparation below), but will - // actively reject them as invalid configuration. + // Delete the keys that we used + delete(v, "only") delete(v, "override") // Verify that the override keys exist... @@ -250,6 +250,17 @@ func ParseTemplate(data []byte) (t *Template, err error) { } } + // Verify that the only settings are good + if len(raw.Only) > 0 { + for _, n := range raw.Only { + if _, ok := t.Builders[n]; !ok { + errors = append(errors, + fmt.Errorf("provisioner %d: 'only' specified builder '%s' not found", + i+1, n)) + } + } + } + raw.RawConfig = v } @@ -425,6 +436,21 @@ 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 len(rawProvisioner.Only) > 0 { + onlyFound := false + for _, n := range rawProvisioner.Only { + if n == name { + onlyFound = true + break + } + } + + if !onlyFound { + // Skip this provisioner + continue + } + } + var provisioner Provisioner provisioner, err = components.Provisioner(rawProvisioner.Type) if err != nil { diff --git a/packer/template_test.go b/packer/template_test.go index 883933367..c8fb6b4ae 100644 --- a/packer/template_test.go +++ b/packer/template_test.go @@ -9,6 +9,26 @@ import ( "testing" ) +func testTemplateComponentFinder() *ComponentFinder { + builder := testBuilder() + provisioner := &MockProvisioner{} + + builderMap := map[string]Builder{ + "test-builder": builder, + } + + provisionerMap := map[string]Provisioner{ + "test-prov": provisioner, + } + + builderFactory := func(n string) (Builder, error) { return builderMap[n], nil } + provFactory := func(n string) (Provisioner, error) { return provisionerMap[n], nil } + return &ComponentFinder{ + Builder: builderFactory, + Provisioner: provFactory, + } +} + func TestParseTemplateFile_basic(t *testing.T) { data := ` { @@ -663,6 +683,86 @@ func TestTemplate_Build(t *testing.T) { } } +func TestTemplateBuild_onlyProvInvalid(t *testing.T) { + data := ` + { + "builders": [ + { + "name": "test1", + "type": "test-builder" + }, + { + "name": "test2", + "type": "test-builder" + } + ], + + "provisioners": [ + { + "type": "test-prov", + "only": "test5" + } + ] + } + ` + + _, err := ParseTemplate([]byte(data)) + if err == nil { + t.Fatal("should have error") + } +} + +func TestTemplateBuild_onlyProv(t *testing.T) { + data := ` + { + "builders": [ + { + "name": "test1", + "type": "test-builder" + }, + { + "name": "test2", + "type": "test-builder" + } + ], + + "provisioners": [ + { + "type": "test-prov", + "only": ["test2"] + } + ] + } + ` + + template, err := ParseTemplate([]byte(data)) + 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 no 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 TestTemplate_Build_ProvisionerOverride(t *testing.T) { assert := asserts.NewTestingAsserts(t, true)