train 1.4.15 → 1.4.19
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 +4 -4
- data/CHANGELOG.md +18 -10
- data/Gemfile +0 -2
- data/lib/train/platforms/detect/helpers/os_linux.rb +3 -1
- data/lib/train/transports/ssh.rb +11 -0
- data/lib/train/transports/ssh_connection.rb +28 -7
- data/lib/train/version.rb +1 -1
- data/test/unit/transports/ssh_test.rb +142 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d49a72baf8b82a9e1a5ca0153de737c7c349ce49bc86237666c4671f3488b27c
|
4
|
+
data.tar.gz: 0bf8c7ef0b17cbb25660397875205653371b96480824e9632fd5e8b98c8c36de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 99531d210957232cec38e96deba36831731b37ba87165bb0aa362bdba5c15849483e9efe1b90ef9b8a1e50b54ea1cf47aad0be6bcfb2eaacda9fa69d963e640a
|
7
|
+
data.tar.gz: 5b4742273713e24028bccca8cef7adad3aa0d5e9e938cbaf46da708b7b6b39640c34687e43f4ce1db8fc11cc75565ab50d99fe2c32c2b4950bffc81ef13dcf1a
|
data/CHANGELOG.md
CHANGED
@@ -1,26 +1,34 @@
|
|
1
|
-
<!-- latest_release 1.4.
|
2
|
-
## [v1.4.
|
1
|
+
<!-- latest_release 1.4.19 -->
|
2
|
+
## [v1.4.19](https://github.com/inspec/train/tree/v1.4.19) (2018-06-29)
|
3
3
|
|
4
4
|
#### Merged Pull Requests
|
5
|
-
-
|
5
|
+
- Remove the deploy config from Travis [#315](https://github.com/inspec/train/pull/315) ([tas50](https://github.com/tas50))
|
6
6
|
<!-- latest_release -->
|
7
7
|
|
8
|
-
<!-- release_rollup since=1.4.
|
9
|
-
### Changes since 1.4.
|
8
|
+
<!-- release_rollup since=1.4.15 -->
|
9
|
+
### Changes since 1.4.15 release
|
10
10
|
|
11
11
|
#### Merged Pull Requests
|
12
|
-
-
|
13
|
-
-
|
14
|
-
- Adding
|
15
|
-
-
|
12
|
+
- Remove the deploy config from Travis [#315](https://github.com/inspec/train/pull/315) ([tas50](https://github.com/tas50)) <!-- 1.4.19 -->
|
13
|
+
- Remove github_changelog_generator [#313](https://github.com/inspec/train/pull/313) ([tas50](https://github.com/tas50)) <!-- 1.4.18 -->
|
14
|
+
- Adding proper bastion support [#310](https://github.com/inspec/train/pull/310) ([frezbo](https://github.com/frezbo)) <!-- 1.4.17 -->
|
15
|
+
- Fix detection of amazon linux 2 [#312](https://github.com/inspec/train/pull/312) ([artem-sidorenko](https://github.com/artem-sidorenko)) <!-- 1.4.16 -->
|
16
16
|
<!-- release_rollup -->
|
17
17
|
|
18
18
|
<!-- latest_stable_release -->
|
19
|
+
## [v1.4.15](https://github.com/inspec/train/tree/v1.4.15) (2018-06-14)
|
20
|
+
|
21
|
+
#### Merged Pull Requests
|
22
|
+
- Allow TrainError to provide a supplement reason [#303](https://github.com/chef/train/pull/303) ([marcparadise](https://github.com/marcparadise))
|
23
|
+
- Adding Oneview to platform detection. [#307](https://github.com/inspec/train/pull/307) ([skpaterson](https://github.com/skpaterson))
|
24
|
+
- Add the mock transport to train-core [#308](https://github.com/inspec/train/pull/308) ([jquick](https://github.com/jquick))
|
25
|
+
- Don't double-escape paths [#306](https://github.com/inspec/train/pull/306) ([voroniys](https://github.com/voroniys))
|
26
|
+
<!-- latest_stable_release -->
|
27
|
+
|
19
28
|
## [v1.4.11](https://github.com/chef/train/tree/v1.4.11) (2018-05-17)
|
20
29
|
|
21
30
|
#### Merged Pull Requests
|
22
31
|
- Add required env for azure shell msi headers [#302](https://github.com/chef/train/pull/302) ([jquick](https://github.com/jquick))
|
23
|
-
<!-- latest_stable_release -->
|
24
32
|
|
25
33
|
## [v1.4.10](https://github.com/chef/train/tree/v1.4.10) (2018-05-17)
|
26
34
|
|
data/Gemfile
CHANGED
@@ -10,7 +10,6 @@ end
|
|
10
10
|
|
11
11
|
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.2.2')
|
12
12
|
gem 'json', '< 2.0'
|
13
|
-
gem 'rack', '< 2.0'
|
14
13
|
end
|
15
14
|
|
16
15
|
group :test do
|
@@ -32,5 +31,4 @@ group :tools do
|
|
32
31
|
gem 'pry', '~> 0.10'
|
33
32
|
gem 'rb-readline'
|
34
33
|
gem 'license_finder'
|
35
|
-
gem 'github_changelog_generator', '~> 1'
|
36
34
|
end
|
@@ -10,7 +10,9 @@ module Train::Platforms::Detect::Helpers
|
|
10
10
|
case conf
|
11
11
|
when /rawhide/i
|
12
12
|
/((\d+) \(Rawhide\))/i.match(conf)[1].downcase
|
13
|
-
when /
|
13
|
+
when /Amazon Linux AMI/i
|
14
|
+
/release ([\d\.]+)/.match(conf)[1]
|
15
|
+
when /derived from .*linux|amazon/i
|
14
16
|
/Linux ((\d+|\.)+)/i.match(conf)[1]
|
15
17
|
else
|
16
18
|
/release ([\d\.]+)/.match(conf)[1]
|
data/lib/train/transports/ssh.rb
CHANGED
@@ -58,6 +58,10 @@ module Train::Transports
|
|
58
58
|
option :max_wait_until_ready, default: 600
|
59
59
|
option :compression, default: false
|
60
60
|
option :pty, default: false
|
61
|
+
option :proxy_command, default: nil
|
62
|
+
option :bastion_host, default: nil
|
63
|
+
option :bastion_user, default: 'root'
|
64
|
+
option :bastion_port, default: 22
|
61
65
|
|
62
66
|
option :compression_level do |opts|
|
63
67
|
# on nil or false: set compression level to 0
|
@@ -109,6 +113,10 @@ module Train::Transports
|
|
109
113
|
logger.warn('[SSH] PTY requested: stderr will be merged into stdout')
|
110
114
|
end
|
111
115
|
|
116
|
+
if [options[:proxy_command], options[:bastion_host]].all? { |type| !type.nil? }
|
117
|
+
fail Train::ClientError, 'Only one of proxy_command or bastion_host needs to be specified'
|
118
|
+
end
|
119
|
+
|
112
120
|
super
|
113
121
|
self
|
114
122
|
end
|
@@ -151,6 +159,9 @@ module Train::Transports
|
|
151
159
|
password: opts[:password],
|
152
160
|
forward_agent: opts[:forward_agent],
|
153
161
|
proxy_command: opts[:proxy_command],
|
162
|
+
bastion_host: opts[:bastion_host],
|
163
|
+
bastion_user: opts[:bastion_user],
|
164
|
+
bastion_port: opts[:bastion_port],
|
154
165
|
transport_options: opts,
|
155
166
|
}
|
156
167
|
|
@@ -43,6 +43,10 @@ class Train::Transports::SSH
|
|
43
43
|
@session = nil
|
44
44
|
@transport_options = @options.delete(:transport_options)
|
45
45
|
@cmd_wrapper = nil
|
46
|
+
@proxy_command = @options.delete(:proxy_command)
|
47
|
+
@bastion_host = @options.delete(:bastion_host)
|
48
|
+
@bastion_user = @options.delete(:bastion_user)
|
49
|
+
@bastion_port = @options.delete(:bastion_port)
|
46
50
|
@cmd_wrapper = CommandWrapper.load(self, @transport_options)
|
47
51
|
end
|
48
52
|
|
@@ -55,8 +59,7 @@ class Train::Transports::SSH
|
|
55
59
|
@session = nil
|
56
60
|
end
|
57
61
|
|
58
|
-
|
59
|
-
def login_command
|
62
|
+
def ssh_opts
|
60
63
|
level = logger.debug? ? 'VERBOSE' : 'ERROR'
|
61
64
|
fwd_agent = options[:forward_agent] ? 'yes' : 'no'
|
62
65
|
|
@@ -65,13 +68,32 @@ class Train::Transports::SSH
|
|
65
68
|
args += %w{ -o IdentitiesOnly=yes } if options[:keys]
|
66
69
|
args += %W( -o LogLevel=#{level} )
|
67
70
|
args += %W( -o ForwardAgent=#{fwd_agent} ) if options.key?(:forward_agent)
|
68
|
-
args += %W( -o ProxyCommand='#{options[:proxy_command]}' ) unless options[:proxy_command].nil?
|
69
71
|
Array(options[:keys]).each do |ssh_key|
|
70
72
|
args += %W( -i #{ssh_key} )
|
71
73
|
end
|
74
|
+
args
|
75
|
+
end
|
76
|
+
|
77
|
+
def check_proxy
|
78
|
+
[@proxy_command, @bastion_host].any? { |type| !type.nil? }
|
79
|
+
end
|
80
|
+
|
81
|
+
def generate_proxy_command
|
82
|
+
return @proxy_command unless @proxy_command.nil?
|
83
|
+
args = %w{ ssh }
|
84
|
+
args += ssh_opts
|
85
|
+
args += %W( #{@bastion_user}@#{@bastion_host} )
|
86
|
+
args += %W( -p #{@bastion_port} )
|
87
|
+
args += %w{ -W %h:%p }
|
88
|
+
args.join(' ')
|
89
|
+
end
|
90
|
+
|
91
|
+
# (see Base::Connection#login_command)
|
92
|
+
def login_command
|
93
|
+
args = ssh_opts
|
94
|
+
args += %W( -o ProxyCommand='#{generate_proxy_command}' ) if check_proxy
|
72
95
|
args += %W( -p #{@port} )
|
73
96
|
args += %W( #{@username}@#{@hostname} )
|
74
|
-
|
75
97
|
LoginCommand.new('ssh', args)
|
76
98
|
end
|
77
99
|
|
@@ -145,10 +167,9 @@ class Train::Transports::SSH
|
|
145
167
|
# @api private
|
146
168
|
def establish_connection(opts)
|
147
169
|
logger.debug("[SSH] opening connection to #{self}")
|
148
|
-
if
|
170
|
+
if check_proxy
|
149
171
|
require 'net/ssh/proxy/command'
|
150
|
-
@options[:proxy] = Net::SSH::Proxy::Command.new(
|
151
|
-
@options.delete(:proxy_command)
|
172
|
+
@options[:proxy] = Net::SSH::Proxy::Command.new(generate_proxy_command)
|
152
173
|
end
|
153
174
|
Net::SSH.start(@hostname, @username, @options.clone.delete_if { |_key, value| value.nil? })
|
154
175
|
rescue *RESCUE_EXCEPTIONS_ON_ESTABLISH => e
|
data/lib/train/version.rb
CHANGED
@@ -96,8 +96,8 @@ describe 'ssh transport' do
|
|
96
96
|
"-o", "IdentitiesOnly=yes",
|
97
97
|
"-o", "LogLevel=VERBOSE",
|
98
98
|
"-o", "ForwardAgent=no",
|
99
|
-
"-o", "ProxyCommand='ssh root@127.0.0.1 -W %h:%p'",
|
100
99
|
"-i", conf[:key_files],
|
100
|
+
"-o", "ProxyCommand='ssh root@127.0.0.1 -W %h:%p'",
|
101
101
|
"-p", "22",
|
102
102
|
"root@#{conf[:host]}",
|
103
103
|
])
|
@@ -175,3 +175,144 @@ describe 'ssh transport' do
|
|
175
175
|
end
|
176
176
|
end
|
177
177
|
end
|
178
|
+
|
179
|
+
describe 'ssh transport with bastion' do
|
180
|
+
let(:cls) do
|
181
|
+
plat = Train::Platforms.name('mock').in_family('linux')
|
182
|
+
plat.add_platform_methods
|
183
|
+
Train::Platforms::Detect.stubs(:scan).returns(plat)
|
184
|
+
Train::Transports::SSH
|
185
|
+
end
|
186
|
+
|
187
|
+
let(:conf) {{
|
188
|
+
host: rand.to_s,
|
189
|
+
password: rand.to_s,
|
190
|
+
key_files: rand.to_s,
|
191
|
+
bastion_host: 'bastion_dummy',
|
192
|
+
}}
|
193
|
+
let(:cls_agent) { cls.new({ host: rand.to_s }) }
|
194
|
+
|
195
|
+
describe 'bastion' do
|
196
|
+
describe 'default options' do
|
197
|
+
let(:ssh) { cls.new({ bastion_host: 'bastion_dummy' }) }
|
198
|
+
|
199
|
+
it 'configures the host' do
|
200
|
+
ssh.options[:bastion_host].must_equal 'bastion_dummy'
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'has default port' do
|
204
|
+
ssh.options[:bastion_port].must_equal 22
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'has default user' do
|
208
|
+
ssh.options[:bastion_user].must_equal 'root'
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe 'opening a connection' do
|
213
|
+
let(:ssh) { cls.new(conf) }
|
214
|
+
let(:connection) { ssh.connection }
|
215
|
+
|
216
|
+
it 'provides a run_command_via_connection method' do
|
217
|
+
methods = connection.class.private_instance_methods(false)
|
218
|
+
methods.include?(:run_command_via_connection).must_equal true
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'provides a file_via_connection method' do
|
222
|
+
methods = connection.class.private_instance_methods(false)
|
223
|
+
methods.include?(:file_via_connection).must_equal true
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'gets the connection' do
|
227
|
+
connection.must_be_kind_of Train::Transports::SSH::Connection
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'provides a uri' do
|
231
|
+
connection.uri.must_equal "ssh://root@#{conf[:host]}:22"
|
232
|
+
end
|
233
|
+
|
234
|
+
it 'must respond to wait_until_ready' do
|
235
|
+
connection.must_respond_to :wait_until_ready
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'can be closed' do
|
239
|
+
connection.close.must_be_nil
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'has a login command == ssh' do
|
243
|
+
connection.login_command.command.must_equal 'ssh'
|
244
|
+
end
|
245
|
+
|
246
|
+
it 'has login command arguments' do
|
247
|
+
connection.login_command.arguments.must_equal([
|
248
|
+
"-o", "UserKnownHostsFile=/dev/null",
|
249
|
+
"-o", "StrictHostKeyChecking=no",
|
250
|
+
"-o", "IdentitiesOnly=yes",
|
251
|
+
"-o", "LogLevel=VERBOSE",
|
252
|
+
"-o", "ForwardAgent=no",
|
253
|
+
"-i", conf[:key_files],
|
254
|
+
"-o", "ProxyCommand='ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentitiesOnly=yes -o LogLevel=VERBOSE -o ForwardAgent=no -i #{conf[:key_files]} root@bastion_dummy -p 22 -W %h:%p'",
|
255
|
+
"-p", "22",
|
256
|
+
"root@#{conf[:host]}",
|
257
|
+
])
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'sets the right auth_methods when password is specified' do
|
261
|
+
conf[:key_files] = nil
|
262
|
+
cls.new(conf).connection.method(:options).call[:auth_methods].must_equal ["none", "password", "keyboard-interactive"]
|
263
|
+
end
|
264
|
+
|
265
|
+
it 'sets the right auth_methods when keys are specified' do
|
266
|
+
conf[:password] = nil
|
267
|
+
cls.new(conf).connection.method(:options).call[:auth_methods].must_equal ["none", "publickey"]
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'sets the right auth_methods for agent auth' do
|
271
|
+
cls_agent.stubs(:ssh_known_identities).returns({:some => 'rsa_key'})
|
272
|
+
cls_agent.connection.method(:options).call[:auth_methods].must_equal ['none', 'publickey']
|
273
|
+
end
|
274
|
+
|
275
|
+
it 'works with ssh agent auth' do
|
276
|
+
cls_agent.stubs(:ssh_known_identities).returns({:some => 'rsa_key'})
|
277
|
+
cls_agent.connection
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'sets up a proxy when ssh proxy command is specified' do
|
281
|
+
mock = MiniTest::Mock.new
|
282
|
+
mock.expect(:call, true) do |hostname, username, options|
|
283
|
+
options[:proxy].kind_of?(Net::SSH::Proxy::Command) &&
|
284
|
+
"ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentitiesOnly=yes -o LogLevel=VERBOSE -o ForwardAgent=no -i #{conf[:key_files]} root@bastion_dummy -p 22 -W %h:%p" == options[:proxy].command_line_template
|
285
|
+
end
|
286
|
+
connection.stubs(:run_command)
|
287
|
+
Net::SSH.stub(:start, mock) do
|
288
|
+
connection.wait_until_ready
|
289
|
+
end
|
290
|
+
mock.verify
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
describe 'ssh transport with bastion and proxy' do
|
297
|
+
let(:cls) do
|
298
|
+
plat = Train::Platforms.name('mock').in_family('linux')
|
299
|
+
plat.add_platform_methods
|
300
|
+
Train::Platforms::Detect.stubs(:scan).returns(plat)
|
301
|
+
Train::Transports::SSH
|
302
|
+
end
|
303
|
+
|
304
|
+
let(:conf) {{
|
305
|
+
host: rand.to_s,
|
306
|
+
password: rand.to_s,
|
307
|
+
key_files: rand.to_s,
|
308
|
+
bastion_host: 'bastion_dummy',
|
309
|
+
proxy_command: 'dummy'
|
310
|
+
}}
|
311
|
+
let(:cls_agent) { cls.new({ host: rand.to_s }) }
|
312
|
+
|
313
|
+
describe 'bastion and proxy' do
|
314
|
+
it 'will throw an exception when both proxy_command and bastion_host is specified' do
|
315
|
+
proc { cls.new(conf).connection }.must_raise Train::ClientError
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
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.4.
|
4
|
+
version: 1.4.19
|
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-06-
|
11
|
+
date: 2018-06-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|