From 037a744be599a4dd5aeb94473da46467ff1971af Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 27 Dec 2013 10:17:45 -0700 Subject: [PATCH] builder/docker: customize run command [GH-648] --- CHANGELOG.md | 2 ++ builder/docker/builder.go | 2 +- builder/docker/config.go | 12 ++++++++++ builder/docker/driver.go | 11 +++++++-- builder/docker/driver_docker.go | 23 ++++++++++++++----- builder/docker/step_run.go | 5 ++-- .../source/docs/builders/docker.html.markdown | 5 ++++ 7 files changed, 49 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7e384ca6..44df47eae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,8 @@ IMPROVEMENTS: "Packer Builder" so that they are easily recognizable. [GH-642] * builder/amazon/all: Copying AMIs to multiple regions now happens in parallel. [GH-495] +* builder/docker: A "run\_command" can be specified, configuring how + the container is started. [GH-648] * builder/openstack: In debug mode, the generated SSH keypair is saved so you can SSH into the machine. [GH-746] * builder/qemu: Floppy files are supported. [GH-686] diff --git a/builder/docker/builder.go b/builder/docker/builder.go index 0cf9d6aa9..f8c3832e9 100644 --- a/builder/docker/builder.go +++ b/builder/docker/builder.go @@ -25,7 +25,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { } func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { - driver := &DockerDriver{Ui: ui} + driver := &DockerDriver{Tpl: b.config.tpl, Ui: ui} if err := driver.Verify(); err != nil { return nil, err } diff --git a/builder/docker/config.go b/builder/docker/config.go index 864ad1fee..c7fb438e4 100644 --- a/builder/docker/config.go +++ b/builder/docker/config.go @@ -12,6 +12,7 @@ type Config struct { ExportPath string `mapstructure:"export_path"` Image string Pull bool + RunCommand []string `mapstructure:"run_command"` tpl *packer.ConfigTemplate } @@ -28,6 +29,17 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { return nil, nil, err } + // Defaults + if len(c.RunCommand) == 0 { + c.RunCommand = []string{ + "run", + "-d", "-i", "-t", + "-v", "{{.Volumes}}", + "{{.Image}}", + "/bin/bash", + } + } + // Default Pull if it wasn't set hasPull := false for _, k := range md.Keys { diff --git a/builder/docker/driver.go b/builder/docker/driver.go index c19a8823b..d182ba145 100644 --- a/builder/docker/driver.go +++ b/builder/docker/driver.go @@ -27,6 +27,13 @@ type Driver interface { // ContainerConfig is the configuration used to start a container. type ContainerConfig struct { - Image string - Volumes map[string]string + Image string + RunCommand []string + Volumes map[string]string +} + +// This is the template that is used for the RunCommand in the ContainerConfig. +type startContainerTemplate struct { + Image string + Volumes string } diff --git a/builder/docker/driver_docker.go b/builder/docker/driver_docker.go index 91e367acc..676045f1a 100644 --- a/builder/docker/driver_docker.go +++ b/builder/docker/driver_docker.go @@ -11,7 +11,8 @@ import ( ) type DockerDriver struct { - Ui packer.Ui + Ui packer.Ui + Tpl *packer.ConfigTemplate } func (d *DockerDriver) Export(id string, dst io.Writer) error { @@ -40,19 +41,29 @@ func (d *DockerDriver) Pull(image string) error { } func (d *DockerDriver) StartContainer(config *ContainerConfig) (string, error) { - // Args that we're going to pass to Docker - args := []string{"run", "-d", "-i", "-t"} - + // Build up the template data + var tplData startContainerTemplate + tplData.Image = config.Image if len(config.Volumes) > 0 { volumes := make([]string, 0, len(config.Volumes)) for host, guest := range config.Volumes { volumes = append(volumes, fmt.Sprintf("%s:%s", host, guest)) } - args = append(args, "-v", strings.Join(volumes, ",")) + tplData.Volumes = strings.Join(volumes, ",") } - args = append(args, config.Image, "/bin/bash") + // Args that we're going to pass to Docker + args := config.RunCommand + for i, v := range args { + var err error + args[i], err = d.Tpl.Process(v, &tplData) + if err != nil { + return "", err + } + } + d.Ui.Message(fmt.Sprintf( + "Run command: docker %s", strings.Join(args, " "))) // Start the container var stdout, stderr bytes.Buffer diff --git a/builder/docker/step_run.go b/builder/docker/step_run.go index 7b3c131b0..97ec8c4cb 100644 --- a/builder/docker/step_run.go +++ b/builder/docker/step_run.go @@ -17,13 +17,14 @@ func (s *StepRun) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) runConfig := ContainerConfig{ - Image: config.Image, + Image: config.Image, + RunCommand: config.RunCommand, Volumes: map[string]string{ tempDir: "/packer-files", }, } - ui.Say("Starting docker container with /bin/bash") + ui.Say("Starting docker container...") containerId, err := driver.StartContainer(&runConfig) if err != nil { err := fmt.Errorf("Error running container: %s", err) diff --git a/website/source/docs/builders/docker.html.markdown b/website/source/docs/builders/docker.html.markdown index e7060aa1d..d71c1600d 100644 --- a/website/source/docs/builders/docker.html.markdown +++ b/website/source/docs/builders/docker.html.markdown @@ -59,6 +59,11 @@ Optional: `docker pull` prior to use. Otherwise, it is assumed the image already exists and can be used. This defaults to true if not set. +* `run_command` (array of strings) - An array of arguments to pass to + `docker` in order to run the container. By default this is set to + `["run", "-d", "-i", "-t", "-v", "{{.Volumes}}", "{{.Image}}", "/bin/bash"]`. + As you can see, you have a couple template variables to customize, as well. + ## Using the generated artifact Once the tar artifact has been generated, you will likely want to import, tag,