diff --git a/CHANGELOG.md b/CHANGELOG.md index e91c39212..ceb865606 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ FEATURES: Packer will look in the PWD and the directory with `packer` for binaries named `packer-TYPE-NAME`. * builder/docker: Images can now be committed instead of exported. [GH-1198] + * builder/docker: Can now specify login credentials to pull images. * builder/virtualbox-ovf: New `import_flags` setting can be used to add new command line flags to `VBoxManage import` to allow things such as EULAs to be accepted. [GH-1383] diff --git a/builder/docker/config.go b/builder/docker/config.go index f0ecc289c..7d52b3856 100644 --- a/builder/docker/config.go +++ b/builder/docker/config.go @@ -15,6 +15,12 @@ type Config struct { Pull bool RunCommand []string `mapstructure:"run_command"` + Login bool + LoginEmail string `mapstructure:"login_email"` + LoginUsername string `mapstructure:"login_username"` + LoginPassword string `mapstructure:"login_password"` + LoginServer string `mapstructure:"login_server"` + tpl *packer.ConfigTemplate } @@ -59,8 +65,12 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { errs := common.CheckUnusedConfig(md) templates := map[string]*string{ - "export_path": &c.ExportPath, - "image": &c.Image, + "export_path": &c.ExportPath, + "image": &c.Image, + "login_email": &c.LoginEmail, + "login_username": &c.LoginUsername, + "login_password": &c.LoginPassword, + "login_server": &c.LoginServer, } for n, ptr := range templates { diff --git a/builder/docker/step_pull.go b/builder/docker/step_pull.go index 6571a6563..346334e1e 100644 --- a/builder/docker/step_pull.go +++ b/builder/docker/step_pull.go @@ -20,6 +20,29 @@ func (s *StepPull) Run(state multistep.StateBag) multistep.StepAction { } ui.Say(fmt.Sprintf("Pulling Docker image: %s", config.Image)) + + if config.Login { + ui.Message("Logging in...") + err := driver.Login( + config.LoginServer, + config.LoginEmail, + config.LoginUsername, + config.LoginPassword) + if err != nil { + err := fmt.Errorf("Error logging in: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + defer func() { + ui.Message("Logging out...") + if err := driver.Logout(config.LoginServer); err != nil { + ui.Error(fmt.Sprintf("Error logging out: %s", err)) + } + }() + } + if err := driver.Pull(config.Image); err != nil { err := fmt.Errorf("Error pulling Docker image: %s", err) state.Put("error", err) diff --git a/builder/docker/step_pull_test.go b/builder/docker/step_pull_test.go index 5c66425bb..7ba5705d5 100644 --- a/builder/docker/step_pull_test.go +++ b/builder/docker/step_pull_test.go @@ -51,6 +51,35 @@ func TestStepPull_error(t *testing.T) { } } +func TestStepPull_login(t *testing.T) { + state := testState(t) + step := new(StepPull) + defer step.Cleanup(state) + + config := state.Get("config").(*Config) + driver := state.Get("driver").(*MockDriver) + + config.Login = true + + // run the step + if action := step.Run(state); action != multistep.ActionContinue { + t.Fatalf("bad action: %#v", action) + } + + // verify we pulled + if !driver.PullCalled { + t.Fatal("should've pulled") + } + + // verify we logged in + if !driver.LoginCalled { + t.Fatal("should've logged in") + } + if !driver.LogoutCalled { + t.Fatal("should've logged out") + } +} + func TestStepPull_noPull(t *testing.T) { state := testState(t) step := new(StepPull) diff --git a/website/source/docs/builders/docker.html.markdown b/website/source/docs/builders/docker.html.markdown index a141c2fbc..a72bf7606 100644 --- a/website/source/docs/builders/docker.html.markdown +++ b/website/source/docs/builders/docker.html.markdown @@ -74,6 +74,18 @@ described. ### Optional: +* `login` (boolean) - Defaults to false. If true, the builder will + login in order to pull the image. The builder only logs in for the + duration of the pull. It always logs out afterwards. + +* `login_email` (string) - The email to use to authenticate to login. + +* `login_username` (string) - The username to use to authenticate to login. + +* `login_password` (string) - The password to use to authenticate to login. + +* `login_server` (string) - The server address to login to. + * `pull` (boolean) - If true, the configured image will be pulled using `docker pull` prior to use. Otherwise, it is assumed the image already exists and can be used. This defaults to true if not set.