diff --git a/plugins/guests/darwin/cap/darwin_version.rb b/plugins/guests/darwin/cap/darwin_version.rb new file mode 100644 index 000000000..5168c6f55 --- /dev/null +++ b/plugins/guests/darwin/cap/darwin_version.rb @@ -0,0 +1,40 @@ +module VagrantPlugins + module GuestDarwin + module Cap + class DarwinVersion + + VERSION_REGEX = /\d+.\d+.?\d*/.freeze + + # Get the darwin version + # + # @param [Machine] + # @return [String] version of drawin + def self.darwin_version(machine) + output = "" + machine.communicate.sudo("sysctl kern.osrelease") do |_, data| + output = data + end + output.scan(VERSION_REGEX).first + end + + # Get the darwin major version + # + # @param [Machine] + # @return [int] major version of drawin (nil if version is not detected) + def self.darwin_major_version(machine) + output = "" + machine.communicate.sudo("sysctl kern.osrelease") do |_, data| + output = data + end + version_string = output.scan(VERSION_REGEX).first + if version_string + major_version = version_string.split(".").first.to_i + else + major_version = nil + end + major_version + end + end + end + end +end diff --git a/plugins/guests/darwin/cap/flavor.rb b/plugins/guests/darwin/cap/flavor.rb deleted file mode 100644 index 9f634d55c..000000000 --- a/plugins/guests/darwin/cap/flavor.rb +++ /dev/null @@ -1,24 +0,0 @@ -module VagrantPlugins - module GuestDarwin - module Cap - class Flavor - def self.flavor(machine) - # Read the version file - output = "" - machine.communicate.sudo("sw_vers -productVersion", error_check: false) do |_, data| - output = data - end - - # Detect various flavors we care about - if output =~ /10.15.\d+/ - return :catalina - elsif output =~ /11.0.?\d*/ - return :big_sur - else - return :darwin - end - end - end - end - end -end diff --git a/plugins/guests/darwin/cap/mount_vmware_shared_folder.rb b/plugins/guests/darwin/cap/mount_vmware_shared_folder.rb index a5d01104b..d4c6e2413 100644 --- a/plugins/guests/darwin/cap/mount_vmware_shared_folder.rb +++ b/plugins/guests/darwin/cap/mount_vmware_shared_folder.rb @@ -4,6 +4,9 @@ module VagrantPlugins module GuestDarwin module Cap class MountVmwareSharedFolder + + MACOS_BIGSUR_DARWIN_VERSION = 20.freeze + # Entry point for hook to called delayed actions # which finalizing the synced folders setup on # the guest @@ -82,14 +85,15 @@ module VagrantPlugins # Write out the synthetic file comm.sudo("echo -e #{content.inspect} > /etc/synthetic.conf") if @apply_firmlinks[machine.id][:bootstrap] - case machine.guest.capability("flavor") - when :big_sur - apfs_bootstrap_flag = "-t" - else + if machine.guest.capability("darwin_major_version").to_i < MACOS_BIGSUR_DARWIN_VERSION apfs_bootstrap_flag = "-B" + expected_rc = 0 + else + apfs_bootstrap_flag = "-t" + expected_rc = 253 end # Re-bootstrap the root container to pick up firmlink updates - comm.sudo("/System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util #{apfs_bootstrap_flag}", good_exit: [0, 253]) + comm.sudo("/System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util #{apfs_bootstrap_flag}", good_exit: [expected_rc]) end end end diff --git a/plugins/guests/darwin/plugin.rb b/plugins/guests/darwin/plugin.rb index d0799a049..d61a2d890 100644 --- a/plugins/guests/darwin/plugin.rb +++ b/plugins/guests/darwin/plugin.rb @@ -31,9 +31,14 @@ module VagrantPlugins Cap::ConfigureNetworks end - guest_capability(:darwin, :flavor) do - require_relative "cap/flavor" - Cap::Flavor + guest_capability(:darwin, :darwin_version) do + require_relative "cap/darwin_version" + Cap::DarwinVersion + end + + guest_capability(:darwin, :darwin_major_version) do + require_relative "cap/darwin_version" + Cap::DarwinVersion end guest_capability(:darwin, :halt) do diff --git a/test/unit/plugins/guests/darwin/cap/darwin_version_test.rb b/test/unit/plugins/guests/darwin/cap/darwin_version_test.rb new file mode 100644 index 000000000..5f1d9790a --- /dev/null +++ b/test/unit/plugins/guests/darwin/cap/darwin_version_test.rb @@ -0,0 +1,49 @@ +require_relative "../../../../base" + +describe "VagrantPlugins::GuestDarwin::Cap::DarwinVersion" do + let(:caps) do + VagrantPlugins::GuestDarwin::Plugin + .components + .guest_capabilities[:darwin] + end + + let(:machine) { double("machine") } + let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + + before do + allow(machine).to receive(:communicate).and_return(comm) + end + + after do + comm.verify_expectations! + end + + describe ".darwin_version" do + let(:cap) { caps.get(:darwin_version) } + + { + "kern.osrelease: 19.6.0" => "19.6.0", + "kern.osrelease: 20.1.10" => "20.1.10", + }.each do |str, expected| + it "returns #{expected} for #{str}" do + comm.stub_command("sysctl kern.osrelease", stdout: str) + expect(cap.darwin_version(machine)).to eq(expected) + end + end + end + + describe ".darwin_major_version" do + let(:cap) { caps.get(:darwin_major_version) } + + { + "kern.osrelease: 19.6.0" => 19, + "kern.osrelease: 20.1.10" => 20, + "" => nil + }.each do |str, expected| + it "returns #{expected} for #{str}" do + comm.stub_command("sysctl kern.osrelease", stdout: str) + expect(cap.darwin_major_version(machine)).to eq(expected) + end + end + end +end diff --git a/test/unit/plugins/guests/darwin/cap/flavor_test.rb b/test/unit/plugins/guests/darwin/cap/flavor_test.rb deleted file mode 100644 index 58e0fc47d..000000000 --- a/test/unit/plugins/guests/darwin/cap/flavor_test.rb +++ /dev/null @@ -1,43 +0,0 @@ -require_relative "../../../../base" - -describe "VagrantPlugins::GuestDarwin::Cap::Flavor" do - let(:caps) do - VagrantPlugins::GuestDarwin::Plugin - .components - .guest_capabilities[:darwin] - end - - let(:machine) { double("machine") } - let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } - - before do - allow(machine).to receive(:communicate).and_return(comm) - end - - after do - comm.verify_expectations! - end - - describe ".flavor" do - let(:cap) { caps.get(:flavor) } - - { - "11.0.1" => :big_sur, - "11.0.11" => :big_sur, - "11.0" => :big_sur, - "10.15.123" => :catalina, - "" => :darwin, - "10.14.1" => :darwin, - }.each do |str, expected| - it "returns #{expected} for #{str}" do - comm.stub_command("sw_vers -productVersion", stdout: str) - expect(cap.flavor(machine)).to be(expected) - end - end - - it "contines if sw_vers is not available" do - comm.stub_command("sw_vers -productVersion", stdout: "something!") - expect(cap.flavor(machine)).to be(:darwin) - end - end -end diff --git a/test/unit/plugins/guests/darwin/cap/mount_vmware_shared_folder_test.rb b/test/unit/plugins/guests/darwin/cap/mount_vmware_shared_folder_test.rb index a706caa21..44302cb53 100644 --- a/test/unit/plugins/guests/darwin/cap/mount_vmware_shared_folder_test.rb +++ b/test/unit/plugins/guests/darwin/cap/mount_vmware_shared_folder_test.rb @@ -8,7 +8,8 @@ describe "VagrantPlugins::GuestDarwin::Cap::MountVmwareSharedFolder" do .get(:mount_vmware_shared_folder) end - let(:machine) { double("machine", communicate: communicator, id: "MACHINE_ID") } + let(:machine) { double("machine", communicate: communicator, id: "MACHINE_ID", guest: guest) } + let(:guest) {double("guest")} let(:communicator) { double("communicator") } before do @@ -27,8 +28,9 @@ describe "VagrantPlugins::GuestDarwin::Cap::MountVmwareSharedFolder" do described_class.reset! end - after { described_class. - mount_vmware_shared_folder(machine, name, guestpath, options) } + after { + described_class.mount_vmware_shared_folder(machine, name, guestpath, options) + } context "with APFS root container" do before do @@ -73,6 +75,21 @@ describe "VagrantPlugins::GuestDarwin::Cap::MountVmwareSharedFolder" do expect(communicator).to receive(:sudo).with(%r{ln -s .+/System/Volumes/Data.+}) end + { + 19 => "-B", + 20 => "-t", + 21 => "-t", + nil => "-B" + }.each do |version, expected_flag| + it "should re-bootstrap root dir for darwin version #{version}" do + expect(communicator).to receive(:sudo).with(/apfs.util #{expected_flag}/, any_args) + expect(guest).to receive(:capability).with("darwin_major_version").and_return(version) + + described_class.mount_vmware_shared_folder(machine, name, guestpath, options) + described_class.apfs_firmlinks_delayed[machine.id].call + end + end + context "when firmlink is provided by the system" do before { expect(described_class).to receive(:system_firmlink?).and_return(true) }