Merge pull request #11108 from chrisroberts/macos-catalina
Fix NFS sharing in macOS 10.15 (based on #11105)
This commit is contained in:
commit
b12a23273e
|
@ -26,8 +26,8 @@ module VagrantPlugins
|
||||||
logger.debug("Compiling map of sub-directories for NFS exports...")
|
logger.debug("Compiling map of sub-directories for NFS exports...")
|
||||||
dirmap = {}
|
dirmap = {}
|
||||||
folders.sort_by { |_, opts| opts[:hostpath] }.each do |_, opts|
|
folders.sort_by { |_, opts| opts[:hostpath] }.each do |_, opts|
|
||||||
|
opts[:hostpath] = environment.host.capability(:resolve_host_path, opts[:hostpath].gsub('"', '\"'))
|
||||||
hostpath = opts[:hostpath].dup
|
hostpath = opts[:hostpath].dup
|
||||||
hostpath.gsub!('"', '\"')
|
|
||||||
|
|
||||||
found = false
|
found = false
|
||||||
dirmap.each do |dirs, diropts|
|
dirmap.each do |dirs, diropts|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module HostBSD
|
||||||
|
module Cap
|
||||||
|
class Path
|
||||||
|
def self.resolve_host_path(env, path)
|
||||||
|
path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -36,6 +36,11 @@ module VagrantPlugins
|
||||||
Cap::NFS
|
Cap::NFS
|
||||||
end
|
end
|
||||||
|
|
||||||
|
host_capability("bsd", "resolve_host_path") do
|
||||||
|
require_relative "cap/path"
|
||||||
|
Cap::Path
|
||||||
|
end
|
||||||
|
|
||||||
host_capability("bsd", "set_ssh_key_permissions") do
|
host_capability("bsd", "set_ssh_key_permissions") do
|
||||||
require_relative "cap/ssh"
|
require_relative "cap/ssh"
|
||||||
Cap::SSH
|
Cap::SSH
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module HostDarwin
|
||||||
|
module Cap
|
||||||
|
class Path
|
||||||
|
@@logger = Log4r::Logger.new("vagrant::host::darwin::path")
|
||||||
|
|
||||||
|
FIRMLINK_DEFS = "/usr/share/firmlinks".freeze
|
||||||
|
FIRMLINK_DATA_PATH = "/System/Volumes/Data".freeze
|
||||||
|
|
||||||
|
# Resolve the given host path to the actual
|
||||||
|
# usable system path by detecting firmlinks
|
||||||
|
# if available on the current system
|
||||||
|
#
|
||||||
|
# @param [String] path Host system path
|
||||||
|
# @return [String] resolved path
|
||||||
|
def self.resolve_host_path(env, path)
|
||||||
|
path = File.expand_path(path)
|
||||||
|
firmlink = firmlink_map.detect do |mount_path, data_path|
|
||||||
|
path.start_with?(mount_path)
|
||||||
|
end
|
||||||
|
return path if firmlink.nil?
|
||||||
|
current_prefix, new_suffix = firmlink
|
||||||
|
new_prefix = File.join(FIRMLINK_DATA_PATH, new_suffix)
|
||||||
|
new_path = path.sub(current_prefix, new_prefix)
|
||||||
|
@@logger.debug("Resolved given path `#{path}` to `#{new_path}`")
|
||||||
|
new_path
|
||||||
|
end
|
||||||
|
|
||||||
|
# Generate mapping of firmlinks if available on the host
|
||||||
|
#
|
||||||
|
# @return [Hash<String,String>]
|
||||||
|
def self.firmlink_map
|
||||||
|
if !@firmlink_map
|
||||||
|
return @firmlink_map = {} if !File.exist?(FIRMLINK_DEFS)
|
||||||
|
begin
|
||||||
|
@firmlink_map = Hash[
|
||||||
|
File.readlines(FIRMLINK_DEFS).map { |d|
|
||||||
|
d.strip.split(/\s+/, 2)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
rescue => err
|
||||||
|
@@logger.warn("Failed to parse firmlink definitions: #{err}")
|
||||||
|
@firmlink_map = {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@firmlink_map
|
||||||
|
end
|
||||||
|
|
||||||
|
# @private
|
||||||
|
# Reset the cached values for capability. This is not considered a public
|
||||||
|
# API and should only be used for testing.
|
||||||
|
def self.reset!
|
||||||
|
instance_variables.each(&method(:remove_instance_variable))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -16,6 +16,11 @@ module VagrantPlugins
|
||||||
Cap::ProviderInstallVirtualBox
|
Cap::ProviderInstallVirtualBox
|
||||||
end
|
end
|
||||||
|
|
||||||
|
host_capability("darwin", "resolve_host_path") do
|
||||||
|
require_relative "cap/path"
|
||||||
|
Cap::Path
|
||||||
|
end
|
||||||
|
|
||||||
host_capability("darwin", "rdp_client") do
|
host_capability("darwin", "rdp_client") do
|
||||||
require_relative "cap/rdp"
|
require_relative "cap/rdp"
|
||||||
Cap::RDP
|
Cap::RDP
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
require_relative "../../../../base"
|
||||||
|
require_relative "../../../../../../plugins/hosts/bsd/cap/nfs"
|
||||||
|
|
||||||
|
describe VagrantPlugins::HostBSD::Cap::NFS do
|
||||||
|
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
describe ".nfs_export" do
|
||||||
|
let(:environment) { double("environment", host: host) }
|
||||||
|
let(:host) { double("host") }
|
||||||
|
let(:ui) { double("ui") }
|
||||||
|
let(:id) { "UUID" }
|
||||||
|
let(:ips) { [] }
|
||||||
|
let(:folders) { {} }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(host).to receive(:capability).and_return("")
|
||||||
|
allow(Vagrant::Util::TemplateRenderer).to receive(:render).and_return("")
|
||||||
|
allow(described_class).to receive(:sleep)
|
||||||
|
allow(described_class).to receive(:nfs_cleanup)
|
||||||
|
allow(described_class).to receive(:system)
|
||||||
|
allow(File).to receive(:writable?).with("/etc/exports")
|
||||||
|
allow(ui).to receive(:info)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should execute successfully when no folders are defined" do
|
||||||
|
expect { described_class.nfs_export(environment, ui, id, ips, folders) }.
|
||||||
|
not_to raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with single folder defined" do
|
||||||
|
let(:folders) {
|
||||||
|
{"/vagrant" => {
|
||||||
|
type: :nfs, guestpath: "/vagrant", hostpath: "/Users/vagrant/paths", disabled: false}}
|
||||||
|
}
|
||||||
|
|
||||||
|
it "should execute successfully" do
|
||||||
|
expect { described_class.nfs_export(environment, ui, id, ips, folders) }.
|
||||||
|
not_to raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should resolve the host path" do
|
||||||
|
expect(host).to receive(:capability).with(:resolve_host_path, folders["/vagrant"][:hostpath]).and_return("")
|
||||||
|
described_class.nfs_export(environment, ui, id, ips, folders)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,13 @@
|
||||||
|
require_relative "../../../../base"
|
||||||
|
require_relative "../../../../../../plugins/hosts/bsd/cap/path"
|
||||||
|
|
||||||
|
describe VagrantPlugins::HostBSD::Cap::Path do
|
||||||
|
describe ".resolve_host_path" do
|
||||||
|
let(:env) { double("environment") }
|
||||||
|
let(:path) { double("path") }
|
||||||
|
|
||||||
|
it "should return the path object provided" do
|
||||||
|
expect(described_class.resolve_host_path(env, path)).to eq(path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,89 @@
|
||||||
|
require_relative "../../../../base"
|
||||||
|
require_relative "../../../../../../plugins/hosts/darwin/cap/path"
|
||||||
|
|
||||||
|
describe VagrantPlugins::HostDarwin::Cap::Path do
|
||||||
|
describe ".resolve_host_path" do
|
||||||
|
let(:env) { double("environment") }
|
||||||
|
let(:path) { "/test/vagrant/path" }
|
||||||
|
let(:firmlink_map) { {} }
|
||||||
|
|
||||||
|
before { allow(described_class).to receive(:firmlink_map).and_return(firmlink_map) }
|
||||||
|
|
||||||
|
it "should not change the path when no firmlinks are defined" do
|
||||||
|
expect(described_class.resolve_host_path(env, path)).to eq(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when firmlink map contains non-matching values" do
|
||||||
|
let(:firmlink_map) { {"/users" => "users", "/system" => "system"} }
|
||||||
|
|
||||||
|
it "should not change the path" do
|
||||||
|
expect(described_class.resolve_host_path(env, path)).to eq(path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when firmlink map contains matching value" do
|
||||||
|
let(:firmlink_map) { {"/users" => "users", "/test" => "test"} }
|
||||||
|
|
||||||
|
it "should update the path" do
|
||||||
|
expect(described_class.resolve_host_path(env, path)).not_to eq(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should prefix the path with the defined data path" do
|
||||||
|
expect(described_class.resolve_host_path(env, path)).to start_with(described_class.const_get(:FIRMLINK_DATA_PATH))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when firmlink map match points to different named target" do
|
||||||
|
let(:firmlink_map) { {"/users" => "users", "/test" => "other"} }
|
||||||
|
|
||||||
|
it "should update the path" do
|
||||||
|
expect(described_class.resolve_host_path(env, path)).not_to eq(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should prefix the path with the defined data path" do
|
||||||
|
expect(described_class.resolve_host_path(env, path)).to start_with(described_class.const_get(:FIRMLINK_DATA_PATH))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should include the updated path name" do
|
||||||
|
expect(described_class.resolve_host_path(env, path)).to include("other")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe ".firmlink_map" do
|
||||||
|
before { described_class.reset! }
|
||||||
|
|
||||||
|
context "when firmlink definition file does not exist" do
|
||||||
|
before { expect(File).to receive(:exist?).with(described_class.const_get(:FIRMLINK_DEFS)).and_return(false) }
|
||||||
|
|
||||||
|
it "should return an empty hash" do
|
||||||
|
expect(described_class.firmlink_map).to eq({})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when firmlink definition file exists with values" do
|
||||||
|
before do
|
||||||
|
expect(File).to receive(:exist?).with(described_class.const_get(:FIRMLINK_DEFS)).and_return(true)
|
||||||
|
expect(File).to receive(:readlines).with.(described_class.const_get(:FIRMLINK_DEFS)).
|
||||||
|
and_return(["/System\tSystem\n", "/Users\tUsers\n", "/Library/Something\tLibrary/Somethingelse"])
|
||||||
|
|
||||||
|
it "should generate a non-empty hash" do
|
||||||
|
expect(described_class.firmlink_map).not_to be_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should properly create entries" do
|
||||||
|
result = described_class.firmlink_map
|
||||||
|
expect(result["/System"]).to eq("System")
|
||||||
|
expect(result["/Users"]).to eq("Users")
|
||||||
|
expect(result["/Library/Something"]).to eq("Library/Somethingelse")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should only load values once" do
|
||||||
|
result = describe_class.firmlink_app
|
||||||
|
expect(File).not_to receive(:readlines)
|
||||||
|
result = describe_class.firmlink_app
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue