diff --git a/lib/vagrant/box_collection.rb b/lib/vagrant/box_collection.rb index bbcf10161..aa961355f 100644 --- a/lib/vagrant/box_collection.rb +++ b/lib/vagrant/box_collection.rb @@ -116,7 +116,7 @@ module Vagrant # Extract the box into a temporary directory. @logger.debug("Unpacking box into temporary directory: #{temp_dir}") result = Util::Subprocess.execute( - "bsdtar", "-v", "-x", "-m", "-C", temp_dir.to_s, "-f", path.to_s) + "bsdtar", "-v", "-x", "-m", "-s", "|\\\\\|/|", "-C", temp_dir.to_s, "-f", path.to_s) if result.exit_code != 0 raise Errors::BoxUnpackageFailure, output: result.stderr.to_s diff --git a/lib/vagrant/util/platform.rb b/lib/vagrant/util/platform.rb index 6e9f993f3..789d61ece 100644 --- a/lib/vagrant/util/platform.rb +++ b/lib/vagrant/util/platform.rb @@ -393,6 +393,7 @@ module Vagrant # @return [String] def wsl_to_windows_path(path) if wsl? && wsl_windows_access? && !path.match(/^[a-zA-Z]:/) + path = File.expand_path(path.to_s) if wsl_path?(path) parts = path.split("/") parts.delete_if(&:empty?) @@ -402,17 +403,15 @@ module Vagrant if root_path.end_with?("lxss") && !(["root", "home"].include?(parts.first)) root_path = "#{root_path}\\rootfs" end - [root_path, *parts].join("\\") + path = [root_path, *parts].join("\\") else path = path.to_s.sub("/mnt/", "") parts = path.split("/") parts.first << ":" path = parts.join("\\") - path end - else - path end + path.to_s end # Takes a windows path and formats it to the diff --git a/lib/vagrant/util/powershell.rb b/lib/vagrant/util/powershell.rb index f77ba9650..d8529f423 100644 --- a/lib/vagrant/util/powershell.rb +++ b/lib/vagrant/util/powershell.rb @@ -27,7 +27,11 @@ module Vagrant @_powershell_executable += ".exe" if Which.which(@_powershell_executable).nil? - @_powershell_executable = nil + @_powershell_executable = "/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe" + + if Which.which(@_powershell_executable).nil? + @_powershell_executable = nil + end end else @_powershell_executable = nil diff --git a/plugins/providers/hyperv/action/delete_vm.rb b/plugins/providers/hyperv/action/delete_vm.rb index 2077a7a41..03d8c0be9 100644 --- a/plugins/providers/hyperv/action/delete_vm.rb +++ b/plugins/providers/hyperv/action/delete_vm.rb @@ -9,6 +9,14 @@ module VagrantPlugins def call(env) env[:ui].info("Deleting the machine...") env[:machine].provider.driver.delete_vm + # NOTE: We remove the data directory and recreate it + # to overcome an issue seen when running within + # the WSL. Hyper-V will successfully remove the + # VM and the files will appear to be gone, but + # on a subsequent up, they will cause collisions. + # This forces them to be gone for real. + FileUtils.rm_rf(env[:machine].data_dir) + FileUtils.mkdir_p(env[:machine].data_dir) @app.call(env) end end diff --git a/plugins/providers/hyperv/action/export.rb b/plugins/providers/hyperv/action/export.rb index d3d8929ed..28b5ab4be 100644 --- a/plugins/providers/hyperv/action/export.rb +++ b/plugins/providers/hyperv/action/export.rb @@ -23,7 +23,8 @@ module VagrantPlugins def export @env[:ui].info I18n.t("vagrant.actions.vm.export.exporting") - @env[:machine].provider.driver.export(@env["export.temp_dir"]) do |progress| + export_tmp_dir = Vagrant::Util::Platform.wsl_to_windows_path(@env["export.temp_dir"]) + @env[:machine].provider.driver.export(export_tmp_dir) do |progress| @env[:ui].clear_line @env[:ui].report_progress(progress.percent, 100, false) end diff --git a/plugins/providers/hyperv/action/import.rb b/plugins/providers/hyperv/action/import.rb index 25229e3d0..afec6f39a 100644 --- a/plugins/providers/hyperv/action/import.rb +++ b/plugins/providers/hyperv/action/import.rb @@ -61,11 +61,11 @@ module VagrantPlugins dest_path = env[:machine].data_dir.join("Virtual Hard Disks").join(image_path.basename).to_s options = { - "VMConfigFile" => config_path.to_s.gsub("/", "\\"), - "DestinationPath" => dest_path.to_s.gsub("/", "\\"), - "DataPath" => env[:machine].data_dir.to_s.gsub("/", "\\"), + "VMConfigFile" => Vagrant::Util::Platform.wsl_to_windows_path(config_path).gsub("/", "\\"), + "DestinationPath" => Vagrant::Util::Platform.wsl_to_windows_path(dest_path).gsub("/", "\\"), + "DataPath" => Vagrant::Util::Platform.wsl_to_windows_path(env[:machine].data_dir).gsub("/", "\\"), "LinkedClone" => !!env[:machine].provider_config.linked_clone, - "SourcePath" => image_path.to_s.gsub("/", "\\"), + "SourcePath" => Vagrant::Util::Platform.wsl_to_windows_path(image_path).gsub("/", "\\"), "VMName" => env[:machine].provider_config.vmname, } diff --git a/plugins/providers/hyperv/driver.rb b/plugins/providers/hyperv/driver.rb index 04efa3eb1..e200a8224 100644 --- a/plugins/providers/hyperv/driver.rb +++ b/plugins/providers/hyperv/driver.rb @@ -221,8 +221,8 @@ module VagrantPlugins def execute_powershell(path, options, &block) lib_path = Pathname.new(File.expand_path("../scripts", __FILE__)) - mod_path = lib_path.join("utils").to_s.gsub("/", "\\") - path = lib_path.join(path).to_s.gsub("/", "\\") + mod_path = Vagrant::Util::Platform.wsl_to_windows_path(lib_path.join("utils")).to_s.gsub("/", "\\") + path = Vagrant::Util::Platform.wsl_to_windows_path(lib_path.join(path)).to_s.gsub("/", "\\") options = options || {} ps_options = [] options.each do |key, value| @@ -239,8 +239,9 @@ module VagrantPlugins # Include our module path so we can nicely load helper modules opts = { notify: [:stdout, :stderr, :stdin], - env: {"PSModulePath" => "$env:PSModulePath+';#{mod_path}'"} + module_path: mod_path } + Vagrant::Util::PowerShell.execute(path, *ps_options, **opts, &block) end end diff --git a/plugins/providers/hyperv/provider.rb b/plugins/providers/hyperv/provider.rb index 5db9c880d..c1808b6dd 100644 --- a/plugins/providers/hyperv/provider.rb +++ b/plugins/providers/hyperv/provider.rb @@ -12,11 +12,12 @@ module VagrantPlugins attr_reader :driver def self.usable?(raise_error=false) - if !Vagrant::Util::Platform.windows? + if !Vagrant::Util::Platform.windows? && + !Vagrant::Util::Platform.wsl? raise Errors::WindowsRequired end - if !Vagrant::Util::Platform.windows_admin? and + if !Vagrant::Util::Platform.windows_admin? && !Vagrant::Util::Platform.windows_hyperv_admin? raise Errors::AdminRequired end diff --git a/plugins/providers/hyperv/scripts/utils/VagrantVM/VagrantVM.psm1 b/plugins/providers/hyperv/scripts/utils/VagrantVM/VagrantVM.psm1 index a380a38f3..fd11bdba1 100644 --- a/plugins/providers/hyperv/scripts/utils/VagrantVM/VagrantVM.psm1 +++ b/plugins/providers/hyperv/scripts/utils/VagrantVM/VagrantVM.psm1 @@ -1,3 +1,6 @@ +# Always stop when errors are encountered unless instructed not to +$ErrorActionPreference = "Stop" + # Vagrant VM creation functions function New-VagrantVM { @@ -123,7 +126,7 @@ function New-VagrantVMVMCX { $Path = $Drive.Path Hyper-V\Remove-VMHardDiskDrive $Drive Hyper-V\New-VHD -Path $DestinationPath -ParentPath $SourcePath - Hyper-V\AddVMHardDiskDrive -VM $VM -Path $DestinationPath + Hyper-V\Add-VMHardDiskDrive -VM $VM -Path $DestinationPath break } } diff --git a/templates/locales/synced_folder_smb.yml b/templates/locales/synced_folder_smb.yml index c73e9a15b..3819f8b32 100644 --- a/templates/locales/synced_folder_smb.yml +++ b/templates/locales/synced_folder_smb.yml @@ -1,10 +1,5 @@ en: vagrant_sf_smb: - not_supported: |- - It appears your machine doesn't support SMB, has not been - properly configured for SMB, or there is not an adapter to - enable SMB on this machine for Vagrant. Ensure SMB host - functionality is available on this machine and try again. mounting: |- Mounting SMB shared folders... mounting_single: |- @@ -26,6 +21,11 @@ en: Vagrant requires administrator access to create SMB shares and may request access to complete setup of configured shares. errors: + not_supported: |- + It appears your machine doesn't support SMB, has not been + properly configured for SMB, or there is not an adapter to + enable SMB on this machine for Vagrant. Ensure SMB host + functionality is available on this machine and try again. start_failed: |- Vagrant failed to automatically start the SMB service. Ensure the required services can be started and try again. diff --git a/test/unit/plugins/providers/hyperv/action/delete_vm_test.rb b/test/unit/plugins/providers/hyperv/action/delete_vm_test.rb index dda24c90c..8d0e42e12 100644 --- a/test/unit/plugins/providers/hyperv/action/delete_vm_test.rb +++ b/test/unit/plugins/providers/hyperv/action/delete_vm_test.rb @@ -8,13 +8,15 @@ describe VagrantPlugins::HyperV::Action::DeleteVM do let(:ui){ double("ui") } let(:provider){ double("provider", driver: driver) } let(:driver){ double("driver") } - let(:machine){ double("machine", provider: provider) } + let(:machine){ double("machine", provider: provider, data_dir: "/dev/null") } let(:subject){ described_class.new(app, env) } before do allow(app).to receive(:call) allow(ui).to receive(:info) allow(driver).to receive(:delete_vm) + allow(FileUtils).to receive(:rm_rf) + allow(FileUtils).to receive(:mkdir_p) end it "should call the app on success" do @@ -26,4 +28,14 @@ describe VagrantPlugins::HyperV::Action::DeleteVM do expect(driver).to receive(:delete_vm) subject.call(env) end + + it "should delete the data directory" do + expect(FileUtils).to receive(:rm_rf).with(machine.data_dir) + subject.call(env) + end + + it "should recreate the data directory" do + expect(FileUtils).to receive(:mkdir_p).with(machine.data_dir) + subject.call(env) + end end diff --git a/test/unit/plugins/providers/hyperv/driver_test.rb b/test/unit/plugins/providers/hyperv/driver_test.rb index fa99484f0..585337600 100644 --- a/test/unit/plugins/providers/hyperv/driver_test.rb +++ b/test/unit/plugins/providers/hyperv/driver_test.rb @@ -144,8 +144,7 @@ describe VagrantPlugins::HyperV::Driver do it "should automatically include module path" do expect(Vagrant::Util::PowerShell).to receive(:execute) do |path, *args| opts = args.detect{|i| i.is_a?(Hash)} - expect(opts[:env]).not_to be_nil - expect(opts[:env]["PSModulePath"]).to include("$env:PSModulePath+") + expect(opts[:module_path]).not_to be_nil end subject.send(:execute_powershell, "path", {}) end diff --git a/test/unit/plugins/providers/hyperv/provider_test.rb b/test/unit/plugins/providers/hyperv/provider_test.rb index bac4512e6..98e9c7d96 100644 --- a/test/unit/plugins/providers/hyperv/provider_test.rb +++ b/test/unit/plugins/providers/hyperv/provider_test.rb @@ -14,6 +14,7 @@ describe VagrantPlugins::HyperV::Provider do stub_const("Vagrant::Util::PowerShell", powershell) allow(machine).to receive(:id).and_return("foo") allow(platform).to receive(:windows?).and_return(true) + allow(platform).to receive(:wsl?).and_return(false) allow(platform).to receive(:windows_admin?).and_return(true) allow(platform).to receive(:windows_hyperv_admin?).and_return(true) allow(powershell).to receive(:available?).and_return(true) @@ -27,6 +28,12 @@ describe VagrantPlugins::HyperV::Provider do expect(subject).to_not be_usable end + it "returns true if within WSL" do + expect(platform).to receive(:windows?).and_return(false) + expect(platform).to receive(:wsl?).and_return(true) + expect(subject).to be_usable + end + it "returns false if neither an admin nor a hyper-v admin" do allow(platform).to receive(:windows_admin?).and_return(false) allow(platform).to receive(:windows_hyperv_admin?).and_return(false) diff --git a/test/unit/vagrant/util/powershell_test.rb b/test/unit/vagrant/util/powershell_test.rb index b00c9bcd0..00c544427 100644 --- a/test/unit/vagrant/util/powershell_test.rb +++ b/test/unit/vagrant/util/powershell_test.rb @@ -63,7 +63,10 @@ describe Vagrant::Util::PowerShell do end context "when within WSL" do - before{ expect(Vagrant::Util::Platform).to receive(:wsl?).and_return(true) } + before do + allow(Vagrant::Util::Which).to receive(:which).with(/powershell/).and_return(nil) + expect(Vagrant::Util::Platform).to receive(:wsl?).and_return(true) + end it "should check PATH with .exe extension" do expect(Vagrant::Util::Which).to receive(:which).with("powershell.exe") @@ -76,9 +79,13 @@ describe Vagrant::Util::PowerShell do end it "should return nil when not found" do - expect(Vagrant::Util::Which).to receive(:which).with("powershell.exe").and_return(nil) expect(described_class.executable).to be_nil end + + it "should check for powershell with full path" do + expect(Vagrant::Util::Which).to receive(:which).with(/Windows\/System32.+powershell.exe/) + described_class.executable + end end end end