Merge pull request #2628 from mitchellh/b-docker-export-validation

Improve artifact validation for docker builder
This commit is contained in:
Chris Bednarski 2015-08-19 13:12:34 -07:00
commit 8f7f82334a
4 changed files with 51 additions and 21 deletions

View File

@ -9,8 +9,10 @@ import (
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
) )
const BuilderId = "packer.docker" const (
const BuilderIdImport = "packer.post-processor.docker-import" BuilderId = "packer.docker"
BuilderIdImport = "packer.post-processor.docker-import"
)
type Builder struct { type Builder struct {
config *Config config *Config
@ -54,10 +56,16 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
&common.StepProvision{}, &common.StepProvision{},
} }
if b.config.Commit { if b.config.Discard {
log.Print("[DEBUG] Container will be discarded")
} else if b.config.Commit {
log.Print("[DEBUG] Container will be committed")
steps = append(steps, new(StepCommit)) steps = append(steps, new(StepCommit))
} else { } else if b.config.ExportPath != "" {
log.Printf("[DEBUG] Container will be exported to %s", b.config.ExportPath)
steps = append(steps, new(StepExport)) steps = append(steps, new(StepExport))
} else {
return nil, errArtifactNotUsed
} }
// Setup the state bag and initial state for the steps // Setup the state bag and initial state for the steps

View File

@ -12,23 +12,33 @@ import (
"github.com/mitchellh/packer/template/interpolate" "github.com/mitchellh/packer/template/interpolate"
) )
var (
errArtifactNotUsed = fmt.Errorf("No instructions given for handling the artifact; expected commit, discard, or export_path")
errArtifactUseConflict = fmt.Errorf("Cannot specify more than one of commit, discard, and export_path")
errExportPathNotFile = fmt.Errorf("export_path must be a file, not a directory")
errImageNotSpecified = fmt.Errorf("Image must be specified")
)
type Config struct { type Config struct {
common.PackerConfig `mapstructure:",squash"` common.PackerConfig `mapstructure:",squash"`
Comm communicator.Config `mapstructure:",squash"` Comm communicator.Config `mapstructure:",squash"`
Commit bool Commit bool
Discard bool
ExportPath string `mapstructure:"export_path"` ExportPath string `mapstructure:"export_path"`
Image string Image string
Pty bool
Pull bool Pull bool
RunCommand []string `mapstructure:"run_command"` RunCommand []string `mapstructure:"run_command"`
Volumes map[string]string Volumes map[string]string
// This is used to login to dockerhub to pull a private base container. For
// pushing to dockerhub, see the docker post-processors
Login bool Login bool
LoginEmail string `mapstructure:"login_email"` LoginEmail string `mapstructure:"login_email"`
LoginUsername string `mapstructure:"login_username"`
LoginPassword string `mapstructure:"login_password"` LoginPassword string `mapstructure:"login_password"`
LoginServer string `mapstructure:"login_server"` LoginServer string `mapstructure:"login_server"`
Pty bool LoginUsername string `mapstructure:"login_username"`
ctx interpolate.Context ctx interpolate.Context
} }
@ -53,11 +63,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
// Defaults // Defaults
if len(c.RunCommand) == 0 { if len(c.RunCommand) == 0 {
c.RunCommand = []string{ c.RunCommand = []string{"-d", "-i", "-t", "{{.Image}}", "/bin/bash"}
"-d", "-i", "-t",
"{{.Image}}",
"/bin/bash",
}
} }
// Default Pull if it wasn't set // Default Pull if it wasn't set
@ -83,19 +89,20 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
errs = packer.MultiErrorAppend(errs, es...) errs = packer.MultiErrorAppend(errs, es...)
} }
if c.Image == "" { if c.Image == "" {
errs = packer.MultiErrorAppend(errs, errs = packer.MultiErrorAppend(errs, errImageNotSpecified)
fmt.Errorf("image must be specified"))
} }
if c.ExportPath != "" && c.Commit { if (c.ExportPath != "" && c.Commit) || (c.ExportPath != "" && c.Discard) || (c.Commit && c.Discard) {
errs = packer.MultiErrorAppend(errs, errs = packer.MultiErrorAppend(errs, errArtifactUseConflict)
fmt.Errorf("both commit and export_path cannot be set")) }
if c.ExportPath == "" && !c.Commit && !c.Discard {
errs = packer.MultiErrorAppend(errs, errArtifactNotUsed)
} }
if c.ExportPath != "" { if c.ExportPath != "" {
if fi, err := os.Stat(c.ExportPath); err == nil && fi.IsDir() { if fi, err := os.Stat(c.ExportPath); err == nil && fi.IsDir() {
errs = packer.MultiErrorAppend(errs, fmt.Errorf( errs = packer.MultiErrorAppend(errs, errExportPathNotFile)
"export_path must be a file, not a directory"))
} }
} }

View File

@ -2,9 +2,10 @@ package docker
import ( import (
"fmt" "fmt"
"os"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"os"
) )
// StepExport exports the container to a flat tar file. // StepExport exports the container to a flat tar file.
@ -17,6 +18,14 @@ func (s *StepExport) Run(state multistep.StateBag) multistep.StepAction {
containerId := state.Get("container_id").(string) containerId := state.Get("container_id").(string)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
// We should catch this in validation, but guard anyway
if config.ExportPath == "" {
err := fmt.Errorf("No output file specified, we can't export anything")
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
// Open the file that we're going to write to // Open the file that we're going to write to
f, err := os.Create(config.ExportPath) f, err := os.Create(config.ExportPath)
if err != nil { if err != nil {

View File

@ -68,11 +68,17 @@ builder.
### Required: ### Required:
You must specify (only) one of `commit`, `discard`, or `export_path`.
- `commit` (boolean) - If true, the container will be committed to an image - `commit` (boolean) - If true, the container will be committed to an image
rather than exported. This cannot be set if `export_path` is set. rather than exported.
- `discard` (boolean) - Throw away the container when the build is complete.
This is useful for the [artifice
post-processor](https://packer.io/docs/post-processors/artifice.html).
- `export_path` (string) - The path where the final container will be exported - `export_path` (string) - The path where the final container will be exported
as a tar file. This cannot be set if `commit` is set to true. as a tar file.
- `image` (string) - The base image for the Docker container that will - `image` (string) - The base image for the Docker container that will
be started. This image will be pulled from the Docker registry if it doesn't be started. This image will be pulled from the Docker registry if it doesn't