diff --git a/builder/docker/builder.go b/builder/docker/builder.go index 67515b645..4c52827ed 100644 --- a/builder/docker/builder.go +++ b/builder/docker/builder.go @@ -56,6 +56,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe state.Put("hook", hook) state.Put("ui", ui) + // Setup the driver that will talk to Docker + state.Put("driver", &DockerDriver{ + Ui: ui, + }) + // Run! if b.config.PackerDebug { b.runner = &multistep.DebugRunner{ diff --git a/builder/docker/driver.go b/builder/docker/driver.go new file mode 100644 index 000000000..c0fb5fa66 --- /dev/null +++ b/builder/docker/driver.go @@ -0,0 +1,9 @@ +package docker + +// Driver is the interface that has to be implemented to communicate with +// Docker. The Driver interface also allows the steps to be tested since +// a mock driver can be shimmed in. +type Driver interface { + // Pull should pull down the given image. + Pull(image string) error +} diff --git a/builder/docker/driver_docker.go b/builder/docker/driver_docker.go new file mode 100644 index 000000000..04d338abd --- /dev/null +++ b/builder/docker/driver_docker.go @@ -0,0 +1,15 @@ +package docker + +import ( + "github.com/mitchellh/packer/packer" + "os/exec" +) + +type DockerDriver struct { + Ui packer.Ui +} + +func (d *DockerDriver) Pull(image string) error { + cmd := exec.Command("docker", "pull", image) + return runAndStream(cmd, d.Ui) +} diff --git a/builder/docker/driver_mock.go b/builder/docker/driver_mock.go new file mode 100644 index 000000000..f5aad13bc --- /dev/null +++ b/builder/docker/driver_mock.go @@ -0,0 +1,15 @@ +package docker + +// MockDriver is a driver implementation that can be used for tests. +type MockDriver struct { + PullError error + + PullCalled bool + PullImage string +} + +func (d *MockDriver) Pull(image string) error { + d.PullCalled = true + d.PullImage = image + return d.PullError +} diff --git a/builder/docker/step_pull.go b/builder/docker/step_pull.go index 28662eccb..19e5a69ab 100644 --- a/builder/docker/step_pull.go +++ b/builder/docker/step_pull.go @@ -4,18 +4,17 @@ import ( "fmt" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" - "os/exec" ) type StepPull struct{} func (s *StepPull) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*Config) + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) ui.Say(fmt.Sprintf("Pulling Docker image: %s", config.Image)) - cmd := exec.Command("docker", "pull", config.Image) - if err := runAndStream(cmd, ui); err != nil { + if err := driver.Pull(config.Image); err != nil { err := fmt.Errorf("Error pulling Docker image: %s", err) state.Put("error", err) ui.Error(err.Error()) diff --git a/builder/docker/step_pull_test.go b/builder/docker/step_pull_test.go new file mode 100644 index 000000000..93e9cf830 --- /dev/null +++ b/builder/docker/step_pull_test.go @@ -0,0 +1,52 @@ +package docker + +import ( + "errors" + "github.com/mitchellh/multistep" + "testing" +) + +func TestStepPull_impl(t *testing.T) { + var _ multistep.Step = new(StepPull) +} + +func TestStepPull(t *testing.T) { + state := testState(t) + step := new(StepPull) + defer step.Cleanup(state) + + config := state.Get("config").(*Config) + driver := state.Get("driver").(*MockDriver) + + // run the step + if action := step.Run(state); action != multistep.ActionContinue { + t.Fatalf("bad action: %#v", action) + } + + // verify we did the right thing + if !driver.PullCalled { + t.Fatal("should've pulled") + } + if driver.PullImage != config.Image { + t.Fatalf("bad: %#v", driver.PullImage) + } +} + +func TestStepPull_error(t *testing.T) { + state := testState(t) + step := new(StepPull) + defer step.Cleanup(state) + + driver := state.Get("driver").(*MockDriver) + driver.PullError = errors.New("foo") + + // run the step + if action := step.Run(state); action != multistep.ActionHalt { + t.Fatalf("bad action: %#v", action) + } + + // verify we have an error + if _, ok := state.GetOk("error"); !ok { + t.Fatal("should have error") + } +} diff --git a/builder/docker/step_test.go b/builder/docker/step_test.go index c6487c55f..0bc190830 100644 --- a/builder/docker/step_test.go +++ b/builder/docker/step_test.go @@ -10,6 +10,7 @@ import ( func testState(t *testing.T) multistep.StateBag { state := new(multistep.BasicStateBag) state.Put("config", testConfigStruct(t)) + state.Put("driver", &MockDriver{}) state.Put("hook", &packer.MockHook{}) state.Put("ui", &packer.BasicUi{ Reader: new(bytes.Buffer),