From b511d23ae1529bff3082bd84a6ca51a715684b4a Mon Sep 17 00:00:00 2001 From: sophia Date: Tue, 12 May 2020 13:36:27 -0400 Subject: [PATCH] Refresh fstab when folders synced --- .../cap/mount_virtualbox_shared_folder.rb | 55 ++++++++++++++----- plugins/guests/linux/plugin.rb | 5 ++ plugins/providers/virtualbox/synced_folder.rb | 5 ++ templates/guests/linux/etc_fstab.erb | 6 ++ .../mount_virtual_box_shared_folder_test.rb | 33 ++++++++++- .../virtualbox/synced_folder_test.rb | 45 ++++++++++++--- 6 files changed, 125 insertions(+), 24 deletions(-) create mode 100644 templates/guests/linux/etc_fstab.erb diff --git a/plugins/guests/linux/cap/mount_virtualbox_shared_folder.rb b/plugins/guests/linux/cap/mount_virtualbox_shared_folder.rb index b8dca416a..2e5b7f9ad 100644 --- a/plugins/guests/linux/cap/mount_virtualbox_shared_folder.rb +++ b/plugins/guests/linux/cap/mount_virtualbox_shared_folder.rb @@ -1,3 +1,5 @@ +require "vagrant/util" + require_relative "../../../synced_folders/unix_mount_helpers" module VagrantPlugins @@ -6,32 +8,22 @@ module VagrantPlugins class MountVirtualBoxSharedFolder extend SyncedFolder::UnixMountHelpers + VB_MOUNT_TYPE = "vboxsf".freeze + def self.mount_virtualbox_shared_folder(machine, name, guestpath, options) guest_path = Shellwords.escape(guestpath) @@logger.debug("Mounting #{name} (#{options[:hostpath]} to #{guestpath})") - mount_type = "vboxsf" - builtin_mount_type = "-cit #{mount_type}" - addon_mount_type = "-t #{mount_type}" + builtin_mount_type = "-cit #{VB_MOUNT_TYPE}" + addon_mount_type = "-t #{VB_MOUNT_TYPE}" - mount_options = options.fetch(:mount_options, []) - detected_ids = detect_owner_group_ids(machine, guest_path, mount_options, options) - mount_uid = detected_ids[:uid] - mount_gid = detected_ids[:gid] - - mount_options << "uid=#{mount_uid}" - mount_options << "gid=#{mount_gid}" - mount_options = mount_options.join(',') + mount_options, mount_uid, mount_gid = self.mount_options(machine, name, guest_path, options) mount_command = "mount #{addon_mount_type} -o #{mount_options} #{name} #{guest_path}" # Create the guest path if it doesn't exist machine.communicate.sudo("mkdir -p #{guest_path}") - # Add mount to fstab so that if the machine reboots, will remount - fstab_entry = "#{name} #{guest_path} #{mount_type} #{mount_options},nofail 0 0" - machine.communicate.sudo("grep -x '#{fstab_entry}' /etc/fstab || echo '#{fstab_entry}' >> /etc/fstab") - stderr = "" result = machine.communicate.sudo(mount_command, error_check: false) do |type, data| stderr << data if type == :stderr @@ -66,6 +58,25 @@ module VagrantPlugins emit_upstart_notification(machine, guest_path) end + def self.persist_mount_virtualbox_shared_folder(machine, fstab_folders) + export_folders = [] + fstab_folders.each do |name, data| + guest_path = Shellwords.escape(data[:guestpath]) + mount_options, mount_uid, mount_gid = self.mount_options(machine, name, guest_path, data) + mount_options = "#{mount_options},nofail" + export_folders.push({ + :name => name, + :mount_point => guest_path, + :mount_type => VB_MOUNT_TYPE, + :mount_options => mount_options, + }) + end + + fstab_entry = Vagrant::Util::TemplateRenderer.render('guests/linux/etc_fstab', folders: export_folders) + # Replace existing vagrant managed fstab entry + machine.communicate.sudo("sed -i '/\#VAGRANT-BEGIN/,/\#VAGRANT-END/d' /etc/fstab") + machine.communicate.sudo("echo '#{fstab_entry}' >> /etc/fstab") + end def self.unmount_virtualbox_shared_folder(machine, guestpath, options) guest_path = Shellwords.escape(guestpath) @@ -75,6 +86,20 @@ module VagrantPlugins machine.communicate.sudo("rmdir #{guest_path}", error_check: false) end end + + private + + def self.mount_options(machine, name, guest_path, options) + mount_options = options.fetch(:mount_options, []) + detected_ids = detect_owner_group_ids(machine, guest_path, mount_options, options) + mount_uid = detected_ids[:uid] + mount_gid = detected_ids[:gid] + + mount_options << "uid=#{mount_uid}" + mount_options << "gid=#{mount_gid}" + mount_options = mount_options.join(',') + return mount_options, mount_uid, mount_gid + end end end end diff --git a/plugins/guests/linux/plugin.rb b/plugins/guests/linux/plugin.rb index 777d5cbec..f8a6f268e 100644 --- a/plugins/guests/linux/plugin.rb +++ b/plugins/guests/linux/plugin.rb @@ -61,6 +61,11 @@ module VagrantPlugins Cap::MountVirtualBoxSharedFolder end + guest_capability(:linux, :persist_mount_virtualbox_shared_folder) do + require_relative "cap/mount_virtualbox_shared_folder" + Cap::MountVirtualBoxSharedFolder + end + guest_capability(:linux, :network_interfaces) do require_relative "cap/network_interfaces" Cap::NetworkInterfaces diff --git a/plugins/providers/virtualbox/synced_folder.rb b/plugins/providers/virtualbox/synced_folder.rb index 89b006cf2..6af10f767 100644 --- a/plugins/providers/virtualbox/synced_folder.rb +++ b/plugins/providers/virtualbox/synced_folder.rb @@ -33,6 +33,7 @@ module VagrantPlugins # Go through each folder and mount machine.ui.output(I18n.t("vagrant.actions.vm.share_folders.mounting")) + fstab_folders = [] folders.each do |id, data| if data[:guestpath] # Guest path specified, so mount the folder to specified point @@ -52,12 +53,16 @@ module VagrantPlugins machine.guest.capability( :mount_virtualbox_shared_folder, os_friendly_id(id), data[:guestpath], data) + fstab_folders.push([os_friendly_id(id), data]) else # If no guest path is specified, then automounting is disabled machine.ui.detail(I18n.t("vagrant.actions.vm.share_folders.nomount_entry", hostpath: data[:hostpath])) end end + if machine.guest.capability?(:persist_mount_virtualbox_shared_folder) + machine.guest.capability(:persist_mount_virtualbox_shared_folder, fstab_folders) + end end def disable(machine, folders, _opts) diff --git a/templates/guests/linux/etc_fstab.erb b/templates/guests/linux/etc_fstab.erb new file mode 100644 index 000000000..b61b04bb3 --- /dev/null +++ b/templates/guests/linux/etc_fstab.erb @@ -0,0 +1,6 @@ +#VAGRANT-BEGIN +# The contents below are automatically generated by Vagrant. Do not modify. +<% folders.each do |opts| %> +<%= opts[:name] %> <%= opts[:mount_point] %> <%= opts[:mount_type] %> <%= opts[:mount_options] || 'default' %> <%= opts[:dump] || 0 %> <%= opts[:fsck] || 0 %> +<%end%> +#VAGRANT-END \ No newline at end of file diff --git a/test/unit/plugins/guests/linux/cap/mount_virtual_box_shared_folder_test.rb b/test/unit/plugins/guests/linux/cap/mount_virtual_box_shared_folder_test.rb index eb7793982..56e65a12b 100644 --- a/test/unit/plugins/guests/linux/cap/mount_virtual_box_shared_folder_test.rb +++ b/test/unit/plugins/guests/linux/cap/mount_virtual_box_shared_folder_test.rb @@ -43,7 +43,6 @@ describe "VagrantPlugins::GuestLinux::Cap::MountVirtualBoxSharedFolder" 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}:") expect(comm).to receive(:sudo).with("mount -t vboxsf -o uid=#{mount_uid},gid=#{mount_gid} #{mount_name} #{mount_guest_path}", anything) - expect(comm).to receive(:sudo).with(/\/etc\/fstab/) cap.mount_virtualbox_shared_folder(machine, mount_name, mount_guest_path, folder_options) end @@ -51,7 +50,6 @@ describe "VagrantPlugins::GuestLinux::Cap::MountVirtualBoxSharedFolder" 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}:") expect(comm).to receive(:sudo).with("mount -t vboxsf -o uid=#{mount_uid},gid=#{mount_gid} #{mount_name} #{mount_guest_path}", anything) - expect(comm).to receive(:sudo).with(/\/etc\/fstab/) expect(comm).to receive(:sudo).with("chown #{mount_uid}:#{mount_gid} #{mount_guest_path}") cap.mount_virtualbox_shared_folder(machine, mount_name, mount_guest_path, folder_options) end @@ -210,6 +208,37 @@ EOF end end + describe ".persist_mount_virtualbox_shared_folder" do + let(:options_gid){ '1234' } + let(:options_uid){ '1234' } + + let (:fstab_folders) { [ + ["test1", {:guestpath=>"/test1", :hostpath=>"/my/host/path", :disabled=>false, :__vagrantfile=>true, :owner=>"vagrant", :group=>"vagrant", :mount_options=>["uid=1234", "gid=1234"] }], + ["vagrant", {:guestpath=>"/vagrant", :hostpath=>"/my/host/vagrant", :disabled=>false, :__vagrantfile=>true, :owner=>"vagrant", :group=>"vagrant", :mount_options=>["uid=1234", "gid=1234"] }] + ]} + + let(:ui){ double(:ui) } + + before do + allow(comm).to receive(:sudo).with(any_args) + allow(ui).to receive(:warn) + allow(machine).to receive(:ui).and_return(ui) + end + + it "inserts folders into /etc/fstab" do + expected_entry_vagrant = "vagrant /vagrant vboxsf uid=1234,gid=1234,nofail 0 0" + expected_entry_test = "test1 /test1 vboxsf uid=1234,gid=1234,nofail 0 0" + + expect(comm).to receive(:sudo).with(/#{expected_entry_test}\n#{expected_entry_vagrant}/) + cap.persist_mount_virtualbox_shared_folder(machine, fstab_folders) + end + + it "inserts empty set of folders" do + # Check for last bit of entry + expect(comm).to receive(:sudo).with(/#VAGRANT-END' >> \/etc\/fstab/) + cap.persist_mount_virtualbox_shared_folder(machine, []) + end + end describe ".unmount_virtualbox_shared_folder" do after { cap.unmount_virtualbox_shared_folder(machine, mount_guest_path, folder_options) } diff --git a/test/unit/plugins/providers/virtualbox/synced_folder_test.rb b/test/unit/plugins/providers/virtualbox/synced_folder_test.rb index a5b121581..1232721b4 100644 --- a/test/unit/plugins/providers/virtualbox/synced_folder_test.rb +++ b/test/unit/plugins/providers/virtualbox/synced_folder_test.rb @@ -13,6 +13,14 @@ describe VagrantPlugins::ProviderVirtualBox::SyncedFolder do end end + let(:folders) { {"/folder"=> + {:SharedFoldersEnableSymlinksCreate=>true, + :guestpath=>"/folder", + :hostpath=>"/Users/brian/vagrant-folder", + :automount=>false, + :disabled=>false, + :__vagrantfile=>true}} } + subject { described_class.new } before do @@ -36,16 +44,39 @@ describe VagrantPlugins::ProviderVirtualBox::SyncedFolder do end end + describe "#enable" do + let(:ui){ double(:ui) } + let(:guest) { double("guest") } + + let(:no_guestpath_folder) { {"/no_guestpath_folder"=> + {:SharedFoldersEnableSymlinksCreate=>false, + :guestpath=>nil, + :hostpath=>"/Users/brian/vagrant-folder", + :automount=>false, + :disabled=>true, + :__vagrantfile=>true}} } + + before do + allow(subject).to receive(:share_folders).and_return(true) + allow(ui).to receive(:detail).with(any_args) + allow(ui).to receive(:output).with(any_args) + allow(machine).to receive(:ui).and_return(ui) + allow(machine).to receive(:ssh_info).and_return({:username => "test"}) + allow(machine).to receive(:guest).and_return(guest) + end + + it "should mount and persist all folders with a guest path" do + expect(guest).to receive(:capability).with(:mount_virtualbox_shared_folder, "folder", any_args) + expect(guest).to receive(:capability?).with(:persist_mount_virtualbox_shared_folder).and_return(true) + expect(guest).to receive(:capability).with(:persist_mount_virtualbox_shared_folder, any_args) + test_folders = folders.merge(no_guestpath_folder) + subject.enable(machine, test_folders, nil) + end + end + describe "#prepare" do let(:driver) { double("driver") } let(:provider) { double("driver", driver: driver) } - let(:folders) { {"/folder"=> - {:SharedFoldersEnableSymlinksCreate=>true, - :guestpath=>"/folder", - :hostpath=>"/Users/brian/vagrant-folder", - :automount=>false, - :disabled=>false, - :__vagrantfile=>true}} } let(:folders_disabled) { {"/folder"=> {:SharedFoldersEnableSymlinksCreate=>false,