packer: post-processors

This commit is contained in:
Mitchell Hashimoto 2015-05-26 09:28:59 -07:00
parent 85e615bbe2
commit 26c7ac2d90
8 changed files with 167 additions and 57 deletions

View File

@ -19,7 +19,7 @@ func testBuild() *coreBuild {
},
postProcessors: [][]coreBuildPostProcessor{
[]coreBuildPostProcessor{
coreBuildPostProcessor{&TestPostProcessor{artifactId: "pp"}, "testPP", make(map[string]interface{}), true},
coreBuildPostProcessor{&MockPostProcessor{ArtifactId: "pp"}, "testPP", make(map[string]interface{}), true},
},
},
variables: make(map[string]string),
@ -66,12 +66,12 @@ func TestBuild_Prepare(t *testing.T) {
}
corePP := build.postProcessors[0][0]
pp := corePP.processor.(*TestPostProcessor)
if !pp.configCalled {
pp := corePP.processor.(*MockPostProcessor)
if !pp.ConfigureCalled {
t.Fatal("should be called")
}
if !reflect.DeepEqual(pp.configVal, []interface{}{make(map[string]interface{}), packerConfig}) {
t.Fatalf("bad: %#v", pp.configVal)
if !reflect.DeepEqual(pp.ConfigureConfigs, []interface{}{make(map[string]interface{}), packerConfig}) {
t.Fatalf("bad: %#v", pp.ConfigureConfigs)
}
}
@ -208,8 +208,8 @@ func TestBuild_Run(t *testing.T) {
}
// Verify post-processor was run
pp := build.postProcessors[0][0].processor.(*TestPostProcessor)
if !pp.ppCalled {
pp := build.postProcessors[0][0].processor.(*MockPostProcessor)
if !pp.PostProcessCalled {
t.Fatal("should be called")
}
}
@ -244,7 +244,7 @@ func TestBuild_Run_Artifacts(t *testing.T) {
build = testBuild()
build.postProcessors = [][]coreBuildPostProcessor{
[]coreBuildPostProcessor{
coreBuildPostProcessor{&TestPostProcessor{artifactId: "pp"}, "pp", make(map[string]interface{}), false},
coreBuildPostProcessor{&MockPostProcessor{ArtifactId: "pp"}, "pp", make(map[string]interface{}), false},
},
}
@ -269,10 +269,10 @@ func TestBuild_Run_Artifacts(t *testing.T) {
build = testBuild()
build.postProcessors = [][]coreBuildPostProcessor{
[]coreBuildPostProcessor{
coreBuildPostProcessor{&TestPostProcessor{artifactId: "pp1"}, "pp", make(map[string]interface{}), false},
coreBuildPostProcessor{&MockPostProcessor{ArtifactId: "pp1"}, "pp", make(map[string]interface{}), false},
},
[]coreBuildPostProcessor{
coreBuildPostProcessor{&TestPostProcessor{artifactId: "pp2"}, "pp", make(map[string]interface{}), true},
coreBuildPostProcessor{&MockPostProcessor{ArtifactId: "pp2"}, "pp", make(map[string]interface{}), true},
},
}
@ -297,12 +297,12 @@ func TestBuild_Run_Artifacts(t *testing.T) {
build = testBuild()
build.postProcessors = [][]coreBuildPostProcessor{
[]coreBuildPostProcessor{
coreBuildPostProcessor{&TestPostProcessor{artifactId: "pp1a"}, "pp", make(map[string]interface{}), false},
coreBuildPostProcessor{&TestPostProcessor{artifactId: "pp1b"}, "pp", make(map[string]interface{}), true},
coreBuildPostProcessor{&MockPostProcessor{ArtifactId: "pp1a"}, "pp", make(map[string]interface{}), false},
coreBuildPostProcessor{&MockPostProcessor{ArtifactId: "pp1b"}, "pp", make(map[string]interface{}), true},
},
[]coreBuildPostProcessor{
coreBuildPostProcessor{&TestPostProcessor{artifactId: "pp2a"}, "pp", make(map[string]interface{}), false},
coreBuildPostProcessor{&TestPostProcessor{artifactId: "pp2b"}, "pp", make(map[string]interface{}), false},
coreBuildPostProcessor{&MockPostProcessor{ArtifactId: "pp2a"}, "pp", make(map[string]interface{}), false},
coreBuildPostProcessor{&MockPostProcessor{ArtifactId: "pp2b"}, "pp", make(map[string]interface{}), false},
},
}
@ -328,7 +328,7 @@ func TestBuild_Run_Artifacts(t *testing.T) {
build.postProcessors = [][]coreBuildPostProcessor{
[]coreBuildPostProcessor{
coreBuildPostProcessor{
&TestPostProcessor{artifactId: "pp", keep: true}, "pp", make(map[string]interface{}), false,
&MockPostProcessor{ArtifactId: "pp", Keep: true}, "pp", make(map[string]interface{}), false,
},
},
}

View File

@ -161,13 +161,54 @@ func (c *Core) Build(n string) (Build, error) {
})
}
// Setup the post-processors
postProcessors := make([][]coreBuildPostProcessor, 0, len(c.template.PostProcessors))
for _, rawPs := range c.template.PostProcessors {
current := make([]coreBuildPostProcessor, 0, len(rawPs))
for _, rawP := range rawPs {
// If we skip, ignore
if rawP.Skip(rawName) {
continue
}
// Get the post-processor
postProcessor, err := c.components.PostProcessor(rawP.Type)
if err != nil {
return nil, fmt.Errorf(
"error initializing post-processor '%s': %s",
rawP.Type, err)
}
if postProcessor == nil {
return nil, fmt.Errorf(
"post-processor type not found: %s", rawP.Type)
}
current = append(current, coreBuildPostProcessor{
processor: postProcessor,
processorType: rawP.Type,
config: rawP.Config,
keepInputArtifact: rawP.KeepInputArtifact,
})
}
// If we have no post-processors in this chain, just continue.
if len(current) == 0 {
continue
}
postProcessors = append(postProcessors, current)
}
// TODO hooks one day
return &coreBuild{
name: n,
builder: builder,
builderConfig: configBuilder.Config,
builderType: configBuilder.Type,
provisioners: provisioners,
variables: c.variables,
name: n,
builder: builder,
builderConfig: configBuilder.Config,
builderType: configBuilder.Type,
postProcessors: postProcessors,
provisioners: provisioners,
variables: c.variables,
}, nil
}

View File

@ -222,6 +222,42 @@ func TestCoreBuild_provSkipInclude(t *testing.T) {
}
}
func TestCoreBuild_postProcess(t *testing.T) {
config := TestCoreConfig(t)
testCoreTemplate(t, config, fixtureDir("build-pp.json"))
b := TestBuilder(t, config, "test")
p := TestPostProcessor(t, config, "test")
core := TestCore(t, config)
ui := TestUi(t)
b.ArtifactId = "hello"
p.ArtifactId = "goodbye"
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(ui, nil)
if err != nil {
t.Fatalf("err: %s", err)
}
if len(artifact) != 1 {
t.Fatalf("bad: %#v", artifact)
}
if artifact[0].Id() != p.ArtifactId {
t.Fatalf("bad: %s", artifact[0].Id())
}
if p.PostProcessArtifact.Id() != b.ArtifactId {
t.Fatalf("bad: %s", p.PostProcessArtifact.Id())
}
}
func TestCoreValidate(t *testing.T) {
cases := []struct {
File string
@ -276,7 +312,7 @@ func TestCoreValidate(t *testing.T) {
func testComponentFinder() *ComponentFinder {
builderFactory := func(n string) (Builder, error) { return new(MockBuilder), nil }
ppFactory := func(n string) (PostProcessor, error) { return new(TestPostProcessor), nil }
ppFactory := func(n string) (PostProcessor, error) { return new(MockPostProcessor), nil }
provFactory := func(n string) (Provisioner, error) { return new(MockProvisioner), nil }
return &ComponentFinder{
Builder: builderFactory,

View File

@ -0,0 +1,33 @@
package packer
// MockPostProcessor is an implementation of PostProcessor that can be
// used for tests.
type MockPostProcessor struct {
ArtifactId string
Keep bool
Error error
ConfigureCalled bool
ConfigureConfigs []interface{}
ConfigureError error
PostProcessCalled bool
PostProcessArtifact Artifact
PostProcessUi Ui
}
func (t *MockPostProcessor) Configure(configs ...interface{}) error {
t.ConfigureCalled = true
t.ConfigureConfigs = configs
return t.ConfigureError
}
func (t *MockPostProcessor) PostProcess(ui Ui, a Artifact) (Artifact, bool, error) {
t.PostProcessCalled = true
t.PostProcessArtifact = a
t.PostProcessUi = ui
return &MockArtifact{
IdValue: t.ArtifactId,
}, t.Keep, t.Error
}

View File

@ -1,24 +0,0 @@
package packer
type TestPostProcessor struct {
artifactId string
keep bool
configCalled bool
configVal []interface{}
ppCalled bool
ppArtifact Artifact
ppUi Ui
}
func (pp *TestPostProcessor) Configure(v ...interface{}) error {
pp.configCalled = true
pp.configVal = v
return nil
}
func (pp *TestPostProcessor) PostProcess(ui Ui, a Artifact) (Artifact, bool, error) {
pp.ppCalled = true
pp.ppArtifact = a
pp.ppUi = ui
return &TestArtifact{id: pp.artifactId}, pp.keep, nil
}

View File

@ -11,7 +11,7 @@ import (
func testTemplateComponentFinder() *ComponentFinder {
builder := new(MockBuilder)
pp := new(TestPostProcessor)
pp := new(MockPostProcessor)
provisioner := &MockProvisioner{}
builderMap := map[string]Builder{
@ -1018,7 +1018,7 @@ func TestTemplate_Build(t *testing.T) {
"test-prov": provisioner,
}
pp := new(TestPostProcessor)
pp := new(MockPostProcessor)
ppMap := map[string]PostProcessor{
"simple": pp,
}

View File

@ -0,0 +1,7 @@
{
"builders": [{
"type": "test"
}],
"post-processors": ["test"]
}

View File

@ -8,14 +8,6 @@ import (
)
func TestCoreConfig(t *testing.T) *CoreConfig {
// Create a UI that is effectively /dev/null everywhere
var buf bytes.Buffer
ui := &BasicUi{
Reader: &buf,
Writer: ioutil.Discard,
ErrorWriter: ioutil.Discard,
}
// Create some test components
components := ComponentFinder{
Builder: func(n string) (Builder, error) {
@ -30,7 +22,7 @@ func TestCoreConfig(t *testing.T) *CoreConfig {
return &CoreConfig{
Cache: &FileCache{CacheDir: os.TempDir()},
Components: components,
Ui: ui,
Ui: TestUi(t),
}
}
@ -43,6 +35,15 @@ func TestCore(t *testing.T, c *CoreConfig) *Core {
return core
}
func TestUi(t *testing.T) Ui {
var buf bytes.Buffer
return &BasicUi{
Reader: &buf,
Writer: ioutil.Discard,
ErrorWriter: ioutil.Discard,
}
}
// TestBuilder sets the builder with the name n to the component finder
// and returns the mock.
func TestBuilder(t *testing.T, c *CoreConfig, n string) *MockBuilder {
@ -74,3 +75,19 @@ func TestProvisioner(t *testing.T, c *CoreConfig, n string) *MockProvisioner {
return &b
}
// TestPostProcessor sets the prov. with the name n to the component finder
// and returns the mock.
func TestPostProcessor(t *testing.T, c *CoreConfig, n string) *MockPostProcessor {
var b MockPostProcessor
c.Components.PostProcessor = func(actual string) (PostProcessor, error) {
if actual != n {
return nil, nil
}
return &b, nil
}
return &b
}