diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fe5188bd..64aca449a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ IMPROVEMENTS: + - providers/docker: Can now start containers from private repositories + more easily. Vagrant will login for you if you specify auth. [GH-4042] - providers/docker: `stop_timeout` can be used to modify the `docker stop` timeout. [GH-4504] diff --git a/plugins/providers/docker/action.rb b/plugins/providers/docker/action.rb index f8b316f80..f3cbfb830 100644 --- a/plugins/providers/docker/action.rb +++ b/plugins/providers/docker/action.rb @@ -241,6 +241,7 @@ module VagrantPlugins b2.use PrepareNFSValidIds b2.use SyncedFolderCleanup b2.use PrepareNFSSettings + b2.use Login b2.use Build if env[:machine_action] != :run_command @@ -295,6 +296,7 @@ module VagrantPlugins autoload :HostMachineSyncFoldersDisable, action_root.join("host_machine_sync_folders_disable") autoload :IsBuild, action_root.join("is_build") autoload :IsHostMachineCreated, action_root.join("is_host_machine_created") + autoload :Login, action_root.join("login") autoload :PrepareSSH, action_root.join("prepare_ssh") autoload :Stop, action_root.join("stop") autoload :PrepareNFSValidIds, action_root.join("prepare_nfs_valid_ids") diff --git a/plugins/providers/docker/action/host_machine.rb b/plugins/providers/docker/action/host_machine.rb index c0e518fe8..56f4385bb 100644 --- a/plugins/providers/docker/action/host_machine.rb +++ b/plugins/providers/docker/action/host_machine.rb @@ -48,9 +48,6 @@ module VagrantPlugins # hold the lock, we'll see the updated state. host_machine.reload - p host_machine.id - p host_machine.ssh_info - # See if the machine is ready already. If not, start it. if host_machine.communicate.ready? env[:machine].ui.detail(I18n.t("docker_provider.host_machine_ready")) diff --git a/plugins/providers/docker/action/login.rb b/plugins/providers/docker/action/login.rb new file mode 100644 index 000000000..a63c0fdc6 --- /dev/null +++ b/plugins/providers/docker/action/login.rb @@ -0,0 +1,39 @@ +require "log4r" + +module VagrantPlugins + module DockerProvider + module Action + class Login + def initialize(app, env) + @app = app + @logger = Log4r::Logger.new("vagrant::docker::login") + end + + def call(env) + config = env[:machine].provider_config + driver = env[:machine].provider.driver + + # If we don't have a password set, don't auth + return @app.call(env) if config.password == "" + + # Grab a host VM lock to do the login so that we only login + # once per container for the rest of this process. + env[:machine].provider.host_vm_lock do + # Login! + env[:ui].output(I18n.t("docker_provider.logging_in")) + driver.login( + config.email, config.username, + config.password, config.auth_server) + + # Continue, within the lock, so that the auth is protected + # from meddling. + @app.call(env) + + # Log out + driver.logout(config.auth_server) + end + end + end + end + end +end diff --git a/plugins/providers/docker/config.rb b/plugins/providers/docker/config.rb index df7a85d2a..7b36ab70c 100644 --- a/plugins/providers/docker/config.rb +++ b/plugins/providers/docker/config.rb @@ -89,6 +89,37 @@ module VagrantPlugins # @return [String] attr_accessor :vagrant_vagrantfile + #-------------------------------------------------------------- + # Auth Settings + #-------------------------------------------------------------- + + # Server to authenticate to. If blank, will use the default + # Docker authentication endpoint (which is the Docker Hub at the + # time of this comment). + # + # @return [String] + attr_accessor :auth_server + + # Email for logging in to a remote Docker server. + # + # @return [String] + attr_accessor :email + + # Email for logging in to a remote Docker server. + # + # @return [String] + attr_accessor :username + + # Password for logging in to a remote Docker server. If this is + # not blank, then Vagrant will run `docker login` prior to any + # Docker runs. + # + # The presence of auth will also force the Docker environments to + # serialize on `up` so that different users/passwords don't overlap. + # + # @return [String] + attr_accessor :password + def initialize @build_args = [] @build_dir = UNSET_VALUE @@ -109,6 +140,11 @@ module VagrantPlugins @volumes = [] @vagrant_machine = UNSET_VALUE @vagrant_vagrantfile = UNSET_VALUE + + @auth_server = UNSET_VALUE + @email = UNSET_VALUE + @username = UNSET_VALUE + @password = UNSET_VALUE end def link(name) @@ -162,6 +198,11 @@ module VagrantPlugins @vagrant_machine = nil if @vagrant_machine == UNSET_VALUE @vagrant_vagrantfile = nil if @vagrant_vagrantfile == UNSET_VALUE + @auth_server = nil if @auth_server == UNSET_VALUE + @email = "" if @email == UNSET_VALUE + @username = "" if @username == UNSET_VALUE + @password = "" if @password == UNSET_VALUE + if @host_vm_build_dir_options == UNSET_VALUE @host_vm_build_dir_options = nil end diff --git a/plugins/providers/docker/driver.rb b/plugins/providers/docker/driver.rb index c35bb01d6..080b5d0f3 100644 --- a/plugins/providers/docker/driver.rb +++ b/plugins/providers/docker/driver.rb @@ -86,6 +86,22 @@ module VagrantPlugins inspect_container(cid)['HostConfig']['Privileged'] end + def login(email, username, password, server) + cmd = %W(docker login) + cmd += ["-e", email] if email != "" + cmd += ["-u", username] if username != "" + cmd += ["-p", password] if password != "" + cmd << server if server && server != "" + + execute(*cmd.flatten) + end + + def logout(server) + cmd = %W(docker logout) + cmd << server if server && server != "" + execute(*cmd.flatten) + end + def start(cid) if !running?(cid) execute('docker', 'start', cid) diff --git a/templates/locales/providers_docker.yml b/templates/locales/providers_docker.yml index 5a208ffc7..c04248a95 100644 --- a/templates/locales/providers_docker.yml +++ b/templates/locales/providers_docker.yml @@ -33,6 +33,8 @@ en: host. You'll see the output of the `vagrant up` for this VM below. host_machine_syncing_folders: |- Syncing folders to the host VM... + logging_in: |- + Logging in to Docker server... logs_host_state_unknown: |- This container requires a host VM, and the state of that VM is unknown. Run `vagrant up` to verify that the container and diff --git a/test/unit/plugins/providers/docker/config_test.rb b/test/unit/plugins/providers/docker/config_test.rb index e1239794c..0d1937994 100644 --- a/test/unit/plugins/providers/docker/config_test.rb +++ b/test/unit/plugins/providers/docker/config_test.rb @@ -50,6 +50,11 @@ describe VagrantPlugins::DockerProvider::Config do its(:stop_timeout) { should eq(1) } its(:vagrant_machine) { should be_nil } its(:vagrant_vagrantfile) { should be_nil } + + its(:auth_server) { should be_nil } + its(:email) { should eq("") } + its(:username) { should eq("") } + its(:password) { should eq("") } end before do diff --git a/website/docs/source/v2/docker/configuration.html.md b/website/docs/source/v2/docker/configuration.html.md index a4d8d760c..a8dfed3c7 100644 --- a/website/docs/source/v2/docker/configuration.html.md +++ b/website/docs/source/v2/docker/configuration.html.md @@ -18,6 +18,8 @@ you may set. A complete reference is shown below. ### Optional +General settings: + * `build_args` (array of strings) - Extra arguments to pass to `docker build` when `build_dir` is in use. @@ -76,3 +78,16 @@ you may set. A complete reference is shown below. volumes into the container. These directories must exist in the host where Docker is running. If you want to sync folders from the host Vagrant is running, just use synced folders. + +Below, we have settings related to auth. If these are set, then Vagrant +will `docker login` prior to starting containers, allowing you to pull +images from private repositories. + + * `email` (string) - Email address for logging in. + + * `username` (string) - Username for logging in. + + * `password` (string) - Password for logging in. + + * `auth_server` (string) - The server to use for authentication. If not + set, the Docker Hub will be used.