train 1.4.15 → 1.4.19
Sign up to get free protection for your applications and to get access to all the features.
- 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
|