From 3d60bfb312d4b638b62a97617bce74ade87ded42 Mon Sep 17 00:00:00 2001 From: Matthew McKeen Date: Thu, 2 Jan 2014 14:49:14 -0800 Subject: [PATCH] Add docker-import post-processor. Implemented initial working version of Docker image importing code. #774 --- config.go | 3 +- plugin/post-processor-docker-import/main.go | 15 ++ .../post-processor-docker-import/main_test.go | 1 + .../docker-import/post-processor.go | 155 ++++++++++++++++++ post-processor/docker-push/post-processor.go | 2 +- 5 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 plugin/post-processor-docker-import/main.go create mode 100644 plugin/post-processor-docker-import/main_test.go create mode 100644 post-processor/docker-import/post-processor.go diff --git a/config.go b/config.go index 7ebdcef66..72ed19618 100644 --- a/config.go +++ b/config.go @@ -43,7 +43,8 @@ const defaultConfig = ` "post-processors": { "vagrant": "packer-post-processor-vagrant", "vsphere": "packer-post-processor-vsphere", - "docker-push": "packer-post-processor-docker-push" + "docker-push": "packer-post-processor-docker-push", + "docker-import": "packer-post-processor-docker-import" }, "provisioners": { diff --git a/plugin/post-processor-docker-import/main.go b/plugin/post-processor-docker-import/main.go new file mode 100644 index 000000000..e9446b113 --- /dev/null +++ b/plugin/post-processor-docker-import/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "github.com/mitchellh/packer/packer/plugin" + "github.com/mitchellh/packer/post-processor/docker-import" +) + +func main() { + server, err := plugin.Server() + if err != nil { + panic(err) + } + server.RegisterPostProcessor(new(dockerimport.PostProcessor)) + server.Serve() +} diff --git a/plugin/post-processor-docker-import/main_test.go b/plugin/post-processor-docker-import/main_test.go new file mode 100644 index 000000000..06ab7d0f9 --- /dev/null +++ b/plugin/post-processor-docker-import/main_test.go @@ -0,0 +1 @@ +package main diff --git a/post-processor/docker-import/post-processor.go b/post-processor/docker-import/post-processor.go new file mode 100644 index 000000000..ef2ec3e39 --- /dev/null +++ b/post-processor/docker-import/post-processor.go @@ -0,0 +1,155 @@ +package dockerimport + +import ( + "fmt" + "github.com/mitchellh/packer/common" + "github.com/mitchellh/packer/packer" + "io" + "os" + "os/exec" +) + +type Config struct { + common.PackerConfig `mapstructure:",squash"` + + Repository string `mapstructure:"repository"` + Tag string `mapstructure:"tag"` + Dockerfile string `mapstructure:"dockerfile"` + + tpl *packer.ConfigTemplate +} + +type PostProcessor struct { + config Config +} + +func (p *PostProcessor) Configure(raws ...interface{}) error { + _, err := common.DecodeConfig(&p.config, raws...) + if err != nil { + return err + } + + p.config.tpl, err = packer.NewConfigTemplate() + if err != nil { + return err + } + p.config.tpl.UserVars = p.config.PackerUserVars + + // Accumulate any errors + errs := new(packer.MultiError) + + templates := map[string]*string{ + "repository": &p.config.Repository, + } + + for key, ptr := range templates { + if *ptr == "" { + errs = packer.MultiErrorAppend( + errs, fmt.Errorf("%s must be set", key)) + } + + *ptr, err = p.config.tpl.Process(*ptr, nil) + if err != nil { + errs = packer.MultiErrorAppend( + errs, fmt.Errorf("Error processing %s: %s", key, err)) + } + } + + if len(errs.Errors) > 0 { + return errs + } + + return nil + +} + +func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { + id := artifact.Id() + ui.Say("Importing image: " + id) + + if p.config.Tag == "" { + + cmd := exec.Command("docker", + "import", + "-", + p.config.Repository) + + stdin, err := cmd.StdinPipe() + + if err != nil { + return nil, false, err + } + + // There should be only one artifact of the Docker builder + file, err := os.Open(artifact.Files()[0]) + + if err != nil { + return nil, false, err + } + + defer file.Close() + + if err := cmd.Start(); err != nil { + ui.Say("Image import failed") + return nil, false, err + } + + go func() { + io.Copy(stdin, file) + // close stdin so that program will exit + stdin.Close() + }() + + cmd.Wait() + + } else { + + cmd := exec.Command("docker", + "import", + "-", + p.config.Repository+":"+p.config.Tag) + + stdin, err := cmd.StdinPipe() + + if err != nil { + return nil, false, err + } + + // There should be only one artifact of the Docker builder + file, err := os.Open(artifact.Files()[0]) + + if err != nil { + return nil, false, err + } + + defer file.Close() + + if err := cmd.Start(); err != nil { + ui.Say("Image import failed") + return nil, false, err + } + + go func() { + io.Copy(stdin, file) + // close stdin so that program will exit + stdin.Close() + }() + + cmd.Wait() + + } + + // Process Dockerfile if provided + if p.config.Dockerfile != "" { + + cmd := exec.Command("docker", "build", id) + if err := cmd.Run(); err != nil { + ui.Say("Failed to build image: " + id) + return nil, false, err + } + + // TODO implement dockerfile provisioning + + } + return nil, false, nil +} diff --git a/post-processor/docker-push/post-processor.go b/post-processor/docker-push/post-processor.go index 80fc3b2f5..0ec2ab492 100644 --- a/post-processor/docker-push/post-processor.go +++ b/post-processor/docker-push/post-processor.go @@ -129,5 +129,5 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac return nil, false, err } - return nil, true, nil + return nil, false, nil }