diff --git a/plugins/guests/linux/cap/mount_smb_shared_folder.rb b/plugins/guests/linux/cap/mount_smb_shared_folder.rb index dfc592639..86c1c66f6 100644 --- a/plugins/guests/linux/cap/mount_smb_shared_folder.rb +++ b/plugins/guests/linux/cap/mount_smb_shared_folder.rb @@ -25,16 +25,19 @@ module VagrantPlugins # Ensure password is scrubbed Vagrant::Util::CredentialScrubber.sensitive(smb_password) - options[:mount_options] ||= [] + mnt_opts = [] if machine.env.host.capability?(:smb_mount_options) - options[:mount_options] += machine.env.host.capability(:smb_mount_options) + mnt_opts += machine.env.host.capability(:smb_mount_options) else - options[:mount_options] << "sec=ntlm" + mnt_opts << "sec=ntlmssp" end - options[:mount_options] << "credentials=/etc/smb_creds_#{name}" + mnt_opts << "credentials=/etc/smb_creds_#{name}" + mnt_opts << "uid=#{mount_uid}" + mnt_opts << "gid=#{mount_gid}" - mount_options = "-o uid=#{mount_uid},gid=#{mount_gid}" - mount_options += ",#{Array(options[:mount_options]).join(",")}" if options[:mount_options] + mnt_opts = merge_mount_options(mnt_opts, options[:mount_options] || []) + + mount_options = "-o #{mnt_opts.join(",")}" mount_command = "mount -t cifs #{mount_options} #{mount_device} #{expanded_guest_path}" # Create the guest path if it doesn't exist @@ -76,6 +79,21 @@ SCRIPT emit_upstart_notification(machine, expanded_guest_path) end + + def self.merge_mount_options(base, overrides) + base = base.join(",").split(",") + overrides = overrides.join(",").split(",") + b_kv = Hash[base.map{|item| item.split("=", 2) }] + o_kv = Hash[overrides.map{|item| item.split("=", 2) }] + merged = {}.tap do |opts| + (b_kv.keys + o_kv.keys).uniq.each do |key| + opts[key] = o_kv.fetch(key, b_kv[key]) + end + end + merged.map do |key, value| + [key, value].compact.join("=") + end + end end end end diff --git a/test/unit/plugins/guests/linux/cap/mount_smb_shared_folder.rb b/test/unit/plugins/guests/linux/cap/mount_smb_shared_folder.rb index 62d4745f2..dd5e7c484 100644 --- a/test/unit/plugins/guests/linux/cap/mount_smb_shared_folder.rb +++ b/test/unit/plugins/guests/linux/cap/mount_smb_shared_folder.rb @@ -7,7 +7,9 @@ describe "VagrantPlugins::GuestLinux::Cap::MountSMBSharedFolder" do .guest_capabilities[:linux] end - let(:machine) { double("machine") } + let(:machine) { double("machine", env: env) } + let(:env) { double("env", host: host) } + let(:host) { double("host") } let(:guest) { double("guest") } let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } let(:mount_owner){ "vagrant" } @@ -29,6 +31,7 @@ describe "VagrantPlugins::GuestLinux::Cap::MountSMBSharedFolder" do before do allow(machine).to receive(:communicate).and_return(comm) + allow(host).to receive(:capability?).and_return(false) end after do @@ -72,5 +75,57 @@ describe "VagrantPlugins::GuestLinux::Cap::MountSMBSharedFolder" do expect(comm).to receive(:sudo).with(/emit/) cap.mount_smb_shared_folder(machine, mount_name, mount_guest_path, folder_options) end + + context "with custom mount options" do + let(:folder_options) do + { + owner: mount_owner, + group: mount_group, + smb_host: "localhost", + smb_username: "user", + smb_password: "pass", + mount_options: ["ro", "sec=custom"] + } + end + + it "adds given mount options to command" do + expect(comm).to receive(:sudo).with(/ro/, any_args) + cap.mount_smb_shared_folder(machine, mount_name, mount_guest_path, folder_options) + end + + it "replaces defined options" do + expect(comm).to receive(:sudo).with(/sec=custom/, any_args) + cap.mount_smb_shared_folder(machine, mount_name, mount_guest_path, folder_options) + end + + it "does not include replaced options" do + expect(comm).not_to receive(:sudo).with(/sec=ntlm/, any_args) + cap.mount_smb_shared_folder(machine, mount_name, mount_guest_path, folder_options) + end + end + end + + describe ".merge_mount_options" do + let(:base){ ["opt1", "opt2=on", "opt3", "opt4,opt5=off"] } + let(:override){ ["opt8", "opt4=on,opt6,opt7=true"] } + + context "with no override" do + it "should split options into individual options" do + result = cap.merge_mount_options(base, []) + expect(result.size).to eq(5) + end + end + + context "with overrides" do + it "should merge all options" do + result = cap.merge_mount_options(base, override) + expect(result.size).to eq(8) + end + + it "should override options defined in base" do + result = cap.merge_mount_options(base, override) + expect(result).to include("opt4=on") + end + end end end