Merge pull request #8570 from chrisroberts/enhancement/wsl-support

Add support for running within WSL
This commit is contained in:
Chris Roberts 2017-05-10 13:50:47 -07:00 committed by GitHub
commit 37901cd43c
10 changed files with 298 additions and 10 deletions

View File

@ -117,6 +117,13 @@ begin
logger.debug("Creating Vagrant environment")
env = Vagrant::Environment.new(opts)
# If we are running with the Windows Subsystem for Linux do
# some extra setup to allow access to Vagrant managed machines
# outside the subsystem
if Vagrant::Util::Platform.wsl?
Vagrant::Util::Platform.wsl_init(env, logger)
end
if !Vagrant.in_installer? && !Vagrant.very_quiet?
# If we're not in the installer, warn.
env.ui.warn(I18n.t("vagrant.general.not_in_installer") + "\n", prefix: false)

View File

@ -780,6 +780,10 @@ module Vagrant
error_key(:vboxmanage_not_found_error)
end
class VBoxManageNotFoundWSLError < VagrantError
error_key(:vboxmanage_not_found_wsl_error)
end
class VirtualBoxBrokenVersion040214 < VagrantError
error_key(:virtualbox_broken_version_040214)
end
@ -887,5 +891,13 @@ module Vagrant
class VMPowerOffToPackage < VagrantError
error_key(:power_off, "vagrant.actions.vm.export")
end
class WSLVagrantVersionMismatch < VagrantError
error_key(:wsl_vagrant_version_mismatch)
end
class WSLVagrantAccessError < VagrantError
error_key(:wsl_vagrant_access_error)
end
end
end

View File

@ -28,6 +28,23 @@ module Vagrant
return @_cygwin
end
def wsl?
if !defined?(@_wsl)
@_wsl = false
SilenceWarnings.silence! do
# Use PATH values to check for `/mnt/c` path indicative of WSL
if ENV.fetch("PATH", "").downcase.include?("/mnt/c")
# Validate WSL via uname output
uname = Subprocess.execute("uname", "-r")
if uname.exit_code == 0 && uname.stdout.downcase.include?("microsoft")
@_wsl = true
end
end
end
end
@_wsl
end
[:darwin, :bsd, :freebsd, :linux, :solaris].each do |type|
define_method("#{type}?") do
platform.include?(type.to_s)
@ -223,6 +240,99 @@ module Vagrant
return @_platform
end
# Determine if given path is within the WSL rootfs. Returns
# true if within the subsystem, or false if outside the subsystem.
#
# @param [String] path Path to check
# @return [Boolean] path is within subsystem
def wsl_path?(path)
wsl? && !path.to_s.downcase.start_with?("/mnt/")
end
# Allow Vagrant to access Vagrant managed machines outside the
# Windows Subsystem for Linux
#
# @return [Boolean]
def wsl_windows_access?
if !defined?(@_wsl_windows_access)
@_wsl_windows_access = wsl? && ENV["VAGRANT_WSL_ACCESS_WINDOWS_USER"]
end
@_wsl_windows_access
end
# The allowed windows system path Vagrant can manage from the Windows
# Subsystem for Linux
#
# @return [Pathname]
def wsl_windows_accessible_path
if !defined?(@_wsl_windows_accessible_path)
access_path = ENV.fetch("VAGRANT_WSL_ACCESS_WINDOWS_USER_HOME_PATH",
"/mnt/c/Users/#{ENV["VAGRANT_WSL_ACCESS_WINDOWS_USER"]}")
@_wsl_windows_accessible_path = Pathname.new(access_path)
end
@_wsl_windows_accessible_path
end
# Checks given path to determine if Vagrant is allowed to bypass checks
#
# @param [String] path Path to check
# @return [Boolean] Vagrant is allowed to bypass checks
def wsl_windows_access_bypass?(path)
wsl? && wsl_windows_access? &&
path.to_s.start_with?(wsl_windows_accessible_path.to_s)
end
# If running within the Windows Subsystem for Linux, this will provide
# simple setup to allow sharing of the user's VAGRANT_HOME directory
# within the subsystem
#
# @param [Environment] env
# @param [Logger] logger Optional logger to display information
def wsl_init(env, logger=nil)
if wsl?
if ENV["VAGRANT_WSL_ACCESS_WINDOWS_USER"]
wsl_validate_matching_vagrant_versions!
shared_user = ENV["VAGRANT_WSL_ACCESS_WINDOWS_USER"]
if logger
logger.warn("Windows Subsystem for Linux detected. Allowing access to user: #{shared_user}")
logger.warn("Vagrant will be allowed to control Vagrant managed machines within the user's home path.")
end
if ENV["VAGRANT_HOME"] || ENV["VAGRANT_WSL_DISABLE_VAGRANT_HOME"]
logger.warn("VAGRANT_HOME environment variable already set. Not overriding!") if logger
else
home_path = wsl_windows_accessible_path
ENV["VAGRANT_HOME"] = File.join(home_path, ".vagrant.d")
if logger
logger.info("Overriding VAGRANT_HOME environment variable to configured windows user. (#{ENV["VAGRANT_HOME"]})")
end
end
else
if env.local_data_path.to_s.start_with?("/mnt/")
raise Vagrant::Errors::WSLVagrantAccessError
end
end
end
end
# Confirm Vagrant versions installed within the WSL and the Windows system
# are the same. Raise error if they do not match.
def wsl_validate_matching_vagrant_versions!
valid = false
result = Util::Subprocess.execute("vagrant.exe", "version")
if result.exit_code == 0
windows_version = result.stdout.match(/Installed Version: (?<version>.+$)/)
if windows_version
windows_version = windows_version[:version].strip
valid = windows_version == Vagrant::VERSION
end
end
if !valid
raise Vagrant::Errors::WSLVagrantVersionMismatch,
wsl_version: Vagrant::VERSION,
windows_version: windows_version || "unknown"
end
end
# @private
# Reset the cached values for platform. This is not considered a public
# API and should only be used for testing.

View File

@ -28,7 +28,7 @@ module Vagrant
def self.check_key_permissions(key_path)
# Don't do anything if we're on Windows, since Windows doesn't worry
# about key permissions.
return if Platform.windows?
return if Platform.windows? || Platform.wsl_windows_access_bypass?(key_path)
LOGGER.debug("Checking key permissions: #{key_path}")
stat = key_path.stat

View File

@ -29,12 +29,14 @@ module Vagrant
exts = ENV['PATHEXT'].split(';')
end
SilenceWarnings.silence! do
ENV['PATH'].encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '').split(File::PATH_SEPARATOR).each do |path|
exts.each do |ext|
exe = "#{path}#{File::SEPARATOR}#{cmd}#{ext}"
return exe if File.executable? exe
end
end
end
return nil
end

View File

@ -66,6 +66,12 @@ module VagrantPlugins
break
end
end
elsif Vagrant::Util::Platform.wsl?
@logger.debug("Linux platform detected but executing within WSL. Locating VBoxManage.")
@vboxmanage_path = Vagrant::Util::Which.which("VBoxManage") || Vagrant::Util::Which.which("VBoxManage.exe")
if !@vboxmanage_path
raise Vagrant::Errors::VBoxManageNotFoundWSLError
end
end
# Fall back to hoping for the PATH to work out

View File

@ -84,12 +84,16 @@ module VagrantPlugins
def state
# We have to check if the UID matches to avoid issues with
# VirtualBox.
if Vagrant::Util::Platform.wsl_windows_access_bypass?(@machine.data_dir)
@logger.warn("Skipping UID check on machine by user request for WSL Windows access.")
else
uid = @machine.uid
if uid && uid.to_s != Process.uid.to_s
raise Vagrant::Errors::VirtualBoxUserMismatch,
original_uid: uid.to_s,
uid: Process.uid.to_s
end
end
# Determine the ID of the state here.
state_id = nil

View File

@ -1381,6 +1381,16 @@ en:
log out and log back in for the new environmental variables to take
effect. If you're on Linux or Mac, verify your PATH contains the folder
that has VBoxManage in it.
vboxmanage_not_found_wsl_error: |-
The "VBoxManage.exe" command or one of its dependencies could not
be found. Please verify VirtualBox is properly installed. You can verify
everything is okay by running "VBoxManage.exe --version" and verifying
that the VirtualBox version is outputted.
If you just installed VirtualBox, you have to log out and log back in for
the new environmental variables to take effect. Using the VirtualBox
provider within the WSL requires VirtualBox executables to be available
on the system PATH.
virtualbox_broken_version_040214: |-
Vagrant detected you have VirtualBox 4.2.14 installed. VirtualBox
4.2.14 contains a critical bug which prevents it from working with
@ -1510,6 +1520,24 @@ en:
VM must be running to open SSH connection. Run `vagrant up`
to start the virtual machine.
test_key: "test value"
wsl_vagrant_version_mismatch: |-
Vagrant cannot currently enable access to manage machines within the Windows
environment because the version of Vagrant installed on Windows does not
match this version of Vagrant running within the Windows Subsystem for Linux.
Please ensure both installation of Vagrant are the same. If you do not want
update your Vagrant installations you can disable Windows access by unsetting
the `VAGRANT_WSL_ACCESS_WINDOWS_USER` environment variable.
Windows Vagrant version: %{windows_version}
Windows Subsystem for Linux Vagrant version: %{wsl_version}
wsl_vagrant_access_error: |-
Vagrant will not operate outside the Windows Subsystem for Linux unless explicitly
instructed. Due to the inability to enforce expected Linux file ownership and
permissions on the Windows system, Vagrant will not make modifications to prevent
unexpected errors. To learn more about this, and the options that are available,
please refer to the Vagrant documentation:
https://www.vagrantup.com/docs/other/wsl
#-------------------------------------------------------------------------------
# Translations for config validation errors

View File

@ -0,0 +1,118 @@
---
layout: "docs"
page_title: "Vagrant and Windows Subsystem for Linux"
sidebar_current: "other-wsl"
description: |-
An overview of using Vagrant on Windows within the Windows Subsystem
for Linux.
---
# Vagrant and Windows Subsystem for Linux
Windows has recently introduced a new feature called the Windows Subsystem
for Linux (WSL). This is a beta feature available in developer mode on recent
releases of Windows 10. It is important to note that this feature is still
in _beta_ on Windows, and Vagrant support should be considered _alpha_.
<div class="alert alert-warning">
<strong>Warning: Advanced Topic!</strong> Using Vagrant within the Windows
Subsystem for Linux is an advanced topic that only experienced Vagrant users
who are reasonably comfortable with Windows, WSL, and Linux should approach.
</div>
# Installation
Installation requires WSL, Ubuntu on Windows, and Vagrant. Read on for installation
instructions for each item.
## Windows Subsystem for Linux and Ubuntu on Windows
First install the Windows Subsystem for Linux, followed by Ubuntu on Windows. This guide
from Microsoft walks through the process:
* https://msdn.microsoft.com/en-us/commandline/wsl/install_guide
## Vagrant Installation
Vagrant _must_ be installed within Ubuntu on Windows. Even though the `vagrant.exe`
file can be executed from within the WSL, it will not function as expected. To
install Vagrant into the WSL, follow these steps:
* Download the 64-bit Debian package from the downloads page.
* Open a `cmd` or `powershell` window
* Enter the command: `bash`
* Install vagrant: `sudo dpkg -i vagrant_VERSION_x86_64.deb`
```
C:\Users\vagrant> bash
vagrant@vagrant-10:/mnt/c/Users/vagrant$ sudo dpkg -i vagrant_VERSION_x86_64.deb
[sudo] password for vagrant:
(Reading database ... 31885 files and directories currently installed.)
Preparing to unpack vagrant_VERSION_x86_64.deb ...
Unpacking vagrant (1:VERSION) ...
Setting up vagrant (1:VERSION) ...
vagrant@vagrant-10:/mnt/c/Users/vagrant$ vagrant help
Usage: vagrant [options] <command> [<args>]
```
# Vagrant Usage
Vagrant will detect when it is being run within the WSL and adjust how it
locates and executes third party executables. For example, when using the
VirtualBox provider Vagrant will interact with VirtualBox installed on
the Windows system, not within the WSL. It is important to ensure that
any required Windows executable is available within your `PATH` to allow
Vagrant to access them.
## Windows Access
Working within the WSL provides a layer of isolation from the actual
Windows system. In some cases, a user may be using Vagrant in a regular
Windows environment, and then transition to using Vagrant within the
WSL. Using Vagrant within the WSL will appear to be isolated from
the Windows system. A new `VAGRANT_HOME` directory will be created within
the WSL (meaning all boxes will require re-downloading). Vagrant will also
lose the ability to control Vagrant managed machines within Windows (due
to user ID mismatches).
Vagrant supports enabling user access to provide seamless behavior and
control between Vagrant on Windows and Vagrant on WSL. By setting the
`VAGRANT_WSL_ACCESS_WINDOWS_USER` environment variable, Vagrant will
allow access to Vagrant managed machines in that user's home path in
Windows (`C:\Users\vagrant` for example), as well as share the `VAGRANT_HOME`
directory. Below is a demonstration of the behavior:
```
C:\Users\vagrant> bash
vagrant@vagrant-10:/mnt/c/Users/vagrant$ mkdir test
vagrant@vagrant-10:/mnt/c/Users/vagrant$ cd test
vagrant@vagrant-10:/mnt/c/Users/vagrant/test$ vagrant init hashicorp/precisec4
vagrant@vagrant-10:/mnt/c/Users/vagrant$ vagrant up
Vagrant will not operate outside the Windows Subsystem for Linux unless explicitly
instructed. Due to the inability to enforce expected Linux file ownership and
permissions on the Windows system, Vagrant will not make modifications to prevent
unexpected errors. To learn more about this, and the options that are available,
please refer to the Vagrant documentation:
https://www.vagrantup.com/docs/other/wsl
vagrant@vagrant-10:/mnt/c/Users/vagrant$ export VAGRANT_WSL_ACCESS_WINDOWS_USER=vagrant
vagrant@vagrant-10:/mnt/c/Users/vagrant$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
```
It is important to note that file permissions cannot be enforced when Vagrant
modifies the Windows file system. It is for this reason that you must explicitly
enable this functionality with the express knowledge of the implication. If you
are unsure of how this may affect your system, do not enable this feature.
## Using Docker
The docker daemon cannot be run inside the Windows Subsystem for Linux. However,
the daemon _can_ be run on Windows and accessed by Vagrant while running in the
WSL. Once docker is installed and running on Windows, export the following
environment variable to give Vagrant access:
```
$ vagrant@vagrant-10:/mnt/c/Users/vagrant$ export DOCKER_HOST=tcp://127.0.0.1:2375
```

View File

@ -211,6 +211,7 @@
<ul class="nav">
<li<%= sidebar_current("other-debugging") %>><a href="/docs/other/debugging.html">Debugging</a></li>
<li<%= sidebar_current("other-envvars") %>><a href="/docs/other/environmental-variables.html">Environmental Variables</a></li>
<li<%= sidebar_current("other-wsl") %>><a href="/docs/other/wsl.html">WSL</a></li>
</ul>
</li>
</ul>