diff --git a/lib/vagrant/guest.rb b/lib/vagrant/guest.rb index be63ff3df..5629af70f 100644 --- a/lib/vagrant/guest.rb +++ b/lib/vagrant/guest.rb @@ -127,7 +127,7 @@ module Vagrant :guest => @chain[0][0].to_s end - cap_method.call(*args) + cap_method.call(@machine, *args) end # This returns whether the guest is ready to work. If this returns diff --git a/plugins/guests/linux/cap/mount_virtualbox_shared_folder.rb b/plugins/guests/linux/cap/mount_virtualbox_shared_folder.rb new file mode 100644 index 000000000..127a673ea --- /dev/null +++ b/plugins/guests/linux/cap/mount_virtualbox_shared_folder.rb @@ -0,0 +1,41 @@ +module VagrantPlugins + module GuestLinux + module Cap + class MountVirtualBoxSharedFolder + def self.mount_virtualbox_shared_folder(machine, name, guestpath, options) + expanded_guest_path = machine.guest.capability( + :shell_expand_guest_path, guestpath) + + # Determine the permission string to attach to the mount command + mount_options = "-o uid=`id -u #{options[:owner]}`,gid=`id -g #{options[:group]}`" + mount_options += ",#{options[:extra]}" if options[:extra] + mount_command = "mount -t vboxsf #{mount_options} #{name} #{expanded_guest_path}" + + # Create the guest path if it doesn't exist + machine.communicate.sudo("mkdir -p #{expanded_guest_path}") + + # Attempt to mount the folder. We retry here a few times because + # it can fail early on. + attempts = 0 + while true + success = true + machine.communicate.sudo(mount_command) do |type, data| + success = false if type == :stderr && data =~ /No such device/i + end + + break if success + + attempts += 1 + # TODO: Nicer exception + raise "Mount failed" + sleep 2 + end + + # Chown the directory to the proper user + machine.communicate.sudo( + "chown `id -u #{options[:owner]}`:`id -g #{options[:group]}` #{expanded_guest_path}") + end + end + end + end +end diff --git a/plugins/guests/linux/cap/shell_expand_guest_path.rb b/plugins/guests/linux/cap/shell_expand_guest_path.rb new file mode 100644 index 000000000..1869ccfb3 --- /dev/null +++ b/plugins/guests/linux/cap/shell_expand_guest_path.rb @@ -0,0 +1,27 @@ +module VagrantPlugins + module GuestLinux + module Cap + class ShellExpandGuestPath + def self.shell_expand_guest_path(machine, path) + real_path = nil + machine.communicate.execute("printf #{guestpath}") do |type, data| + if type == :stdout + real_path ||= "" + real_path += data + end + end + + if !real_path + # If no real guest path was detected, this is really strange + # and we raise an exception because this is a bug. + # TODO: Nice exception + raise "No expanded guest path detected." + end + + # Chomp the string so that any trailing newlines are killed + return real_path.chomp + end + end + end + end +end diff --git a/plugins/guests/linux/guest.rb b/plugins/guests/linux/guest.rb index f0bc77c1d..bef17506f 100644 --- a/plugins/guests/linux/guest.rb +++ b/plugins/guests/linux/guest.rb @@ -52,15 +52,6 @@ module VagrantPlugins end end - def mount_shared_folder(name, guestpath, options) - real_guestpath = expanded_guest_path(guestpath) - @logger.debug("Shell expanded guest path: #{real_guestpath}") - - @vm.communicate.sudo("mkdir -p #{real_guestpath}") - mount_folder(name, real_guestpath, options) - @vm.communicate.sudo("chown `id -u #{options[:owner]}`:`id -g #{options[:group]}` #{real_guestpath}") - end - def mount_nfs(ip, folders) # TODO: Maybe check for nfs support on the guest, since its often # not installed by default @@ -105,26 +96,6 @@ module VagrantPlugins # Chomp the string so that any trailing newlines are killed return real_guestpath.chomp end - - def mount_folder(name, guestpath, options) - # Determine the permission string to attach to the mount command - mount_options = "-o uid=`id -u #{options[:owner]}`,gid=`id -g #{options[:group]}`" - mount_options += ",#{options[:extra]}" if options[:extra] - - attempts = 0 - while true - success = true - @vm.communicate.sudo("mount -t vboxsf #{mount_options} #{name} #{guestpath}") do |type, data| - success = false if type == :stderr && data =~ /No such device/i - end - - break if success - - attempts += 1 - raise LinuxError, :mount_fail if attempts >= 10 - sleep 5 - end - end end end end diff --git a/plugins/guests/linux/plugin.rb b/plugins/guests/linux/plugin.rb index 7c766edb5..ee0ce1065 100644 --- a/plugins/guests/linux/plugin.rb +++ b/plugins/guests/linux/plugin.rb @@ -15,6 +15,16 @@ module VagrantPlugins require File.expand_path("../guest", __FILE__) Guest end + + guest_capability("linux", "shell_expand_guest_path") do + require_relative "cap/shell_expand_guest_path" + Cap::ShellExpandGuestPath + end + + guest_capability("linux", "mount_virtualbox_shared_folder") do + require_relative "cap/mount_virtualbox_shared_folder" + Cap::MountVirtualBoxSharedFolder + end end end end diff --git a/plugins/providers/virtualbox/action/share_folders.rb b/plugins/providers/virtualbox/action/share_folders.rb index 9dd394c0c..e795a56ed 100644 --- a/plugins/providers/virtualbox/action/share_folders.rb +++ b/plugins/providers/virtualbox/action/share_folders.rb @@ -108,7 +108,8 @@ module VagrantPlugins data[:group] ||= @env[:machine].config.ssh.username # Mount the actual folder - @env[:machine].guest.mount_shared_folder(id, data[:guestpath], data) + @env[:machine].guest.capability( + :mount_virtualbox_shared_folder, id, data[:guestpath], data) else # If no guest path is specified, then automounting is disabled @env[:ui].info(I18n.t("vagrant.actions.vm.share_folders.nomount_entry", diff --git a/test/unit/vagrant/guest_test.rb b/test/unit/vagrant/guest_test.rb index 454dce84e..d778ccd05 100644 --- a/test/unit/vagrant/guest_test.rb +++ b/test/unit/vagrant/guest_test.rb @@ -7,7 +7,11 @@ describe Vagrant::Guest do let(:capabilities) { {} } let(:guests) { {} } - let(:machine) { double("machine") } + let(:machine) do + double("machine").tap do |m| + m.stub(:inspect => "machine") + end + end subject { described_class.new(machine, guests, capabilities) } @@ -58,14 +62,14 @@ describe Vagrant::Guest do register_capability(:bar, :test) expect { subject.capability(:test) }. - to raise_error(RuntimeError, "cap: test []") + to raise_error(RuntimeError, "cap: test [machine]") end it "executes the capability with arguments" do register_capability(:bar, :test) expect { subject.capability(:test, 1) }. - to raise_error(RuntimeError, "cap: test [1]") + to raise_error(RuntimeError, "cap: test [machine, 1]") end it "raises an exception if the capability doesn't exist" do