beaker 3.23.0 → 3.24.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/docs/how_to/ssh_connection_preference.md +47 -0
- data/lib/beaker/host.rb +1 -1
- data/lib/beaker/hypervisor.rb +19 -0
- data/lib/beaker/ssh_connection.rb +21 -16
- data/lib/beaker/version.rb +1 -1
- data/spec/beaker/hypervisor/hypervisor_spec.rb +34 -4
- data/spec/beaker/ssh_connection_spec.rb +18 -20
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
N2FiNDY2YjhkNzI2MThmMjJiNWE4NTQyZDBiYjkyZTU3ZGMxYzViYQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MGRiYzJiNDU4NDg3ZTdmYTkzZDk2YjA4NmU2MDE1MzM4ZGIyZGU2Yg==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NGU5ZDg5NGIxMzUxYTNjYzc1ZWY4OGNhYzEwMTExYTllOGEzY2I1MjE2ZTQ3
|
10
|
+
MzViOTUyNmI5MmVmYzMyMjE5MTljOWI5YTAwZDdlYzZkNzMwMGQ4NDNiYjc3
|
11
|
+
MjFmZjVmN2U4YTNkN2NlYjUyNGUyOTY3ODIwMjU3MjUwMDE0MDI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NWQ0YzQ3NjViMWIxNDYwMjUxZDZiNTZkOTY0MTE1NTE5NjE3Y2UyYTJhYjY3
|
14
|
+
MTY1ODYwZjZmOGZiYTJmNDFiZmFmNDM5NTBmNDc2NDlkZmNmZTM1OTc1NmRm
|
15
|
+
NDlkOTI4ZTQzZDkyNGY3YWMwMzZkNGU2OGE3Nzc3YjllZjQ5NzQ=
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# Set SSH connection methods preference
|
2
|
+
|
3
|
+
Setting up a SSH connection to hosts can be tricky. Beaker supports three methods to SSH to hosts:
|
4
|
+
|
5
|
+
1. `ip`
|
6
|
+
2. `vmhostname (dns name)`
|
7
|
+
3. `hostname`
|
8
|
+
|
9
|
+
Beaker tries to SSH to hosts using these methods in a particular preference (order). Default preference is mentioned above. We allow hypervisor authors and end users to provide an array of these methods that reflects their preference.
|
10
|
+
|
11
|
+
### Why set a preference?
|
12
|
+
|
13
|
+
Depending upon your hypervisor, your host could have specific method that it uses to SSH better and faster than other methods. For example, hosts generated by vmpooler connects better with `vmhostname` as some change their ip adderess on restart. Therefore vmpooler hypervisor sets its connection preference to use vmhostname first.
|
14
|
+
|
15
|
+
### Setting SSH connection preference at hypervisor level
|
16
|
+
|
17
|
+
Hypervisor authors can set SSH connection preference. The only thing they have to do is override the `connection_preference` method set in [hypervisor.rb](https://github.com/puppetlabs/beaker/blob/master/lib/beaker/hypervisor.rb) file in their own hypervisor file.
|
18
|
+
|
19
|
+
For example, `beaker-vmpooler` overriding this in [vmpooler.rb](https://github.com/puppetlabs/beaker-vmpooler/blob/master/lib/beaker/hypervisor/vmpooler.rb) file.
|
20
|
+
|
21
|
+
### Setting SSH connection methods in hosts file
|
22
|
+
|
23
|
+
End users can override the connection preference that is default or set by their hypervisor. This can be done from your hosts file. All you need to do is provide a `ssh_preference` for each host. The value of this key should be an array of the methods specified above in an order you prefer. Beaker then will attempt to SSH to the hosts in that particular order.
|
24
|
+
|
25
|
+
Example of a host file:
|
26
|
+
|
27
|
+
```
|
28
|
+
HOSTS:
|
29
|
+
ubuntu1604-64-1:
|
30
|
+
hypervisor: vmpooler
|
31
|
+
platform: ubuntu-16.04-amd64
|
32
|
+
template: ubuntu-1604-x86_64
|
33
|
+
ssh_preference: ['vmhostname', 'hostname', 'ip']
|
34
|
+
roles:
|
35
|
+
- agent
|
36
|
+
- default
|
37
|
+
ubuntu1604-64-2:
|
38
|
+
hypervisor: vmpooler
|
39
|
+
platform: ubuntu-16.04-amd64
|
40
|
+
template: ubuntu-1604-x86_64
|
41
|
+
ssh_preference: ['ip, 'vmhostname']
|
42
|
+
roles:
|
43
|
+
- agent
|
44
|
+
CONFIG:
|
45
|
+
nfs_server: none
|
46
|
+
consoleport: 443
|
47
|
+
```
|
data/lib/beaker/host.rb
CHANGED
@@ -276,7 +276,7 @@ module Beaker
|
|
276
276
|
# create new connection object if necessary
|
277
277
|
@connection ||= SshConnection.connect( { :ip => self['ip'], :vmhostname => self['vmhostname'], :hostname => @name },
|
278
278
|
self['user'],
|
279
|
-
self['ssh'], { :logger => @logger } )
|
279
|
+
self['ssh'], { :logger => @logger, :ssh_connection_preference => self[:ssh_connection_preference]} )
|
280
280
|
# update connection information
|
281
281
|
if self['ip'] && (@connection.ip != self['ip'])
|
282
282
|
@connection.ip = self['ip']
|
data/lib/beaker/hypervisor.rb
CHANGED
@@ -37,6 +37,7 @@ module Beaker
|
|
37
37
|
end
|
38
38
|
|
39
39
|
hypervisor = hyper_class.new(hosts_to_provision, options)
|
40
|
+
self.set_ssh_connection_preference(hosts_to_provision, hypervisor)
|
40
41
|
hypervisor.provision if options[:provision]
|
41
42
|
|
42
43
|
hypervisor
|
@@ -57,6 +58,24 @@ module Beaker
|
|
57
58
|
nil
|
58
59
|
end
|
59
60
|
|
61
|
+
DEFAULT_CONNECTION_PREFERENCE = [:ip, :vmhostname, :hostname]
|
62
|
+
# SSH connection method preference. Can be overwritten by hypervisor to change the order
|
63
|
+
def connection_preference(host)
|
64
|
+
DEFAULT_CONNECTION_PREFERENCE
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.set_ssh_connection_preference(hosts_to_provision, hypervisor)
|
68
|
+
hosts_to_provision.each do |host|
|
69
|
+
ssh_methods = hypervisor.connection_preference(host) + DEFAULT_CONNECTION_PREFERENCE
|
70
|
+
if host[:ssh_preference]
|
71
|
+
# If user has provided ssh_connection_preference in hosts file then concat the preference provided by hypervisor
|
72
|
+
# Followed by concatenating the default preference and keeping the unique once
|
73
|
+
ssh_methods = host[:ssh_preference] + ssh_methods
|
74
|
+
end
|
75
|
+
host[:ssh_connection_preference] = ssh_methods.uniq
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
60
79
|
#Proxy package managers on tests hosts created by this hypervisor, runs before validation and configuration.
|
61
80
|
def proxy_package_manager
|
62
81
|
if @options[:package_proxy]
|
@@ -6,7 +6,9 @@ module Beaker
|
|
6
6
|
class SshConnection
|
7
7
|
|
8
8
|
attr_accessor :logger
|
9
|
-
attr_accessor :ip, :vmhostname, :hostname
|
9
|
+
attr_accessor :ip, :vmhostname, :hostname, :ssh_connection_preference
|
10
|
+
|
11
|
+
SUPPORTED_CONNECTION_METHODS = [:ip, :vmhostname, :hostname]
|
10
12
|
|
11
13
|
RETRYABLE_EXCEPTIONS = [
|
12
14
|
SocketError,
|
@@ -33,6 +35,7 @@ module Beaker
|
|
33
35
|
@ssh_opts = ssh_opts
|
34
36
|
@logger = options[:logger]
|
35
37
|
@options = options
|
38
|
+
@ssh_connection_preference = @options[:ssh_connection_preference]
|
36
39
|
end
|
37
40
|
|
38
41
|
def self.connect name_hash, user = 'root', ssh_opts = {}, options = {}
|
@@ -65,22 +68,24 @@ module Beaker
|
|
65
68
|
|
66
69
|
# connect to the host
|
67
70
|
def connect
|
68
|
-
#
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
71
|
+
# Try three ways to connect to host (vmhostname, ip, hostname)
|
72
|
+
# Try each method in turn until we succeed
|
73
|
+
methods = @ssh_connection_preference.dup
|
74
|
+
while (not @ssh) && (not methods.empty?) do
|
75
|
+
unless instance_variable_get("@#{methods[0]}").nil?
|
76
|
+
if SUPPORTED_CONNECTION_METHODS.include?(methods[0])
|
77
|
+
@ssh = connect_block(instance_variable_get("@#{methods[0].to_s}"), @user, @ssh_opts)
|
78
|
+
else
|
79
|
+
@logger.warn "Beaker does not support #{methods[0]} to SSH to host, trying next available method."
|
80
|
+
@ssh_connection_preference.delete(methods[0])
|
81
|
+
end
|
82
|
+
else
|
83
|
+
@logger.warn "Skipping #{methods[0]} method to ssh to host as its value is not set. Refer to https://github.com/puppetlabs/beaker/tree/master/docs/how_to/ssh_connection_preference.md to remove this warning"
|
84
|
+
end
|
85
|
+
methods.shift
|
81
86
|
end
|
82
|
-
|
83
|
-
@logger.error "Failed to connect to #{@hostname}, attempted #{
|
87
|
+
unless @ssh
|
88
|
+
@logger.error "Failed to connect to #{@hostname}, attempted #{@ssh_connection_preference.join(', ')}"
|
84
89
|
raise RuntimeError, "Cannot connect to #{@hostname}"
|
85
90
|
end
|
86
91
|
@ssh
|
data/lib/beaker/version.rb
CHANGED
@@ -2,15 +2,45 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module Beaker
|
4
4
|
describe Hypervisor do
|
5
|
-
let( :
|
5
|
+
let( :hosts ) { make_hosts( { :platform => 'el-5' } ) }
|
6
|
+
|
7
|
+
context "#create" do
|
8
|
+
let( :hypervisor ) { Beaker::Hypervisor }
|
9
|
+
|
10
|
+
it "includes custom hypervisor and call set_ssh_connection_preference" do
|
11
|
+
allow(hypervisor).to receive(:set_ssh_connection_preference).with([], hypervisor)
|
12
|
+
expect{ hypervisor.create('custom_hypervisor', [], make_opts() )}.to raise_error(RuntimeError, "Invalid hypervisor: custom_hypervisor")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "sets ssh connection preference if connection_preference method is not overwritten" do
|
16
|
+
hypervisor.create('none', hosts, make_opts())
|
17
|
+
expect(hosts[0][:ssh_connection_preference]).to eq([:ip,:vmhostname,:hostname])
|
18
|
+
end
|
19
|
+
|
20
|
+
it "concats overriding connection_preference array with the default connection_preference" do
|
21
|
+
allow(hypervisor).to receive(:connection_preference).and_return([:my,:invalid,:method_name])
|
22
|
+
hypervisor.set_ssh_connection_preference(hosts, hypervisor)
|
23
|
+
expect(hosts[0][:ssh_connection_preference]).to eq([:my,:invalid,:method_name,:ip,:vmhostname,:hostname])
|
24
|
+
end
|
25
|
+
|
26
|
+
it "removes unique elements from concated array while preserving order of overriding methods" do
|
27
|
+
allow(hypervisor).to receive(:connection_preference).and_return([:my,:ip,:vmhostname,:method_name])
|
28
|
+
hypervisor.set_ssh_connection_preference(hosts, hypervisor)
|
29
|
+
expect(hosts[0][:ssh_connection_preference]).to eq([:my,:ip,:vmhostname,:method_name,:hostname])
|
30
|
+
end
|
31
|
+
|
32
|
+
it "gives highest precedence to preference specified in host file followed by hypervisor" do
|
33
|
+
hosts[0].options[:ssh_preference] = ['set', 'in', 'hostfile']
|
34
|
+
hypervisor.create('none', hosts, make_opts())
|
35
|
+
allow(hypervisor).to receive(:connection_preference).and_return([:hypervisor, :pref])
|
36
|
+
hypervisor.set_ssh_connection_preference(hosts, hypervisor)
|
37
|
+
expect(hosts[0][:ssh_connection_preference]).to eq(['set', 'in', 'hostfile', :hypervisor, :pref, :ip, :vmhostname, :hostname])
|
38
|
+
end
|
6
39
|
|
7
|
-
it "includes custom hypervisor" do
|
8
|
-
expect{ hypervisor.create('custom_hypervisor', [], make_opts() )}.to raise_error(RuntimeError, "Invalid hypervisor: custom_hypervisor")
|
9
40
|
end
|
10
41
|
|
11
42
|
context "#configure" do
|
12
43
|
let( :options ) { make_opts.merge({ 'logger' => double().as_null_object }) }
|
13
|
-
let( :hosts ) { make_hosts( { :platform => 'el-5' } ) }
|
14
44
|
let( :hypervisor ) { Beaker::Hypervisor.new( hosts, options ) }
|
15
45
|
|
16
46
|
context 'if :timesync option set true on host' do
|
@@ -5,7 +5,7 @@ module Beaker
|
|
5
5
|
describe SshConnection do
|
6
6
|
let( :user ) { 'root' }
|
7
7
|
let( :ssh_opts ) { { keepalive: true, keepalive_interval: 2 } }
|
8
|
-
let( :options ) { { :logger => double('logger').as_null_object }
|
8
|
+
let( :options ) { { :logger => double('logger').as_null_object, :ssh_connection_preference => [:ip, :vmhostname, :hostname]} }
|
9
9
|
let( :ip ) { "default.ip.address" }
|
10
10
|
let( :vmhostname ){ "vmhostname" }
|
11
11
|
let( :hostname) { "my_host" }
|
@@ -17,26 +17,24 @@ module Beaker
|
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'self.connect creates connects and returns a proxy for that connection' do
|
20
|
-
|
21
|
-
expect( Net::SSH ).to receive(:start).with( vmhostname, user, ssh_opts ).and_return(true)
|
20
|
+
expect( Net::SSH ).to receive(:start).with( "default.ip.address", user, ssh_opts ).and_return(true)
|
22
21
|
connection_constructor = SshConnection.connect name_hash, user, ssh_opts, options
|
23
22
|
expect( connection_constructor ).to be_a_kind_of SshConnection
|
24
23
|
end
|
25
24
|
|
26
25
|
it 'connect creates a new connection' do
|
27
|
-
expect( Net::SSH ).to receive( :start ).with(
|
26
|
+
expect( Net::SSH ).to receive( :start ).with( ip, user, ssh_opts).and_return(true)
|
28
27
|
connection.connect
|
29
28
|
end
|
30
29
|
|
31
30
|
it 'connect caches its connection' do
|
32
|
-
expect( Net::SSH ).to receive( :start ).with(
|
33
|
-
connection.connect
|
31
|
+
expect( Net::SSH ).to receive( :start ).with( ip, user, ssh_opts ).once.and_return true
|
34
32
|
connection.connect
|
35
33
|
end
|
36
34
|
|
37
|
-
it 'attempts to connect by
|
38
|
-
expect( Net::SSH ).to receive( :start ).with(
|
39
|
-
expect( Net::SSH ).to receive( :start ).with(
|
35
|
+
it 'attempts to connect by vmhostname address if ip connection fails' do
|
36
|
+
expect( Net::SSH ).to receive( :start ).with( ip, user, ssh_opts).and_return(false)
|
37
|
+
expect( Net::SSH ).to receive( :start ).with( vmhostname, user, ssh_opts).and_return(true).once
|
40
38
|
expect( Net::SSH ).to receive( :start ).with( hostname, user, ssh_opts).never
|
41
39
|
connection.connect
|
42
40
|
end
|
@@ -53,7 +51,7 @@ module Beaker
|
|
53
51
|
|
54
52
|
it 'runs ssh close' do
|
55
53
|
mock_ssh = Object.new
|
56
|
-
expect( Net::SSH ).to receive( :start ).with(
|
54
|
+
expect( Net::SSH ).to receive( :start ).with( ip, user, ssh_opts) { mock_ssh }
|
57
55
|
connection.connect
|
58
56
|
|
59
57
|
allow( mock_ssh).to receive( :closed? ).once.and_return(false)
|
@@ -63,7 +61,7 @@ module Beaker
|
|
63
61
|
|
64
62
|
it 'sets the @ssh variable to nil' do
|
65
63
|
mock_ssh = Object.new
|
66
|
-
expect( Net::SSH ).to receive( :start ).with(
|
64
|
+
expect( Net::SSH ).to receive( :start ).with( ip, user, ssh_opts) { mock_ssh }
|
67
65
|
connection.connect
|
68
66
|
|
69
67
|
allow( mock_ssh).to receive( :closed? ).once.and_return(false)
|
@@ -76,7 +74,7 @@ module Beaker
|
|
76
74
|
it 'calls ssh shutdown & re-raises if ssh close fails with an unexpected Error' do
|
77
75
|
mock_ssh = Object.new
|
78
76
|
allow( mock_ssh ).to receive( :close ) { raise StandardError }
|
79
|
-
expect( Net::SSH ).to receive( :start ).with(
|
77
|
+
expect( Net::SSH ).to receive( :start ).with( ip, user, ssh_opts) { mock_ssh }
|
80
78
|
connection.connect
|
81
79
|
|
82
80
|
allow( mock_ssh).to receive( :closed? ).once.and_return(false)
|
@@ -90,7 +88,7 @@ module Beaker
|
|
90
88
|
describe '#execute' do
|
91
89
|
it 'retries if failed with a retryable exception' do
|
92
90
|
mock_ssh = Object.new
|
93
|
-
expect( Net::SSH ).to receive( :start ).with(
|
91
|
+
expect( Net::SSH ).to receive( :start ).with( ip, user, ssh_opts) { mock_ssh }
|
94
92
|
connection.connect
|
95
93
|
|
96
94
|
allow( subject ).to receive( :close )
|
@@ -102,7 +100,7 @@ module Beaker
|
|
102
100
|
|
103
101
|
it 'raises an error if it fails both times' do
|
104
102
|
mock_ssh = Object.new
|
105
|
-
expect( Net::SSH ).to receive( :start ).with(
|
103
|
+
expect( Net::SSH ).to receive( :start ).with( ip, user, ssh_opts) { mock_ssh }
|
106
104
|
connection.connect
|
107
105
|
|
108
106
|
allow( subject ).to receive( :close )
|
@@ -115,7 +113,7 @@ module Beaker
|
|
115
113
|
describe '#request_terminal_for' do
|
116
114
|
it 'fails correctly by raising Net::SSH::Exception' do
|
117
115
|
mock_ssh = Object.new
|
118
|
-
expect( Net::SSH ).to receive( :start ).with(
|
116
|
+
expect( Net::SSH ).to receive( :start ).with( ip, user, ssh_opts) { mock_ssh }
|
119
117
|
connection.connect
|
120
118
|
|
121
119
|
mock_channel = Object.new
|
@@ -128,7 +126,7 @@ module Beaker
|
|
128
126
|
describe '#register_stdout_for' do
|
129
127
|
before :each do
|
130
128
|
@mock_ssh = Object.new
|
131
|
-
expect( Net::SSH ).to receive( :start ).with(
|
129
|
+
expect( Net::SSH ).to receive( :start ).with( ip, user, ssh_opts) { @mock_ssh }
|
132
130
|
connection.connect
|
133
131
|
|
134
132
|
@data = '7 of clubs'
|
@@ -164,7 +162,7 @@ module Beaker
|
|
164
162
|
|
165
163
|
before :each do
|
166
164
|
@mock_ssh = Object.new
|
167
|
-
expect( Net::SSH ).to receive( :start ).with(
|
165
|
+
expect( Net::SSH ).to receive( :start ).with( ip, user, ssh_opts) { @mock_ssh }
|
168
166
|
connection.connect
|
169
167
|
|
170
168
|
@data = '3 of spades'
|
@@ -203,7 +201,7 @@ module Beaker
|
|
203
201
|
|
204
202
|
it 'assigns the output\'s exit code correctly from the data' do
|
205
203
|
mock_ssh = Object.new
|
206
|
-
expect( Net::SSH ).to receive( :start ).with(
|
204
|
+
expect( Net::SSH ).to receive( :start ).with( ip, user, ssh_opts) { mock_ssh }
|
207
205
|
connection.connect
|
208
206
|
|
209
207
|
data = '10 of jeromes'
|
@@ -236,7 +234,7 @@ module Beaker
|
|
236
234
|
@mock_scp = Object.new
|
237
235
|
allow( @mock_scp ).to receive( :upload! )
|
238
236
|
allow( @mock_ssh ).to receive( :scp ).and_return( @mock_scp )
|
239
|
-
expect( Net::SSH ).to receive( :start ).with(
|
237
|
+
expect( Net::SSH ).to receive( :start ).with( ip, user, ssh_opts) { @mock_ssh }
|
240
238
|
connection.connect
|
241
239
|
end
|
242
240
|
|
@@ -263,7 +261,7 @@ module Beaker
|
|
263
261
|
@mock_scp = Object.new
|
264
262
|
allow( @mock_scp ).to receive( :download! )
|
265
263
|
allow( @mock_ssh ).to receive( :scp ).and_return( @mock_scp )
|
266
|
-
expect( Net::SSH ).to receive( :start ).with(
|
264
|
+
expect( Net::SSH ).to receive( :start ).with( ip, user, ssh_opts) { @mock_ssh }
|
267
265
|
connection.connect
|
268
266
|
end
|
269
267
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: beaker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.24.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppet
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-09-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -591,6 +591,7 @@ files:
|
|
591
591
|
- docs/how_to/recipes.md
|
592
592
|
- docs/how_to/run_in_parallel.md
|
593
593
|
- docs/how_to/ssh_agent_forwarding.md
|
594
|
+
- docs/how_to/ssh_connection_preference.md
|
594
595
|
- docs/how_to/test_arbitrary_beaker_versions.md
|
595
596
|
- docs/how_to/the_beaker_dsl.md
|
596
597
|
- docs/how_to/upgrade_from_2_to_3.md
|