Merge pull request #9943 from chrisroberts/e-wsl-hyperv

Support Hyper-V provider within WSL
This commit is contained in:
Chris Roberts 2018-06-18 15:29:01 -07:00 committed by GitHub
commit 0134a235e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 69 additions and 27 deletions

View File

@ -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

View File

@ -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

View File

@ -26,9 +26,13 @@ module Vagrant
if Platform.wsl?
@_powershell_executable += ".exe"
if Which.which(@_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
end

View File

@ -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

View File

@ -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

View File

@ -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,
}

View File

@ -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

View File

@ -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

View File

@ -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
}
}

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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