diff --git a/lib/vagrant/action/builtin/mixin_synced_folders.rb b/lib/vagrant/action/builtin/mixin_synced_folders.rb index d6f2739f2..0faa6ecab 100644 --- a/lib/vagrant/action/builtin/mixin_synced_folders.rb +++ b/lib/vagrant/action/builtin/mixin_synced_folders.rb @@ -107,10 +107,14 @@ module Vagrant end # Apply the scoped hash overrides to get the options - folders.each do |impl_name, fs| + folders.dup.each do |impl_name, fs| + new_fs = {} fs.each do |id, data| - fs[id] = scoped_hash_override(data, impl_name) + id = data[:id] if data[:id] + new_fs[id] = scoped_hash_override(data, impl_name) end + + folders[impl_name] = new_fs end return folders diff --git a/lib/vagrant/action/builtin/synced_folders.rb b/lib/vagrant/action/builtin/synced_folders.rb index efcabaa5a..db2077ad0 100644 --- a/lib/vagrant/action/builtin/synced_folders.rb +++ b/lib/vagrant/action/builtin/synced_folders.rb @@ -33,6 +33,8 @@ module Vagrant # it does not exist on host folders.each do |_, fs| fs.each do |id, data| + next if data[:hostpath_exact] + data[:hostpath] = File.expand_path( data[:hostpath], env[:root_path]) diff --git a/plugins/providers/docker/action.rb b/plugins/providers/docker/action.rb index fc6dfc7c7..150f5b8cd 100644 --- a/plugins/providers/docker/action.rb +++ b/plugins/providers/docker/action.rb @@ -10,13 +10,8 @@ module VagrantPlugins Vagrant::Action::Builder.new.tap do |b| b.use ConfigValidate b.use HandleBox - - b.use Call, IsState, :host_state_unknown do |env, b2| - if env[:result] - b2.use HostMachine - end - end - + b.use HostMachine + b.use HostMachineSyncFolders b.use Call, IsState, :not_created do |env, b2| # If the VM is NOT created yet, then do the setup steps if env[:result] @@ -224,6 +219,7 @@ module VagrantPlugins autoload :ForwardPorts, action_root.join("forward_ports") autoload :HasSSH, action_root.join("has_ssh") autoload :HostMachine, action_root.join("host_machine") + autoload :HostMachineSyncFolders, action_root.join("host_machine_sync_folders") 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/create.rb b/plugins/providers/docker/action/create.rb index 38ca3890d..a19aafd6a 100644 --- a/plugins/providers/docker/action/create.rb +++ b/plugins/providers/docker/action/create.rb @@ -21,8 +21,11 @@ module VagrantPlugins cid = '' @@mutex.synchronize do env[:ui].output(I18n.t("docker_provider.creating")) - env[:ui].detail(" Name: #{params[:name]}") - env[:ui].detail("Image: #{params[:image]}") + env[:ui].detail(" Name: #{params[:name]}") + env[:ui].detail(" Image: #{params[:image]}") + params[:volumes].each do |volume| + env[:ui].detail("Volume: #{volume}") + end cid = @driver.create(params) end diff --git a/plugins/providers/docker/action/host_machine.rb b/plugins/providers/docker/action/host_machine.rb index ddcaae216..1d6c75ae3 100644 --- a/plugins/providers/docker/action/host_machine.rb +++ b/plugins/providers/docker/action/host_machine.rb @@ -2,9 +2,6 @@ require "digest/md5" require "log4r" -require "vagrant/util/platform" -require "vagrant/util/silence_warnings" - module VagrantPlugins module DockerProvider module Action @@ -46,23 +43,22 @@ module VagrantPlugins protected def setup_host_machine(host_machine, env) - # See if the machine is ready already. - if host_machine.communicate.ready? - env[:machine].ui.detail(I18n.t("docker_provider.host_machine_ready")) - return - end - # Create a UI for this machine that stays at the detail level proxy_ui = host_machine.ui.dup proxy_ui.opts[:bold] = false proxy_ui.opts[:prefix_spaces] = true proxy_ui.opts[:target] = env[:machine].name.to_s - env[:machine].ui.detail( - I18n.t("docker_provider.host_machine_starting")) - env[:machine].ui.detail(" ") - host_machine.with_ui(proxy_ui) do - host_machine.action(:up) + # 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")) + else + env[:machine].ui.detail( + I18n.t("docker_provider.host_machine_starting")) + env[:machine].ui.detail(" ") + host_machine.with_ui(proxy_ui) do + host_machine.action(:up) + end end end end diff --git a/plugins/providers/docker/action/host_machine_sync_folders.rb b/plugins/providers/docker/action/host_machine_sync_folders.rb new file mode 100644 index 000000000..07011f80c --- /dev/null +++ b/plugins/providers/docker/action/host_machine_sync_folders.rb @@ -0,0 +1,113 @@ +require "digest/md5" + +require "log4r" + +require "vagrant/action/builtin/mixin_synced_folders" + +module VagrantPlugins + module DockerProvider + module Action + # This action is responsible for creating the host machine if + # we need to. The host machine is where Docker containers will + # live. + class HostMachineSyncFolders + include Vagrant::Action::Builtin::MixinSyncedFolders + + def initialize(app, env) + @app = app + @logger = Log4r::Logger.new("vagrant::docker::hostmachine") + end + + def call(env) + return @app.call(env) if !env[:machine].provider.host_vm? + + host_machine = env[:machine].provider.host_vm + + # Grab a process-level lock on the data directory of this VM + # so that we only try to modify this one at a time. + hash = Digest::MD5.hexdigest(host_machine.data_dir.to_s) + begin + env[:machine].env.lock(hash) do + setup_synced_folders(host_machine, env) + end + rescue Vagrant::Errors::EnvironmentLockedError + sleep 1 + retry + end + + @app.call(env) + end + + protected + + def setup_synced_folders(host_machine, env) + # Create a UI for this machine that stays at the detail level + proxy_ui = host_machine.ui.dup + proxy_ui.opts[:bold] = false + proxy_ui.opts[:prefix_spaces] = true + proxy_ui.opts[:target] = env[:machine].name.to_s + + # Sync some folders so that our volumes work later. + new_config = VagrantPlugins::Kernel_V2::VMConfig.new + our_folders = synced_folders(env[:machine]) + our_folders.each do |type, folders| + folders.each do |id, data| + data = data.dup + + if type == :docker + # We don't use the Docker type explicitly on the host VM + data.delete(:type) + end + + # Generate a new guestpath + data[:docker_guestpath] = data[:guestpath] + data[:guestpath] = "/mnt/docker_#{Time.now.to_i}_#{rand(100000)}" + data[:id] = + Digest::MD5.hexdigest(Time.now.to_i.to_s)[0...6] + + rand(10000).to_s + + # Add this synced folder onto the new config + new_config.synced_folder( + data[:hostpath], + data[:guestpath], + data) + + # Remove from our machine + env[:machine].config.vm.synced_folders.delete(id) + end + end + + # Sync the folders! + env[:machine].ui.output(I18n.t( + "docker_provider.host_machine_syncing_folders")) + host_machine.with_ui(proxy_ui) do + action_env = { synced_folders_config: new_config } + begin + host_machine.action(:sync_folders, action_env) + rescue Vagrant::Errors::UnimplementedProviderAction + callable = Vagrant::Action::Builder.new + callable.use Vagrant::Action::Builtin::SyncedFolders + host_machine.action_raw(:sync_folders, callable, action_env) + end + end + + # Re-add to our machine the "fixed" synced folders + new_folders = synced_folders(host_machine, new_config) + new_folders.each do |_type, folders| + folders.each do |id, data| + data = data.merge({ + hostpath_exact: true, + type: :docker, + }) + + env[:machine].config.vm.synced_folder( + data[:guestpath], + data[:docker_guestpath], + data) + end + end + end + end + end + end +end diff --git a/plugins/providers/docker/provider.rb b/plugins/providers/docker/provider.rb index 7b6cf46a8..87e636b8a 100644 --- a/plugins/providers/docker/provider.rb +++ b/plugins/providers/docker/provider.rb @@ -2,7 +2,6 @@ require "fileutils" require "log4r" -require "vagrant/action/builtin/mixin_synced_folders" require "vagrant/util/silence_warnings" module VagrantPlugins @@ -88,32 +87,6 @@ module VagrantPlugins host_env.machine(host_machine_name, :virtualbox) end - # Make sure we swap all the synced folders out from our - # machine so that we do a double synced folder: normal synced - # folders to the host machine, then Docker volumes within that host. - sf_helper_klass = Class.new do - include Vagrant::Action::Builtin::MixinSyncedFolders - end - sf_helper = sf_helper_klass.new - our_folders = sf_helper.synced_folders(@machine) - if our_folders[:docker] - our_folders[:docker].each do |id, data| - data = data.dup - data.delete(:type) - - # Add them to the host machine -=begin - @host_vm.config.vm.synced_folder( - data[:hostpath], - data[:guestpath], - data) -=end - - # Remove from our machine - @machine.config.vm.synced_folders.delete(id) - end - end - @host_vm end diff --git a/plugins/providers/docker/synced_folder.rb b/plugins/providers/docker/synced_folder.rb index 1416b6c39..248502b1b 100644 --- a/plugins/providers/docker/synced_folder.rb +++ b/plugins/providers/docker/synced_folder.rb @@ -19,7 +19,7 @@ module VagrantPlugins # FIXME: Check whether the container has already been created with # different synced folders and let the user know about it folders.each do |id, data| - host_path = File.expand_path(data[:hostpath], machine.env.root_path) + host_path = data[:hostpath] guest_path = data[:guestpath] machine.provider_config.volumes << "#{host_path}:#{guest_path}" end diff --git a/plugins/providers/virtualbox/synced_folder.rb b/plugins/providers/virtualbox/synced_folder.rb index 14f9b0b24..351b5adfe 100644 --- a/plugins/providers/virtualbox/synced_folder.rb +++ b/plugins/providers/virtualbox/synced_folder.rb @@ -13,7 +13,10 @@ module VagrantPlugins # Export the shared folders to the VM defs = [] folders.each do |id, data| - hostpath = Vagrant::Util::Platform.cygwin_windows_path(data[:hostpath]) + hostpath = data[:hostpath] + if !data[:hostpath_exact] + hostpath = Vagrant::Util::Platform.cygwin_windows_path(hostpath) + end defs << { name: os_friendly_id(id), diff --git a/templates/locales/providers_docker.yml b/templates/locales/providers_docker.yml index 1ea9c0334..ef1675999 100644 --- a/templates/locales/providers_docker.yml +++ b/templates/locales/providers_docker.yml @@ -11,6 +11,8 @@ en: host_machine_starting: |- Vagrant will now create or start a local VM to act as the Docker host. You'll see the output of the `vagrant up` for this VM below. + host_machine_syncing_folders: |- + Syncing folders to the host VM... 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