(#4666) Remove duplicate export folders before writing /etc/exports
Prior to this commit, if you set up multiple folders to export with NFS on linux with the exact same hostpath, the template used to write /etc/exports would end up placing the same path with the same IP in /etc/exports and cause an error preventing the folders from being properly mounted. This commit fixes that by first looking at which folders are being exported and if there are any duplicates. If so, remove the duplicates and only export 1 hostpath folder. If these duplicate folders have differing nfs linux options, an exception must be thrown because we cannot assume which options the user intended to export with.
This commit is contained in:
parent
2170d40bb2
commit
f0f60a1075
|
@ -468,6 +468,10 @@ module Vagrant
|
||||||
error_key(:nfs_bad_exports)
|
error_key(:nfs_bad_exports)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class NFSDupePerms < VagrantError
|
||||||
|
error_key(:nfs_dupe_permissions)
|
||||||
|
end
|
||||||
|
|
||||||
class NFSExportsFailed < VagrantError
|
class NFSExportsFailed < VagrantError
|
||||||
error_key(:nfs_exports_failed)
|
error_key(:nfs_exports_failed)
|
||||||
end
|
end
|
||||||
|
|
|
@ -29,6 +29,7 @@ module VagrantPlugins
|
||||||
nfs_start_command = env.host.capability(:nfs_start_command)
|
nfs_start_command = env.host.capability(:nfs_start_command)
|
||||||
|
|
||||||
nfs_opts_setup(folders)
|
nfs_opts_setup(folders)
|
||||||
|
folders = folder_dupe_check(folders)
|
||||||
output = Vagrant::Util::TemplateRenderer.render('nfs/exports_linux',
|
output = Vagrant::Util::TemplateRenderer.render('nfs/exports_linux',
|
||||||
uuid: id,
|
uuid: id,
|
||||||
ips: ips,
|
ips: ips,
|
||||||
|
@ -84,6 +85,37 @@ module VagrantPlugins
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
|
# Takes a hash of folders and removes any duplicate exports that
|
||||||
|
# share the same hostpath to avoid duplicate entries in /etc/exports
|
||||||
|
# ref: GH-4666
|
||||||
|
def self.folder_dupe_check(folders)
|
||||||
|
return_folders = {}
|
||||||
|
# Group by hostpath to see if there are multiple exports coming
|
||||||
|
# from the same folder
|
||||||
|
export_groups = folders.values.group_by { |h| h[:hostpath] }
|
||||||
|
|
||||||
|
# We need to check that each group key only has 1 value,
|
||||||
|
# and if not, check each nfs option. If all nfs options are the same
|
||||||
|
# we're good, otherwise throw an exception
|
||||||
|
export_groups.each do |path,group|
|
||||||
|
if group.size > 1
|
||||||
|
# if the linux nfs options aren't all the same throw an exception
|
||||||
|
group1_opts = group.first[:linux__nfs_options]
|
||||||
|
|
||||||
|
if !group.all? {|g| g[:linux__nfs_options] == group1_opts}
|
||||||
|
raise Vagrant::Errors::NFSDupePerms, hostpath: group.first[:hostpath]
|
||||||
|
else
|
||||||
|
# if they're the same just pick the first one
|
||||||
|
return_folders[path] = group.first
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# just return folder, there are no duplicates
|
||||||
|
return_folders[path] = group.first
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return_folders
|
||||||
|
end
|
||||||
|
|
||||||
def self.nfs_cleanup(remove_ids)
|
def self.nfs_cleanup(remove_ids)
|
||||||
return if !File.exist?(NFS_EXPORTS_PATH)
|
return if !File.exist?(NFS_EXPORTS_PATH)
|
||||||
|
|
||||||
|
|
|
@ -912,6 +912,9 @@ en:
|
||||||
command: %{command}
|
command: %{command}
|
||||||
stdout: %{stdout}
|
stdout: %{stdout}
|
||||||
stderr: %{stderr}
|
stderr: %{stderr}
|
||||||
|
nfs_dupe_permissions: |-
|
||||||
|
You have attempted to export the same nfs host path at %{hostpath} with
|
||||||
|
different nfs permissions. Please pick one permission and reload your guest.
|
||||||
nfs_cant_read_exports: |-
|
nfs_cant_read_exports: |-
|
||||||
Vagrant can't read your current NFS exports! The exports file should be
|
Vagrant can't read your current NFS exports! The exports file should be
|
||||||
readable by any user. This is usually caused by invalid permissions
|
readable by any user. This is usually caused by invalid permissions
|
||||||
|
|
|
@ -79,6 +79,42 @@ EOH
|
||||||
expect(exports_content).to include("/tmp")
|
expect(exports_content).to include("/tmp")
|
||||||
expect(exports_content).not_to include("/var")
|
expect(exports_content).not_to include("/var")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "throws an exception with at least 2 different nfs options" do
|
||||||
|
folders = {"/vagrant"=>
|
||||||
|
{:hostpath=>"/home/vagrant",
|
||||||
|
:linux__nfs_options=>["rw","all_squash"]},
|
||||||
|
"/var/www/project"=>
|
||||||
|
{:hostpath=>"/home/vagrant",
|
||||||
|
:linux__nfs_options=>["rw","sync"]}}
|
||||||
|
|
||||||
|
expect { cap.nfs_export(env, ui, SecureRandom.uuid, ["127.0.0.1"], folders) }.
|
||||||
|
to raise_error Vagrant::Errors::NFSDupePerms
|
||||||
|
end
|
||||||
|
|
||||||
|
it "writes only 1 hostpath for multiple exports" do
|
||||||
|
folders = {"/vagrant"=>
|
||||||
|
{:hostpath=>"/home/vagrant",
|
||||||
|
:linux__nfs_options=>["rw","all_squash"]},
|
||||||
|
"/var/www/otherproject"=>
|
||||||
|
{:hostpath=>"/newhome/otherproject",
|
||||||
|
:linux__nfs_options=>["rw","all_squash"]},
|
||||||
|
"/var/www/project"=>
|
||||||
|
{:hostpath=>"/home/vagrant",
|
||||||
|
:linux__nfs_options=>["rw","all_squash"]}}
|
||||||
|
valid_id = SecureRandom.uuid
|
||||||
|
content =<<-EOH
|
||||||
|
\n# VAGRANT-BEGIN: #{Process.uid} #{valid_id}
|
||||||
|
"/home/vagrant" 127.0.0.1(rw,all_squash,anonuid=,anongid=,fsid=)
|
||||||
|
"/newhome/otherproject" 127.0.0.1(rw,all_squash,anonuid=,anongid=,fsid=)
|
||||||
|
# VAGRANT-END: #{Process.uid} #{valid_id}
|
||||||
|
EOH
|
||||||
|
|
||||||
|
cap.nfs_export(env, ui, valid_id, ["127.0.0.1"], folders)
|
||||||
|
exports_content = File.read(exports_path)
|
||||||
|
expect(exports_content).to eq(content)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe ".nfs_prune" do
|
describe ".nfs_prune" do
|
||||||
|
|
Loading…
Reference in New Issue