diff --git a/builder/docker/driver.go b/builder/docker/driver.go index d9cb94f9b..7c9e6b868 100644 --- a/builder/docker/driver.go +++ b/builder/docker/driver.go @@ -46,7 +46,7 @@ type Driver interface { StopContainer(id string) error // TagImage tags the image with the given ID - TagImage(id string, repo string) error + TagImage(id string, repo string, force bool) error // Verify verifies that the driver can run Verify() error diff --git a/builder/docker/driver_docker.go b/builder/docker/driver_docker.go index 017c33ee0..ea895d362 100644 --- a/builder/docker/driver_docker.go +++ b/builder/docker/driver_docker.go @@ -240,9 +240,15 @@ func (d *DockerDriver) StopContainer(id string) error { return exec.Command("docker", "rm", id).Run() } -func (d *DockerDriver) TagImage(id string, repo string) error { +func (d *DockerDriver) TagImage(id string, repo string, force bool) error { + args := []string{"tag"} + if force { + args = append(args, "-f") + } + args = append(args, id, repo) + var stderr bytes.Buffer - cmd := exec.Command("docker", "tag", id, repo) + cmd := exec.Command("docker", args...) cmd.Stderr = &stderr if err := cmd.Start(); err != nil { diff --git a/builder/docker/driver_mock.go b/builder/docker/driver_mock.go index 390a7e308..420856742 100644 --- a/builder/docker/driver_mock.go +++ b/builder/docker/driver_mock.go @@ -46,6 +46,7 @@ type MockDriver struct { TagImageCalled bool TagImageImageId string TagImageRepo string + TagImageForce bool TagImageErr error ExportReader io.Reader @@ -156,10 +157,11 @@ func (d *MockDriver) StopContainer(id string) error { return d.StopError } -func (d *MockDriver) TagImage(id string, repo string) error { +func (d *MockDriver) TagImage(id string, repo string, force bool) error { d.TagImageCalled = true d.TagImageImageId = id d.TagImageRepo = repo + d.TagImageForce = force return d.TagImageErr } diff --git a/post-processor/docker-tag/post-processor.go b/post-processor/docker-tag/post-processor.go index 64d3e0479..7fc47901f 100644 --- a/post-processor/docker-tag/post-processor.go +++ b/post-processor/docker-tag/post-processor.go @@ -18,6 +18,7 @@ type Config struct { Repository string `mapstructure:"repository"` Tag string `mapstructure:"tag"` + Force bool ctx interpolate.Context } @@ -64,7 +65,7 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac ui.Message("Tagging image: " + artifact.Id()) ui.Message("Repository: " + importRepo) - err := driver.TagImage(artifact.Id(), importRepo) + err := driver.TagImage(artifact.Id(), importRepo, p.config.Force) if err != nil { return nil, false, err } diff --git a/post-processor/docker-tag/post-processor_test.go b/post-processor/docker-tag/post-processor_test.go index c28e7cac0..1501a3e15 100644 --- a/post-processor/docker-tag/post-processor_test.go +++ b/post-processor/docker-tag/post-processor_test.go @@ -68,4 +68,47 @@ func TestPostProcessor_PostProcess(t *testing.T) { if driver.TagImageRepo != "foo:bar" { t.Fatal("bad repo") } + if driver.TagImageForce { + t.Fatal("bad force. force=false in default") + } +} + +func TestPostProcessor_PostProcess_Force(t *testing.T) { + driver := &docker.MockDriver{} + p := &PostProcessor{Driver: driver} + config := testConfig() + config["force"] = true + _, err := common.DecodeConfig(&p.config, config) + if err != nil { + t.Fatalf("err %s", err) + } + + artifact := &packer.MockArtifact{ + BuilderIdValue: dockerimport.BuilderId, + IdValue: "1234567890abcdef", + } + + result, keep, err := p.PostProcess(testUi(), artifact) + if _, ok := result.(packer.Artifact); !ok { + t.Fatal("should be instance of Artifact") + } + if !keep { + t.Fatal("should keep") + } + if err != nil { + t.Fatalf("err: %s", err) + } + + if !driver.TagImageCalled { + t.Fatal("should call TagImage") + } + if driver.TagImageImageId != "1234567890abcdef" { + t.Fatal("bad image id") + } + if driver.TagImageRepo != "foo:bar" { + t.Fatal("bad repo") + } + if !driver.TagImageForce { + t.Fatal("bad force") + } }