Skip to content

Commit

Permalink
Merge pull request #43 from chef/chris-rock/win-local
Browse files Browse the repository at this point in the history
Support for local transport on Windows
  • Loading branch information
arlimus committed Dec 29, 2015
2 parents 8c1b249 + 1c41a57 commit d143c52
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 6 deletions.
40 changes: 34 additions & 6 deletions lib/train/extras/command_wrapper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,44 @@ def build_prefix
end
end

# this is required if you run locally on windows,
# winrm connections provide a PowerShell shell automatically
# TODO: only activate in local mode
class PowerShellCommand < CommandWrapperBase
Train::Options.attach(self)

def initialize(backend, options)
@backend = backend
validate_options(options)

@prefix = 'powershell '
end

def run(command)
@prefix + command
end

def to_s
'PowerShell CommandWrapper'
end
end

class CommandWrapper
include_options LinuxCommand

def self.load(transport, options)
return nil unless LinuxCommand.active?(options)
return nil unless transport.os.unix?
res = LinuxCommand.new(transport, options)
msg = res.verify
fail Train::UserError, "Sudo failed: #{msg}" unless msg.nil?
res
if transport.os.unix?
return nil unless LinuxCommand.active?(options)
res = LinuxCommand.new(transport, options)
msg = res.verify
fail Train::UserError, "Sudo failed: #{msg}" unless msg.nil?
res
# only use powershell command for local transport. winrm transport
# uses powershell as default
elsif transport.os.windows? && transport.class == Train::Transports::Local::Connection
PowerShellCommand.new(transport, options)
end
nil
end
end
end
11 changes: 11 additions & 0 deletions lib/train/extras/os_detect_windows.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#

require 'json'
require 'winrm'

module Train::Extras
module DetectWindows
Expand Down Expand Up @@ -57,7 +58,16 @@ def detect_windows
'-Name OS -Value (Get-WmiObject -Class Win32_OperatingSystem) '\
'-PassThru | Add-Member -MemberType NoteProperty -Name OSVersion '\
'-Value ([Environment]::OSVersion) -PassThru | ConvertTo-Json'

# wrap the script to ensure we always run it via powershell
# especially in local mode, we cannot be sure that we get a Powershell
# we may just get a `cmd`. os detection and powershell command wrapper is
# not available when this code is executed
script = WinRM::PowershellScript.new(cmd)
cmd = "powershell -encodedCommand #{script.encoded}"

res = @backend.run_command(cmd)

# TODO: error as this shouldnt be happening at this point
return false if res.exit_status != 0 or res.stdout.empty?

Expand All @@ -67,6 +77,7 @@ def detect_windows

@platform[:family] = 'windows'
@platform[:release] = WINDOWS_VERSIONS[version]

true
end
end
Expand Down
15 changes: 15 additions & 0 deletions test/unit/extras/command_wrapper_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,18 @@
lc.run(cmd).must_equal "echo #{bpw} | base64 -d | sudo -S #{cmd}"
end
end

describe 'powershell command' do
let(:cls) { Train::Extras::PowerShellCommand }
let(:cmd) { rand.to_s }
let(:backend) {
backend = Train::Transports::Mock.new.connection
backend.mock_os({ family: 'windows' })
backend
}

it 'wraps commands in powershell' do
lc = cls.new(backend, {})
lc.run(cmd).must_equal "powershell #{cmd}"
end
end
14 changes: 14 additions & 0 deletions test/unit/transports/local_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@
require 'helper'
require 'train/transports/local'

# overwrite os detection to simplify mock tests, otherwise run_command tries to
# determine the OS first and fails the tests
class Train::Transports::Local::Connection
class OS < OSCommon
def initialize(backend)
super(backend, { family: 'train_mock_os' })
end

def detect_family
# no op, we do not need to detect the os
end
end
end

describe 'local transport' do
let(:transport) { Train::Transports::Local.new }
let(:connection) { transport.connection }
Expand Down
14 changes: 14 additions & 0 deletions test/unit/transports/ssh_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@
require 'helper'
require 'train/transports/ssh'

# overwrite os detection to simplify mock tests, otherwise run_command tries to
# determine the OS first and fails the tests
class Train::Transports::SSH::Connection
class OS < OSCommon
def initialize(backend)
super(backend, { family: 'train_mock_os' })
end

def detect_family
# no op, we do not need to detect the os
end
end
end

describe 'ssh transport' do
let(:cls) { Train::Transports::SSH }
let(:conf) {{
Expand Down

0 comments on commit d143c52

Please sign in to comment.