From b25ae21e13996f9f2bf3a5b5f1558d30c156c64a Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 26 May 2015 09:14:29 -0700 Subject: [PATCH] packer: run provisioners --- packer/builder_mock.go | 6 ++++ packer/core.go | 44 +++++++++++++++++++++++++++- packer/core_test.go | 34 +++++++++++++++++++++ packer/test-fixtures/build-prov.json | 9 ++++++ packer/testing.go | 16 ++++++++++ 5 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 packer/test-fixtures/build-prov.json diff --git a/packer/builder_mock.go b/packer/builder_mock.go index bfa0a0e47..9cb016963 100644 --- a/packer/builder_mock.go +++ b/packer/builder_mock.go @@ -42,6 +42,12 @@ func (tb *MockBuilder) Run(ui Ui, h Hook, c Cache) (Artifact, error) { return nil, nil } + if h != nil { + if err := h.Run(HookProvision, ui, nil, nil); err != nil { + return nil, err + } + } + return &MockArtifact{ IdValue: tb.ArtifactId, }, nil diff --git a/packer/core.go b/packer/core.go index cabf10359..4a0bf6a4d 100644 --- a/packer/core.go +++ b/packer/core.go @@ -118,13 +118,55 @@ func (c *Core) Build(n string) (Build, error) { "builder type not found: %s", configBuilder.Type) } - // TODO: template process name + // rawName is the uninterpolated name that we use for various lookups + rawName := configBuilder.Name + + // Setup the provisioners for this build + provisioners := make([]coreBuildProvisioner, 0, len(c.template.Provisioners)) + for _, rawP := range c.template.Provisioners { + // If we're skipping this, then ignore it + if rawP.Skip(rawName) { + continue + } + + // Get the provisioner + provisioner, err := c.components.Provisioner(rawP.Type) + if err != nil { + return nil, fmt.Errorf( + "error initializing provisioner '%s': %s", + rawP.Type, err) + } + if provisioner == nil { + return nil, fmt.Errorf( + "provisioner type not found: %s", rawP.Type) + } + + // Get the configuration + config := make([]interface{}, 1, 2) + config[0] = rawP.Config + + // TODO override + + // If we're pausing, we wrap the provisioner in a special pauser. + if rawP.PauseBefore > 0 { + provisioner = &PausedProvisioner{ + PauseBefore: rawP.PauseBefore, + Provisioner: provisioner, + } + } + + provisioners = append(provisioners, coreBuildProvisioner{ + provisioner: provisioner, + config: config, + }) + } return &coreBuild{ name: n, builder: builder, builderConfig: configBuilder.Config, builderType: configBuilder.Type, + provisioners: provisioners, variables: c.variables, }, nil } diff --git a/packer/core_test.go b/packer/core_test.go index 31ee34218..c8cdfbfb8 100644 --- a/packer/core_test.go +++ b/packer/core_test.go @@ -120,6 +120,40 @@ func TestCoreBuild_nonExist(t *testing.T) { } } +func TestCoreBuild_prov(t *testing.T) { + config := TestCoreConfig(t) + testCoreTemplate(t, config, fixtureDir("build-prov.json")) + b := TestBuilder(t, config, "test") + p := TestProvisioner(t, config, "test") + core := TestCore(t, config) + + b.ArtifactId = "hello" + + build, err := core.Build("test") + if err != nil { + t.Fatalf("err: %s", err) + } + + if _, err := build.Prepare(); err != nil { + t.Fatalf("err: %s", err) + } + + artifact, err := build.Run(nil, nil) + if err != nil { + t.Fatalf("err: %s", err) + } + if len(artifact) != 1 { + t.Fatalf("bad: %#v", artifact) + } + + if artifact[0].Id() != b.ArtifactId { + t.Fatalf("bad: %s", artifact[0].Id()) + } + if !p.ProvCalled { + t.Fatal("provisioner not called") + } +} + func TestCoreValidate(t *testing.T) { cases := []struct { File string diff --git a/packer/test-fixtures/build-prov.json b/packer/test-fixtures/build-prov.json new file mode 100644 index 000000000..332c28b1d --- /dev/null +++ b/packer/test-fixtures/build-prov.json @@ -0,0 +1,9 @@ +{ + "builders": [{ + "type": "test" + }], + + "provisioners": [{ + "type": "test" + }] +} diff --git a/packer/testing.go b/packer/testing.go index 389b02f90..30b95c6e4 100644 --- a/packer/testing.go +++ b/packer/testing.go @@ -58,3 +58,19 @@ func TestBuilder(t *testing.T, c *CoreConfig, n string) *MockBuilder { return &b } + +// TestProvisioner sets the prov. with the name n to the component finder +// and returns the mock. +func TestProvisioner(t *testing.T, c *CoreConfig, n string) *MockProvisioner { + var b MockProvisioner + + c.Components.Provisioner = func(actual string) (Provisioner, error) { + if actual != n { + return nil, nil + } + + return &b, nil + } + + return &b +}