*nix commands are now filtered out instead of being sent to the guest. This means the command_alias PowerShell script is no longer needed. Moved the PowerShell exit code helper to the WinRM shell and changed it to always return an exit code.
123 lines
3.8 KiB
Ruby
123 lines
3.8 KiB
Ruby
require "timeout"
|
|
|
|
require "log4r"
|
|
|
|
require_relative "helper"
|
|
require_relative "shell"
|
|
require_relative "command_filter"
|
|
|
|
module VagrantPlugins
|
|
module CommunicatorWinRM
|
|
# Provides communication channel for Vagrant commands via WinRM.
|
|
class Communicator < Vagrant.plugin("2", :communicator)
|
|
def self.match?(machine)
|
|
# This is useless, and will likely be removed in the future (this
|
|
# whole method).
|
|
true
|
|
end
|
|
|
|
def initialize(machine)
|
|
@machine = machine
|
|
@shell = nil
|
|
@logger = Log4r::Logger.new("vagrant::communication::winrm")
|
|
@cmd_filter = CommandFilter.new()
|
|
|
|
@logger.info("Initializing WinRMCommunicator")
|
|
end
|
|
|
|
def ready?
|
|
@logger.info("Checking whether WinRM is ready...")
|
|
|
|
Timeout.timeout(@machine.config.winrm.timeout) do
|
|
shell(true).powershell("hostname")
|
|
end
|
|
|
|
@logger.info("WinRM is ready!")
|
|
return true
|
|
rescue Vagrant::Errors::VagrantError => e
|
|
# We catch a `VagrantError` which would signal that something went
|
|
# wrong expectedly in the `connect`, which means we didn't connect.
|
|
@logger.info("WinRM not up: #{e.inspect}")
|
|
|
|
# We reset the shell to trigger calling of winrm_finder again.
|
|
# This resolves a problem when using vSphere where the ssh_info was not refreshing
|
|
# thus never getting the correct hostname.
|
|
@shell = nil
|
|
return false
|
|
end
|
|
|
|
def shell(reload=false)
|
|
@shell = nil if reload
|
|
@shell ||= create_shell
|
|
end
|
|
|
|
def execute(command, opts={}, &block)
|
|
# If this is a *nix command with no Windows equivilant, don't run it
|
|
command = @cmd_filter.filter(command)
|
|
return 0 if command.empty?
|
|
|
|
opts = {
|
|
:error_check => true,
|
|
:error_class => Errors::ExecutionError,
|
|
:error_key => :execution_error,
|
|
:command => command,
|
|
:shell => :powershell
|
|
}.merge(opts || {})
|
|
|
|
output = shell.send(opts[:shell], command, &block)
|
|
|
|
return output if opts[:shell] == :wql
|
|
exitcode = output[:exitcode]
|
|
raise_execution_error(opts, exitcode) if opts[:error_check] && exitcode != 0
|
|
exitcode
|
|
end
|
|
alias_method :sudo, :execute
|
|
|
|
def test(command, opts=nil)
|
|
# If this is a *nix command with no Windows equivilant, assume failure
|
|
command = @cmd_filter.filter(command)
|
|
return false if command.empty?
|
|
|
|
opts = { :error_check => false }.merge(opts || {})
|
|
execute(command, opts) == 0
|
|
end
|
|
|
|
def upload(from, to)
|
|
@logger.info("Uploading: #{from} to #{to}")
|
|
shell.upload(from, to)
|
|
end
|
|
|
|
def download(from, to)
|
|
@logger.info("Downloading: #{from} to #{to}")
|
|
shell.download(from, to)
|
|
end
|
|
|
|
protected
|
|
|
|
# This creates anew WinRMShell based on the information we know
|
|
# about this machine.
|
|
def create_shell
|
|
host_address = Helper.winrm_address(@machine)
|
|
host_port = Helper.winrm_port(@machine)
|
|
|
|
WinRMShell.new(
|
|
host_address,
|
|
@machine.config.winrm.username,
|
|
@machine.config.winrm.password,
|
|
port: host_port,
|
|
timeout_in_seconds: @machine.config.winrm.timeout,
|
|
max_tries: @machine.config.winrm.max_tries,
|
|
)
|
|
end
|
|
|
|
def raise_execution_error(opts, exit_code)
|
|
# The error classes expect the translation key to be _key, but that makes for an ugly
|
|
# configuration parameter, so we set it here from `error_key`
|
|
msg = "Command execution failed with an exit code of #{exit_code}"
|
|
error_opts = opts.merge(:_key => opts[:error_key], :message => msg)
|
|
raise opts[:error_class], error_opts
|
|
end
|
|
end #WinRM class
|
|
end
|
|
end
|