Better error handling for WinRM (using winrm v1.3.0.dev.2)
This commit is contained in:
parent
e787291717
commit
ba7b964b1e
|
@ -25,22 +25,95 @@ module VagrantPlugins
|
|||
@logger.info("Initializing WinRMCommunicator")
|
||||
end
|
||||
|
||||
def wait_for_ready(timeout)
|
||||
Timeout.timeout(timeout) do
|
||||
# Wait for winrm_info to be ready
|
||||
winrm_info = nil
|
||||
while true
|
||||
winrm_info = Helper.winrm_info(@machine)
|
||||
break if winrm_info
|
||||
sleep 0.5
|
||||
end
|
||||
|
||||
# Got it! Let the user know what we're connecting to.
|
||||
@machine.ui.detail("WinRM address: #{shell.host}:#{shell.port}")
|
||||
@machine.ui.detail("WinRM username: #{shell.username}")
|
||||
@machine.ui.detail("WinRM transport: #{shell.config.transport}")
|
||||
|
||||
last_message = nil
|
||||
last_message_repeat_at = 0
|
||||
while true
|
||||
message = nil
|
||||
begin
|
||||
begin
|
||||
standard_shell = shell.cmd('echo vagrant')
|
||||
powershell = shell.cmd('@PowerShell Write-Host vagrant')
|
||||
|
||||
unless standard_shell[:exitcode] == 0 || powershell[:exitcode] == 0
|
||||
raise Errors::InvalidShell
|
||||
end
|
||||
return true if shell(true).sane?
|
||||
rescue Vagrant::Errors::VagrantError => e
|
||||
@logger.info("WinRM not ready: #{e.inspect}")
|
||||
raise
|
||||
end
|
||||
rescue Errors::ConnectionTimeout
|
||||
message = "Connection timeout."
|
||||
rescue Errors::AuthenticationFailed
|
||||
message = "Authentication failure."
|
||||
rescue Errors::Disconnected
|
||||
message = "Remote connection disconnect."
|
||||
rescue Errors::ConnectionRefused
|
||||
message = "Connection refused."
|
||||
rescue Errors::ConnectionReset
|
||||
message = "Connection reset."
|
||||
rescue Errors::HostDown
|
||||
message = "Host appears down."
|
||||
rescue Errors::NoRoute
|
||||
message = "Host unreachable."
|
||||
rescue Errors::TransientError => e
|
||||
# Any other retriable errors
|
||||
message = e.message
|
||||
end
|
||||
|
||||
# If we have a message to show, then show it. We don't show
|
||||
# repeated messages unless they've been repeating longer than
|
||||
# 10 seconds.
|
||||
if message
|
||||
message_at = Time.now.to_f
|
||||
show_message = true
|
||||
if last_message == message
|
||||
show_message = (message_at - last_message_repeat_at) > 10.0
|
||||
end
|
||||
|
||||
if show_message
|
||||
@machine.ui.detail("Warning: #{message} Retrying...")
|
||||
last_message = message
|
||||
last_message_repeat_at = message_at
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue Timeout::Error
|
||||
return false
|
||||
end
|
||||
|
||||
def ready?
|
||||
@logger.info("Checking whether WinRM is ready...")
|
||||
|
||||
Timeout.timeout(@machine.config.winrm.timeout) do
|
||||
result = 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.
|
||||
rescue Errors::TransientError => e
|
||||
# We catch a `TransientError` which would signal that something went
|
||||
# that might work if we wait and retry.
|
||||
@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
|
||||
# This resolves a problem when using vSphere where the winrm_info was not refreshing
|
||||
# thus never getting the correct hostname.
|
||||
@shell = nil
|
||||
return false
|
||||
|
|
|
@ -6,8 +6,11 @@ module VagrantPlugins
|
|||
error_namespace("vagrant_winrm.errors")
|
||||
end
|
||||
|
||||
class AuthError < WinRMError
|
||||
error_key(:auth_error)
|
||||
class TransientError < WinRMError
|
||||
end
|
||||
|
||||
class AuthenticationFailed < WinRMError
|
||||
error_key(:authentication_failed)
|
||||
end
|
||||
|
||||
class ExecutionError < WinRMError
|
||||
|
@ -30,9 +33,37 @@ module VagrantPlugins
|
|||
error_key(:winrm_file_transfer_error)
|
||||
end
|
||||
|
||||
class WinRMInvalidTransport < WinRMError
|
||||
class InvalidTransport < WinRMError
|
||||
error_key(:invalid_transport)
|
||||
end
|
||||
|
||||
class SSLError < WinRMError
|
||||
error_key(:ssl_error)
|
||||
end
|
||||
|
||||
class ConnectionTimeout < TransientError
|
||||
error_key(:connection_timeout)
|
||||
end
|
||||
|
||||
class Disconnected < TransientError
|
||||
error_key(:disconnected)
|
||||
end
|
||||
|
||||
class ConnectionRefused < TransientError
|
||||
error_key(:connection_refused)
|
||||
end
|
||||
|
||||
class ConnectionReset < TransientError
|
||||
error_key(:connection_reset)
|
||||
end
|
||||
|
||||
class HostDown < TransientError
|
||||
error_key(:host_down)
|
||||
end
|
||||
|
||||
class NoRoute < TransientError
|
||||
error_key(:no_route)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -96,20 +96,49 @@ module VagrantPlugins
|
|||
end
|
||||
end
|
||||
|
||||
def raise_winrm_exception(winrm_exception, shell, command)
|
||||
# If the error is a 401, we can return a more specific error message
|
||||
if winrm_exception.message.include?("401")
|
||||
raise Errors::AuthError,
|
||||
user: @config.username,
|
||||
password: @config.password,
|
||||
endpoint: endpoint,
|
||||
message: winrm_exception.message
|
||||
end
|
||||
def raise_winrm_exception(exception, shell = nil, command = nil)
|
||||
case exception
|
||||
when WinRM::WinRMAuthorizationError
|
||||
raise Errors::AuthenticationFailed,
|
||||
user: @config.username,
|
||||
password: @config.password,
|
||||
endpoint: endpoint,
|
||||
message: exception.message
|
||||
when WinRM::WinRMHTTPTransportError
|
||||
case exception.response_code
|
||||
# If the error is a 401, we can return a more specific error message
|
||||
when 401
|
||||
raise Errors::AuthenticationFailed,
|
||||
user: @config.username,
|
||||
password: @config.password,
|
||||
endpoint: endpoint,
|
||||
message: exception.message
|
||||
end
|
||||
|
||||
raise Errors::ExecutionError,
|
||||
shell: shell,
|
||||
command: command,
|
||||
message: winrm_exception.message
|
||||
raise Errors::ExecutionError,
|
||||
shell: shell,
|
||||
command: command,
|
||||
message: exception.message
|
||||
when OpenSSL::SSL::SSLError
|
||||
raise Errors::SSLError, message: exception.message
|
||||
when HTTPClient::TimeoutError
|
||||
raise Errors::ConnectionTimeout, message: exception.message
|
||||
when Errno::ECONNREFUSED
|
||||
# This is raised if we failed to connect the max amount of times
|
||||
raise Errors::ConnectionRefused
|
||||
when Errno::ECONNRESET
|
||||
# This is raised if we failed to connect the max number of times
|
||||
# due to an ECONNRESET.
|
||||
raise Errors::ConnectionReset
|
||||
when Errno::EHOSTDOWN
|
||||
# This is raised if we get an ICMP DestinationUnknown error.
|
||||
raise Errors::HostDown
|
||||
when Errno::EHOSTUNREACH
|
||||
# This is raised if we can't work out how to route traffic.
|
||||
raise Errors::NoRoute
|
||||
else
|
||||
raise
|
||||
end
|
||||
end
|
||||
|
||||
def new_session
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
en:
|
||||
vagrant_winrm:
|
||||
errors:
|
||||
auth_error: |-
|
||||
authentication_failed: |-
|
||||
An authorization error occurred while connecting to WinRM.
|
||||
|
||||
User: %{user}
|
||||
Password: %{password}
|
||||
Endpoint: %{endpoint}
|
||||
Message: %{message}
|
||||
winrm_bad_exit_status: |-
|
||||
|
@ -31,6 +30,13 @@ en:
|
|||
%{shell} is not a supported type of Windows shell.
|
||||
invalid_transport: |-
|
||||
%{transport} is not a supported WinRM transport.
|
||||
ssl_error: |-
|
||||
An SSL error occurred while connecting to WinRM. This usually
|
||||
occurs when you are using a self-signed certificate and have
|
||||
not set the WinRM `ssl_peer_verification` config setting to false.
|
||||
|
||||
Message: %{message}
|
||||
|
||||
winrm_not_ready: |-
|
||||
The box is not able to report an address for WinRM to connect to yet.
|
||||
WinRM cannot access this Vagrant environment. Please wait for the
|
||||
|
@ -41,3 +47,36 @@ en:
|
|||
From: %{from}
|
||||
To: %{to}
|
||||
Message: %{message}
|
||||
|
||||
connection_refused: |-
|
||||
WinRM connection was refused! This usually happens if the VM failed to
|
||||
boot properly. Some steps to try to fix this: First, try reloading your
|
||||
VM with `vagrant reload`, since a simple restart sometimes fixes things.
|
||||
If that doesn't work, destroy your VM and recreate it with a `vagrant destroy`
|
||||
followed by a `vagrant up`. If that doesn't work, contact a Vagrant
|
||||
maintainer (support channels listed on the website) for more assistance.
|
||||
connection_reset: |-
|
||||
WinRM connection was reset! This usually happens when the machine is
|
||||
taking too long to reboot. First, try reloading your machine with
|
||||
`vagrant reload`, since a simple restart sometimes fixes things.
|
||||
If that doesn't work, destroy your machine and recreate it with
|
||||
a `vagrant destroy` followed by a `vagrant up`. If that doesn't work,
|
||||
contact support.
|
||||
connection_timeout: |-
|
||||
Vagrant timed out while attempting to connect via WinRM. This usually
|
||||
means that the VM booted, but there are issues with the WinRM configuration
|
||||
or network connectivity issues. Please try to `vagrant reload` or
|
||||
`vagrant up` again.
|
||||
disconnected: |-
|
||||
The WinRM connection was unexpectedly closed by the remote end. This
|
||||
usually indicates that WinRM within the guest machine was unable to
|
||||
properly start up. Please boot the VM in GUI mode to check whether
|
||||
it is booting properly.
|
||||
no_route: |-
|
||||
While attempting to connect with WinRM, a "no route to host" (EHOSTUNREACH)
|
||||
error was received. Please verify your network settings are correct
|
||||
and try again.
|
||||
host_down: |-
|
||||
While attempting to connect with WinRM, a "host is down" (EHOSTDOWN)
|
||||
error was received. Please verify your WinRM settings are correct
|
||||
and try again.
|
||||
|
|
Loading…
Reference in New Issue