diff --git a/lib/vagrant/action/builtin/synced_folders.rb b/lib/vagrant/action/builtin/synced_folders.rb index 6369195f0..f1fde5657 100644 --- a/lib/vagrant/action/builtin/synced_folders.rb +++ b/lib/vagrant/action/builtin/synced_folders.rb @@ -85,12 +85,39 @@ module Vagrant # Once booted, setup the folder contents folders.each do |impl, impl_name, fs| - @logger.info("Invoking synced folder enable: #{impl_name}") - impl.enable(env[:machine], fs, impl_opts(impl_name, env)) + if !env[:synced_folders_disable] + @logger.info("Invoking synced folder enable: #{impl_name}") + impl.enable(env[:machine], fs, impl_opts(impl_name, env)) + next + end + + # We're disabling synced folders + to_disable = {} + fs.each do |id, data| + next if !env[:synced_folders_disable].include?(id) + to_disable[id] = data + end + + impl.disable(env[:machine], fs, impl_opts(impl_name, env)) end - # Save the synced folders - save_synced_folders(env[:machine], original_folders, merge: true) + # If we disabled folders, we have to delete some from the + # save, so we load the entire cached thing, and delete them. + if env[:synced_folders_disable] + all = synced_folders(env[:machine], cached: true) + all.each do |impl, fs| + fs.keys.each do |id| + if env[:synced_folders_disable].include?(id) + fs.delete(id) + end + end + end + + save_synced_folders(env[:machine], all) + else + # Save the synced folders + save_synced_folders(env[:machine], original_folders, merge: true) + end end end end diff --git a/plugins/providers/docker/action.rb b/plugins/providers/docker/action.rb index 150f5b8cd..747295b01 100644 --- a/plugins/providers/docker/action.rb +++ b/plugins/providers/docker/action.rb @@ -133,6 +133,7 @@ module VagrantPlugins b3.use ConfigValidate b3.use EnvSet, :force_halt => true b3.use action_halt + b3.use HostMachineSyncFoldersDisable b3.use Destroy b3.use ProvisionerCleanup else @@ -220,6 +221,7 @@ module VagrantPlugins autoload :HasSSH, action_root.join("has_ssh") autoload :HostMachine, action_root.join("host_machine") autoload :HostMachineSyncFolders, action_root.join("host_machine_sync_folders") + autoload :HostMachineSyncFoldersDisable, action_root.join("host_machine_sync_folders_disable") 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 1d6c75ae3..e1210a874 100644 --- a/plugins/providers/docker/action/host_machine.rb +++ b/plugins/providers/docker/action/host_machine.rb @@ -1,5 +1,3 @@ -require "digest/md5" - require "log4r" module VagrantPlugins @@ -25,11 +23,8 @@ module VagrantPlugins 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 spin up one at a time - hash = Digest::MD5.hexdigest(host_machine.data_dir.to_s) begin - env[:machine].env.lock(hash) do + env[:machine].provider.host_vm_lock do setup_host_machine(host_machine, env) end rescue Vagrant::Errors::EnvironmentLockedError diff --git a/plugins/providers/docker/action/host_machine_sync_folders.rb b/plugins/providers/docker/action/host_machine_sync_folders.rb index 14f5fb16b..00f008c61 100644 --- a/plugins/providers/docker/action/host_machine_sync_folders.rb +++ b/plugins/providers/docker/action/host_machine_sync_folders.rb @@ -1,4 +1,5 @@ require "digest/md5" +require "securerandom" require "log4r" @@ -23,11 +24,9 @@ module VagrantPlugins 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) + # Lock while we make changes begin - env[:machine].env.lock(hash) do + env[:machine].provider.host_vm_lock do setup_synced_folders(host_machine, env) end rescue Vagrant::Errors::EnvironmentLockedError @@ -41,6 +40,19 @@ module VagrantPlugins protected def setup_synced_folders(host_machine, env) + # Write the host machine SFID if we have one + id_path = env[:machine].data_dir.join("host_machine_sfid") + host_sfid = nil + if !id_path.file? + host_sfid = SecureRandom.uuid + id_path.open("w") do |f| + f.binmode + f.write("#{host_sfid}\n") + end + else + host_sfid = id_path.read.chomp + end + # Create a UI for this machine that stays at the detail level proxy_ui = host_machine.ui.dup proxy_ui.opts[:bold] = false @@ -53,7 +65,7 @@ module VagrantPlugins if existing_folders existing_folders.each do |impl, fs| fs.each do |_name, data| - if data[:docker_sfid] + if data[:docker_sfid] && data[:docker_host_sfid] == host_sfid existing_ids[data[:docker_sfid]] = data end end @@ -80,6 +92,7 @@ module VagrantPlugins # Generate a new guestpath data[:docker_guestpath] = data[:guestpath] data[:docker_sfid] = id + data[:docker_host_sfid] = host_sfid data[:guestpath] = "/mnt/docker_#{Time.now.to_i}_#{rand(100000)}" data[:id] = id[0...6] + rand(10000).to_s diff --git a/plugins/providers/docker/action/host_machine_sync_folders_disable.rb b/plugins/providers/docker/action/host_machine_sync_folders_disable.rb new file mode 100644 index 000000000..944889b3f --- /dev/null +++ b/plugins/providers/docker/action/host_machine_sync_folders_disable.rb @@ -0,0 +1,85 @@ +require "log4r" + +require "vagrant/action/builtin/mixin_synced_folders" + +module VagrantPlugins + module DockerProvider + module Action + # This action disables the synced folders we created. + class HostMachineSyncFoldersDisable + 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 + + begin + env[:machine].provider.host_vm_lock 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) + # Read our random ID for this instance + id_path = env[:machine].data_dir.join("host_machine_sfid") + return if !id_path.file? + host_sfid = id_path.read.chomp + + to_disable = [] + + # Read the existing folders that are setup + existing_folders = synced_folders(host_machine, cached: true) + if existing_folders + existing_folders.each do |impl, fs| + fs.each do |id, data| + if data[:docker_host_sfid] == host_sfid + to_disable << id + end + end + end + end + + # Nothing to do if we have no bad folders + return if to_disable.empty? + + # 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.output(I18n.t( + "docker_provider.host_machine_disabling_folders")) + host_machine.with_ui(proxy_ui) do + action_env = { + synced_folders_cached: true, + synced_folders_disable: to_disable, + } + + 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 + end + end + end + end +end diff --git a/plugins/providers/docker/provider.rb b/plugins/providers/docker/provider.rb index 87e636b8a..35a1e8724 100644 --- a/plugins/providers/docker/provider.rb +++ b/plugins/providers/docker/provider.rb @@ -1,3 +1,4 @@ +require "digest/md5" require "fileutils" require "log4r" @@ -90,6 +91,14 @@ module VagrantPlugins @host_vm end + # This acquires a lock on the host VM. + def host_vm_lock + hash = Digest::MD5.hexdigest(host_vm.data_dir.to_s) + @machine.env.lock(hash) do + return yield + end + end + # This says whether or not Docker will be running within a VM # rather than directly on our system. Docker needs to run in a VM # when we're not on Linux, or not on a Linux that supports Docker. diff --git a/templates/locales/providers_docker.yml b/templates/locales/providers_docker.yml index ef1675999..7e5eb8295 100644 --- a/templates/locales/providers_docker.yml +++ b/templates/locales/providers_docker.yml @@ -4,6 +4,8 @@ en: Creating the container... created: |- Container created: %{id} + host_machine_disabling_folders: |- + Removing synced folders... host_machine_needed: |- Docker host is required. One will be created if necessary... host_machine_ready: |-