From 49c98ad8af054546455794747b1ac0825549508b Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 5 Mar 2010 19:16:57 -0800 Subject: [PATCH] Mounting a folder now waits for the mount to succeed before continuing. Fixed a race condition between SSH daemon starting and the VBox kernel extensions loading... --- lib/vagrant/actions/vm/shared_folders.rb | 22 +++++++- .../vagrant/actions/vm/shared_folders_test.rb | 55 ++++++++++++++++++- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/lib/vagrant/actions/vm/shared_folders.rb b/lib/vagrant/actions/vm/shared_folders.rb index 81c0db5a9..a45167db7 100644 --- a/lib/vagrant/actions/vm/shared_folders.rb +++ b/lib/vagrant/actions/vm/shared_folders.rb @@ -38,11 +38,31 @@ module Vagrant shared_folders.each do |name, hostpath, guestpath| logger.info "-- #{name}: #{guestpath}" ssh.exec!("sudo mkdir -p #{guestpath}") - ssh.exec!("sudo mount -t vboxsf #{name} #{guestpath}") + mount_folder(ssh, name, guestpath) ssh.exec!("sudo chown #{Vagrant.config.ssh.username} #{guestpath}") end end end + + def mount_folder(ssh, name, guestpath, sleeptime=5) + # Note: This method seems pretty OS-specific and could also use + # some configuration options. For now its duct tape and "works" + # but should be looked at in the future. + attempts = 0 + + while true + result = ssh.exec!("sudo mount -t vboxsf #{name} #{guestpath}") do |ch, type, data| + # net/ssh returns the value in ch[:result] (based on looking at source) + ch[:result] = !!(type == :stderr && data =~ /No such device/i) + end + + break unless result + + attempts += 1 + raise ActionException.new("Failed to mount shared folders. vboxsf was not available.") if attempts >= 10 + sleep sleeptime + end + end end end end diff --git a/test/vagrant/actions/vm/shared_folders_test.rb b/test/vagrant/actions/vm/shared_folders_test.rb index 07ffdd124..dadd0b031 100644 --- a/test/vagrant/actions/vm/shared_folders_test.rb +++ b/test/vagrant/actions/vm/shared_folders_test.rb @@ -53,7 +53,7 @@ class SharedFoldersActionTest < Test::Unit::TestCase ssh = mock("ssh") @folders.each do |name, hostpath, guestpath| ssh.expects(:exec!).with("sudo mkdir -p #{guestpath}").in_sequence(mount_seq) - ssh.expects(:exec!).with("sudo mount -t vboxsf #{name} #{guestpath}").in_sequence(mount_seq) + @action.expects(:mount_folder).with(ssh, name, guestpath).in_sequence(mount_seq) ssh.expects(:exec!).with("sudo chown #{Vagrant.config.ssh.username} #{guestpath}").in_sequence(mount_seq) end Vagrant::SSH.expects(:execute).yields(ssh) @@ -61,4 +61,57 @@ class SharedFoldersActionTest < Test::Unit::TestCase @action.after_boot end end + + context "mounting the main folder" do + setup do + @ssh = mock("ssh") + @name = "foo" + @guestpath = "bar" + @sleeptime = 0 + @limit = 10 + + @success_return = false + end + + def mount_folder + @action.mount_folder(@ssh, @name, @guestpath, @sleeptime) + end + + should "execute the proper mount command" do + @ssh.expects(:exec!).with("sudo mount -t vboxsf #{@name} #{@guestpath}").returns(@success_return) + mount_folder + end + + should "test type of text and text string to detect error" do + data = mock("data") + data.expects(:[]=).with(:result, !@success_return) + + @ssh.expects(:exec!).yields(data, :stderr, "No such device").returns(@success_return) + mount_folder + end + + should "test type of text and test string to detect success" do + data = mock("data") + data.expects(:[]=).with(:result, @success_return) + + @ssh.expects(:exec!).yields(data, :stdout, "Nothing such device").returns(@success_return) + mount_folder + end + + should "raise an ActionException if the command fails constantly" do + @ssh.expects(:exec!).times(@limit).returns(!@success_return) + + assert_raises(Vagrant::Actions::ActionException) { + mount_folder + } + end + + should "not raise any exception if the command succeeded" do + @ssh.expects(:exec!).once.returns(@success_return) + + assert_nothing_raised { + mount_folder + } + end + end end