From f78cbb45a6c37a0b9ac99af672b2f25f198648ba Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 1 Jul 2013 11:30:39 -0700 Subject: [PATCH] packer: PostProcessor API change so they can keep artifacts [GH-55] --- CHANGELOG.md | 1 + packer/build.go | 7 +++--- packer/build_test.go | 27 +++++++++++++++++++++++ packer/plugin/post_processor.go | 2 +- packer/plugin/post_processor_test.go | 4 ++-- packer/post_processor.go | 5 +++-- packer/post_processor_test.go | 5 +++-- packer/rpc/post_processor.go | 16 ++++++++------ packer/rpc/post_processor_test.go | 6 ++--- post-processor/vagrant/aws.go | 20 ++++++++--------- post-processor/vagrant/post-processor.go | 8 +++---- post-processor/vagrant/virtualbox.go | 28 ++++++++++++------------ post-processor/vagrant/vmware.go | 24 ++++++++++---------- 13 files changed, 93 insertions(+), 60 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1edb00e63..56bcaad3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ IMPROVEMENTS: BUG FIXES: * core: More plugin server fixes that avoid hangs on OS X 10.7 [GH-87] +* vagrant: AWS boxes will keep the AMI artifact around [GH-55] * virtualbox: More robust version parsing for uploading guest additions. [GH-69] * virtualbox: Output dir and VM name defaults depend on build name, avoiding collisions. [GH-91] diff --git a/packer/build.go b/packer/build.go index 7903fff15..2aa76887f 100644 --- a/packer/build.go +++ b/packer/build.go @@ -194,7 +194,7 @@ PostProcessorRunSeqLoop: } builderUi.Say(fmt.Sprintf("Running post-processor: %s", corePP.processorType)) - artifact, err := corePP.processor.PostProcess(ppUi, priorArtifact) + artifact, keep, err := corePP.processor.PostProcess(ppUi, priorArtifact) if err != nil { errors = append(errors, fmt.Errorf("Post-processor failed: %s", err)) continue PostProcessorRunSeqLoop @@ -205,11 +205,12 @@ PostProcessorRunSeqLoop: continue PostProcessorRunSeqLoop } + keep = keep || corePP.keepInputArtifact if i == 0 { // This is the first post-processor. We handle deleting // previous artifacts a bit different because multiple // post-processors may be using the original and need it. - if !keepOriginalArtifact && corePP.keepInputArtifact { + if !keepOriginalArtifact && keep { log.Printf( "Flagging to keep original artifact from post-processor '%s'", corePP.processorType) @@ -218,7 +219,7 @@ PostProcessorRunSeqLoop: } else { // We have a prior artifact. If we want to keep it, we append // it to the results list. Otherwise, we destroy it. - if corePP.keepInputArtifact { + if keep { artifacts = append(artifacts, priorArtifact) } else { log.Printf("Deleting prior artifact from post-processor '%s'", corePP.processorType) diff --git a/packer/build_test.go b/packer/build_test.go index 19e91a466..28e2fd43a 100644 --- a/packer/build_test.go +++ b/packer/build_test.go @@ -245,6 +245,33 @@ func TestBuild_Run_Artifacts(t *testing.T) { if !reflect.DeepEqual(artifactIds, expectedIds) { t.Fatalf("unexpected ids: %#v", artifactIds) } + + // Test case: Test that with a single post-processor that forcibly + // keeps inputs, that the artifacts are kept. + build = testBuild() + build.postProcessors = [][]coreBuildPostProcessor{ + []coreBuildPostProcessor{ + coreBuildPostProcessor{ + &TestPostProcessor{artifactId: "pp", keep: true}, "pp", 42, false, + }, + }, + } + + build.Prepare() + artifacts, err = build.Run(ui, cache) + if err != nil { + t.Fatalf("err: %s", err) + } + + expectedIds = []string{"b", "pp"} + artifactIds = make([]string, len(artifacts)) + for i, artifact := range artifacts { + artifactIds[i] = artifact.Id() + } + + if !reflect.DeepEqual(artifactIds, expectedIds) { + t.Fatalf("unexpected ids: %#v", artifactIds) + } } func TestBuild_RunBeforePrepare(t *testing.T) { diff --git a/packer/plugin/post_processor.go b/packer/plugin/post_processor.go index 74d49a7bc..d32701532 100644 --- a/packer/plugin/post_processor.go +++ b/packer/plugin/post_processor.go @@ -19,7 +19,7 @@ func (c *cmdPostProcessor) Configure(config interface{}) error { return c.p.Configure(config) } -func (c *cmdPostProcessor) PostProcess(ui packer.Ui, a packer.Artifact) (packer.Artifact, error) { +func (c *cmdPostProcessor) PostProcess(ui packer.Ui, a packer.Artifact) (packer.Artifact, bool, error) { defer func() { r := recover() c.checkExit(r, nil) diff --git a/packer/plugin/post_processor_test.go b/packer/plugin/post_processor_test.go index 81e7dca77..0e3cb0a7c 100644 --- a/packer/plugin/post_processor_test.go +++ b/packer/plugin/post_processor_test.go @@ -12,8 +12,8 @@ func (helperPostProcessor) Configure(interface{}) error { return nil } -func (helperPostProcessor) PostProcess(packer.Ui, packer.Artifact) (packer.Artifact, error) { - return nil, nil +func (helperPostProcessor) PostProcess(packer.Ui, packer.Artifact) (packer.Artifact, bool, error) { + return nil, false, nil } func TestPostProcessor_NoExist(t *testing.T) { diff --git a/packer/post_processor.go b/packer/post_processor.go index e95a36561..606581f42 100644 --- a/packer/post_processor.go +++ b/packer/post_processor.go @@ -12,6 +12,7 @@ type PostProcessor interface { Configure(interface{}) error // PostProcess takes a previously created Artifact and produces another - // Artifact. If an error occurs, it should return that error. - PostProcess(Ui, Artifact) (Artifact, error) + // Artifact. If an error occurs, it should return that error. If `keep` + // is to true, then the previous artifact is forcibly kept. + PostProcess(Ui, Artifact) (a Artifact, keep bool, err error) } diff --git a/packer/post_processor_test.go b/packer/post_processor_test.go index 476bbe762..3c373a913 100644 --- a/packer/post_processor_test.go +++ b/packer/post_processor_test.go @@ -2,6 +2,7 @@ package packer type TestPostProcessor struct { artifactId string + keep bool configCalled bool configVal interface{} ppCalled bool @@ -15,9 +16,9 @@ func (pp *TestPostProcessor) Configure(v interface{}) error { return nil } -func (pp *TestPostProcessor) PostProcess(ui Ui, a Artifact) (Artifact, error) { +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}, nil + return &TestArtifact{id: pp.artifactId}, pp.keep, nil } diff --git a/packer/rpc/post_processor.go b/packer/rpc/post_processor.go index c9af13543..fea078b04 100644 --- a/packer/rpc/post_processor.go +++ b/packer/rpc/post_processor.go @@ -19,6 +19,7 @@ type PostProcessorServer struct { type PostProcessorProcessResponse struct { Err error + Keep bool RPCAddress string } @@ -33,30 +34,30 @@ func (p *postProcessor) Configure(raw interface{}) (err error) { return } -func (p *postProcessor) PostProcess(ui packer.Ui, a packer.Artifact) (packer.Artifact, error) { +func (p *postProcessor) PostProcess(ui packer.Ui, a packer.Artifact) (packer.Artifact, bool, error) { server := rpc.NewServer() RegisterArtifact(server, a) RegisterUi(server, ui) var response PostProcessorProcessResponse if err := p.client.Call("PostProcessor.PostProcess", serveSingleConn(server), &response); err != nil { - return nil, err + return nil, false, err } if response.Err != nil { - return nil, response.Err + return nil, false, response.Err } if response.RPCAddress == "" { - return nil, nil + return nil, false, nil } client, err := rpc.Dial("tcp", response.RPCAddress) if err != nil { - return nil, err + return nil, false, err } - return Artifact(client), nil + return Artifact(client), response.Keep, nil } func (p *PostProcessorServer) Configure(raw *interface{}, reply *error) error { @@ -76,7 +77,7 @@ func (p *PostProcessorServer) PostProcess(address string, reply *PostProcessorPr responseAddress := "" - artifact, err := p.p.PostProcess(&Ui{client}, Artifact(client)) + artifact, keep, err := p.p.PostProcess(&Ui{client}, Artifact(client)) if err == nil && artifact != nil { server := rpc.NewServer() RegisterArtifact(server, artifact) @@ -89,6 +90,7 @@ func (p *PostProcessorServer) PostProcess(address string, reply *PostProcessorPr *reply = PostProcessorProcessResponse{ Err: err, + Keep: keep, RPCAddress: responseAddress, } diff --git a/packer/rpc/post_processor_test.go b/packer/rpc/post_processor_test.go index 577c01a39..26e49b022 100644 --- a/packer/rpc/post_processor_test.go +++ b/packer/rpc/post_processor_test.go @@ -22,11 +22,11 @@ func (pp *TestPostProcessor) Configure(v interface{}) error { return nil } -func (pp *TestPostProcessor) PostProcess(ui packer.Ui, a packer.Artifact) (packer.Artifact, error) { +func (pp *TestPostProcessor) PostProcess(ui packer.Ui, a packer.Artifact) (packer.Artifact, bool, error) { pp.ppCalled = true pp.ppArtifact = a pp.ppUi = ui - return testPostProcessorArtifact, nil + return testPostProcessorArtifact, false, nil } func TestPostProcessorRPC(t *testing.T) { @@ -63,7 +63,7 @@ func TestPostProcessorRPC(t *testing.T) { // Test PostProcess a := new(testArtifact) ui := new(testUi) - artifact, err := pClient.PostProcess(ui, a) + artifact, _, err := pClient.PostProcess(ui, a) if err != nil { t.Fatalf("err: %s", err) } diff --git a/post-processor/vagrant/aws.go b/post-processor/vagrant/aws.go index a7dc8baa0..c6e9f9120 100644 --- a/post-processor/vagrant/aws.go +++ b/post-processor/vagrant/aws.go @@ -33,7 +33,7 @@ func (p *AWSBoxPostProcessor) Configure(raw interface{}) error { return nil } -func (p *AWSBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, error) { +func (p *AWSBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { // Determine the regions... tplData := &AWSVagrantfileTemplate{ Images: make(map[string]string), @@ -42,7 +42,7 @@ func (p *AWSBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact for _, regions := range strings.Split(artifact.Id(), ",") { parts := strings.Split(regions, ":") if len(parts) != 2 { - return nil, fmt.Errorf("Poorly formatted artifact ID: %s", artifact.Id()) + return nil, false, fmt.Errorf("Poorly formatted artifact ID: %s", artifact.Id()) } tplData.Images[parts[0]] = parts[1] @@ -51,20 +51,20 @@ func (p *AWSBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact // Compile the output path outputPath, err := ProcessOutputPath(p.config.OutputPath, "aws", artifact) if err != nil { - return nil, err + return nil, false, err } // Create a temporary directory for us to build the contents of the box in dir, err := ioutil.TempDir("", "packer") if err != nil { - return nil, err + return nil, false, err } defer os.RemoveAll(dir) // Create the Vagrantfile from the template vf, err := os.Create(filepath.Join(dir, "Vagrantfile")) if err != nil { - return nil, err + return nil, false, err } defer vf.Close() @@ -72,13 +72,13 @@ func (p *AWSBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact if p.config.VagrantfileTemplate != "" { f, err := os.Open(p.config.VagrantfileTemplate) if err != nil { - return nil, err + return nil, false, err } defer f.Close() contents, err := ioutil.ReadAll(f) if err != nil { - return nil, err + return nil, false, err } vagrantfileContents = string(contents) @@ -91,15 +91,15 @@ func (p *AWSBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact // Create the metadata metadata := map[string]string{"provider": "aws"} if err := WriteMetadata(dir, metadata); err != nil { - return nil, err + return nil, false, err } // Compress the directory to the given output path if err := DirToBox(outputPath, dir); err != nil { - return nil, err + return nil, false, err } - return NewArtifact("aws", outputPath), nil + return NewArtifact("aws", outputPath), true, nil } var defaultAWSVagrantfile = ` diff --git a/post-processor/vagrant/post-processor.go b/post-processor/vagrant/post-processor.go index ccbd4beaa..8ce2f9842 100644 --- a/post-processor/vagrant/post-processor.go +++ b/post-processor/vagrant/post-processor.go @@ -68,10 +68,10 @@ func (p *PostProcessor) Configure(raw interface{}) error { return nil } -func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, error) { +func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { ppName, ok := builtins[artifact.BuilderId()] if !ok { - return nil, fmt.Errorf("Unknown artifact type, can't build box: %s", artifact.BuilderId()) + return nil, false, fmt.Errorf("Unknown artifact type, can't build box: %s", artifact.BuilderId()) } // Use the premade PostProcessor if we have one. Otherwise, we @@ -81,12 +81,12 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac log.Printf("Premade post-processor for '%s' not found. Creating.", ppName) pp = keyToPostProcessor(ppName) if pp == nil { - return nil, fmt.Errorf("Vagrant box post-processor not found: %s", ppName) + return nil, false, fmt.Errorf("Vagrant box post-processor not found: %s", ppName) } config := map[string]string{"output": p.config.OutputPath} if err := pp.Configure(config); err != nil { - return nil, err + return nil, false, err } } diff --git a/post-processor/vagrant/virtualbox.go b/post-processor/vagrant/virtualbox.go index 005a05c3e..068c759e3 100644 --- a/post-processor/vagrant/virtualbox.go +++ b/post-processor/vagrant/virtualbox.go @@ -37,24 +37,24 @@ func (p *VBoxBoxPostProcessor) Configure(raw interface{}) error { return nil } -func (p *VBoxBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, error) { +func (p *VBoxBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { var err error tplData := &VBoxVagrantfileTemplate{} tplData.BaseMacAddress, err = p.findBaseMacAddress(artifact) if err != nil { - return nil, err + return nil, false, err } // Compile the output path outputPath, err := ProcessOutputPath(p.config.OutputPath, "virtualbox", artifact) if err != nil { - return nil, err + return nil, false, err } // Create a temporary directory for us to build the contents of the box in dir, err := ioutil.TempDir("", "packer") if err != nil { - return nil, err + return nil, false, err } defer os.RemoveAll(dir) @@ -63,25 +63,25 @@ func (p *VBoxBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifac ui.Message(fmt.Sprintf("Copying: %s", path)) src, err := os.Open(path) if err != nil { - return nil, err + return nil, false, err } defer src.Close() dst, err := os.Create(filepath.Join(dir, filepath.Base(path))) if err != nil { - return nil, err + return nil, false, err } defer dst.Close() if _, err := io.Copy(dst, src); err != nil { - return nil, err + return nil, false, err } } // Create the Vagrantfile from the template vf, err := os.Create(filepath.Join(dir, "Vagrantfile")) if err != nil { - return nil, err + return nil, false, err } defer vf.Close() @@ -89,13 +89,13 @@ func (p *VBoxBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifac if p.config.VagrantfileTemplate != "" { f, err := os.Open(p.config.VagrantfileTemplate) if err != nil { - return nil, err + return nil, false, err } defer f.Close() contents, err := ioutil.ReadAll(f) if err != nil { - return nil, err + return nil, false, err } vagrantfileContents = string(contents) @@ -108,22 +108,22 @@ func (p *VBoxBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifac // Create the metadata metadata := map[string]string{"provider": "virtualbox"} if err := WriteMetadata(dir, metadata); err != nil { - return nil, err + return nil, false, err } // Rename the OVF file to box.ovf, as required by Vagrant ui.Message("Renaming the OVF to box.ovf...") if err := p.renameOVF(dir); err != nil { - return nil, err + return nil, false, err } // Compress the directory to the given output path ui.Message(fmt.Sprintf("Compressing box...")) if err := DirToBox(outputPath, dir); err != nil { - return nil, err + return nil, false, err } - return NewArtifact("virtualbox", outputPath), nil + return NewArtifact("virtualbox", outputPath), false, nil } func (p *VBoxBoxPostProcessor) findBaseMacAddress(a packer.Artifact) (string, error) { diff --git a/post-processor/vagrant/vmware.go b/post-processor/vagrant/vmware.go index a9412c6e4..33f4998e8 100644 --- a/post-processor/vagrant/vmware.go +++ b/post-processor/vagrant/vmware.go @@ -29,17 +29,17 @@ func (p *VMwareBoxPostProcessor) Configure(raw interface{}) error { return nil } -func (p *VMwareBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, error) { +func (p *VMwareBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { // Compile the output path outputPath, err := ProcessOutputPath(p.config.OutputPath, "vmware", artifact) if err != nil { - return nil, err + return nil, false, err } // Create a temporary directory for us to build the contents of the box in dir, err := ioutil.TempDir("", "packer") if err != nil { - return nil, err + return nil, false, err } defer os.RemoveAll(dir) @@ -48,37 +48,37 @@ func (p *VMwareBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artif ui.Message(fmt.Sprintf("Copying: %s", path)) src, err := os.Open(path) if err != nil { - return nil, err + return nil, false, err } defer src.Close() dst, err := os.Create(filepath.Join(dir, filepath.Base(path))) if err != nil { - return nil, err + return nil, false, err } defer dst.Close() if _, err := io.Copy(dst, src); err != nil { - return nil, err + return nil, false, err } } if p.config.VagrantfileTemplate != "" { f, err := os.Open(p.config.VagrantfileTemplate) if err != nil { - return nil, err + return nil, false, err } defer f.Close() contents, err := ioutil.ReadAll(f) if err != nil { - return nil, err + return nil, false, err } // Create the Vagrantfile from the template vf, err := os.Create(filepath.Join(dir, "Vagrantfile")) if err != nil { - return nil, err + return nil, false, err } defer vf.Close() @@ -90,14 +90,14 @@ func (p *VMwareBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artif // Create the metadata metadata := map[string]string{"provider": "vmware_desktop"} if err := WriteMetadata(dir, metadata); err != nil { - return nil, err + return nil, false, err } // Compress the directory to the given output path ui.Message(fmt.Sprintf("Compressing box...")) if err := DirToBox(outputPath, dir); err != nil { - return nil, err + return nil, false, err } - return NewArtifact("vmware", outputPath), nil + return NewArtifact("vmware", outputPath), false, nil }