guests/bsd: Move NFS mounting logic into shared

A number of the BSD guests used very old mounting options or just
ignored some parameters entirely. This fixes that.

- Closes #7474
- Fixes #7466
This commit is contained in:
Seth Vargo 2016-06-17 20:56:04 -04:00
parent 5dde0cdc4d
commit 6284a9ac50
No known key found for this signature in database
GPG Key ID: 905A90C2949E8787
17 changed files with 138 additions and 185 deletions

View File

@ -324,10 +324,6 @@ module Vagrant
error_key(:darwin_mount_failed)
end
class DarwinNFSMountFailed < VagrantError
error_key(:darwin_nfs_mount_failed)
end
class DestroyRequiresForce < VagrantError
error_key(:destroy_requires_force)
end
@ -404,10 +400,6 @@ module Vagrant
error_key(:linux_mount_failed)
end
class LinuxNFSMountFailed < VagrantError
error_key(:linux_nfs_mount_failed)
end
class LinuxRDPClientNotFound < VagrantError
error_key(:linux_rdp_client_not_found)
end
@ -464,6 +456,10 @@ module Vagrant
error_key(:nfs_cant_read_exports)
end
class NFSMountFailed < VagrantError
error_key(:nfs_mount_failed)
end
class NFSNoGuestIP < VagrantError
error_key(:nfs_no_guest_ip)
end

View File

@ -0,0 +1,49 @@
require "shellwords"
require "vagrant/util/retryable"
module VagrantPlugins
module GuestBSD
module Cap
class NFS
extend Vagrant::Util::Retryable
# Mount the given NFS folder.
def self.mount_nfs_folder(machine, ip, folders)
comm = machine.communicate
folders.each do |name, opts|
# Mount each folder separately so we can retry.
commands = ["set -e"]
# Shellescape the paths in case they do not have special characters.
guest_path = Shellwords.escape(opts[:guestpath])
host_path = Shellwords.escape(opts[:hostpath])
# Build the list of mount options.
mount_opts = []
mount_opts << "nfsv#{opts[:nfs_version]}" if opts[:nfs_version]
mount_opts << "mntudp" if opts[:nfs_udp]
if opts[:mount_options]
mount_opts = mount_opts + opts[:mount_options].dup
end
mount_opts = mount_opts.join(",")
# Make the directory on the guest.
commands << "mkdir -p #{guest_path}"
# Perform the mount operation.
commands << "/sbin/mount -t nfs -o '#{mount_opts}' #{ip}:#{host_path} #{guest_path}"
# Run the command, raising a specific error.
retryable(on: Vagrant::Errors::NFSMountFailed, tries: 3, sleep: 5) do
machine.communicate.sudo(commands.join("\n"),
error_class: Vagrant::Errors::NFSMountFailed,
shell: "sh",
)
end
end
end
end
end
end
end

View File

@ -15,6 +15,11 @@ module VagrantPlugins
require_relative "cap/insert_public_key"
Cap::InsertPublicKey
end
guest_capability(:bsd, :mount_nfs_folder) do
require_relative "cap/nfs"
Cap::NFS
end
end
end
end

View File

@ -1,37 +0,0 @@
require "vagrant/util/retryable"
module VagrantPlugins
module GuestDarwin
module Cap
class MountNFSFolder
extend Vagrant::Util::Retryable
def self.mount_nfs_folder(machine, ip, folders)
folders.each do |name, opts|
# Expand the guest path so we can handle things like "~/vagrant"
expanded_guest_path = machine.guest.capability(
:shell_expand_guest_path, opts[:guestpath])
# Create the folder
machine.communicate.sudo("mkdir -p #{expanded_guest_path}")
# Figure out any options
mount_opts = ["vers=#{opts[:nfs_version]}"]
mount_opts << "udp" if opts[:nfs_udp]
if opts[:mount_options]
mount_opts = opts[:mount_options].dup
end
mount_command = "mount -t nfs " +
"-o '#{mount_opts.join(",")}' " +
"'#{ip}:#{opts[:hostpath]}' '#{expanded_guest_path}'"
retryable(on: Vagrant::Errors::DarwinNFSMountFailed, tries: 10, sleep: 5) do
machine.communicate.sudo(
mount_command,
error_class: Vagrant::Errors::DarwinNFSMountFailed)
end
end
end
end
end
end
end

View File

@ -31,11 +31,6 @@ module VagrantPlugins
Cap::Halt
end
guest_capability(:darwin, :mount_nfs_folder) do
require_relative "cap/mount_nfs_folder"
Cap::MountNFSFolder
end
guest_capability(:darwin, :mount_smb_shared_folder) do
require_relative "cap/mount_smb_shared_folder"
Cap::MountSMBSharedFolder

View File

@ -13,9 +13,9 @@ module VagrantPlugins
comm.execute("localcli storage nfs remove -v #{volume}")
end
mount_command = "localcli storage nfs add -H #{ip} -s '#{opts[:hostpath]}' -v '#{volume}'"
retryable(on: Vagrant::Errors::LinuxNFSMountFailed, tries: 5, sleep: 2) do
retryable(on: Vagrant::Errors::NFSMountFailed, tries: 5, sleep: 2) do
comm.execute(mount_command,
error_class: Vagrant::Errors::LinuxNFSMountFailed)
error_class: Vagrant::Errors::NFSMountFailed)
end
# symlink vmfs volume to :guestpath

View File

@ -1,24 +0,0 @@
module VagrantPlugins
module GuestFreeBSD
module Cap
class MountNFSFolder
def self.mount_nfs_folder(machine, ip, folders)
comm = machine.communicate
commands = []
folders.each do |_, opts|
if opts[:nfs_version]
mount_opts = "-o nfsv#{opts[:nfs_version]}"
end
commands << "mkdir -p '#{opts[:guestpath]}'"
commands << "mount -t nfs #{mount_opts} '#{ip}:#{opts[:hostpath]}' '#{opts[:guestpath]}'"
end
comm.sudo(commands.join("\n"), { shell: "sh" })
end
end
end
end
end

View File

@ -26,11 +26,6 @@ module VagrantPlugins
Cap::Halt
end
guest_capability(:freebsd, :mount_nfs_folder) do
require_relative "cap/mount_nfs_folder"
Cap::MountNFSFolder
end
guest_capability(:freebsd, :remove_public_key) do
require_relative "cap/remove_public_key"
Cap::RemovePublicKey

View File

@ -40,8 +40,8 @@ module VagrantPlugins
EOH
end
retryable(on: Vagrant::Errors::LinuxNFSMountFailed, tries: 8, sleep: 3) do
comm.sudo(commands.join("\n"), error_class: Vagrant::Errors::LinuxNFSMountFailed)
retryable(on: Vagrant::Errors::NFSMountFailed, tries: 8, sleep: 3) do
comm.sudo(commands.join("\n"), error_class: Vagrant::Errors::NFSMountFailed)
end
end
end

View File

@ -1,17 +0,0 @@
module VagrantPlugins
module GuestNetBSD
module Cap
class MountNFSFolder
def self.mount_nfs_folder(machine, ip, folders)
folders.each do |name, opts|
machine.communicate.sudo(<<CMDS, {shell: "sh"})
set -e
mkdir -p #{opts[:guestpath]}
/sbin/mount -t nfs '#{ip}:#{opts[:hostpath]}' '#{opts[:guestpath]}'
CMDS
end
end
end
end
end
end

View File

@ -26,11 +26,6 @@ module VagrantPlugins
Cap::Halt
end
guest_capability(:netbsd, :mount_nfs_folder) do
require_relative "cap/mount_nfs_folder"
Cap::MountNFSFolder
end
guest_capability(:netbsd, :remove_public_key) do
require_relative "cap/remove_public_key"
Cap::RemovePublicKey

View File

@ -1,14 +0,0 @@
module VagrantPlugins
module GuestOpenBSD
module Cap
class MountNFSFolder
def self.mount_nfs_folder(machine, ip, folders)
folders.each do |name, opts|
machine.communicate.sudo("mkdir -p #{opts[:guestpath]}")
machine.communicate.sudo("mount '#{ip}:#{opts[:hostpath]}' '#{opts[:guestpath]}'")
end
end
end
end
end
end

View File

@ -26,11 +26,6 @@ module VagrantPlugins
Cap::Halt
end
guest_capability(:openbsd, :mount_nfs_folder) do
require_relative "cap/mount_nfs_folder"
Cap::MountNFSFolder
end
guest_capability(:openbsd, :remove_public_key) do
require_relative "cap/remove_public_key"
Cap::RemovePublicKey

View File

@ -27,9 +27,9 @@ module VagrantPlugins
end
mount_command = "mount.nfs -o '#{mount_opts.join(",")}' #{ip}:'#{hostpath}' #{expanded_guest_path}"
retryable(on: Vagrant::Errors::LinuxNFSMountFailed, tries: 8, sleep: 3) do
retryable(on: Vagrant::Errors::NFSMountFailed, tries: 8, sleep: 3) do
machine.communicate.sudo(mount_command,
error_class: Vagrant::Errors::LinuxNFSMountFailed)
error_class: Vagrant::Errors::NFSMountFailed)
end
# Emit an upstart event if we can

View File

@ -822,12 +822,6 @@ en:
The error output from the last command was:
%{output}
linux_nfs_mount_failed: |-
Mounting NFS shared folders failed. This is most often caused by the NFS
client software not being installed on the guest machine. Please verify
that the NFS client software is properly installed, and consult any resources
specific to the linux distro you're using for more information on how to
do this.
linux_rdp_client_not_found: |-
An appropriate RDP client was not found. Vagrant requires either
`xfreerdp` or `rdesktop` in order to connect via RDP to the Vagrant
@ -885,6 +879,12 @@ en:
Vagrant can't read your current NFS exports! The exports file should be
readable by any user. This is usually caused by invalid permissions
on your NFS exports file. Please fix them and try again.
nfs_mount_failed: |-
Mounting NFS shared folders failed. This is most often caused by the NFS
client software not being installed on the guest machine. Please verify
that the NFS client software is properly installed, and consult any resources
specific to the linux distro you're using for more information on how to
do this.
nfs_no_guest_ip: |-
No guest IP was given to the Vagrant core NFS helper. This is an
internal error that should be reported as a bug.

View File

@ -0,0 +1,68 @@
require_relative "../../../../base"
describe "VagrantPlugins::GuestBSD::Cap::NFS" do
let(:caps) do
VagrantPlugins::GuestBSD::Plugin
.components
.guest_capabilities[:bsd]
end
let(:machine) { double("machine") }
let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) }
before do
allow(machine).to receive(:communicate).and_return(comm)
end
after do
comm.verify_expectations!
end
describe ".mount_nfs_folder" do
let(:cap) { caps.get(:mount_nfs_folder) }
let(:ip) { "1.2.3.4" }
it "mounts the folder" do
folders = {
"/vagrant-nfs" => {
guestpath: "/guest",
hostpath: "/host",
}
}
cap.mount_nfs_folder(machine, ip, folders)
expect(comm.received_commands[0]).to match(/set -e/)
expect(comm.received_commands[0]).to match(/mkdir -p \/guest/)
expect(comm.received_commands[0]).to match(/mount -t nfs/)
expect(comm.received_commands[0]).to match(/1.2.3.4:\/host \/guest/)
end
it "mounts with options" do
folders = {
"/vagrant-nfs" => {
guestpath: "/guest",
hostpath: "/host",
nfs_version: 2,
nfs_udp: true,
mount_options: ["banana"]
}
}
cap.mount_nfs_folder(machine, ip, folders)
expect(comm.received_commands[0]).to match(/mount -t nfs -o 'nfsv2,mntudp,banana'/)
end
it "escapes host and guest paths" do
folders = {
"/vagrant-nfs" => {
guestpath: "/guest with spaces",
hostpath: "/host's",
}
}
cap.mount_nfs_folder(machine, ip, folders)
expect(comm.received_commands[0]).to match(/host\\\'s/)
expect(comm.received_commands[0]).to match(/guest\\\ with\\\ spaces/)
end
end
end

View File

@ -1,53 +0,0 @@
require_relative "../../../../base"
describe "VagrantPlugins::GuestFreeBSD::Cap::MountNFSFolder" do
let(:described_class) do
VagrantPlugins::GuestFreeBSD::Plugin
.components
.guest_capabilities[:freebsd]
.get(:mount_nfs_folder)
end
let(:machine) { double("machine") }
let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) }
before do
allow(machine).to receive(:communicate).and_return(comm)
end
after do
comm.verify_expectations!
end
describe ".mount_nfs_folder" do
let(:ip) { "1.2.3.4" }
it "mounts the folder" do
folders = {
"/vagrant-nfs" => {
type: :nfs,
guestpath: "/guest",
hostpath: "/host",
}
}
described_class.mount_nfs_folder(machine, ip, folders)
expect(comm.received_commands[0]).to match(/mkdir -p '\/guest'/)
expect(comm.received_commands[0]).to match(/'1.2.3.4:\/host' '\/guest'/)
end
it "mounts with options" do
folders = {
"/vagrant-nfs" => {
type: :nfs,
guestpath: "/guest",
hostpath: "/host",
nfs_version: 2,
}
}
described_class.mount_nfs_folder(machine, ip, folders)
expect(comm.received_commands[0]).to match(/mount -t nfs -o nfsv2/)
end
end
end