Merge pull request #9943 from chrisroberts/e-wsl-hyperv
Support Hyper-V provider within WSL
This commit is contained in:
commit
0134a235e7
|
@ -116,7 +116,7 @@ module Vagrant
|
||||||
# Extract the box into a temporary directory.
|
# Extract the box into a temporary directory.
|
||||||
@logger.debug("Unpacking box into temporary directory: #{temp_dir}")
|
@logger.debug("Unpacking box into temporary directory: #{temp_dir}")
|
||||||
result = Util::Subprocess.execute(
|
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
|
if result.exit_code != 0
|
||||||
raise Errors::BoxUnpackageFailure,
|
raise Errors::BoxUnpackageFailure,
|
||||||
output: result.stderr.to_s
|
output: result.stderr.to_s
|
||||||
|
|
|
@ -393,6 +393,7 @@ module Vagrant
|
||||||
# @return [String]
|
# @return [String]
|
||||||
def wsl_to_windows_path(path)
|
def wsl_to_windows_path(path)
|
||||||
if wsl? && wsl_windows_access? && !path.match(/^[a-zA-Z]:/)
|
if wsl? && wsl_windows_access? && !path.match(/^[a-zA-Z]:/)
|
||||||
|
path = File.expand_path(path.to_s)
|
||||||
if wsl_path?(path)
|
if wsl_path?(path)
|
||||||
parts = path.split("/")
|
parts = path.split("/")
|
||||||
parts.delete_if(&:empty?)
|
parts.delete_if(&:empty?)
|
||||||
|
@ -402,17 +403,15 @@ module Vagrant
|
||||||
if root_path.end_with?("lxss") && !(["root", "home"].include?(parts.first))
|
if root_path.end_with?("lxss") && !(["root", "home"].include?(parts.first))
|
||||||
root_path = "#{root_path}\\rootfs"
|
root_path = "#{root_path}\\rootfs"
|
||||||
end
|
end
|
||||||
[root_path, *parts].join("\\")
|
path = [root_path, *parts].join("\\")
|
||||||
else
|
else
|
||||||
path = path.to_s.sub("/mnt/", "")
|
path = path.to_s.sub("/mnt/", "")
|
||||||
parts = path.split("/")
|
parts = path.split("/")
|
||||||
parts.first << ":"
|
parts.first << ":"
|
||||||
path = parts.join("\\")
|
path = parts.join("\\")
|
||||||
path
|
|
||||||
end
|
end
|
||||||
else
|
|
||||||
path
|
|
||||||
end
|
end
|
||||||
|
path.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
# Takes a windows path and formats it to the
|
# Takes a windows path and formats it to the
|
||||||
|
|
|
@ -27,7 +27,11 @@ module Vagrant
|
||||||
@_powershell_executable += ".exe"
|
@_powershell_executable += ".exe"
|
||||||
|
|
||||||
if Which.which(@_powershell_executable).nil?
|
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
|
end
|
||||||
else
|
else
|
||||||
@_powershell_executable = nil
|
@_powershell_executable = nil
|
||||||
|
|
|
@ -9,6 +9,14 @@ module VagrantPlugins
|
||||||
def call(env)
|
def call(env)
|
||||||
env[:ui].info("Deleting the machine...")
|
env[:ui].info("Deleting the machine...")
|
||||||
env[:machine].provider.driver.delete_vm
|
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)
|
@app.call(env)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -23,7 +23,8 @@ module VagrantPlugins
|
||||||
|
|
||||||
def export
|
def export
|
||||||
@env[:ui].info I18n.t("vagrant.actions.vm.export.exporting")
|
@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].clear_line
|
||||||
@env[:ui].report_progress(progress.percent, 100, false)
|
@env[:ui].report_progress(progress.percent, 100, false)
|
||||||
end
|
end
|
||||||
|
|
|
@ -61,11 +61,11 @@ module VagrantPlugins
|
||||||
dest_path = env[:machine].data_dir.join("Virtual Hard Disks").join(image_path.basename).to_s
|
dest_path = env[:machine].data_dir.join("Virtual Hard Disks").join(image_path.basename).to_s
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
"VMConfigFile" => config_path.to_s.gsub("/", "\\"),
|
"VMConfigFile" => Vagrant::Util::Platform.wsl_to_windows_path(config_path).gsub("/", "\\"),
|
||||||
"DestinationPath" => dest_path.to_s.gsub("/", "\\"),
|
"DestinationPath" => Vagrant::Util::Platform.wsl_to_windows_path(dest_path).gsub("/", "\\"),
|
||||||
"DataPath" => env[:machine].data_dir.to_s.gsub("/", "\\"),
|
"DataPath" => Vagrant::Util::Platform.wsl_to_windows_path(env[:machine].data_dir).gsub("/", "\\"),
|
||||||
"LinkedClone" => !!env[:machine].provider_config.linked_clone,
|
"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,
|
"VMName" => env[:machine].provider_config.vmname,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -221,8 +221,8 @@ module VagrantPlugins
|
||||||
|
|
||||||
def execute_powershell(path, options, &block)
|
def execute_powershell(path, options, &block)
|
||||||
lib_path = Pathname.new(File.expand_path("../scripts", __FILE__))
|
lib_path = Pathname.new(File.expand_path("../scripts", __FILE__))
|
||||||
mod_path = lib_path.join("utils").to_s.gsub("/", "\\")
|
mod_path = Vagrant::Util::Platform.wsl_to_windows_path(lib_path.join("utils")).to_s.gsub("/", "\\")
|
||||||
path = lib_path.join(path).to_s.gsub("/", "\\")
|
path = Vagrant::Util::Platform.wsl_to_windows_path(lib_path.join(path)).to_s.gsub("/", "\\")
|
||||||
options = options || {}
|
options = options || {}
|
||||||
ps_options = []
|
ps_options = []
|
||||||
options.each do |key, value|
|
options.each do |key, value|
|
||||||
|
@ -239,8 +239,9 @@ module VagrantPlugins
|
||||||
# Include our module path so we can nicely load helper modules
|
# Include our module path so we can nicely load helper modules
|
||||||
opts = {
|
opts = {
|
||||||
notify: [:stdout, :stderr, :stdin],
|
notify: [:stdout, :stderr, :stdin],
|
||||||
env: {"PSModulePath" => "$env:PSModulePath+';#{mod_path}'"}
|
module_path: mod_path
|
||||||
}
|
}
|
||||||
|
|
||||||
Vagrant::Util::PowerShell.execute(path, *ps_options, **opts, &block)
|
Vagrant::Util::PowerShell.execute(path, *ps_options, **opts, &block)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,11 +12,12 @@ module VagrantPlugins
|
||||||
attr_reader :driver
|
attr_reader :driver
|
||||||
|
|
||||||
def self.usable?(raise_error=false)
|
def self.usable?(raise_error=false)
|
||||||
if !Vagrant::Util::Platform.windows?
|
if !Vagrant::Util::Platform.windows? &&
|
||||||
|
!Vagrant::Util::Platform.wsl?
|
||||||
raise Errors::WindowsRequired
|
raise Errors::WindowsRequired
|
||||||
end
|
end
|
||||||
|
|
||||||
if !Vagrant::Util::Platform.windows_admin? and
|
if !Vagrant::Util::Platform.windows_admin? &&
|
||||||
!Vagrant::Util::Platform.windows_hyperv_admin?
|
!Vagrant::Util::Platform.windows_hyperv_admin?
|
||||||
raise Errors::AdminRequired
|
raise Errors::AdminRequired
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
# Always stop when errors are encountered unless instructed not to
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
# Vagrant VM creation functions
|
# Vagrant VM creation functions
|
||||||
|
|
||||||
function New-VagrantVM {
|
function New-VagrantVM {
|
||||||
|
@ -123,7 +126,7 @@ function New-VagrantVMVMCX {
|
||||||
$Path = $Drive.Path
|
$Path = $Drive.Path
|
||||||
Hyper-V\Remove-VMHardDiskDrive $Drive
|
Hyper-V\Remove-VMHardDiskDrive $Drive
|
||||||
Hyper-V\New-VHD -Path $DestinationPath -ParentPath $SourcePath
|
Hyper-V\New-VHD -Path $DestinationPath -ParentPath $SourcePath
|
||||||
Hyper-V\AddVMHardDiskDrive -VM $VM -Path $DestinationPath
|
Hyper-V\Add-VMHardDiskDrive -VM $VM -Path $DestinationPath
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
en:
|
en:
|
||||||
vagrant_sf_smb:
|
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: |-
|
||||||
Mounting SMB shared folders...
|
Mounting SMB shared folders...
|
||||||
mounting_single: |-
|
mounting_single: |-
|
||||||
|
@ -26,6 +21,11 @@ en:
|
||||||
Vagrant requires administrator access to create SMB shares and
|
Vagrant requires administrator access to create SMB shares and
|
||||||
may request access to complete setup of configured shares.
|
may request access to complete setup of configured shares.
|
||||||
errors:
|
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: |-
|
start_failed: |-
|
||||||
Vagrant failed to automatically start the SMB service. Ensure the
|
Vagrant failed to automatically start the SMB service. Ensure the
|
||||||
required services can be started and try again.
|
required services can be started and try again.
|
||||||
|
|
|
@ -8,13 +8,15 @@ describe VagrantPlugins::HyperV::Action::DeleteVM do
|
||||||
let(:ui){ double("ui") }
|
let(:ui){ double("ui") }
|
||||||
let(:provider){ double("provider", driver: driver) }
|
let(:provider){ double("provider", driver: driver) }
|
||||||
let(:driver){ double("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) }
|
let(:subject){ described_class.new(app, env) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow(app).to receive(:call)
|
allow(app).to receive(:call)
|
||||||
allow(ui).to receive(:info)
|
allow(ui).to receive(:info)
|
||||||
allow(driver).to receive(:delete_vm)
|
allow(driver).to receive(:delete_vm)
|
||||||
|
allow(FileUtils).to receive(:rm_rf)
|
||||||
|
allow(FileUtils).to receive(:mkdir_p)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should call the app on success" do
|
it "should call the app on success" do
|
||||||
|
@ -26,4 +28,14 @@ describe VagrantPlugins::HyperV::Action::DeleteVM do
|
||||||
expect(driver).to receive(:delete_vm)
|
expect(driver).to receive(:delete_vm)
|
||||||
subject.call(env)
|
subject.call(env)
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -144,8 +144,7 @@ describe VagrantPlugins::HyperV::Driver do
|
||||||
it "should automatically include module path" do
|
it "should automatically include module path" do
|
||||||
expect(Vagrant::Util::PowerShell).to receive(:execute) do |path, *args|
|
expect(Vagrant::Util::PowerShell).to receive(:execute) do |path, *args|
|
||||||
opts = args.detect{|i| i.is_a?(Hash)}
|
opts = args.detect{|i| i.is_a?(Hash)}
|
||||||
expect(opts[:env]).not_to be_nil
|
expect(opts[:module_path]).not_to be_nil
|
||||||
expect(opts[:env]["PSModulePath"]).to include("$env:PSModulePath+")
|
|
||||||
end
|
end
|
||||||
subject.send(:execute_powershell, "path", {})
|
subject.send(:execute_powershell, "path", {})
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,6 +14,7 @@ describe VagrantPlugins::HyperV::Provider do
|
||||||
stub_const("Vagrant::Util::PowerShell", powershell)
|
stub_const("Vagrant::Util::PowerShell", powershell)
|
||||||
allow(machine).to receive(:id).and_return("foo")
|
allow(machine).to receive(:id).and_return("foo")
|
||||||
allow(platform).to receive(:windows?).and_return(true)
|
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_admin?).and_return(true)
|
||||||
allow(platform).to receive(:windows_hyperv_admin?).and_return(true)
|
allow(platform).to receive(:windows_hyperv_admin?).and_return(true)
|
||||||
allow(powershell).to receive(:available?).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
|
expect(subject).to_not be_usable
|
||||||
end
|
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
|
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_admin?).and_return(false)
|
||||||
allow(platform).to receive(:windows_hyperv_admin?).and_return(false)
|
allow(platform).to receive(:windows_hyperv_admin?).and_return(false)
|
||||||
|
|
|
@ -63,7 +63,10 @@ describe Vagrant::Util::PowerShell do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when within WSL" do
|
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
|
it "should check PATH with .exe extension" do
|
||||||
expect(Vagrant::Util::Which).to receive(:which).with("powershell.exe")
|
expect(Vagrant::Util::Which).to receive(:which).with("powershell.exe")
|
||||||
|
@ -76,9 +79,13 @@ describe Vagrant::Util::PowerShell do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should return nil when not found" do
|
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
|
expect(described_class.executable).to be_nil
|
||||||
end
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue