Merge pull request #8582 from chrisroberts/updates/wsl

Update WSL integration
This commit is contained in:
Chris Roberts 2017-05-12 15:08:29 -07:00 committed by GitHub
commit 6c83743980
9 changed files with 157 additions and 47 deletions

View File

@ -121,7 +121,11 @@ begin
# some extra setup to allow access to Vagrant managed machines # some extra setup to allow access to Vagrant managed machines
# outside the subsystem # outside the subsystem
if Vagrant::Util::Platform.wsl? if Vagrant::Util::Platform.wsl?
Vagrant::Util::Platform.wsl_init(env, logger) recreate_env = Vagrant::Util::Platform.wsl_init(env, logger)
if recreate_env
logger.info("Re-creating Vagrant environment due to WSL modifications.")
env = Vagrant::Environment.new(opts)
end
end end
if !Vagrant.in_installer? && !Vagrant.very_quiet? if !Vagrant.in_installer? && !Vagrant.very_quiet?

View File

@ -899,5 +899,9 @@ module Vagrant
class WSLVagrantAccessError < VagrantError class WSLVagrantAccessError < VagrantError
error_key(:wsl_vagrant_access_error) error_key(:wsl_vagrant_access_error)
end end
class WSLVirtualBoxWindowsAccessError < VagrantError
error_key(:wsl_virtualbox_windows_access)
end
end end
end end

View File

@ -4,15 +4,18 @@ module Vagrant
autoload :CommandDeprecation, 'vagrant/util/command_deprecation' autoload :CommandDeprecation, 'vagrant/util/command_deprecation'
autoload :Counter, 'vagrant/util/counter' autoload :Counter, 'vagrant/util/counter'
autoload :CredentialScrubber, 'vagrant/util/credential_scrubber' autoload :CredentialScrubber, 'vagrant/util/credential_scrubber'
autoload :DeepMerge, 'vagrant/util/deep_merge'
autoload :Env, 'vagrant/util/env' autoload :Env, 'vagrant/util/env'
autoload :HashWithIndifferentAccess, 'vagrant/util/hash_with_indifferent_access' autoload :HashWithIndifferentAccess, 'vagrant/util/hash_with_indifferent_access'
autoload :GuestInspection, 'vagrant/util/guest_inspection' autoload :GuestInspection, 'vagrant/util/guest_inspection'
autoload :Platform, 'vagrant/util/platform' autoload :Platform, 'vagrant/util/platform'
autoload :Retryable, 'vagrant/util/retryable' autoload :Retryable, 'vagrant/util/retryable'
autoload :SafeExec, 'vagrant/util/safe_exec' autoload :SafeExec, 'vagrant/util/safe_exec'
autoload :SilenceWarnings, 'vagrant/util/silence_warnings'
autoload :StackedProcRunner, 'vagrant/util/stacked_proc_runner' autoload :StackedProcRunner, 'vagrant/util/stacked_proc_runner'
autoload :TemplateRenderer, 'vagrant/util/template_renderer'
autoload :StringBlockEditor, 'vagrant/util/string_block_editor' autoload :StringBlockEditor, 'vagrant/util/string_block_editor'
autoload :Subprocess, 'vagrant/util/subprocess' autoload :Subprocess, 'vagrant/util/subprocess'
autoload :TemplateRenderer, 'vagrant/util/template_renderer'
autoload :Which, 'vagrant/util/which'
end end
end end

View File

@ -249,13 +249,52 @@ module Vagrant
wsl? && !path.to_s.downcase.start_with?("/mnt/") wsl? && !path.to_s.downcase.start_with?("/mnt/")
end end
# Convert a WSL path to the local Windows path. This is useful
# for conversion when calling out to Windows executables from
# the WSL
#
# @param [String, Pathname] path Path to convert
# @return [String]
def wsl_to_windows_path(path)
if wsl? && wsl_windows_access?
if wsl_path?(path)
parts = path.split("/")
parts.delete_if(&:empty?)
[wsl_windows_appdata_local, "lxss", *parts].join("\\")
else
path = path.to_s.sub("/mnt/", "")
parts = path.split("/")
parts.first << ":"
path = parts.join("\\")
path
end
else
path
end
end
# Automatically convert a given path to a Windows path. Will only
# be applied if running on a Windows host. If running on Windows
# host within the WSL, the actual Windows path will be returned.
#
# @param [Pathname, String] path Path to convert
# @return [String]
def windows_path(path)
path = cygwin_windows_path(path)
path = wsl_to_windows_path(path)
if windows? || wsl?
path = windows_unc_path(path)
end
path
end
# Allow Vagrant to access Vagrant managed machines outside the # Allow Vagrant to access Vagrant managed machines outside the
# Windows Subsystem for Linux # Windows Subsystem for Linux
# #
# @return [Boolean] # @return [Boolean]
def wsl_windows_access? def wsl_windows_access?
if !defined?(@_wsl_windows_access) if !defined?(@_wsl_windows_access)
@_wsl_windows_access = wsl? && ENV["VAGRANT_WSL_ACCESS_WINDOWS_USER"] @_wsl_windows_access = wsl? && ENV["VAGRANT_WSL_ENABLE_WINDOWS_ACCESS"]
end end
@_wsl_windows_access @_wsl_windows_access
end end
@ -266,8 +305,12 @@ module Vagrant
# @return [Pathname] # @return [Pathname]
def wsl_windows_accessible_path def wsl_windows_accessible_path
if !defined?(@_wsl_windows_accessible_path) if !defined?(@_wsl_windows_accessible_path)
access_path = ENV.fetch("VAGRANT_WSL_ACCESS_WINDOWS_USER_HOME_PATH", access_path = ENV["VAGRANT_WSL_WINDOWS_ACCESS_USER_HOME_PATH"]
"/mnt/c/Users/#{ENV["VAGRANT_WSL_ACCESS_WINDOWS_USER"]}") if access_path.to_s.empty?
access_path = wsl_windows_home.gsub("\\", "/").sub(":", "")
access_path[0] = access_path[0].downcase
access_path = "/mnt/#{access_path}"
end
@_wsl_windows_accessible_path = Pathname.new(access_path) @_wsl_windows_accessible_path = Pathname.new(access_path)
end end
@_wsl_windows_accessible_path @_wsl_windows_accessible_path
@ -290,9 +333,12 @@ module Vagrant
# @param [Logger] logger Optional logger to display information # @param [Logger] logger Optional logger to display information
def wsl_init(env, logger=nil) def wsl_init(env, logger=nil)
if wsl? if wsl?
if ENV["VAGRANT_WSL_ACCESS_WINDOWS_USER"] if ENV["VAGRANT_WSL_ENABLE_WINDOWS_ACCESS"]
wsl_validate_matching_vagrant_versions! wsl_validate_matching_vagrant_versions!
shared_user = ENV["VAGRANT_WSL_ACCESS_WINDOWS_USER"] shared_user = ENV["VAGRANT_WSL_WINDOWS_ACCESS_USER"]
if shared_user.to_s.empty?
shared_user = wsl_windows_username
end
if logger if logger
logger.warn("Windows Subsystem for Linux detected. Allowing access to user: #{shared_user}") 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.") logger.warn("Vagrant will be allowed to control Vagrant managed machines within the user's home path.")
@ -300,11 +346,12 @@ module Vagrant
if ENV["VAGRANT_HOME"] || ENV["VAGRANT_WSL_DISABLE_VAGRANT_HOME"] if ENV["VAGRANT_HOME"] || ENV["VAGRANT_WSL_DISABLE_VAGRANT_HOME"]
logger.warn("VAGRANT_HOME environment variable already set. Not overriding!") if logger logger.warn("VAGRANT_HOME environment variable already set. Not overriding!") if logger
else else
home_path = wsl_windows_accessible_path home_path = wsl_windows_accessible_path.to_s
ENV["VAGRANT_HOME"] = File.join(home_path, ".vagrant.d") ENV["VAGRANT_HOME"] = File.join(home_path, ".vagrant.d")
if logger if logger
logger.info("Overriding VAGRANT_HOME environment variable to configured windows user. (#{ENV["VAGRANT_HOME"]})") logger.info("Overriding VAGRANT_HOME environment variable to configured windows user. (#{ENV["VAGRANT_HOME"]})")
end end
true
end end
else else
if env.local_data_path.to_s.start_with?("/mnt/") if env.local_data_path.to_s.start_with?("/mnt/")
@ -314,6 +361,45 @@ module Vagrant
end end
end end
# Fetch the Windows username currently in use
#
# @return [String, Nil]
def wsl_windows_username
if !@_wsl_windows_username
result = Util::Subprocess.execute("cmd.exe", "/c", "echo %USERNAME%")
if result.exit_code == 0
@_wsl_windows_username = result.stdout.strip
end
end
@_wsl_windows_username
end
# Fetch the Windows user home directory
#
# @return [String, Nil]
def wsl_windows_home
if !@_wsl_windows_home
result = Util::Subprocess.execute("cmd.exe", "/c" "echo %USERPROFILE%")
if result.exit_code == 0
@_wsl_windows_home = result.stdout.gsub("\"", "").strip
end
end
@_wsl_windows_home
end
# Fetch the Windows user local app data directory
#
# @return [String, Nil]
def wsl_windows_appdata_local
if !@_wsl_windows_appdata_local
result = Util::Subprocess.execute("cmd.exe", "/c", "echo %LOCALAPPDATA%")
if result.exit_code == 0
@_wsl_windows_appdata_local = result.stdout.gsub("\"", "").strip
end
end
@_wsl_windows_appdata_local
end
# Confirm Vagrant versions installed within the WSL and the Windows system # Confirm Vagrant versions installed within the WSL and the Windows system
# are the same. Raise error if they do not match. # are the same. Raise error if they do not match.
def wsl_validate_matching_vagrant_versions! def wsl_validate_matching_vagrant_versions!

View File

@ -45,7 +45,19 @@ module VagrantPlugins
run_cmd += expose.map { |p| ['--expose', "#{p}"] } run_cmd += expose.map { |p| ['--expose', "#{p}"] }
run_cmd += links.map { |k, v| ['--link', "#{k}:#{v}"] } run_cmd += links.map { |k, v| ['--link', "#{k}:#{v}"] }
run_cmd += ports.map { |p| ['-p', p.to_s] } run_cmd += ports.map { |p| ['-p', p.to_s] }
run_cmd += volumes.map { |v| ['-v', v.to_s] } run_cmd += volumes.map { |v|
v = v.to_s
if v.include?(":") && (Vagrant::Util::Platform.windows? || Vagrant::Util::Platform.wsl?)
host, guest = v.split(":", 2)
host = Vagrant::Util::Platform.windows_path(host)
# NOTE: Docker does not support UNC style paths (which also
# means that there's no long path support). Hopefully this
# will be fixed someday and the gsub below can be removed.
host.gsub!(/^[^A-Za-z]+/, "")
v = [host, guest].join(":")
end
['-v', v.to_s]
}
run_cmd += %W(--privileged) if params[:privileged] run_cmd += %W(--privileged) if params[:privileged]
run_cmd += %W(-h #{params[:hostname]}) if params[:hostname] run_cmd += %W(-h #{params[:hostname]}) if params[:hostname]
run_cmd << "-t" if params[:pty] run_cmd << "-t" if params[:pty]

View File

@ -67,6 +67,10 @@ module VagrantPlugins
end end
end end
elsif Vagrant::Util::Platform.wsl? elsif Vagrant::Util::Platform.wsl?
if !Vagrant::Util::Platform.wsl_windows_access?
@logger.error("No user Windows access defined for the Windows Subsystem for Linux. This is required for VirtualBox.")
raise Vagrant::Errors::WSLVirtualBoxWindowsAccessError
end
@logger.debug("Linux platform detected but executing within WSL. Locating VBoxManage.") @logger.debug("Linux platform detected but executing within WSL. Locating VBoxManage.")
@vboxmanage_path = Vagrant::Util::Which.which("VBoxManage") || Vagrant::Util::Which.which("VBoxManage.exe") @vboxmanage_path = Vagrant::Util::Which.which("VBoxManage") || Vagrant::Util::Which.which("VBoxManage.exe")
if !@vboxmanage_path if !@vboxmanage_path

View File

@ -270,7 +270,7 @@ module VagrantPlugins
end end
def import(ovf) def import(ovf)
ovf = Vagrant::Util::Platform.cygwin_windows_path(ovf) ovf = Vagrant::Util::Platform.windows_path(ovf)
output = "" output = ""
total = "" total = ""
@ -614,10 +614,7 @@ module VagrantPlugins
def share_folders(folders) def share_folders(folders)
folders.each do |folder| folders.each do |folder|
hostpath = folder[:hostpath] hostpath = Vagrant::Util::Platform.windows_path(folder[:hostpath])
if Vagrant::Util::Platform.windows?
hostpath = Vagrant::Util::Platform.windows_unc_path(hostpath)
end
args = ["--name", args = ["--name",
folder[:name], folder[:name],
"--hostpath", "--hostpath",

View File

@ -1538,7 +1538,14 @@ en:
please refer to the Vagrant documentation: please refer to the Vagrant documentation:
https://www.vagrantup.com/docs/other/wsl https://www.vagrantup.com/docs/other/wsl
wsl_virtualbox_windows_access: |-
Vagrant is unable to use the VirtualBox provider from the Windows Subsystem for
Linux without access to the Windows environment. Enabling this access must be
done with caution and an understanding of the implications. For more information
on enabing Windows access and using VirtualBox from the Windows Subsystem for
Linux, please refer to the Vagrant documentation:
https://www.vagrantup.com/docs/other/wsl
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# Translations for config validation errors # Translations for config validation errors
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------

View File

@ -68,43 +68,36 @@ Vagrant to access them.
## Windows Access ## Windows Access
Working within the WSL provides a layer of isolation from the actual 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 system. In most cases Vagrant will need access to the actual
Windows environment, and then transition to using Vagrant within the Windows system to function correctly. As most Vagrant providers will
WSL. Using Vagrant within the WSL will appear to be isolated from need to be installed on Windows directly (not within the WSL) Vagrant
the Windows system. A new `VAGRANT_HOME` directory will be created within will require Windows access. Access to the Windows system is controlled
the WSL (meaning all boxes will require re-downloading). Vagrant will also via an environment variable: `VAGRANT_WSL_ENABLE_WINDOWS_ACCESS`. If
lose the ability to control Vagrant managed machines within Windows (due this environment variable is set, Vagrant will access the Windows system
to user ID mismatches). to run executables and enable things like synced folders. When running
in a bash shell within WSL, the environment variable can be setup like so:
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 $ export VAGRANT_WSL_ENABLE_WINDOWS_ACCESS="1"
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 This will enable Vagrant to access the Windows system outside of the
modifies the Windows file system. It is for this reason that you must explicitly WSL and properly interact with Windows executables. This will automatically
enable this functionality with the express knowledge of the implication. If you modify the `VAGRANT_HOME` environment variable if it is not already defined,
are unsure of how this may affect your system, do not enable this feature. setting it to be within the user's home directory on Windows.
It is important to note that paths shared with the Windows system will
not have Linux permissions enforced. For example, when a directory within
the WSL is synced to a guest using the VirtualBox provider, any local
permissions defined on that directory (or its contents) will not be
visible from the guest. Likewise, any files created from the guest within
the synced folder will be world readable/writeable in WSL.
Other useful WSL related environment variables:
* `VAGRANT_WSL_WINDOWS_ACCESS_USER` - Override current Windows username
* `VAGRANT_WSL_DISABLE_VAGRANT_HOME` - Do not modify the `VAGRANT_HOME` variable
* `VAGRANT_WSL_WINDOWS_ACCESS_USER_HOME_PATH` - Custom Windows system home path
## Using Docker ## Using Docker