train 0.19.1 → 0.20.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: a52a5c7ef67219ce7efa1358a142c6a26d400d61
4
- data.tar.gz: 0e4a108030e0164506191a128463d691cdbfa177
3
+ metadata.gz: e2e42871db47191abec6fe3d94b56a60863abd48
4
+ data.tar.gz: 9004baaebe7b8021f840647bdc5032b88fb130fc
5
5
  SHA512:
6
- metadata.gz: 58bc527291b454cdd415a2c39fdc3166e010b2b5106f4917b5b845933612d6b9ea01914dafb932eea0760157c925d2f58abb1cd6be626f513c165a37db12acdd
7
- data.tar.gz: d67667d29a6cb0bebe830c0c6c4d8706c4c15054ecc7eae6c1f774d0d8c58b9ed51bce96dd4e807444210419e98ff15a6b47ad2d04d4b35240908d87b9948ba0
6
+ metadata.gz: 32c7d11c6aeaee6a856dfa3ce914e8d6a64d23108d8239473a7364b82929cace43c495f21765486d5b4fec02911c67747075376bde4ed8239fb88c54d30cac6d
7
+ data.tar.gz: 1335190030d7f53d31b7c5ee4f7c882fc101e80b9ae808da030c4090ecac2cc95a1b609049dbccd78ab9e7235a1c649dc9a206700de9c4689c2c1b890425f77f
@@ -69,3 +69,5 @@ Style/SpaceAroundOperators:
69
69
  Enabled: false
70
70
  Style/IfUnlessModifier:
71
71
  Enabled: false
72
+ Style/FrozenStringLiteralComment:
73
+ Enabled: false
@@ -1,7 +1,20 @@
1
1
  # Change Log
2
2
 
3
- ## [0.19.1](https://github.com/chef/train/tree/0.19.1) (2016-09-16)
4
- [Full Changelog](https://github.com/chef/train/compare/v0.19.0...0.19.1)
3
+ ## [0.20.0](https://github.com/chef/train/tree/0.20.0) (2016-09-21)
4
+ [Full Changelog](https://github.com/chef/train/compare/v0.19.1...0.20.0)
5
+
6
+ **Fixed bugs:**
7
+
8
+ - get `Preparing modules for first use.` when I use train on Windows [\#153](https://github.com/chef/train/issues/153)
9
+
10
+ **Merged pull requests:**
11
+
12
+ - `Preparing modules for first use.` error message on Windows [\#152](https://github.com/chef/train/pull/152) ([chris-rock](https://github.com/chris-rock))
13
+ - Convert `wmic` architecture to a normal standard [\#151](https://github.com/chef/train/pull/151) ([jerryaldrichiii](https://github.com/jerryaldrichiii))
14
+ - Login shell [\#149](https://github.com/chef/train/pull/149) ([jonathanmorley](https://github.com/jonathanmorley))
15
+
16
+ ## [v0.19.1](https://github.com/chef/train/tree/v0.19.1) (2016-09-16)
17
+ [Full Changelog](https://github.com/chef/train/compare/v0.19.0...v0.19.1)
5
18
 
6
19
  **Implemented enhancements:**
7
20
 
@@ -28,6 +28,9 @@ module Train::Extras
28
28
  class LinuxCommand < CommandWrapperBase
29
29
  Train::Options.attach(self)
30
30
 
31
+ option :shell, default: false
32
+ option :shell_options, default: nil
33
+ option :shell_command, default: nil
31
34
  option :sudo, default: false
32
35
  option :sudo_options, default: nil
33
36
  option :sudo_password, default: nil
@@ -38,12 +41,14 @@ module Train::Extras
38
41
  @backend = backend
39
42
  validate_options(options)
40
43
 
44
+ @shell = options[:shell]
45
+ @shell_options = options[:shell_options] # e.g. '--login'
46
+ @shell_command = options[:shell_command] # e.g. '/bin/sh'
41
47
  @sudo = options[:sudo]
42
48
  @sudo_options = options[:sudo_options]
43
49
  @sudo_password = options[:sudo_password]
44
50
  @sudo_command = options[:sudo_command]
45
51
  @user = options[:user]
46
- @prefix = build_prefix
47
52
  end
48
53
 
49
54
  # (see CommandWrapperBase::verify)
@@ -71,29 +76,48 @@ module Train::Extras
71
76
 
72
77
  # (see CommandWrapperBase::run)
73
78
  def run(command)
74
- @prefix + command
79
+ shell_wrap(sudo_wrap(command))
75
80
  end
76
81
 
77
82
  def self.active?(options)
78
- options.is_a?(Hash) && options[:sudo]
83
+ options.is_a?(Hash) && (
84
+ options[:sudo] ||
85
+ options[:shell]
86
+ )
79
87
  end
80
88
 
81
89
  private
82
90
 
83
- def build_prefix
84
- return '' unless @sudo
85
- return '' if @user == 'root'
91
+ # wrap the cmd in a sudo command
92
+ def sudo_wrap(cmd)
93
+ return cmd unless @sudo
94
+ return cmd if @user == 'root'
86
95
 
87
96
  res = (@sudo_command || 'sudo') + ' '
88
97
 
89
- unless @sudo_password.nil?
90
- b64pw = Base64.strict_encode64(@sudo_password + "\n")
91
- res = "echo #{b64pw} | base64 --decode | #{res}-S "
92
- end
98
+ res = "#{safe_string(@sudo_password + "\n")} | #{res}-S " unless @sudo_password.nil?
93
99
 
94
100
  res << @sudo_options.to_s + ' ' unless @sudo_options.nil?
95
101
 
96
- res
102
+ res + cmd
103
+ end
104
+
105
+ # wrap the cmd in a subshell allowing for options to
106
+ # passed to the subshell
107
+ def shell_wrap(cmd)
108
+ return cmd unless @shell
109
+
110
+ shell = @shell_command || '$SHELL'
111
+ options = ' ' + @shell_options.to_s unless @shell_options.nil?
112
+
113
+ "#{safe_string(cmd)} | #{shell}#{options}"
114
+ end
115
+
116
+ # encapsulates encoding the string into a safe form, and decoding for use.
117
+ # @return [String] A command line snippet that can be used as part of a pipeline.
118
+ def safe_string(str)
119
+ b64str = Base64.strict_encode64(str)
120
+ "echo #{b64str} | base64 --decode"
97
121
  end
98
122
  end
99
123
 
@@ -113,7 +137,7 @@ module Train::Extras
113
137
  # especially in local mode, we cannot be sure that we get a Powershell
114
138
  # we may just get a `cmd`.
115
139
  # TODO: we may want to opt for powershell.exe -command instead of `encodeCommand`
116
- "powershell -encodedCommand #{encoded(safe_script(script))}"
140
+ "powershell -NoProfile -encodedCommand #{encoded(safe_script(script))}"
117
141
  end
118
142
 
119
143
  # suppress the progress stream from leaking to stderr
@@ -50,8 +50,37 @@ module Train::Extras
50
50
  @platform[:build] = sys_info[:BuildNumber]
51
51
  @platform[:name] = sys_info[:Caption]
52
52
  @platform[:name] = @platform[:name].gsub('Microsoft', '').strip unless @platform[:name].empty?
53
- @platform[:arch] = sys_info[:OSArchitecture]
53
+ @platform[:arch] = read_wmic_cpu
54
54
  end
55
55
  end
56
+
57
+ # `OSArchitecture` from `read_wmic` does not match a normal standard
58
+ # For example, `x86_64` shows as `64-bit`
59
+ def read_wmic_cpu
60
+ res = @backend.run_command('wmic cpu get architecture /format:list')
61
+ if res.exit_status == 0
62
+ sys_info = {}
63
+ res.stdout.lines.each { |line|
64
+ m = /^\s*([^=]*?)\s*=\s*(.*?)\s*$/.match(line)
65
+ sys_info[m[1].to_sym] = m[2] unless m.nil? || m[1].nil?
66
+ }
67
+ end
68
+
69
+ # This converts `wmic os get architecture` output to a normal standard
70
+ # https://msdn.microsoft.com/en-us/library/aa394373(VS.85).aspx
71
+ arch_map = {
72
+ 0 => 'i386',
73
+ 1 => 'mips',
74
+ 2 => 'alpha',
75
+ 3 => 'powerpc',
76
+ 5 => 'arm',
77
+ 6 => 'ia64',
78
+ 9 => 'x86_64',
79
+ }
80
+
81
+ # The value of `wmic cpu get architecture` is always a number between 0-9
82
+ arch_number = sys_info[:Architecture].to_i
83
+ arch_map[arch_number]
84
+ end
56
85
  end
57
86
  end
@@ -3,5 +3,5 @@
3
3
  # Author:: Dominik Richter (<dominik.richter@gmail.com>)
4
4
 
5
5
  module Train
6
- VERSION = '0.19.1'.freeze
6
+ VERSION = '0.20.0'.freeze
7
7
  end
@@ -16,47 +16,95 @@ describe 'linux command' do
16
16
  backend
17
17
  }
18
18
 
19
- it 'wraps commands in sudo' do
20
- lc = cls.new(backend, { sudo: true })
21
- lc.run(cmd).must_equal "sudo #{cmd}"
22
- end
19
+ describe 'sudo wrapping' do
20
+ it 'wraps commands in sudo' do
21
+ lc = cls.new(backend, { sudo: true })
22
+ lc.run(cmd).must_equal "sudo #{cmd}"
23
+ end
23
24
 
24
- it 'doesnt wrap commands in sudo if user == root' do
25
- lc = cls.new(backend, { sudo: true, user: 'root' })
26
- lc.run(cmd).must_equal cmd
27
- end
25
+ it 'doesnt wrap commands in sudo if user == root' do
26
+ lc = cls.new(backend, { sudo: true, user: 'root' })
27
+ lc.run(cmd).must_equal cmd
28
+ end
28
29
 
29
- it 'wraps commands in sudo with all options' do
30
- opts = rand.to_s
31
- lc = cls.new(backend, { sudo: true, sudo_options: opts })
32
- lc.run(cmd).must_equal "sudo #{opts} #{cmd}"
33
- end
30
+ it 'wraps commands in sudo with all options' do
31
+ opts = rand.to_s
32
+ lc = cls.new(backend, { sudo: true, sudo_options: opts })
33
+ lc.run(cmd).must_equal "sudo #{opts} #{cmd}"
34
+ end
34
35
 
35
- it 'runs commands in sudo with password' do
36
- pw = rand.to_s
37
- lc = cls.new(backend, { sudo: true, sudo_password: pw })
38
- bpw = Base64.strict_encode64(pw + "\n")
39
- lc.run(cmd).must_equal "echo #{bpw} | base64 --decode | sudo -S #{cmd}"
40
- end
36
+ it 'runs commands in sudo with password' do
37
+ pw = rand.to_s
38
+ lc = cls.new(backend, { sudo: true, sudo_password: pw })
39
+ bpw = Base64.strict_encode64(pw + "\n")
40
+ lc.run(cmd).must_equal "echo #{bpw} | base64 --decode | sudo -S #{cmd}"
41
+ end
41
42
 
42
- it 'wraps commands in sudo_command instead of sudo' do
43
- sudo_command = rand.to_s
44
- lc = cls.new(backend, { sudo: true, sudo_command: sudo_command })
45
- lc.run(cmd).must_equal "#{sudo_command} #{cmd}"
46
- end
43
+ it 'wraps commands in sudo_command instead of sudo' do
44
+ sudo_command = rand.to_s
45
+ lc = cls.new(backend, { sudo: true, sudo_command: sudo_command })
46
+ lc.run(cmd).must_equal "#{sudo_command} #{cmd}"
47
+ end
48
+
49
+ it 'wraps commands in sudo_command with all options' do
50
+ opts = rand.to_s
51
+ sudo_command = rand.to_s
52
+ lc = cls.new(backend, { sudo: true, sudo_command: sudo_command, sudo_options: opts })
53
+ lc.run(cmd).must_equal "#{sudo_command} #{opts} #{cmd}"
54
+ end
47
55
 
48
- it 'wraps commands in sudo_command with all options' do
49
- opts = rand.to_s
50
- sudo_command = rand.to_s
51
- lc = cls.new(backend, { sudo: true, sudo_command: sudo_command, sudo_options: opts })
52
- lc.run(cmd).must_equal "#{sudo_command} #{opts} #{cmd}"
56
+ it 'runs commands in sudo_command with password' do
57
+ pw = rand.to_s
58
+ sudo_command = rand.to_s
59
+ lc = cls.new(backend, { sudo: true, sudo_command: sudo_command, sudo_password: pw })
60
+ bpw = Base64.strict_encode64(pw + "\n")
61
+ lc.run(cmd).must_equal "echo #{bpw} | base64 --decode | #{sudo_command} -S #{cmd}"
62
+ end
53
63
  end
54
64
 
55
- it 'runs commands in sudo_command with password' do
56
- pw = rand.to_s
57
- sudo_command = rand.to_s
58
- lc = cls.new(backend, { sudo: true, sudo_command: sudo_command, sudo_password: pw })
59
- bpw = Base64.strict_encode64(pw + "\n")
60
- lc.run(cmd).must_equal "echo #{bpw} | base64 --decode | #{sudo_command} -S #{cmd}"
65
+ describe 'shell wrapping' do
66
+ it 'wraps commands in a default shell with login' do
67
+ lc = cls.new(backend, { shell: true, shell_options: '--login' })
68
+ bcmd = Base64.strict_encode64(cmd)
69
+ lc.run(cmd).must_equal "echo #{bcmd} | base64 --decode | $SHELL --login"
70
+ end
71
+
72
+ it 'wraps sudo commands in a default shell with login' do
73
+ lc = cls.new(backend, { sudo: true, shell: true, shell_options: '--login' })
74
+ bcmd = Base64.strict_encode64("sudo #{cmd}")
75
+ lc.run(cmd).must_equal "echo #{bcmd} | base64 --decode | $SHELL --login"
76
+ end
77
+
78
+ it 'wraps sudo commands and sudo passwords in a default shell with login' do
79
+ pw = rand.to_s
80
+ lc = cls.new(backend, { sudo: true, sudo_password: pw, shell: true, shell_options: '--login' })
81
+ bpw = Base64.strict_encode64(pw + "\n")
82
+ bcmd = Base64.strict_encode64("echo #{bpw} | base64 --decode | sudo -S #{cmd}")
83
+ lc.run(cmd).must_equal "echo #{bcmd} | base64 --decode | $SHELL --login"
84
+ p bcmd
85
+ end
86
+
87
+ it 'wraps commands in a default shell when shell is true' do
88
+ lc = cls.new(backend, { shell: true })
89
+ bcmd = Base64.strict_encode64(cmd)
90
+ lc.run(cmd).must_equal "echo #{bcmd} | base64 --decode | $SHELL"
91
+ end
92
+
93
+ it 'doesnt wrap commands in a shell when shell is false' do
94
+ lc = cls.new(backend, { shell: false })
95
+ lc.run(cmd).must_equal cmd
96
+ end
97
+
98
+ it 'wraps commands in a `shell` instead of default shell' do
99
+ lc = cls.new(backend, { shell: true, shell_command: '/bin/bash' })
100
+ bcmd = Base64.strict_encode64(cmd)
101
+ lc.run(cmd).must_equal "echo #{bcmd} | base64 --decode | /bin/bash"
102
+ end
103
+
104
+ it 'wraps commands in a default shell with login' do
105
+ lc = cls.new(backend, { shell: true, shell_command: '/bin/bash', shell_options: '--login' })
106
+ bcmd = Base64.strict_encode64(cmd)
107
+ lc.run(cmd).must_equal "echo #{bcmd} | base64 --decode | /bin/bash --login"
108
+ end
61
109
  end
62
110
  end
@@ -17,6 +17,7 @@ describe 'os_detect_windows' do
17
17
  detector = OsDetectWindowsTester.new
18
18
  detector.backend.mock_command('cmd /c ver', "\r\nMicrosoft Windows [Version 6.3.9600]\r\n", '', 0)
19
19
  detector.backend.mock_command('wmic os get * /format:list',"\r\r\nBuildNumber=9600\r\r\nCaption=Microsoft Windows Server 2012 R2 Standard\r\r\nOSArchitecture=64-bit\r\r\nVersion=6.3.9600\r\r\n" , '', 0)
20
+ detector.backend.mock_command('wmic cpu get architecture /format:list',"\r\r\nArchitecture=9\r\r\n" , '', 0)
20
21
  detector
21
22
  }
22
23
 
@@ -24,7 +25,7 @@ describe 'os_detect_windows' do
24
25
  detector.detect_windows
25
26
  detector.platform[:family].must_equal('windows')
26
27
  detector.platform[:name].must_equal('Windows Server 2012 R2 Standard')
27
- detector.platform[:arch].must_equal('64-bit')
28
+ detector.platform[:arch].must_equal('x86_64')
28
29
  detector.platform[:release].must_equal('6.3.9600')
29
30
  end
30
31
  end
@@ -34,6 +35,7 @@ describe 'os_detect_windows' do
34
35
  detector = OsDetectWindowsTester.new
35
36
  detector.backend.mock_command('cmd /c ver', "\r\nMicrosoft Windows [Version 6.1.7601]\r\n", '', 0)
36
37
  detector.backend.mock_command('wmic os get * /format:list',"\r\r\nBuildNumber=7601\r\r\nCaption=Microsoft Windows Server 2008 R2 Standard \r\r\nOSArchitecture=64-bit\r\r\nVersion=6.1.7601\r\r\n" , '', 0)
38
+ detector.backend.mock_command('wmic cpu get architecture /format:list',"\r\r\nArchitecture=9\r\r\n" , '', 0)
37
39
  detector
38
40
  }
39
41
 
@@ -41,7 +43,7 @@ describe 'os_detect_windows' do
41
43
  detector.detect_windows
42
44
  detector.platform[:family].must_equal('windows')
43
45
  detector.platform[:name].must_equal('Windows Server 2008 R2 Standard')
44
- detector.platform[:arch].must_equal('64-bit')
46
+ detector.platform[:arch].must_equal('x86_64')
45
47
  detector.platform[:release].must_equal('6.1.7601')
46
48
  end
47
49
  end
@@ -51,6 +53,7 @@ describe 'os_detect_windows' do
51
53
  detector = OsDetectWindowsTester.new
52
54
  detector.backend.mock_command('cmd /c ver', "\r\nMicrosoft Windows [Version 6.1.7601]\r\n", '', 0)
53
55
  detector.backend.mock_command('wmic os get * /format:list',"\r\r\nBuildNumber=7601\r\r\nCaption=Microsoft Windows 7 Enterprise \r\r\nOSArchitecture=32-bit\r\r\nVersion=6.1.7601\r\r\n\r\r\n" , '', 0)
56
+ detector.backend.mock_command('wmic cpu get architecture /format:list',"\r\r\nArchitecture=0\r\r\n" , '', 0)
54
57
  detector
55
58
  }
56
59
 
@@ -58,7 +61,7 @@ describe 'os_detect_windows' do
58
61
  detector.detect_windows
59
62
  detector.platform[:family].must_equal('windows')
60
63
  detector.platform[:name].must_equal('Windows 7 Enterprise')
61
- detector.platform[:arch].must_equal('32-bit')
64
+ detector.platform[:arch].must_equal('i386')
62
65
  detector.platform[:release].must_equal('6.1.7601')
63
66
  end
64
67
  end
@@ -68,6 +71,7 @@ describe 'os_detect_windows' do
68
71
  detector = OsDetectWindowsTester.new
69
72
  detector.backend.mock_command('cmd /c ver', "\r\nMicrosoft Windows [Version 10.0.10240]\r\n", '', 0)
70
73
  detector.backend.mock_command('wmic os get * /format:list',"\r\r\nBuildNumber=10240\r\r\nCaption=Microsoft Windows 10 Pro\r\r\nOSArchitecture=64-bit\r\r\nVersion=10.0.10240\r\r\n\r\r\n" , '', 0)
74
+ detector.backend.mock_command('wmic cpu get architecture /format:list',"\r\r\nArchitecture=9\r\r\n" , '', 0)
71
75
  detector
72
76
  }
73
77
 
@@ -75,7 +79,7 @@ describe 'os_detect_windows' do
75
79
  detector.detect_windows
76
80
  detector.platform[:family].must_equal('windows')
77
81
  detector.platform[:name].must_equal('Windows 10 Pro')
78
- detector.platform[:arch].must_equal('64-bit')
82
+ detector.platform[:arch].must_equal('x86_64')
79
83
  detector.platform[:release].must_equal('10.0.10240')
80
84
  end
81
85
  end
@@ -84,7 +88,8 @@ describe 'os_detect_windows' do
84
88
  let(:detector) {
85
89
  detector = OsDetectWindowsTester.new
86
90
  detector.backend.mock_command('cmd /c ver', "\r\nMicrosoft Windows [Version 4.10.1998]\r\n", '', 0)
87
- detector.backend.mock_command('wmic os get * /format:list', nil , '', 1)
91
+ detector.backend.mock_command('wmic os get * /format:list', nil, '', 1)
92
+ detector.backend.mock_command('wmic cpu get architecture /format:list', nil, '', 1)
88
93
  detector
89
94
  }
90
95
 
@@ -24,7 +24,7 @@ describe 'windows local command' do
24
24
  os[:name].must_equal 'Windows Server 2012 R2 Datacenter'
25
25
  os[:family].must_equal "windows"
26
26
  os[:release].must_equal '6.3.9600'
27
- os[:arch].must_equal '64-bit'
27
+ os[:arch].must_equal 'x86_64'
28
28
  end
29
29
 
30
30
  it 'run echo test' do
@@ -30,7 +30,7 @@ describe 'windows winrm command' do
30
30
  os[:name].must_equal 'Windows Server 2012 R2 Datacenter'
31
31
  os[:family].must_equal 'windows'
32
32
  os[:release].must_equal '6.3.9600'
33
- os[:arch].must_equal '64-bit'
33
+ os[:arch].must_equal 'x86_64'
34
34
  end
35
35
 
36
36
  it 'run echo test' do
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: 0.19.1
4
+ version: 0.20.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: 2016-09-16 00:00:00.000000000 Z
11
+ date: 2016-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json