train 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8d1f4e075a5038b0b0a9775e730adb61029aa31c
4
- data.tar.gz: e6bca8857718107fcaae0683d99e921dc38cdf7e
3
+ metadata.gz: 124fd4ed4c208f576481fb0b295fb8db93d9dd21
4
+ data.tar.gz: '0680e4d022b89b9e94abcd2f76ec830c69936ec9'
5
5
  SHA512:
6
- metadata.gz: 1ad43c36e91b4471e56d623433239db881c32ba7a266bf8de70bf7f863feaee87dc78b5628c4fa7980db451a8c220c604a97ee4346df2109d0010be1411ee115
7
- data.tar.gz: 8fde9bf9ae3281f82abd7785ba8e4886c878b152bc4fa00434a2d3271cbaccc9e86abb9262394baa66798eb9a8a6522ca0905eee4016d17abfd4400c2de0ac1a
6
+ metadata.gz: 7a82299c5aea2a11cbaf596a8aaa6bee503e7a169c86934b7af9a379ae70fc72fddbde527dcea1b717b08795d270a8092a223f72d7b582e8ded18b5c99180d56
7
+ data.tar.gz: db232796a60f74458d26ceff2273e72a233fcb14f794b03c6c9e45dfda7ba84e0632005a2c3c6df2ef9b2d7e816044f9589003cea87c890ea0e369fdc9f68838
data/CHANGELOG.md CHANGED
@@ -1,10 +1,31 @@
1
1
  # Change Log
2
2
 
3
- ## [1.1.1](https://github.com/chef/train/tree/1.1.1) (2018-02-14)
4
- [Full Changelog](https://github.com/chef/train/compare/v1.1.0...1.1.1)
3
+ ## [1.2.0](https://github.com/chef/train/tree/1.2.0) (2018-03-15)
4
+ [Full Changelog](https://github.com/chef/train/compare/v1.1.1...1.2.0)
5
+
6
+ **Implemented enhancements:**
7
+
8
+ - Change error message to use `connection` [\#263](https://github.com/chef/train/pull/263) ([jerryaldrichiii](https://github.com/jerryaldrichiii))
9
+
10
+ **Closed issues:**
11
+
12
+ - Force 64bit powershell if using ruby32 on a 64bit os [\#265](https://github.com/chef/train/issues/265)
13
+ - Master OS detect family [\#260](https://github.com/chef/train/issues/260)
14
+
15
+ **Merged pull requests:**
16
+
17
+ - Force 64bit powershell for 32bit ruby running on 64bit windows [\#266](https://github.com/chef/train/pull/266) ([jquick](https://github.com/jquick))
18
+ - support cisco ios xe [\#262](https://github.com/chef/train/pull/262) ([arlimus](https://github.com/arlimus))
19
+ - Create a master OS family and refactor specifications [\#261](https://github.com/chef/train/pull/261) ([jquick](https://github.com/jquick))
20
+ - Support for Brocade FOS-based SAN devices [\#254](https://github.com/chef/train/pull/254) ([marcelhuth](https://github.com/marcelhuth))
21
+ - ProxyCommand support [\#227](https://github.com/chef/train/pull/227) ([cbeckr](https://github.com/cbeckr))
22
+
23
+ ## [v1.1.1](https://github.com/chef/train/tree/v1.1.1) (2018-02-14)
24
+ [Full Changelog](https://github.com/chef/train/compare/v1.1.0...v1.1.1)
5
25
 
6
26
  **Merged pull requests:**
7
27
 
28
+ - Release train 1.1.1 [\#259](https://github.com/chef/train/pull/259) ([jquick](https://github.com/jquick))
8
29
  - Add api sdk versions as platform release [\#258](https://github.com/chef/train/pull/258) ([jquick](https://github.com/jquick))
9
30
  - Add plat helper methods to api direct platforms. [\#257](https://github.com/chef/train/pull/257) ([jquick](https://github.com/jquick))
10
31
 
@@ -53,6 +53,18 @@ module Train::Platforms::Detect::Helpers
53
53
  @uname[:m] = command_output('uname -m')
54
54
  end
55
55
 
56
+ def brocade_version
57
+ return @cache[:brocade] if @cache.key?(:brocade)
58
+ res = command_output('version')
59
+
60
+ m = res.match(/^Fabric OS:\s+v(\S+)$/)
61
+ unless m.nil?
62
+ return @cache[:brocade] = { version: m[1], type: 'fos' }
63
+ end
64
+
65
+ @cache[:brocade] = nil
66
+ end
67
+
56
68
  def cisco_show_version
57
69
  return @cache[:cisco] if @cache.key?(:cisco)
58
70
  res = command_output('show version')
@@ -62,6 +74,11 @@ module Train::Platforms::Detect::Helpers
62
74
  return @cache[:cisco] = { version: m[2], model: m[1], type: 'ios' }
63
75
  end
64
76
 
77
+ m = res.match(/^Cisco IOS Software, IOS-XE Software, [^,]+? \(([^,]+?)\), Version (\d+\.\d+\.\d+[A-Z]*)/)
78
+ unless m.nil?
79
+ return @cache[:cisco] = { version: m[2], model: m[1], type: 'ios-xe' }
80
+ end
81
+
65
82
  m = res.match(/^Cisco Nexus Operating System \(NX-OS\) Software/)
66
83
  unless m.nil?
67
84
  v = res[/^\s*system:\s+version (\d+\.\d+)/, 1]
@@ -12,7 +12,10 @@ module Train::Platforms::Detect::Specifications
12
12
  def self.load
13
13
  plat = Train::Platforms
14
14
 
15
- plat.family('windows')
15
+ # master family
16
+ plat.family('os').detect { true }
17
+
18
+ plat.family('windows').in_family('os')
16
19
  .detect {
17
20
  if winrm? || (@backend.local? && ruby_host_os(/mswin|mingw32|windows/))
18
21
  true
@@ -25,81 +28,16 @@ module Train::Platforms::Detect::Specifications
25
28
  }
26
29
 
27
30
  # unix master family
28
- plat.family('unix')
31
+ plat.family('unix').in_family('os')
29
32
  .detect {
30
33
  # we want to catch a special case here where cisco commands
31
34
  # don't return an exit status and still print to stdout
32
- if unix_uname_s =~ /./ && !unix_uname_s.start_with?('Line has invalid autocommand ')
35
+ if unix_uname_s =~ /./ && !unix_uname_s.start_with?('Line has invalid autocommand ') && !unix_uname_s.start_with?('The command you have entered')
33
36
  @platform[:arch] = unix_uname_m
34
37
  true
35
38
  end
36
39
  }
37
40
 
38
- # cisco_ios family
39
- plat.family('cisco').title('Cisco Family')
40
- .detect {
41
- !cisco_show_version.nil?
42
- }
43
-
44
- plat.name('cisco_ios').title('Cisco IOS').in_family('cisco')
45
- .detect {
46
- v = cisco_show_version
47
- next unless v[:type] == 'ios'
48
- @platform[:release] = v[:version]
49
- @platform[:arch] = nil
50
- true
51
- }
52
-
53
- plat.name('cisco_nexus').title('Cisco Nexus').in_family('cisco')
54
- .detect {
55
- v = cisco_show_version
56
- next unless v[:type] == 'nexus'
57
- @platform[:release] = v[:version]
58
- @platform[:arch] = nil
59
- true
60
- }
61
-
62
- # arista_eos family
63
- # this has to be before redhat as EOS is based off fedora
64
- plat.family('arista_eos').title('Arista EOS Family').in_family('unix')
65
- .detect {
66
- # we need a better way to determin this family
67
- # for now we are going to just try each platform
68
- true
69
- }
70
- plat.name('arista_eos').title('Arista EOS').in_family('arista_eos')
71
- .detect {
72
- cmd = @backend.run_command('show version | json')
73
- if cmd.exit_status == 0 && !cmd.stdout.empty?
74
- require 'json'
75
- begin
76
- eos_ver = JSON.parse(cmd.stdout)
77
- @platform[:release] = eos_ver['version']
78
- @platform[:arch] = eos_ver['architecture']
79
- true
80
- rescue JSON::ParserError
81
- nil
82
- end
83
- end
84
- }
85
- plat.name('arista_eos_bash').title('Arista EOS Bash Shell').in_family('arista_eos')
86
- .detect {
87
- if unix_file_exist?('/usr/bin/FastCli')
88
- cmd = @backend.run_command('FastCli -p 15 -c "show version | json"')
89
- if cmd.exit_status == 0 && !cmd.stdout.empty?
90
- require 'json'
91
- begin
92
- eos_ver = JSON.parse(cmd.stdout)
93
- @platform[:release] = eos_ver['version']
94
- @platform[:arch] = eos_ver['architecture']
95
- true
96
- rescue JSON::ParserError
97
- nil
98
- end
99
- end
100
- end
101
- }
102
-
103
41
  # linux master family
104
42
  plat.family('linux').in_family('unix')
105
43
  .detect {
@@ -159,6 +97,31 @@ module Train::Platforms::Detect::Specifications
159
97
  true
160
98
  }
161
99
 
100
+ # arista_eos family
101
+ # this checks for the arista bash shell
102
+ # must come before redhat as it uses fedora under the hood
103
+ plat.family('arista_eos').title('Arista EOS Family').in_family('linux')
104
+ .detect {
105
+ true
106
+ }
107
+ plat.name('arista_eos_bash').title('Arista EOS Bash Shell').in_family('arista_eos')
108
+ .detect {
109
+ if unix_file_exist?('/usr/bin/FastCli')
110
+ cmd = @backend.run_command('FastCli -p 15 -c "show version | json"')
111
+ if cmd.exit_status == 0 && !cmd.stdout.empty?
112
+ require 'json'
113
+ begin
114
+ eos_ver = JSON.parse(cmd.stdout)
115
+ @platform[:release] = eos_ver['version']
116
+ @platform[:arch] = eos_ver['architecture']
117
+ true
118
+ rescue JSON::ParserError
119
+ nil
120
+ end
121
+ end
122
+ end
123
+ }
124
+
162
125
  # redhat family
163
126
  plat.family('redhat').in_family('linux')
164
127
  .detect {
@@ -325,6 +288,13 @@ module Train::Platforms::Detect::Specifications
325
288
  end
326
289
  }
327
290
 
291
+ # brocade family detected here if device responds to 'uname' command,
292
+ # happens when logging in as root
293
+ plat.family('brocade').title('Brocade Family').in_family('linux')
294
+ .detect {
295
+ !brocade_version.nil?
296
+ }
297
+
328
298
  # genaric linux
329
299
  # this should always be last in the linux family list
330
300
  plat.name('linux').title('Genaric Linux').in_family('linux')
@@ -348,18 +318,6 @@ module Train::Platforms::Detect::Specifications
348
318
  end
349
319
  }
350
320
 
351
- # esx
352
- plat.family('esx').title('ESXi Family')
353
- .detect {
354
- true if unix_uname_s =~ /vmkernel/i
355
- }
356
- plat.name('vmkernel').in_family('esx')
357
- .detect {
358
- @platform[:name] = unix_uname_s.lines[0].chomp
359
- @platform[:release] = unix_uname_r.lines[0].chomp
360
- true
361
- }
362
-
363
321
  # aix
364
322
  plat.family('aix').in_family('unix')
365
323
  .detect {
@@ -475,8 +433,8 @@ module Train::Platforms::Detect::Specifications
475
433
  }
476
434
  plat.family('darwin').in_family('bsd')
477
435
  .detect {
478
- cmd = unix_file_contents('/usr/bin/sw_vers')
479
- if unix_uname_s =~ /darwin/i || !cmd.nil?
436
+ if unix_uname_s =~ /darwin/i
437
+ cmd = unix_file_contents('/usr/bin/sw_vers')
480
438
  unless cmd.nil?
481
439
  m = cmd.match(/^ProductVersion:\s+(.+)$/)
482
440
  @platform[:release] = m.nil? ? nil : m[1]
@@ -523,6 +481,84 @@ module Train::Platforms::Detect::Specifications
523
481
  true
524
482
  end
525
483
  }
484
+
485
+ # arista_eos family
486
+ plat.family('arista_eos').title('Arista EOS Family').in_family('os')
487
+ .detect {
488
+ true
489
+ }
490
+ plat.name('arista_eos').title('Arista EOS').in_family('arista_eos')
491
+ .detect {
492
+ cmd = @backend.run_command('show version | json')
493
+ if cmd.exit_status == 0 && !cmd.stdout.empty?
494
+ require 'json'
495
+ begin
496
+ eos_ver = JSON.parse(cmd.stdout)
497
+ @platform[:release] = eos_ver['version']
498
+ @platform[:arch] = eos_ver['architecture']
499
+ true
500
+ rescue JSON::ParserError
501
+ nil
502
+ end
503
+ end
504
+ }
505
+
506
+ # esx
507
+ plat.family('esx').title('ESXi Family').in_family('os')
508
+ .detect {
509
+ true if unix_uname_s =~ /vmkernel/i
510
+ }
511
+ plat.name('vmkernel').in_family('esx')
512
+ .detect {
513
+ @platform[:name] = unix_uname_s.lines[0].chomp
514
+ @platform[:release] = unix_uname_r.lines[0].chomp
515
+ true
516
+ }
517
+
518
+ # cisco_ios family
519
+ plat.family('cisco').title('Cisco Family').in_family('os')
520
+ .detect {
521
+ !cisco_show_version.nil?
522
+ }
523
+ plat.name('cisco_ios').title('Cisco IOS').in_family('cisco')
524
+ .detect {
525
+ v = cisco_show_version
526
+ next unless v[:type] == 'ios'
527
+ @platform[:release] = v[:version]
528
+ @platform[:arch] = nil
529
+ true
530
+ }
531
+ plat.name('cisco_ios_xe').title('Cisco IOS XE').in_family('cisco')
532
+ .detect {
533
+ v = cisco_show_version
534
+ next unless v[:type] == 'ios-xe'
535
+ @platform[:release] = v[:version]
536
+ @platform[:arch] = nil
537
+ true
538
+ }
539
+ plat.name('cisco_nexus').title('Cisco Nexus').in_family('cisco')
540
+ .detect {
541
+ v = cisco_show_version
542
+ next unless v[:type] == 'nexus'
543
+ @platform[:release] = v[:version]
544
+ @platform[:arch] = nil
545
+ true
546
+ }
547
+
548
+ # brocade family
549
+ plat.family('brocade').title('Brocade Family').in_family('os')
550
+ .detect {
551
+ !brocade_version.nil?
552
+ }
553
+
554
+ plat.name('brocade_fos').title('Brocade FOS').in_family('brocade')
555
+ .detect {
556
+ v = brocade_version
557
+ next unless v[:type] == 'fos'
558
+ @platform[:release] = v[:version]
559
+ @platform[:arch] = nil
560
+ true
561
+ }
526
562
  end
527
563
  end
528
564
  end
@@ -30,7 +30,7 @@ class Train::Plugins
30
30
  # @param [Hash] _options = nil provide optional configuration params
31
31
  # @return [Connection] the connection for this configuration
32
32
  def connection(_options = nil)
33
- fail Train::ClientError, "#{self.class} does not implement #connect()"
33
+ fail Train::ClientError, "#{self.class} does not implement #connection()"
34
34
  end
35
35
 
36
36
  # Register the inheriting class with as a train plugin using the
@@ -43,11 +43,18 @@ module Train::Transports
43
43
 
44
44
  def select_runner(options)
45
45
  if os.windows?
46
+ # Force a 64 bit poweshell if needed
47
+ if RUBY_PLATFORM == 'i386-mingw32' && os.arch == 'x86_64'
48
+ powershell_cmd = "#{ENV['SystemRoot']}\\sysnative\\WindowsPowerShell\\v1.0\\powershell.exe"
49
+ else
50
+ powershell_cmd = 'powershell'
51
+ end
52
+
46
53
  # Attempt to use a named pipe but fallback to ShellOut if that fails
47
54
  begin
48
- WindowsPipeRunner.new
55
+ WindowsPipeRunner.new(powershell_cmd)
49
56
  rescue PipeError
50
- WindowsShellRunner.new
57
+ WindowsShellRunner.new(powershell_cmd)
51
58
  end
52
59
  else
53
60
  GenericRunner.new(self, options)
@@ -111,6 +118,10 @@ module Train::Transports
111
118
  require 'json'
112
119
  require 'base64'
113
120
 
121
+ def initialize(powershell_cmd = 'powershell')
122
+ @powershell_cmd = powershell_cmd
123
+ end
124
+
114
125
  def run_command(script)
115
126
  # Prevent progress stream from leaking into stderr
116
127
  script = "$ProgressPreference='SilentlyContinue';" + script
@@ -119,7 +130,7 @@ module Train::Transports
119
130
  script = script.encode('UTF-16LE', 'UTF-8')
120
131
  base64_script = Base64.strict_encode64(script)
121
132
 
122
- cmd = "powershell -NoProfile -EncodedCommand #{base64_script}"
133
+ cmd = "#{@powershell_cmd} -NoProfile -EncodedCommand #{base64_script}"
123
134
 
124
135
  res = Mixlib::ShellOut.new(cmd)
125
136
  res.run_command
@@ -132,7 +143,8 @@ module Train::Transports
132
143
  require 'base64'
133
144
  require 'securerandom'
134
145
 
135
- def initialize
146
+ def initialize(powershell_cmd = 'powershell')
147
+ @powershell_cmd = powershell_cmd
136
148
  @pipe = acquire_pipe
137
149
  fail PipeError if @pipe.nil?
138
150
  end
@@ -206,7 +218,7 @@ module Train::Transports
206
218
 
207
219
  utf8_script = script.encode('UTF-16LE', 'UTF-8')
208
220
  base64_script = Base64.strict_encode64(utf8_script)
209
- cmd = "powershell -NoProfile -ExecutionPolicy bypass -NonInteractive -EncodedCommand #{base64_script}"
221
+ cmd = "#{@powershell_cmd} -NoProfile -ExecutionPolicy bypass -NonInteractive -EncodedCommand #{base64_script}"
210
222
 
211
223
  server_pid = Process.create(command_line: cmd).process_id
212
224
 
@@ -149,6 +149,7 @@ module Train::Transports
149
149
  keys: opts[:key_files],
150
150
  password: opts[:password],
151
151
  forward_agent: opts[:forward_agent],
152
+ proxy_command: opts[:proxy_command],
152
153
  transport_options: opts,
153
154
  }
154
155
 
@@ -65,6 +65,7 @@ class Train::Transports::SSH
65
65
  args += %w{ -o IdentitiesOnly=yes } if options[:keys]
66
66
  args += %W( -o LogLevel=#{level} )
67
67
  args += %W( -o ForwardAgent=#{fwd_agent} ) if options.key?(:forward_agent)
68
+ args += %W( -o ProxyCommand='#{options[:proxy_command]}' ) unless options[:proxy_command].nil?
68
69
  Array(options[:keys]).each do |ssh_key|
69
70
  args += %W( -i #{ssh_key} )
70
71
  end
@@ -113,7 +114,7 @@ class Train::Transports::SSH
113
114
  message: "Waiting for SSH service on #{@hostname}:#{@port}, " \
114
115
  "retrying in #{delay} seconds",
115
116
  )
116
- execute(PING_COMMAND.dup)
117
+ run_command(PING_COMMAND.dup)
117
118
  end
118
119
 
119
120
  def uri
@@ -144,6 +145,11 @@ class Train::Transports::SSH
144
145
  # @api private
145
146
  def establish_connection(opts)
146
147
  logger.debug("[SSH] opening connection to #{self}")
148
+ if @options[:proxy_command]
149
+ require 'net/ssh/proxy/command'
150
+ @options[:proxy] = Net::SSH::Proxy::Command.new(@options[:proxy_command])
151
+ @options.delete(:proxy_command)
152
+ end
147
153
  Net::SSH.start(@hostname, @username, @options.clone.delete_if { |_key, value| value.nil? })
148
154
  rescue *RESCUE_EXCEPTIONS_ON_ESTABLISH => e
149
155
  if (opts[:retries] -= 1) <= 0
@@ -80,7 +80,7 @@ class Train::Transports::WinRM
80
80
  retry_limit: @max_wait_until_ready / delay,
81
81
  retry_delay: delay,
82
82
  )
83
- execute(PING_COMMAND.dup)
83
+ run_command(PING_COMMAND.dup)
84
84
  end
85
85
 
86
86
  def uri
data/lib/train/version.rb CHANGED
@@ -3,5 +3,5 @@
3
3
  # Author:: Dominik Richter (<dominik.richter@gmail.com>)
4
4
 
5
5
  module Train
6
- VERSION = '1.1.1'.freeze
6
+ VERSION = '1.2.0'.freeze
7
7
  end
@@ -204,6 +204,16 @@ describe 'os_detect' do
204
204
  platform[:release].must_equal('12.2')
205
205
  end
206
206
 
207
+ it 'recognizes Cisco IOS XE' do
208
+ mock = Train::Transports::Mock::Connection.new
209
+ mock.mock_command('show version', "Cisco IOS Software, IOS-XE Software, Catalyst L3 Switch Software (CAT3K_CAA-UNIVERSALK9-M), Version 03.03.03SE RELEASE SOFTWARE (fc2)")
210
+ platform = Train::Platforms::Detect.scan(mock)
211
+
212
+ platform[:name].must_equal('cisco_ios_xe')
213
+ platform[:family].must_equal('cisco')
214
+ platform[:release].must_equal('03.03.03SE')
215
+ end
216
+
207
217
  it 'recognizes Cisco Nexus' do
208
218
  mock = Train::Transports::Mock::Connection.new
209
219
  mock.mock_command('show version', "Cisco Nexus Operating System (NX-OS) Software\n system: version 5.2(1)N1(8b)\n")
@@ -214,4 +224,16 @@ describe 'os_detect' do
214
224
  platform[:release].must_equal('5.2')
215
225
  end
216
226
  end
227
+
228
+ describe 'brocade' do
229
+ it 'recognizes Brocade FOS-based SAN switches' do
230
+ mock = Train::Transports::Mock::Connection.new
231
+ mock.mock_command('version', "Kernel: 2.6.14.2\nFabric OS: v7.4.2a\nMade on: Thu Jun 29 19:22:14 2017\nFlash: Sat Sep 9 17:30:42 2017\nBootProm: 1.0.11")
232
+ platform = Train::Platforms::Detect.scan(mock)
233
+
234
+ platform[:name].must_equal('brocade_fos')
235
+ platform[:family].must_equal('brocade')
236
+ platform[:release].must_equal('7.4.2a')
237
+ end
238
+ end
217
239
  end
@@ -50,7 +50,7 @@ describe 'v1 Connection Plugin' do
50
50
  plat.cloud?.must_equal false
51
51
  plat.unix?.must_equal true
52
52
  plat.family.must_equal 'darwin'
53
- plat.family_hierarchy.must_equal ['darwin', 'bsd', 'unix']
53
+ plat.family_hierarchy.must_equal ['darwin', 'bsd', 'unix', 'os']
54
54
  end
55
55
 
56
56
  it 'provides api direct platform' do
@@ -75,7 +75,7 @@ describe 'v1 Connection Plugin' do
75
75
  it 'provides family hierarchy' do
76
76
  plat = Train::Platforms.name('linux')
77
77
  family = connection.family_hierarchy(plat)
78
- family.flatten.must_equal ['linux', 'unix']
78
+ family.flatten.must_equal ['linux', 'unix', 'os']
79
79
  end
80
80
 
81
81
  it 'must use the user-provided logger' do
@@ -14,6 +14,7 @@ describe 'ssh transport' do
14
14
  host: rand.to_s,
15
15
  password: rand.to_s,
16
16
  key_files: rand.to_s,
17
+ proxy_command: 'ssh root@127.0.0.1 -W %h:%p',
17
18
  }}
18
19
  let(:cls_agent) { cls.new({ host: rand.to_s }) }
19
20
 
@@ -95,6 +96,7 @@ describe 'ssh transport' do
95
96
  "-o", "IdentitiesOnly=yes",
96
97
  "-o", "LogLevel=VERBOSE",
97
98
  "-o", "ForwardAgent=no",
99
+ "-o", "ProxyCommand='ssh root@127.0.0.1 -W %h:%p'",
98
100
  "-i", conf[:key_files],
99
101
  "-p", "22",
100
102
  "root@#{conf[:host]}",
@@ -120,6 +122,19 @@ describe 'ssh transport' do
120
122
  cls_agent.stubs(:ssh_known_identities).returns({:some => 'rsa_key'})
121
123
  cls_agent.connection
122
124
  end
125
+
126
+ it 'sets up a proxy when ssh proxy command is specified' do
127
+ mock = MiniTest::Mock.new
128
+ mock.expect(:call, true) do |hostname, username, options|
129
+ options[:proxy].kind_of?(Net::SSH::Proxy::Command) &&
130
+ 'ssh root@127.0.0.1 -W %h:%p' == options[:proxy].command_line_template
131
+ end
132
+ connection.stubs(:run_command)
133
+ Net::SSH.stub(:start, mock) do
134
+ connection.wait_until_ready
135
+ end
136
+ mock.verify
137
+ end
123
138
  end
124
139
 
125
140
  describe 'converting connection to string for logging' do
@@ -154,6 +169,7 @@ describe 'ssh transport' do
154
169
  it 'wont connect if it is not possible' do
155
170
  conf[:host] = 'localhost'
156
171
  conf[:port] = 1
172
+ conf.delete :proxy_command
157
173
  conn = cls.new(conf).connection
158
174
  proc { conn.run_command('uname') }.must_raise Train::Transports::SSHFailed
159
175
  end
@@ -12,16 +12,13 @@ require 'tempfile'
12
12
  require 'train/transports/local'
13
13
 
14
14
  describe 'windows local command' do
15
- let(:conn) {
15
+ let(:backend) do
16
16
  # get final config
17
17
  target_config = Train.target_config({})
18
18
  # initialize train
19
19
  backend = Train.create('local', target_config)
20
-
21
- # start or reuse a connection
22
- conn = backend.connection
23
- conn
24
- }
20
+ end
21
+ let(:conn) { backend.connection }
25
22
 
26
23
  it 'verify os' do
27
24
  os = conn.os
@@ -37,6 +34,65 @@ describe 'windows local command' do
37
34
  cmd.stderr.must_equal ''
38
35
  end
39
36
 
37
+ describe 'force 64 bit powershell command' do
38
+ let(:runner) { conn.instance_variable_get(:@runner) }
39
+ let(:powershell) { runner.instance_variable_get(:@powershell_cmd) }
40
+ RUBY_PLATFORM_DUP = RUBY_PLATFORM.dup
41
+
42
+ def override_platform(platform)
43
+ ::Object.send(:remove_const, :RUBY_PLATFORM)
44
+ ::Object.const_set(:RUBY_PLATFORM, platform)
45
+ end
46
+
47
+ after do
48
+ backend.instance_variable_set(:@connection, nil)
49
+ ::Object.send(:remove_const, :RUBY_PLATFORM)
50
+ ::Object.const_set(:RUBY_PLATFORM, RUBY_PLATFORM_DUP)
51
+ end
52
+
53
+ it 'use normal powershell with PipeRunner' do
54
+ Train::Transports::Local::Connection::WindowsPipeRunner
55
+ .any_instance
56
+ .expects(:acquire_pipe)
57
+ .returns('acquired')
58
+
59
+ override_platform('x64-mingw32')
60
+ powershell.must_equal 'powershell'
61
+ end
62
+
63
+ it 'use 64bit powershell with PipeRunner' do
64
+ Train::Transports::Local::Connection::WindowsPipeRunner
65
+ .any_instance
66
+ .expects(:acquire_pipe)
67
+ .returns('acquired')
68
+
69
+ override_platform('i386-mingw32')
70
+ powershell.must_equal "#{ENV['SystemRoot']}\\sysnative\\WindowsPowerShell\\v1.0\\powershell.exe"
71
+ end
72
+
73
+ it 'use normal powershell with ShellRunner' do
74
+ Train::Transports::Local::Connection::WindowsPipeRunner
75
+ .any_instance
76
+ .expects(:acquire_pipe)
77
+ .returns(nil)
78
+
79
+ override_platform('x64-mingw32')
80
+ runner.class.must_equal Train::Transports::Local::Connection::WindowsShellRunner
81
+ powershell.must_equal 'powershell'
82
+ end
83
+
84
+ it 'use 64bit powershell with ShellRunner' do
85
+ Train::Transports::Local::Connection::WindowsPipeRunner
86
+ .any_instance
87
+ .expects(:acquire_pipe)
88
+ .returns(nil)
89
+
90
+ override_platform('i386-mingw32')
91
+ runner.class.must_equal Train::Transports::Local::Connection::WindowsShellRunner
92
+ powershell.must_equal "#{ENV['SystemRoot']}\\sysnative\\WindowsPowerShell\\v1.0\\powershell.exe"
93
+ end
94
+ end
95
+
40
96
  it 'use powershell piping' do
41
97
  cmd = conn.run_command("New-Object -Type PSObject | Add-Member -MemberType NoteProperty -Name A -Value (Write-Output 'PropertyA') -PassThru | Add-Member -MemberType NoteProperty -Name B -Value (Write-Output 'PropertyB') -PassThru | ConvertTo-Json")
42
98
  cmd.stdout.must_equal "{\r\n \"A\": \"PropertyA\",\r\n \"B\": \"PropertyB\"\r\n}\r\n"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: train
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dominik Richter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-02-14 00:00:00.000000000 Z
11
+ date: 2018-03-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -316,7 +316,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
316
316
  version: '0'
317
317
  requirements: []
318
318
  rubyforge_project:
319
- rubygems_version: 2.5.2
319
+ rubygems_version: 2.6.14
320
320
  signing_key:
321
321
  specification_version: 4
322
322
  summary: Transport interface to talk to different backends.