Adds Hyper-V synced folder plugin

This PR adds synced folder plugin for Hyper-V provider. This plugin
leverages Hyper-V daemons (hv_fcopy_daemon) to sync files from host
in a realiable way for supported guest operation systems over SMB
and rsync.
This commit is contained in:
Zhongcheng Lao 2019-06-19 19:16:01 +08:00
parent 7e0e7ff7e9
commit 38bbe2ba8a
23 changed files with 900 additions and 1 deletions

View File

@ -388,6 +388,10 @@ module Vagrant
error_key(:hyperv_virtualbox_error)
end
class HypervNotSupported < VagrantError
error_key(:hyperv_not_supported)
end
class ForwardPortAdapterNotFound < VagrantError
error_key(:forward_port_adapter_not_found)
end

View File

@ -0,0 +1,64 @@
module Vagrant
module Util
module HypervDaemons
HYPERV_DAEMON_SERVICES = %i[kvp vss fcopy]
def hyperv_daemons_activate(machine)
result = HYPERV_DAEMON_SERVICES.map do |service|
hyperv_daemon_activate machine, service
end
result.all?
end
def hyperv_daemon_activate(machine, service)
comm = machine.communicate
service_name = hyperv_service_name(machine, service)
return false unless comm.test("systemctl enable #{service_name}",
sudo: true)
return false unless comm.test("systemctl restart #{service_name}",
sudo: true)
hyperv_daemon_running machine, service
end
def hyperv_daemons_running(machine)
result = HYPERV_DAEMON_SERVICES.map do |service|
hyperv_daemon_running machine, service
end
result.all?
end
def hyperv_daemon_running(machine, service)
comm = machine.communicate
service_name = hyperv_service_name(machine, service)
comm.test("systemctl -q is-active #{service_name}")
end
def hyperv_daemons_installed(machine)
result = HYPERV_DAEMON_SERVICES.map do |service|
hyperv_daemon_installed machine, service
end
result.all?
end
def hyperv_daemon_installed(machine, service)
comm = machine.communicate
daemon_name = hyperv_daemon_name(service)
comm.test("which #{daemon_name}")
end
protected
def hyperv_service_name(machine, service)
is_deb = machine.communicate.test("which apt-get")
separator = is_deb ? '-' : '_'
['hv', service.to_s, 'daemon'].join separator
end
def hyperv_daemon_name(service)
['hv', service.to_s, 'daemon'].join '_'
end
end
end
end

View File

@ -651,6 +651,19 @@ module Vagrant
@_wsl_windows_appdata_local
end
# Fetch the Windows temp directory
#
# @return [String, Nil]
def windows_temp
if !@_windows_temp
result = Util::Subprocess.execute("cmd.exe", "/c", "echo %TEMP%")
if result.exit_code == 0
@_windows_temp = result.stdout.gsub("\"", "").strip
end
end
@_windows_temp
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!

View File

@ -0,0 +1,19 @@
module VagrantPlugins
module GuestArch
module Cap
class HypervDaemons
def self.hyperv_daemons_installed(machine)
machine.communicate.test("pacman -Q hyperv")
end
def self.hyperv_daemons_install(machine)
comm = machine.communicate
comm.sudo <<-EOH.gsub(/^ {12}/, "")
pacman --noconfirm -Syy &&
pacman --noconfirm -S hyperv
EOH
end
end
end
end
end

View File

@ -45,6 +45,16 @@ module VagrantPlugins
require_relative "cap/smb"
Cap::SMB
end
guest_capability(:arch, :hyperv_daemons_installed) do
require_relative "cap/hyperv_daemons"
Cap::HypervDaemons
end
guest_capability(:arch, :hyperv_daemons_install) do
require_relative "cap/hyperv_daemons"
Cap::HypervDaemons
end
end
end
end

View File

@ -0,0 +1,19 @@
module VagrantPlugins
module GuestDebian
module Cap
class HypervDaemons
def self.hyperv_daemons_installed(machine)
machine.communicate.test('dpkg -s linux-cloud-tools-common', sudo: true)
end
def self.hyperv_daemons_install(machine)
comm = machine.communicate
comm.sudo <<-EOH.gsub(/^ {12}/, "")
DEBIAN_FRONTEND=noninteractive apt-get update -y &&
apt-get install -y -o Dpkg::Options::="--force-confdef" linux-cloud-tools-common
EOH
end
end
end
end
end

View File

@ -35,6 +35,16 @@ module VagrantPlugins
require_relative "cap/smb"
Cap::SMB
end
guest_capability(:debian, :hyperv_daemons_installed) do
require_relative "cap/hyperv_daemons"
Cap::HypervDaemons
end
guest_capability(:debian, :hyperv_daemons_install) do
require_relative "cap/hyperv_daemons"
Cap::HypervDaemons
end
end
end
end

View File

@ -73,6 +73,41 @@ module VagrantPlugins
cmds.each{ |cmd| comm.execute(cmd) }
true
end
# Create directories at given locations on guest
#
# @param [Vagrant::Machine] machine Vagrant guest machine
# @param [array] paths to create on guest
def self.create_directories(machine, dirs)
return [] if dirs.empty?
remote_fn = create_tmp_path(machine, {})
tmp = Tempfile.new('hv_dirs')
begin
tmp.write dirs.join("\n") + "\n"
tmp.close
machine.communicate.upload(tmp.path, remote_fn)
ensure
tmp.close
tmp.unlink
end
created_paths = []
machine.communicate.sudo("bash -c 'while IFS= read -r line
do
if [ ! -z \"${line}\" ] && [ ! -d \"${line}\" ]; then
if [ -f \"${line}\" ]; then
rm \"${line}\"
fi
mkdir -p -v \"${line}\" || true
fi
done < #{remote_fn}'
") do |type, data|
if type == :stdout && /^.*\'(?<dir>.*)\'/ =~ data
created_paths << dir.strip
end
end
created_paths
end
end
end
end

View File

@ -0,0 +1,11 @@
require "vagrant/util/hyperv_daemons"
module VagrantPlugins
module GuestLinux
module Cap
class HypervDaemons
extend Vagrant::Util::HypervDaemons
end
end
end
end

View File

@ -107,10 +107,30 @@ module VagrantPlugins
Cap::RSync
end
guest_capability(:linux, :create_directories) do
require_relative "cap/file_system"
Cap::FileSystem
end
guest_capability(:linux, :unmount_virtualbox_shared_folder) do
require_relative "cap/mount_virtualbox_shared_folder"
Cap::MountVirtualBoxSharedFolder
end
guest_capability(:linux, :hyperv_daemons_running) do
require_relative "cap/hyperv_daemons"
Cap::HypervDaemons
end
guest_capability(:linux, :hyperv_daemons_activate) do
require_relative "cap/hyperv_daemons"
Cap::HypervDaemons
end
guest_capability(:linux, :hyperv_daemons_installed) do
require_relative "cap/hyperv_daemons"
Cap::HypervDaemons
end
end
end
end

View File

@ -0,0 +1,22 @@
module VagrantPlugins
module GuestRedHat
module Cap
class HypervDaemons
def self.hyperv_daemons_installed(machine)
machine.communicate.test("rpm -q hyperv-daemons")
end
def self.hyperv_daemons_install(machine)
comm = machine.communicate
comm.sudo <<-EOH.gsub(/^ {12}/, "")
if command -v dnf; then
dnf -y install hyperv-daemons
else
yum -y install hyperv-daemons
fi
EOH
end
end
end
end
end

View File

@ -40,6 +40,16 @@ module VagrantPlugins
require_relative "cap/rsync"
Cap::RSync
end
guest_capability(:redhat, :hyperv_daemons_installed) do
require_relative "cap/hyperv_daemons"
Cap::HypervDaemons
end
guest_capability(:redhat, :hyperv_daemons_install) do
require_relative "cap/hyperv_daemons"
Cap::HypervDaemons
end
end
end
end

View File

@ -161,6 +161,15 @@ module VagrantPlugins
end
end
# This is the action that is called to sync folders to a running
# machine without a reboot.
def self.action_sync_folders
Vagrant::Action::Builder.new.tap do |b|
b.use SyncedFolderCleanup
b.use SyncedFolders
end
end
def self.action_up
Vagrant::Action::Builder.new.tap do |b|
b.use CheckEnabled

View File

@ -0,0 +1,72 @@
require 'find'
require_relative '../helper'
module VagrantPlugins
module HyperV
module Cap
module SyncFolder
def self.sync_folder(machine, data)
is_win_guest = machine.guest.name == :windows
host_path = VagrantPlugins::HyperV::SyncHelper.expand_path(data[:hostpath])
guest_path = data[:guestpath]
win_host_path = Vagrant::Util::Platform.format_windows_path(
host_path, :disable_unc)
win_guest_path = guest_path.tr '/', '\\'
includes = find_includes(data[:hostpath], data[:exclude])
dir_mappings = {}
file_mappings = {}
platform_guest_path = is_win_guest ? win_guest_path : guest_path
{ dirs: dir_mappings,
files: file_mappings }.map do |sym, mapping|
includes[sym].map do |e|
guest_rel = e.gsub(host_path, '')
guest_rel = guest_rel[1..-1] if guest_rel.start_with? '\\', '/'
guest_rel.tr! '\\', '/'
# make sure the dir names are Windows-style for them to pass to Hyper-V
if guest_rel == ''
win_path = win_host_path
target = platform_guest_path
else
win_path = HyperV::SyncHelper.platform_join(win_host_path, guest_rel)
target = HyperV::SyncHelper.platform_join(platform_guest_path, guest_rel,
is_windows: is_win_guest)
end
mapping[win_path] = target
end
end
machine.guest.capability(:create_directories, dir_mappings.values)
machine.provider.driver.sync_files(machine.id, dir_mappings, file_mappings,
is_win_guest: is_win_guest)
end
protected
def self.find_includes(path, exclude)
expanded_path = HyperV::SyncHelper.expand_path(path)
excludes = HyperV::SyncHelper.expand_excludes(path, exclude)
included_dirs = []
included_files = []
Find.find(expanded_path) do |e|
if VagrantPlugins::HyperV::SyncHelper.directory?(e)
path = File.join e, ''
next if excludes[:dirs].include? path
next if excludes[:dirs].select { |x| path.start_with? x }.any?
included_dirs << e
else
next if excludes[:files].include? e
next if excludes[:dirs].select { |x| e.start_with? x }.any?
included_files << e
end
end
{ dirs: included_dirs,
files: included_files }
end
end
end
end
end

View File

@ -0,0 +1,69 @@
require 'optparse'
require "vagrant/action/builtin/mixin_synced_folders"
require_relative "../helper"
module VagrantPlugins
module HyperV
module Command
class Sync < Vagrant.plugin("2", :command)
include Vagrant::Action::Builtin::MixinSyncedFolders
def self.synopsis
"syncs synced folders to remote machine"
end
def execute
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant sync [vm-name]"
o.separator ""
o.separator "This command forces any synced folders to sync."
o.separator "Hyper-V currently does not provider an automatic sync so a manual command is used."
o.separator ""
end
# Parse the options and return if we don't have any target.
argv = parse_options(opts)
return if !argv
# Go through each machine and perform the rsync
error = false
with_target_vms(argv) do |machine|
if !machine.communicate.ready?
machine.ui.error(I18n.t("vagrant_hyperv.sync.communicator_not_ready"))
error = true
next
end
# Determine the rsync synced folders for this machine
folders = synced_folders(machine, cached: true)[:hyperv]
next if !folders || folders.empty?
# short guestpaths first, so we don't step on ourselves
folders = folders.sort_by do |id, data|
if data[:guestpath]
data[:guestpath].length
else
# A long enough path to just do this at the end.
10000
end
end
# Calculate the owner and group
ssh_info = machine.ssh_info
# Sync them!
folders.each do |id, data|
next unless data[:guestpath]
SyncHelper.sync_single machine, ssh_info, data
end
end
return error ? 1 : 0
end
end
end
end
end

View File

@ -0,0 +1,196 @@
require "log4r"
require 'optparse'
require "thread"
require "vagrant/action/builtin/mixin_synced_folders"
require "vagrant/util/busy"
require "vagrant/util/platform"
require "listen"
require_relative '../helper'
module VagrantPlugins
module HyperV
module Command
class SyncAuto < Vagrant.plugin("2", :command)
include Vagrant::Action::Builtin::MixinSyncedFolders
def self.synopsis
"syncs synced folders automatically when files change"
end
def execute
@logger = Log4r::Logger.new("vagrant::commands::sync-auto")
options = {}
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant sync-auto [vm-name]"
o.separator ""
o.separator "Options:"
o.separator ""
o.on("--[no-]poll", "Force polling filesystem (slow)") do |poll|
options[:poll] = poll
end
end
# Parse the options and return if we don't have any target.
argv = parse_options(opts)
return if !argv
# Build up the paths that we need to listen to.
paths = {}
ignores = []
with_target_vms(argv) do |machine|
next if machine.state.id == :not_created
cached = synced_folders(machine, cached: true)
fresh = synced_folders(machine)
diff = synced_folders_diff(cached, fresh)
if !diff[:added].empty?
machine.ui.warn(I18n.t("vagrant_hyperv.sync.auto_new_folders"))
end
folders = cached[:hyperv]
next if !folders || folders.empty?
# Get the SSH info for this machine so we can do an initial
# sync to the VM.
ssh_info = machine.ssh_info
if ssh_info
machine.ui.info(I18n.t("vagrant_hyperv.sync.auto_initial"))
folders.each do |id, data|
next unless data[:guestpath]
SyncHelper.sync_single machine, ssh_info, data
end
end
folders.each do |id, folder_opts|
# If we marked this folder to not auto sync, then
# don't do it.
next if folder_opts.key?(:auto) && !folder_opts[:auto]
hostpath = folder_opts[:hostpath]
expanded_hostpath = HyperV::SyncHelper.expand_path(hostpath, machine.env.root_path)
paths[expanded_hostpath] ||= []
paths[expanded_hostpath] << {
id: id,
machine: machine,
opts: folder_opts,
}
excludes = HyperV::SyncHelper.expand_excludes(hostpath, folder_opts[:exclude])
excludes[:dirs].each do |dir|
dir = dir.gsub File.join(expanded_hostpath, ''), ''
dir = dir.gsub '.', '\.'
ignores << Regexp.new("#{dir}.*")
end
end
end
# Exit immediately if there is nothing to watch
if paths.empty?
@env.ui.info(I18n.t("vagrant_hyperv.sync.auto_no_paths"))
return 1
end
# Output to the user what paths we'll be watching
paths.keys.sort.each do |path|
paths[path].each do |path_opts|
path_opts[:machine].ui.info(I18n.t(
"vagrant_hyperv.sync.auto_path",
path: path.to_s,
))
end
end
@logger.info("Listening to paths: #{paths.keys.sort.inspect}")
@logger.info("Ignoring #{ignores.length} paths:")
ignores.each do |ignore|
@logger.info(" -- #{ignore.to_s}")
end
@logger.info("Listening via: #{Listen::Adapter.select.inspect}")
callback = method(:callback).to_proc.curry[paths]
listopts = { ignore: ignores, force_polling: !!options[:poll] }
listener = Listen.to(*paths.keys, listopts, &callback)
# Create the callback that lets us know when we've been interrupted
queue = Queue.new
callback = lambda do
# This needs to execute in another thread because Thread
# synchronization can't happen in a trap context.
Thread.new { queue << true }
end
# Run the listener in a busy block so that we can cleanly
# exit once we receive an interrupt.
Vagrant::Util::Busy.busy(callback) do
listener.start
queue.pop
listener.stop if listener.state != :stopped
end
0
end
# This is the callback that is called when any changes happen
def callback(paths, modified, added, removed)
@logger.info("File change callback called!")
@logger.info(" - Modified: #{modified.inspect}")
@logger.info(" - Added: #{added.inspect}")
@logger.info(" - Removed: #{removed.inspect}")
tosync = []
paths.each do |hostpath, folders|
# Find out if this path should be synced
found = catch(:done) do
[modified, added, removed].each do |changed|
changed.each do |listenpath|
throw :done, true if listenpath.start_with?(hostpath)
end
end
# Make sure to return false if all else fails so that we
# don't sync to this machine.
false
end
# If it should be synced, store it for later
tosync << folders if found
end
# Sync all the folders that need to be synced
tosync.each do |folders|
folders.each do |opts|
# Reload so we get the latest ID
opts[:machine].reload
if !opts[:machine].id || opts[:machine].id == ""
# Skip since we can't get SSH info without an ID
next
end
ssh_info = opts[:machine].ssh_info
begin
start = Time.now
SyncHelper.sync_single opts[:machine], ssh_info, opts[:opts]
finish = Time.now
@logger.info("Time spent in sync: #{finish - start} (in seconds)")
rescue Vagrant::Errors::MachineGuestNotReady
# Error communicating to the machine, probably a reload or
# halt is happening. Just notify the user but don't fail out.
opts[:machine].ui.error(I18n.t(
"vagrant_hyperv.sync.communicator_not_ready_callback"))
rescue Vagrant::Errors::VagrantError => e
# Error auto sync folder, show an error
opts[:machine].ui.error(I18n.t(
"vagrant_hyperv.sync.auto_sync_error", message: e.to_s))
end
end
end
end
end
end
end
end

View File

@ -1,6 +1,10 @@
require 'fileutils'
require 'find'
require "json"
require 'tempfile'
require "vagrant/util/powershell"
require "vagrant/util/subprocess"
require_relative "plugin"
@ -120,7 +124,7 @@ module VagrantPlugins
#
# @return [nil]
def start
execute(:start_vm, VmId: vm_id )
execute(:start_vm, VmId: vm_id)
end
# Stop the VM
@ -217,6 +221,36 @@ module VagrantPlugins
execute(:set_name, VMID: vm_id, VMName: vmname)
end
# Sync files
#
# @return [nil]
def sync_files(vm_id, dirs, files, is_win_guest: true)
network_info = read_guest_ip
guest_ip = network_info["ip"]
suffix = (0...8).map { ('a'..'z').to_a[rand(26)] }.join
windows_temp = Vagrant::Util::Platform.windows_temp
if Vagrant::Util::Platform.wsl?
process = Vagrant::Util::Subprocess.execute(
"wslpath", "-u", "-a", windows_temp)
windows_temp = process.stdout.chomp if process.exit_code == 0
end
fn = File.join(windows_temp, ".hv_sync_files_#{suffix}")
begin
File.open(fn, 'w') do |file|
file.write dirs.to_json
end
win_path = Vagrant::Util::Platform.format_windows_path(
fn, :disable_unc)
status = execute(:sync_files,
vm_id: vm_id,
guest_ip: guest_ip,
dir_list: win_path)
status
ensure
FileUtils.rm_f(fn)
end
end
protected
def execute_powershell(path, options, &block)

View File

@ -41,6 +41,18 @@ module VagrantPlugins
class SystemAccessRequired < HyperVError
error_key(:system_access_required)
end
class DaemonsNotInstalledInGuest < HyperVError
error_key(:daemons_not_installed_in_guest)
end
class DaemonsNotEnabledInGuest < HyperVError
error_key(:daemons_not_enabled_in_guest)
end
class DaemonsEnableFailedInGuest < HyperVError
error_key(:daemons_enable_failed_in_guest)
end
end
end
end

View File

@ -0,0 +1,60 @@
require "vagrant/util/platform"
module VagrantPlugins
module HyperV
class SyncHelper
WINDOWS_SEPARATOR = "\\"
UNIX_SEPARATOR = "/"
def self.expand_excludes(path, exclude)
excludes = ['.vagrant/']
excludes += Array(exclude).map(&:to_s) if exclude
excludes.uniq!
expanded_path = expand_path(path)
excluded_dirs = []
excluded_files = []
excludes.map do |exclude|
excluded_path = platform_join expanded_path, exclude,
is_windows: !Vagrant::Util::Platform.wsl?
Dir.glob(excluded_path) do |e|
if directory?(e)
excluded_dirs << e
else
excluded_files << e
end
end
end
{dirs: excluded_dirs,
files: excluded_files}
end
def self.platform_join(string, *smth, is_windows: true)
joined = [string, *smth].join is_windows ? WINDOWS_SEPARATOR : UNIX_SEPARATOR
if is_windows
joined.tr! UNIX_SEPARATOR, WINDOWS_SEPARATOR
else
joined.tr! WINDOWS_SEPARATOR, UNIX_SEPARATOR
end
joined
end
def self.sync_single(machine, ssh_info, opts)
opts = opts.dup
opts[:owner] ||= ssh_info[:username]
opts[:group] ||= ssh_info[:username]
machine.provider.capability(:sync_folder, opts)
end
def self.expand_path(*path)
# stub for unit test
File.expand_path(*path)
end
def self.directory?(path)
# stub for unit test
File.directory? path
end
end
end
end

View File

@ -16,12 +16,22 @@ module VagrantPlugins
Provider
end
synced_folder(:hyperv) do
require File.expand_path("../synced_folder", __FILE__)
SyncedFolder
end
config(:hyperv, :provider) do
require_relative "config"
init!
Config
end
provider_capability("hyperv", "sync_folder") do
require_relative "cap/sync_folder"
Cap::SyncFolder
end
provider_capability("hyperv", "public_address") do
require_relative "cap/public_address"
Cap::PublicAddress
@ -32,6 +42,16 @@ module VagrantPlugins
Cap::SnapshotList
end
command("hyperv-sync", primary: false) do
require_relative "command/sync"
Command::Sync
end
command("hyperv-sync-auto", primary: false) do
require_relative "command/sync_auto"
Command::SyncAuto
end
protected
def self.init!

View File

@ -0,0 +1,53 @@
#Requires -Modules VagrantMessages
#-------------------------------------------------------------------------
# Copyright (c) 2019 Microsoft
# All Rights Reserved. Licensed under the MIT License.
#--------------------------------------------------------------------------
param (
[parameter (Mandatory=$true)]
[string]$vm_id,
[parameter (Mandatory=$true)]
[string]$guest_ip,
[parameter (Mandatory=$true)]
[string]$dir_list,
[string]$path_separator
)
function copy-file($machine, $dir_list, $path_separator) {
$files = Get-Content $dir_list | ConvertFrom-Json
$succeeded = @()
$failed = @()
foreach ($line in $files.PSObject.Properties) {
$sourceDir = $line.Name
$destDir = $line.Value
Get-ChildItem $sourceDir -File | ForEach-Object -Process {
$from = $sourceDir + "\" + $_.Name
$to = $destDir
Write-Host "Copying $from to $($machine) => $to..."
Try {
Hyper-V\Copy-VMFile -VM $machine -SourcePath $from -DestinationPath $to -CreateFullPath -FileSource Host -Force
$succeeded += $from
Write-Host "Copied $from to $($machine) => $to."
} Catch {
$failed += $from
Break
}
}
}
[hashtable]$return = @{}
$return.succeeded = $succeeded
$return.failed = $failed
return $return
}
$machine = Hyper-V\Get-VM -Id $vm_id
$status = copy-file $machine $dir_list $path_separator
$resultHash = @{
message = "OK"
status = $status
}
$result = ConvertTo-Json $resultHash
Write-OutputMessage $result

View File

@ -0,0 +1,87 @@
require "fileutils"
require "vagrant/util/platform"
require_relative 'helper'
module VagrantPlugins
module HyperV
class SyncedFolder < Vagrant.plugin("2", :synced_folder)
def usable?(machine, raise_errors=false)
# These synced folders only work if the provider if VirtualBox
return false if machine.provider_name != :hyperv
true
end
def prepare(machine, folders, _opts)
# Nothing is necessary to do before VM boot.
end
def enable(machine, folders, _opts)
return unless configure_hv_daemons(machine)
# short guestpaths first, so we don't step on ourselves
folders = folders.sort_by do |id, data|
if data[:guestpath]
data[:guestpath].length
else
# A long enough path to just do this at the end.
10000
end
end
# Go through each folder and mount
machine.ui.output(I18n.t("vagrant_hyperv.share_folders.syncing"))
folders.each do |id, data|
if data[:guestpath]
# Guest path specified, so sync the folder to specified point
machine.ui.detail(I18n.t("vagrant_hyperv.share_folders.syncing_entry",
guestpath: data[:guestpath],
hostpath: data[:hostpath]))
# Dup the data so we can pass it to the guest API
SyncHelper.sync_single machine, machine.ssh_info, data.dup
else
# If no guest path is specified, then automounting is disabled
machine.ui.detail(I18n.t("vagrant_hyperv.share_folders.nosync_entry",
hostpath: data[:hostpath]))
end
end
end
def disable(machine, folders, _opts) end
def cleanup(machine, opts) end
protected
def configure_hv_daemons(machine)
return false unless machine.guest.capability?(:hyperv_daemons_running)
unless machine.guest.capability(:hyperv_daemons_running)
installed = machine.guest.capability(:hyperv_daemons_installed)
unless installed
can_install = machine.guest.capability?(:hyperv_daemons_install)
raise Errors::DaemonsNotInstalledInGuest unless can_install
machine.ui.info I18n.t("vagrant_hyperv.daemons.installing")
machine.guest.capability(:hyperv_daemons_install)
end
can_activate = machine.guest.capability?(:hyperv_daemons_activate)
raise Errors::DaemonsNotEnabledInGuest unless can_activate
machine.ui.info I18n.t("vagrant_hyperv.daemons.activating")
activated = machine.guest.capability(:hyperv_daemons_activate)
raise Errors::DaemonsEnableFailedInGuest unless activated
end
true
end
# This is here so that we can stub it for tests
def driver(machine)
machine.provider.driver
end
end
end
end

View File

@ -10,6 +10,41 @@ en:
VM not created. Moving on...
message_not_running: |-
Hyper-V machine isn't running. Can't SSH in!
share_folders:
syncing: Syncing shared folders...
syncing_entry: "%{guestpath} => %{hostpath}"
nosync_entry: "Sync disabled: %{hostpath}"
daemons:
installing: |-
Installing Hyper-V daemons...
activating: |-
Activating Hyper-V daemons...
sync:
auto_initial: |-
Doing an initial sync...
auto_new_folders: |-
New synced folders were added to the Vagrantfile since running
`vagrant reload`. If these new synced folders are backed by Hyper-V
auto sync, they won't be automatically synced until a
`vagrant reload` is run.
auto_no_paths: |-
There are no paths to watch! This is either because you have no
synced folders, or any synced folders you have have specified `auto`
to be false.
auto_path: "Watching: %{path}"
auto_sync_error: |-
There was an error while syncing. The error is shown below.
This may not be critical since syncing sometimes fails, but if this
message repeats, then please fix the issue:
%{message}
communicator_not_ready: |-
The machine is reporting that it is not ready to communicate with it.
Verify that this machine is properly running.
communicator_not_ready_callback: |-
Failed to connect to remote machine. This is usually caused by the
machine rebooting or being halted. Please make sure the machine is
running, and modify a file to try again.
config:
invalid_auto_start_action: |-
@ -106,3 +141,18 @@ en:
problem:
icacls.exe %{root_dir} /T /Q /grant "NT AUTHORITY\SYSTEM:(IO)(CI)(F)"
daemons_not_installed_in_guest: |-
Hyper-V daemons are not installed in the guest operation system.
Hyper-V shared folder plugin relies on Hyper-V daemons to function
properly. For guest operation system which does not support Hyper-V
daemons, you may use Rsync or SMB plugin instead.
daemons_not_enabled_in_guest: |-
Hyper-V daemons are not enabled in the guest operation system.
Hyper-V shared folder plugin relies on Hyper-V daemons to function
properly. For guest operation system which does not support Hyper-V
daemons, you may use Rsync or SMB plugin instead.
daemons_enable_failed_in_guest: |-
Failed to enable Hyper-V daemons in the guest operation system.
Hyper-V shared folder plugin relies on Hyper-V daemons to function
properly. For guest operation system which does not support Hyper-V
daemons, you may use Rsync or SMB plugin instead.