vagrant/plugins/guests/linux/cap/mount_smb_shared_folder.rb

106 lines
3.5 KiB
Ruby

require "shellwords"
module VagrantPlugins
module GuestLinux
module Cap
class MountSMBSharedFolder
def self.mount_smb_shared_folder(machine, name, guestpath, options)
expanded_guest_path = machine.guest.capability(
:shell_expand_guest_path, guestpath)
mount_commands = []
mount_device = "//#{options[:smb_host]}/#{name}"
if options[:owner].is_a? Integer
mount_uid = options[:owner]
else
mount_uid = "`id -u #{options[:owner]}`"
end
if options[:group].is_a? Integer
mount_gid = options[:group]
mount_gid_old = options[:group]
else
mount_gid = "`getent group #{options[:group]} | cut -d: -f3`"
mount_gid_old = "`id -g #{options[:group]}`"
end
# If a domain is provided in the username, separate it
username, domain = (options[:smb_username] || '').split('@', 2)
smb_password = options[:smb_password]
options[:mount_options] ||= []
options[:mount_options] << "sec=ntlm"
options[:mount_options] << "credentials=/etc/smb_creds_#{name}"
# 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 cifs #{mount_options} #{mount_device} #{expanded_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 cifs #{mount_options} #{mount_device} #{expanded_guest_path}"
# Create the guest path if it doesn't exist
machine.communicate.sudo("mkdir -p #{expanded_guest_path}")
# Write the credentials file
machine.communicate.sudo(<<-SCRIPT)
cat <<"EOF" >/etc/smb_creds_#{name}
username=#{username}
password=#{smb_password}
#{domain ? "domain=#{domain}" : ""}
EOF
chmod 0600 /etc/smb_creds_#{name}
SCRIPT
# 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
command = mount_commands.join("\n")
command.gsub!(smb_password, "PASSWORDHIDDEN")
raise Vagrant::Errors::LinuxMountFailed,
command: command,
output: stderr
end
sleep 2
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
end
end
end
end
end