diff --git a/lib/vagrant/action/builtin/synced_folders.rb b/lib/vagrant/action/builtin/synced_folders.rb index d516d1657..d271cdae5 100644 --- a/lib/vagrant/action/builtin/synced_folders.rb +++ b/lib/vagrant/action/builtin/synced_folders.rb @@ -90,7 +90,12 @@ module Vagrant folders.each do |impl, impl_name, fs| if !env[:synced_folders_disable] @logger.info("Invoking synced folder enable: #{impl_name}") - impl.enable(env[:machine], fs, impl_opts(impl_name, env)) + synced_folder_opts = impl_opts(impl_name, env) + # Add synced folder options to synced folder hash + fs.each do |_, v| + v.merge!(synced_folder_opts) + end + impl.enable(env[:machine], fs, synced_folder_opts) next end diff --git a/plugins/synced_folders/nfs/cap/mount_options.rb b/plugins/synced_folders/nfs/cap/mount_options.rb index 828618e8d..8615938d0 100644 --- a/plugins/synced_folders/nfs/cap/mount_options.rb +++ b/plugins/synced_folders/nfs/cap/mount_options.rb @@ -30,7 +30,15 @@ module VagrantPlugins end def self.mount_type(machine) - return MOUNT_TYPE + MOUNT_TYPE + end + + # Mounts options for NFS synced folder + # + # @param [Machine] machine + # @param [Hash] hash of mount options + def self.mount_name(machine, options) + "#{options[:nfs_host_ip]}:#{options[:hostpath]}" end end end diff --git a/plugins/synced_folders/nfs/plugin.rb b/plugins/synced_folders/nfs/plugin.rb index 4c3ebfa1d..382aa7bf2 100644 --- a/plugins/synced_folders/nfs/plugin.rb +++ b/plugins/synced_folders/nfs/plugin.rb @@ -45,6 +45,11 @@ module VagrantPlugins Cap::MountOptions end + synced_folder_capability("nfs", "mount_name") do + require_relative "cap/mount_options" + Cap::MountOptions + end + action_hook("nfs_cleanup") do |hook| require_relative "action_cleanup" hook.before( diff --git a/test/unit/plugins/guests/linux/cap/mount_nfs_test.rb b/test/unit/plugins/guests/linux/cap/mount_nfs_test.rb index f1f0a7254..9e88586d8 100644 --- a/test/unit/plugins/guests/linux/cap/mount_nfs_test.rb +++ b/test/unit/plugins/guests/linux/cap/mount_nfs_test.rb @@ -9,9 +9,30 @@ describe "VagrantPlugins::GuestLinux::Cap::MountNFS" do let(:machine) { double("machine") } let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + let(:folder_plugin) { double("folder_plugin") } + + let(:mount_uid){ "1000" } + let(:mount_gid){ "1000" } + + let(:ip) { "1.2.3.4" } + let(:hostpath) { "/host" } + let(:guestpath) { "/guest" } + + let(:folders) do + {"/vagrant-nfs" => + Vagrant::Plugin::V2::SyncedFolder::Collection[ + { type: :nfs, guestpath: guestpath, + hostpath: hostpath, plugin: folder_plugin}] + } + end before do allow(machine).to receive(:communicate).and_return(comm) + + allow(folder_plugin).to receive(:capability).with(:mount_options, any_args). + and_return(["", mount_uid, mount_gid]) + allow(folder_plugin).to receive(:capability).with(:mount_type).and_return("nfs") + allow(folder_plugin).to receive(:capability).with(:mount_name, any_args).and_return("#{ip}:#{hostpath}") end after do @@ -21,11 +42,6 @@ describe "VagrantPlugins::GuestLinux::Cap::MountNFS" do describe ".mount_nfs_folder" do let(:cap) { caps.get(:mount_nfs_folder) } - let(:ip) { "1.2.3.4" } - - let(:hostpath) { "/host" } - let(:guestpath) { "/guest" } - before do allow(machine).to receive(:guest).and_return( double("capability", capability: guestpath) @@ -33,42 +49,13 @@ describe "VagrantPlugins::GuestLinux::Cap::MountNFS" do end it "mounts the folder" do - folders = { - "/vagrant-nfs" => { - type: :nfs, - guestpath: "/guest", - hostpath: "/host", - } - } cap.mount_nfs_folder(machine, ip, folders) expect(comm.received_commands[0]).to match(/mkdir -p #{guestpath}/) expect(comm.received_commands[1]).to match(/1.2.3.4:#{hostpath} #{guestpath}/) end - it "mounts with options" do - folders = { - "/vagrant-nfs" => { - type: :nfs, - guestpath: "/guest", - hostpath: "/host", - nfs_version: 2, - nfs_udp: true, - } - } - cap.mount_nfs_folder(machine, ip, folders) - - expect(comm.received_commands[1]).to match(/mount -o vers=2,udp/) - end - it "emits an event" do - folders = { - "/vagrant-nfs" => { - type: :nfs, - guestpath: "/guest", - hostpath: "/host", - } - } cap.mount_nfs_folder(machine, ip, folders) expect(comm.received_commands[2]).to include( @@ -76,12 +63,12 @@ describe "VagrantPlugins::GuestLinux::Cap::MountNFS" do end it "escapes host and guest paths" do - folders = { - "/vagrant-nfs" => { - guestpath: "/guest with spaces", - hostpath: "/host's", + folders = + {"/vagrant-nfs" => + Vagrant::Plugin::V2::SyncedFolder::Collection[ + { type: :nfs, guestpath: "/guest with spaces", + hostpath: "/host's", plugin: folder_plugin}] } - } cap.mount_nfs_folder(machine, ip, folders) expect(comm.received_commands[1]).to match(/host\\\'s/) diff --git a/test/unit/plugins/synced_folders/nfs/cap/mount_options_test.rb b/test/unit/plugins/synced_folders/nfs/cap/mount_options_test.rb new file mode 100644 index 000000000..ac2f7473b --- /dev/null +++ b/test/unit/plugins/synced_folders/nfs/cap/mount_options_test.rb @@ -0,0 +1,95 @@ +require_relative "../../../../base" + +require_relative "../../../../../../plugins/synced_folders/nfs/cap/mount_options" + +describe VagrantPlugins::SyncedFolderNFS::Cap::MountOptions do + include_context "unit" + + let(:caps) do + VagrantPlugins::SyncedFolderNFS::Plugin + .components + .synced_folder_capabilities[:nfs] + end + let(:cap){ caps.get(:mount_options) } + + let(:machine) { double("machine") } + let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + let(:mount_owner){ "vagrant" } + let(:mount_group){ "vagrant" } + let(:mount_uid){ "1000" } + let(:mount_gid){ "1000" } + let(:mount_name){ "vagrant" } + let(:mount_guest_path){ "/vagrant" } + let(:folder_options) do + { + owner: mount_owner, + group: mount_group, + hostpath: "/host/directory/path" + } + end + + before do + allow(machine).to receive(:communicate).and_return(comm) + allow(machine).to receive_message_chain(:env, :host, :capability?).with(:smb_mount_options).and_return(false) + stub_env("GEM_SKIP" => nil) + end + + describe ".mount_options" do + context "with valid existent owner group" do + + before do + expect(comm).to receive(:execute).with("id -u #{mount_owner}", anything).and_yield(:stdout, mount_uid) + expect(comm).to receive(:execute).with("getent group #{mount_group}", anything).and_yield(:stdout, "vagrant:x:#{mount_gid}:") + end + + it "generates the expected default mount command" do + out_opts, out_uid, out_gid = cap.mount_options(machine, mount_name, mount_guest_path, folder_options) + expect(out_opts).to eq("") + expect(out_uid).to eq(mount_uid) + expect(out_gid).to eq(mount_gid) + end + + it "includes provided mount options" do + folder_options[:mount_options] =["ro"] + out_opts, out_uid, out_gid = cap.mount_options(machine, mount_name, mount_guest_path, folder_options) + expect(out_opts).to eq("ro") + expect(out_uid).to eq(mount_uid) + expect(out_gid).to eq(mount_gid) + end + + context "with nfs options set" do + let(:folder_options) { { + owner: mount_owner, group: mount_group, hostpath: "/host/directory/path", + nfs_version: 4, nfs_udp: true + } } + + it "generates the expected default mount command" do + out_opts, out_uid, out_gid = cap.mount_options(machine, mount_name, mount_guest_path, folder_options) + expect(out_opts).to eq("vers=4,udp") + expect(out_uid).to eq(mount_uid) + expect(out_gid).to eq(mount_gid) + end + + it "overwrites default mount options" do + folder_options[:mount_options] =["ro", "vers=3"] + out_opts, out_uid, out_gid = cap.mount_options(machine, mount_name, mount_guest_path, folder_options) + expect(out_opts).to eq("vers=3,udp,ro") + expect(out_uid).to eq(mount_uid) + expect(out_gid).to eq(mount_gid) + end + end + end + + + context "with non-existent owner group" do + it "raises an error" do + expect(comm).to receive(:execute).with("id -u #{mount_owner}", anything).and_yield(:stdout, mount_uid) + expect(comm).to receive(:execute).with("id -g #{mount_group}", anything).and_yield(:stdout, mount_gid) + expect(comm).to receive(:execute).with("getent group #{mount_group}", anything).and_raise(Vagrant::Errors::VirtualBoxMountFailed, {command: '', output: ''}) + expect do + cap.mount_options(machine, mount_name, mount_guest_path, folder_options) + end.to raise_error Vagrant::Errors::VirtualBoxMountFailed + end + end + end +end