diff --git a/plugins/providers/virtualbox/synced_folder.rb b/plugins/providers/virtualbox/synced_folder.rb index 695b41ee5..5b8a9799b 100644 --- a/plugins/providers/virtualbox/synced_folder.rb +++ b/plugins/providers/virtualbox/synced_folder.rb @@ -1,3 +1,4 @@ +require "fileutils" require "vagrant/util/platform" module VagrantPlugins @@ -97,35 +98,51 @@ module VagrantPlugins # transient. def share_folders(machine, folders, transient) defs = [] + warn_user_symlink = false + folders.each do |id, data| hostpath = data[:hostpath] if !data[:hostpath_exact] hostpath = Vagrant::Util::Platform.cygwin_windows_path(hostpath) end - sharefoldersenablesymlinkscreate = true + enable_symlink_create = true if ENV['VAGRANT_DISABLE_VBOXSYMLINKCREATE'] - sharefoldersenablesymlinkscreate = false + enable_symlink_create = false end unless data[:SharedFoldersEnableSymlinksCreate].nil? - sharefoldersenablesymlinkscreate = data[:SharedFoldersEnableSymlinksCreate] + enable_symlink_create = data[:SharedFoldersEnableSymlinksCreate] end + warn_user_symlink ||= enable_symlink_create + # Only setup the shared folders that match our transient level if (!!data[:transient]) == transient defs << { name: os_friendly_id(id), hostpath: hostpath.to_s, transient: transient, - SharedFoldersEnableSymlinksCreate: sharefoldersenablesymlinkscreate + SharedFoldersEnableSymlinksCreate: enable_symlink_create } end end + if warn_user_symlink + display_symlink_create_warning(machine.env) + end + driver(machine).share_folders(defs) end + + def display_symlink_create_warning(env) + d_file = env.data_dir.join("vbox_symlink_create_warning") + if !d_file.exist? + FileUtils.touch(d_file.to_path) + env.ui.warn(I18n.t("vagrant.virtualbox.warning.shared_folder_symlink_create")) + end + end end end end diff --git a/templates/locales/en.yml b/templates/locales/en.yml index 0f591b94c..f205fd819 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -329,7 +329,22 @@ en: invalid_event: |- %{event} is not a valid event for customization. Valid events are: %{valid_events} + warning: + shared_folder_symlink_create: |- + Vagrant is currently configured to create VirtualBox synced folders with + the `SharedFoldersEnableSymlinksCreate` option enabled. If the Vagrant + guest is not trusted, you may want to disable this option. For more + information on this option, please refer to the VirtualBox manual: + https://www.virtualbox.org/manual/ch04.html#sharedfolders + + This option can be disabled globally with an environment variable: + + VAGRANT_DISABLE_VBOXSYMLINKCREATE=1 + + or on a per folder basis within the Vagrantfile: + + config.vm.synced_folder '/host/path', '/guest/path', SharedFoldersEnableSymlinksCreate: false general: batch_notify_error: |- An error occurred. The error will be shown after all tasks complete. diff --git a/test/unit/plugins/providers/virtualbox/synced_folder_test.rb b/test/unit/plugins/providers/virtualbox/synced_folder_test.rb index 683fd9dee..1eb3d77c3 100644 --- a/test/unit/plugins/providers/virtualbox/synced_folder_test.rb +++ b/test/unit/plugins/providers/virtualbox/synced_folder_test.rb @@ -19,7 +19,7 @@ describe VagrantPlugins::ProviderVirtualBox::SyncedFolder do machine.provider_config.finalize! end - describe "usable" do + describe "#usable?" do it "should be with virtualbox provider" do allow(machine).to receive(:provider_name).and_return(:virtualbox) expect(subject).to be_usable(machine) @@ -36,7 +36,7 @@ describe VagrantPlugins::ProviderVirtualBox::SyncedFolder do end end - describe "prepare" do + describe "#prepare" do let(:driver) { double("driver") } let(:provider) { double("driver", driver: driver) } let(:folders) { {"/folder"=> @@ -61,6 +61,8 @@ describe VagrantPlugins::ProviderVirtualBox::SyncedFolder do before do allow(machine).to receive(:provider).and_return(provider) + allow(machine).to receive(:env) + allow(subject).to receive(:display_symlink_create_warning) end it "should prepare and share the folders" do @@ -88,7 +90,7 @@ describe VagrantPlugins::ProviderVirtualBox::SyncedFolder do end end - describe "os_friendly_id" do + describe "#os_friendly_id" do it "should not replace normal chars" do expect(subject.send(:os_friendly_id, 'perfectly_valid0_name')).to eq('perfectly_valid0_name') end @@ -113,4 +115,89 @@ describe VagrantPlugins::ProviderVirtualBox::SyncedFolder do expect(subject.send(:os_friendly_id, 'foo\\bar')).to eq('foo_bar') end end + + describe "#share_folders" do + let(:folders){ {'folder1' => {hostpath: '/vagrant', transient: true}, + 'folder2' => {hostpath: '/vagrant2', transient: false}} } + let(:symlink_create_disable){ nil } + let(:driver){ double("driver") } + + before do + allow(subject).to receive(:display_symlink_create_warning) + allow(machine).to receive(:env) + allow(subject).to receive(:driver).and_return(driver) + allow(driver).to receive(:share_folders) + allow(ENV).to receive(:[]).with("VAGRANT_DISABLE_VBOXSYMLINKCREATE").and_return(symlink_create_disable) + end + + it "should only add transient folder" do + expect(driver).to receive(:share_folders).with(any_args) do |defs| + expect(defs.size).to eq(1) + end + subject.send(:share_folders, machine, folders, true) + end + + it "should display symlink create warning" do + expect(subject).to receive(:display_symlink_create_warning) + subject.send(:share_folders, machine, folders, true) + end + + context "with create symlink globally disabled" do + let(:symlink_create_disable){ "1" } + + it "should not enable option within definitions" do + expect(driver).to receive(:share_folders).with(any_args) do |defs| + expect(defs.first[:SharedFoldersEnableSymlinksCreate]).to be(false) + end + subject.send(:share_folders, machine, folders, true) + end + + it "should not display symlink warning" do + expect(subject).not_to receive(:display_symlink_create_warning) + subject.send(:share_folders, machine, folders, true) + end + end + end + + describe "#display_symlink_create_warning" do + let(:env){ double("env", ui: double("ui"), data_dir: double("data_dir")) } + let(:gate_file){ double("gate") } + + before{ allow(gate_file).to receive(:to_path).and_return("PATH") } + after{ subject.send(:display_symlink_create_warning, env) } + + context "gate file does not exist" do + before do + allow(env.data_dir).to receive(:join).and_return(gate_file) + allow(gate_file).to receive(:exist?).and_return(false) + allow(FileUtils).to receive(:touch) + allow(env.ui).to receive(:warn) + end + + it "should create file" do + expect(FileUtils).to receive(:touch).with("PATH") + end + + it "should output warning to user" do + expect(env.ui).to receive(:warn) + end + end + + context "gate file does exist" do + before do + allow(env.data_dir).to receive(:join).and_return(gate_file) + allow(gate_file).to receive(:exist?).and_return(true) + allow(FileUtils).to receive(:touch) + allow(env.ui).to receive(:warn) + end + + it "should not create/update file" do + expect(FileUtils).not_to receive(:touch).with("PATH") + end + + it "should not output warning to user" do + expect(env.ui).not_to receive(:warn) + end + end + end end