Class: Kitchen::Transport::Winrm::Connection

Inherits:
Base::Connection show all
Defined in:
lib/kitchen/transport/winrm.rb

Overview

A Connection instance can be generated and re-generated, given new connection details such as connection port, hostname, credentials, etc. This object is responsible for carrying out the actions on the remote host such as executing commands, transferring files, etc.

Author:

Instance Method Summary collapse

Methods inherited from Base::Connection

#execute_with_retry

Methods included from Logging

#banner, #debug, #error, #fatal, #info, #warn

Constructor Details

#initialize(config = {}) {|self| ... } ⇒ Connection

Create a new Connection instance.

Parameters:

  • config (Hash) (defaults to: {})

    connection options

Yields:

  • (self)

    yields itself for block-style invocation



94
95
96
97
98
# File 'lib/kitchen/transport/winrm.rb', line 94

def initialize(config = {})
  super(config)
  @unelevated_session = nil
  @elevated_session = nil
end

Instance Method Details

#closeObject

Closes the session connection, if it is still active.



101
102
103
104
105
106
107
108
# File 'lib/kitchen/transport/winrm.rb', line 101

def close
  @unelevated_session.close if @unelevated_session
  @elevated_session.close if @elevated_session
ensure
  @unelevated_session = nil
  @elevated_session = nil
  @file_transporter = nil
end

#download(remotes, local) ⇒ Object

Download remote files or directories to local host.

Parameters:

  • remotes (Array<String>)

    paths to remote files or directories

  • local (String)

    path to local destination. If local is an existing directory, remote will be downloaded into the directory using its original name

Raises:

  • (TransportFailed)

    if the files could not all be downloaded successfully, which may vary by implementation



168
169
170
171
172
173
174
175
# File 'lib/kitchen/transport/winrm.rb', line 168

def download(remotes, local)
  # ensure the parent dir of the local target exists
  FileUtils.mkdir_p(File.dirname(local))

  Array(remotes).each do |remote|
    file_manager.download(remote, local)
  end
end

#execute(command) ⇒ Object

Execute a command on the remote host.

Parameters:

  • command (String)

    command string to execute

Raises:

  • (TransportFailed)

    if the command does not exit successfully, which may vary by implementation



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/kitchen/transport/winrm.rb', line 111

def execute(command)
  return if command.nil?

  string_to_mask = "[WinRM] #{self} (#{command})"
  masked_string = Util.mask_values(string_to_mask, %w{password ssh_http_proxy_password})
  logger.debug(masked_string)

  exit_code, stderr = execute_with_exit_code(command)

  if logger.debug? && exit_code == 0
    log_stderr_on_warn(stderr)
  elsif exit_code != 0
    log_stderr_on_warn(stderr)
    raise Transport::WinrmFailed.new(
      "WinRM exited (#{exit_code}) for command: [#{command}]",
      exit_code
    )
  end
end

#file_managerWinrm::FileManager

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a file transporter.

Returns:

  • (Winrm::FileManager)

    a file transporter



179
180
181
# File 'lib/kitchen/transport/winrm.rb', line 179

def file_manager
  @file_manager ||= WinRM::FS::FileManager.new(connection)
end

#login_commandLoginCommand

Builds a LoginCommand which can be used to open an interactive session on the remote host.

Returns:

  • (LoginCommand)

    an object containing the array of command line tokens and exec options to be used in a fork/exec

Raises:



148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/kitchen/transport/winrm.rb', line 148

def 
  case RbConfig::CONFIG["host_os"]
  when /darwin/
    
  when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
    
  when /linux/
    
  else
    raise ActionFailed, "Remote login not supported in #{self.class} " \
      "from host OS '#{RbConfig::CONFIG["host_os"]}'."
  end
end

#retry?(current_try, max_retries, retryable_exit_codes, exception) ⇒ Boolean

Returns:

  • (Boolean)


131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/kitchen/transport/winrm.rb', line 131

def retry?(current_try, max_retries, retryable_exit_codes, exception)
  # Avoid duplicating Kitchen::Transport::Base#retry?
  result = super
  return result if result == true

  case exception
  when WinRM::WinRMHTTPTransportError
    return current_try <= max_retries &&
        [400, 500].include?(exception.status_code)
  when WinRM::WinRMWSManFault
    return current_try <= max_retries
  end

  false
end

#upload(locals, remote) ⇒ Object

Uploads local files or directories to remote host.

Parameters:

  • locals (Array<String>)

    paths to local files or directories

  • remote (String)

    path to remote destination

Raises:

  • (TransportFailed)

    if the files could not all be uploaded successfully, which may vary by implementation



163
164
165
# File 'lib/kitchen/transport/winrm.rb', line 163

def upload(locals, remote)
  file_transporter.upload(locals, remote)
end

#wait_until_readyObject

Block and return only when the remote host is prepared and ready to execute command and upload files. The semantics and details will vary by implementation, but a round trip through the hosted service is preferred to simply waiting on a socket to become available.



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/kitchen/transport/winrm.rb', line 184

def wait_until_ready
  delay = 3
  unelevated_session(
    retry_limit: max_wait_until_ready / delay,
    retry_delay: delay
  )
  execute(PING_COMMAND.dup)
rescue *RESCUE_EXCEPTIONS_ON_ESTABLISH => e
  retries ||= connection_retries.to_i
  raise e if (retries -= 1) < 0

  logger.debug("[WinRM] PING_COMMAND failed. Retrying...")
  logger.debug("#{e.class}::#{e.message}")
  sleep(connection_retry_sleep.to_i)
  retry
end