class Train::Transports::WinRM::Connection

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 Fletcher Nichol <fnichol@nichol.ca>

Constants

PING_COMMAND

Public Class Methods

new(options) click to toggle source
Calls superclass method
# File lib/train/transports/winrm_connection.rb, line 31
def initialize(options)
  super(options)
  @endpoint               = @options.delete(:endpoint)
  @rdp_port               = @options.delete(:rdp_port)
  @winrm_transport        = @options.delete(:winrm_transport)
  @connection_retries     = @options.delete(:connection_retries)
  @connection_retry_sleep = @options.delete(:connection_retry_sleep)
  @max_wait_until_ready   = @options.delete(:max_wait_until_ready)
  @files                  = {}
end

Public Instance Methods

close() click to toggle source

(see Base::Connection#close)

# File lib/train/transports/winrm_connection.rb, line 43
def close
  return if @session.nil?

  session.close
ensure
  @session = nil
end
file(path) click to toggle source
# File lib/train/transports/winrm_connection.rb, line 55
def file(path)
  @files[path] ||= WindowsFile.new(self, path)
end
login_command() click to toggle source

(see Base::Connection#login_command)

# File lib/train/transports/winrm_connection.rb, line 72
def login_command
  case RbConfig::CONFIG['host_os']
  when /darwin/
    login_command_for_mac
  when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
    login_command_for_windows
  when /linux/
    login_command_for_linux
  else
    fail ActionFailed,
         "Remote login not supported in #{self.class} " \
         "from host OS '#{RbConfig::CONFIG['host_os']}'."
  end
end
os() click to toggle source
# File lib/train/transports/winrm_connection.rb, line 51
def os
  @os ||= OS.new(self)
end
run_command(command) click to toggle source
# File lib/train/transports/winrm_connection.rb, line 59
def run_command(command)
  return if command.nil?
  logger.debug("[WinRM] #{self} (#{command})")
  out = ''

  response = session.run_powershell_script(command) do |stdout, _|
    out << stdout if stdout
  end

  CommandResult.new(out, response.stderr, response[:exitcode])
end
upload(locals, remote) click to toggle source

(see Base::Connection#upload)

# File lib/train/transports/winrm_connection.rb, line 88
def upload(locals, remote)
  file_transporter.upload(locals, remote)
end
wait_until_ready() click to toggle source

(see Base::Connection#wait_until_ready)

# File lib/train/transports/winrm_connection.rb, line 93
def wait_until_ready
  delay = 3
  session(
    retry_limit: @max_wait_until_ready / delay,
    retry_delay: delay,
  )
  execute(PING_COMMAND.dup)
end

Private Instance Methods

file_transporter() click to toggle source

@return [Winrm::FileTransporter] a file transporter @api private

# File lib/train/transports/winrm_connection.rb, line 127
def file_transporter
  @file_transporter ||= WinRM::FS::Core::FileTransporter.new(session)
end
login_command_for_linux() click to toggle source

Builds a `LoginCommand` for use by Linux-based platforms.

TODO: determine whether or not `desktop` exists

@return [LoginCommand] a login command @api private

# File lib/train/transports/winrm_connection.rb, line 137
def login_command_for_linux
  args  = %W( -u #{options[:user]} )
  args += %W( -p #{options[:pass]} ) if options.key?(:pass)
  args += %W( #{URI.parse(@endpoint).host}:#{@rdp_port} )
  LoginCommand.new('rdesktop', args)
end
login_command_for_mac() click to toggle source

Builds a `LoginCommand` for use by Mac-based platforms.

@return [LoginCommand] a login command @api private

# File lib/train/transports/winrm_connection.rb, line 148
def login_command_for_mac
  LoginCommand.new('open', rdp_doc(mac: true))
end
login_command_for_windows() click to toggle source

Builds a `LoginCommand` for use by Windows-based platforms.

@return [LoginCommand] a login command @api private

# File lib/train/transports/winrm_connection.rb, line 156
def login_command_for_windows
  LoginCommand.new('mstsc', rdp_doc)
end
rdp_doc(opts = {}) click to toggle source

Create a local RDP document and return it

@param opts [Hash] configuration options @option opts [true,false] :mac whether or not the document is for a

Mac system

@api private

# File lib/train/transports/winrm_connection.rb, line 112
def rdp_doc(opts = {})
  host = URI.parse(@endpoint).host
  content = [
    "full address:s:#{host}:#{@rdp_port}",
    'prompt for credentials:i:1',
    "username:s:#{options[:user]}",
  ].join("\n")

  content.prepend("drivestoredirect:s:*\n") if opts[:mac]

  content
end
session(retry_options = {}) click to toggle source

Establishes a remote shell session, or establishes one when invoked the first time.

@param retry_options [Hash] retry options for the initial connection @return [Winrm::CommandExecutor] the command executor session @api private

# File lib/train/transports/winrm_connection.rb, line 166
def session(retry_options = {})
  @session ||= begin
    opts = {
      retry_limit: @connection_retries.to_i,
      retry_delay: @connection_retry_sleep.to_i,
    }.merge(retry_options)

    service_args = [@endpoint, @winrm_transport, options.merge(opts)]
    @service = ::WinRM::WinRMWebService.new(*service_args)
    @service.logger = logger
    @service.create_executor
  end
end
to_s() click to toggle source

String representation of object, reporting its connection details and configuration.

@api private

# File lib/train/transports/winrm_connection.rb, line 184
def to_s
  "#{@winrm_transport}::#{@endpoint}<#{options.inspect}>"
end