guests/linux: Properly escape and retry vbox shared folder mounting
This commit is contained in:
parent
4aaa600bd6
commit
7e88266999
|
@ -780,6 +780,10 @@ module Vagrant
|
|||
error_key(:virtualbox_no_name)
|
||||
end
|
||||
|
||||
class VirtualBoxMountFailed < VagrantError
|
||||
error_key(:virtualbox_mount_failed)
|
||||
end
|
||||
|
||||
class VirtualBoxNameExists < VagrantError
|
||||
error_key(:virtualbox_name_exists)
|
||||
end
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
require "shellwords"
|
||||
|
||||
require "vagrant/util/retryable"
|
||||
|
||||
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)
|
||||
extend Vagrant::Util::Retryable
|
||||
|
||||
mount_commands = []
|
||||
def self.mount_virtualbox_shared_folder(machine, name, guestpath, options)
|
||||
guest_path = Shellwords.escape(guestpath)
|
||||
|
||||
mount_commands = ["set -e"]
|
||||
|
||||
if options[:owner].is_a? Integer
|
||||
mount_uid = options[:owner]
|
||||
|
@ -25,73 +30,54 @@ module VagrantPlugins
|
|||
# First mount command uses getent to get the group
|
||||
mount_options = "-o uid=#{mount_uid},gid=#{mount_gid}"
|
||||
mount_options += ",#{options[:mount_options].join(",")}" if options[:mount_options]
|
||||
mount_commands << "mount -t vboxsf #{mount_options} #{name} #{expanded_guest_path}"
|
||||
mount_commands << "mount -t vboxsf #{mount_options} #{name} #{guest_path}"
|
||||
|
||||
# Second mount command uses the old style `id -g`
|
||||
mount_options = "-o uid=#{mount_uid},gid=#{mount_gid_old}"
|
||||
mount_options += ",#{options[:mount_options].join(",")}" if options[:mount_options]
|
||||
mount_commands << "mount -t vboxsf #{mount_options} #{name} #{expanded_guest_path}"
|
||||
mount_commands << "mount -t vboxsf #{mount_options} #{name} #{guest_path}"
|
||||
|
||||
# Create the guest path if it doesn't exist
|
||||
machine.communicate.sudo("mkdir -p #{expanded_guest_path}")
|
||||
machine.communicate.sudo("mkdir -p #{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
|
||||
|
||||
stderr = ""
|
||||
mount_commands.each do |command|
|
||||
no_such_device = false
|
||||
stderr = ""
|
||||
status = machine.communicate.sudo(command, error_check: false) do |type, data|
|
||||
if type == :stderr
|
||||
no_such_device = true if data =~ /No such device/i
|
||||
stderr += data.to_s
|
||||
end
|
||||
end
|
||||
|
||||
success = status == 0 && !no_such_device
|
||||
break if success
|
||||
end
|
||||
|
||||
break if success
|
||||
|
||||
attempts += 1
|
||||
if attempts > 10
|
||||
raise Vagrant::Errors::LinuxMountFailed,
|
||||
command: mount_commands.join("\n"),
|
||||
output: stderr
|
||||
end
|
||||
|
||||
sleep(2*attempts)
|
||||
command = mount_commands.join("\n")
|
||||
stderr = ""
|
||||
retryable(on: Vagrant::Errors::VirtualBoxMountFailed, tries: 3, sleep: 5) do
|
||||
machine.communicate.sudo(command,
|
||||
error_class: Vagrant::Errors::VirtualBoxMountFailed,
|
||||
error_key: :virtualbox_mount_failed,
|
||||
command: command,
|
||||
output: stderr,
|
||||
) { |type, data| stderr = data if type == :stderr }
|
||||
end
|
||||
|
||||
# Chown the directory to the proper user. We skip this if the
|
||||
# mount options contained a readonly flag, because it won't work.
|
||||
if !options[:mount_options] || !options[:mount_options].include?("ro")
|
||||
chown_commands = []
|
||||
chown_commands << "chown #{mount_uid}:#{mount_gid} #{expanded_guest_path}"
|
||||
chown_commands << "chown #{mount_uid}:#{mount_gid_old} #{expanded_guest_path}"
|
||||
chown_commands << "chown #{mount_uid}:#{mount_gid} #{guest_path}"
|
||||
chown_commands << "chown #{mount_uid}:#{mount_gid_old} #{guest_path}"
|
||||
|
||||
exit_status = machine.communicate.sudo(chown_commands[0], error_check: false)
|
||||
machine.communicate.sudo(chown_commands[1]) if exit_status != 0
|
||||
end
|
||||
|
||||
# Emit an upstart event if we can
|
||||
machine.communicate.sudo <<-SCRIPT
|
||||
if command -v /sbin/init && /sbin/init --version | grep upstart; then
|
||||
/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT='#{expanded_guest_path}'
|
||||
fi
|
||||
SCRIPT
|
||||
machine.communicate.sudo <<-EOH.gsub(/^ {12}/, "")
|
||||
if command -v /sbin/init && /sbin/init --version | grep upstart; then
|
||||
/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT=#{guest_path}
|
||||
fi
|
||||
EOH
|
||||
end
|
||||
|
||||
def self.unmount_virtualbox_shared_folder(machine, guestpath, options)
|
||||
result = machine.communicate.sudo(
|
||||
"umount #{guestpath}", error_check: false)
|
||||
guest_path = Shellwords.escape(guestpath)
|
||||
|
||||
result = machine.communicate.sudo("umount #{guest_path}", error_check: false)
|
||||
if result == 0
|
||||
machine.communicate.sudo("rmdir #{guestpath}", error_check: false)
|
||||
machine.communicate.sudo("rmdir #{guest_path}", error_check: false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1342,6 +1342,19 @@ en:
|
|||
VirtualBox is complaining that the installation is incomplete. Please
|
||||
run `VBoxManage --version` to see the error message which should contain
|
||||
instructions on how to fix this error.
|
||||
virtualbox_mount_failed: |-
|
||||
Vagrant was unable to mount VirtualBox shared folders. This is usually
|
||||
because the filesystem "vboxsf" is not available. This filesystem is
|
||||
made available via the VirtualBox Guest Additions and kernel module.
|
||||
Please verify that these guest additions are properly installed in the
|
||||
guest. This is not a bug in Vagrant and is usually caused by a faulty
|
||||
Vagrant box. For context, the command attemped was:
|
||||
|
||||
%{command}
|
||||
|
||||
The error output from the command was:
|
||||
|
||||
%{output}
|
||||
virtualbox_name_exists: |-
|
||||
The name of your virtual machine couldn't be set because VirtualBox
|
||||
is reporting another VM with that name already exists. Most of the
|
||||
|
|
Loading…
Reference in New Issue