beaker 2.7.1 → 2.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/HISTORY.md +121 -2
- data/lib/beaker/dsl.rb +2 -2
- data/lib/beaker/dsl/helpers.rb +13 -1429
- data/lib/beaker/dsl/helpers/facter_helpers.rb +48 -0
- data/lib/beaker/dsl/helpers/hiera_helpers.rb +71 -0
- data/lib/beaker/dsl/helpers/host_helpers.rb +506 -0
- data/lib/beaker/dsl/helpers/puppet_helpers.rb +698 -0
- data/lib/beaker/dsl/helpers/tk_helpers.rb +101 -0
- data/lib/beaker/dsl/helpers/web_helpers.rb +115 -0
- data/lib/beaker/dsl/install_utils.rb +8 -1570
- data/lib/beaker/dsl/install_utils/ezbake_utils.rb +256 -0
- data/lib/beaker/dsl/install_utils/module_utils.rb +237 -0
- data/lib/beaker/dsl/install_utils/pe_utils.rb +518 -0
- data/lib/beaker/dsl/install_utils/puppet_utils.rb +722 -0
- data/lib/beaker/dsl/outcomes.rb +0 -4
- data/lib/beaker/dsl/roles.rb +0 -3
- data/lib/beaker/dsl/structure.rb +127 -4
- data/lib/beaker/dsl/wrappers.rb +0 -4
- data/lib/beaker/host.rb +23 -0
- data/lib/beaker/host/unix/pkg.rb +4 -4
- data/lib/beaker/host_prebuilt_steps.rb +11 -5
- data/lib/beaker/hypervisor/vagrant.rb +1 -0
- data/lib/beaker/hypervisor/vmpooler.rb +38 -0
- data/lib/beaker/logger.rb +10 -4
- data/lib/beaker/network_manager.rb +5 -4
- data/lib/beaker/options/command_line_parser.rb +7 -0
- data/lib/beaker/shared.rb +2 -1
- data/lib/beaker/shared/semvar.rb +41 -0
- data/lib/beaker/test_suite.rb +20 -6
- data/lib/beaker/version.rb +1 -1
- data/spec/beaker/dsl/helpers/facter_helpers_spec.rb +59 -0
- data/spec/beaker/dsl/helpers/hiera_helpers_spec.rb +96 -0
- data/spec/beaker/dsl/helpers/host_helpers_spec.rb +413 -0
- data/spec/beaker/dsl/{helpers_spec.rb → helpers/puppet_helpers_spec.rb} +2 -611
- data/spec/beaker/dsl/helpers/tk_helpers_spec.rb +83 -0
- data/spec/beaker/dsl/helpers/web_helpers_spec.rb +60 -0
- data/spec/beaker/dsl/install_utils/module_utils_spec.rb +241 -0
- data/spec/beaker/dsl/install_utils/pe_utils_spec.rb +475 -0
- data/spec/beaker/dsl/install_utils/puppet_utils_spec.rb +523 -0
- data/spec/beaker/dsl/structure_spec.rb +108 -0
- data/spec/beaker/host_prebuilt_steps_spec.rb +44 -0
- data/spec/beaker/host_spec.rb +41 -0
- data/spec/beaker/hypervisor/vagrant_spec.rb +2 -1
- data/spec/beaker/logger_spec.rb +9 -2
- data/spec/beaker/network_manager_spec.rb +7 -1
- data/spec/beaker/options/command_line_parser_spec.rb +3 -2
- data/spec/beaker/shared/semvar_spec.rb +36 -0
- data/spec/beaker/test_suite_spec.rb +48 -0
- data/spec/mocks.rb +10 -0
- metadata +23 -5
- data/lib/beaker/dsl/ezbake_utils.rb +0 -259
- data/spec/beaker/dsl/install_utils_spec.rb +0 -1242
@@ -137,6 +137,13 @@ module Beaker
|
|
137
137
|
@cmd_options[:log_level] = val
|
138
138
|
end
|
139
139
|
|
140
|
+
opts.on '--log-prefix PREFIX',
|
141
|
+
'Use a custom prefix for your Beaker log files',
|
142
|
+
'can provide nested directories (ie. face/man)',
|
143
|
+
'(defaults to hostfile name. ie. ../i/07.yml --> "07")' do |val|
|
144
|
+
@cmd_options[:log_prefix] = val
|
145
|
+
end
|
146
|
+
|
140
147
|
opts.on '-d', '--[no-]dry-run',
|
141
148
|
'Report what would happen on targets',
|
142
149
|
'(default: false)' do |bool|
|
data/lib/beaker/shared.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
[ 'repetition', 'error_handler', 'host_manager', 'timed' ].each do |lib|
|
1
|
+
[ 'repetition', 'error_handler', 'host_manager', 'timed', 'semvar' ].each do |lib|
|
2
2
|
require "beaker/shared/#{lib}"
|
3
3
|
end
|
4
4
|
module Beaker
|
@@ -7,6 +7,7 @@ module Beaker
|
|
7
7
|
include Beaker::Shared::HostManager
|
8
8
|
include Beaker::Shared::Repetition
|
9
9
|
include Beaker::Shared::Timed
|
10
|
+
include Beaker::Shared::Semvar
|
10
11
|
end
|
11
12
|
end
|
12
13
|
include Beaker::Shared
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Beaker
|
2
|
+
module Shared
|
3
|
+
module Semvar
|
4
|
+
|
5
|
+
#Is semver-ish version a less than semver-ish version b
|
6
|
+
#@param [String] a A version of the from '\d.\d.\d.*'
|
7
|
+
#@param [String] b A version of the form '\d.\d.\d.*'
|
8
|
+
#@return [Boolean] true if a is less than b, otherwise return false
|
9
|
+
#
|
10
|
+
#@note 3.0.0-160-gac44cfb is greater than 3.0.0, and 2.8.2
|
11
|
+
#@note -rc being less than final builds is not yet implemented.
|
12
|
+
def version_is_less a, b
|
13
|
+
a_nums = a.split('-')[0].split('.')
|
14
|
+
b_nums = b.split('-')[0].split('.')
|
15
|
+
(0...a_nums.length).each do |i|
|
16
|
+
if i < b_nums.length
|
17
|
+
if a_nums[i] < b_nums[i]
|
18
|
+
return true
|
19
|
+
elsif a_nums[i] > b_nums[i]
|
20
|
+
return false
|
21
|
+
end
|
22
|
+
else
|
23
|
+
return false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
#checks all dots, they are equal so examine the rest
|
27
|
+
a_rest = a.split('-', 2)[1]
|
28
|
+
b_rest = b.split('-', 2)[1]
|
29
|
+
if a_rest and b_rest and a_rest < b_rest
|
30
|
+
return false
|
31
|
+
elsif a_rest and not b_rest
|
32
|
+
return false
|
33
|
+
elsif not a_rest and b_rest
|
34
|
+
return true
|
35
|
+
end
|
36
|
+
return false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
data/lib/beaker/test_suite.rb
CHANGED
@@ -336,7 +336,7 @@ module Beaker
|
|
336
336
|
# Gives a full file path for output to be written to, maintaining the latest symlink
|
337
337
|
# @param [String] name The file name that we want to write to.
|
338
338
|
# @param [String] log_dir The desired output directory.
|
339
|
-
# A symlink will be made from ./
|
339
|
+
# A symlink will be made from ./basedir/latest to that.
|
340
340
|
# @example
|
341
341
|
# log_path('output.txt', 'log/2014-06-02_16_31_22')
|
342
342
|
#
|
@@ -344,17 +344,31 @@ module Beaker
|
|
344
344
|
#
|
345
345
|
# ./log/2014-06-02_16_31_22/output.txt
|
346
346
|
# ./log/latest -> 2014-06-02_16_31_22
|
347
|
+
#
|
348
|
+
# @example
|
349
|
+
# log_path('foo.log', 'log/man/date')
|
350
|
+
#
|
351
|
+
# This will create the structure:
|
352
|
+
#
|
353
|
+
# ./log/man/date/foo.log
|
354
|
+
# ./log/latest -> man/date
|
347
355
|
def log_path(name, log_dir)
|
348
|
-
log_parent_dir = File.dirname(log_dir)
|
349
356
|
FileUtils.mkdir_p(log_dir) unless File.directory?(log_dir)
|
350
357
|
|
351
|
-
|
358
|
+
base_dir = log_dir
|
359
|
+
link_dir = ''
|
360
|
+
while File.dirname(base_dir) != '.' do
|
361
|
+
link_dir = link_dir == '' ? File.basename(base_dir) : File.join(File.basename(base_dir), link_dir)
|
362
|
+
base_dir = File.dirname(base_dir)
|
363
|
+
end
|
364
|
+
|
365
|
+
latest = File.join(base_dir, "latest")
|
352
366
|
if !File.exist?(latest) or File.symlink?(latest) then
|
353
|
-
File.delete(latest) if File.exist?(latest)
|
354
|
-
File.symlink(
|
367
|
+
File.delete(latest) if File.exist?(latest) || File.symlink?(latest)
|
368
|
+
File.symlink(link_dir, latest)
|
355
369
|
end
|
356
370
|
|
357
|
-
File.join(
|
371
|
+
File.join(log_dir, name)
|
358
372
|
end
|
359
373
|
|
360
374
|
end
|
data/lib/beaker/version.rb
CHANGED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class ClassMixedWithDSLHelpers
|
4
|
+
include Beaker::DSL::Helpers
|
5
|
+
include Beaker::DSL::Wrappers
|
6
|
+
include Beaker::DSL::Roles
|
7
|
+
include Beaker::DSL::Patterns
|
8
|
+
|
9
|
+
def logger
|
10
|
+
RSpec::Mocks::Double.new('logger').as_null_object
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
describe ClassMixedWithDSLHelpers do
|
16
|
+
let( :command ){ 'ls' }
|
17
|
+
let( :host ) { double.as_null_object }
|
18
|
+
let( :result ) { Beaker::Result.new( host, command ) }
|
19
|
+
|
20
|
+
let( :master ) { make_host( 'master', :roles => %w( master agent default) ) }
|
21
|
+
let( :agent ) { make_host( 'agent', :roles => %w( agent ) ) }
|
22
|
+
let( :custom ) { make_host( 'custom', :roles => %w( custom agent ) ) }
|
23
|
+
let( :dash ) { make_host( 'console', :roles => %w( dashboard agent ) ) }
|
24
|
+
let( :db ) { make_host( 'db', :roles => %w( database agent ) ) }
|
25
|
+
let( :hosts ) { [ master, agent, dash, db, custom ] }
|
26
|
+
|
27
|
+
|
28
|
+
describe '#fact_on' do
|
29
|
+
it 'retrieves a fact on a single host' do
|
30
|
+
result.stdout = "family\n"
|
31
|
+
expect( subject ).to receive(:facter).with('osfamily',{}).once
|
32
|
+
expect( subject ).to receive(:on).and_return(result)
|
33
|
+
|
34
|
+
expect( subject.fact_on('host','osfamily') ).to be === result.stdout.chomp
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'retrieves an array of facts from multiple hosts' do
|
38
|
+
allow( subject ).to receive( :hosts ).and_return( hosts )
|
39
|
+
times = hosts.length
|
40
|
+
result.stdout = "family\n"
|
41
|
+
hosts.each do |host|
|
42
|
+
expect( host ).to receive(:exec).and_return(result)
|
43
|
+
end
|
44
|
+
|
45
|
+
expect( subject.fact_on(hosts,'osfamily') ).to be === [result.stdout.chomp] * hosts.length
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#fact' do
|
51
|
+
it 'delegates to #fact_on with the default host' do
|
52
|
+
allow( subject ).to receive(:hosts).and_return(hosts)
|
53
|
+
expect( subject ).to receive(:fact_on).with(master,"osfamily",{}).once
|
54
|
+
|
55
|
+
subject.fact('osfamily')
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class ClassMixedWithDSLHelpers
|
4
|
+
include Beaker::DSL::Helpers
|
5
|
+
include Beaker::DSL::Wrappers
|
6
|
+
include Beaker::DSL::Roles
|
7
|
+
include Beaker::DSL::Patterns
|
8
|
+
|
9
|
+
def logger
|
10
|
+
RSpec::Mocks::Double.new('logger').as_null_object
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
describe ClassMixedWithDSLHelpers do
|
16
|
+
let( :opts ) { Beaker::Options::Presets.env_vars }
|
17
|
+
let( :command ){ 'ls' }
|
18
|
+
let( :host ) { double.as_null_object }
|
19
|
+
let( :result ) { Beaker::Result.new( host, command ) }
|
20
|
+
|
21
|
+
let( :master ) { make_host( 'master', :roles => %w( master agent default) ) }
|
22
|
+
let( :agent ) { make_host( 'agent', :roles => %w( agent ) ) }
|
23
|
+
let( :custom ) { make_host( 'custom', :roles => %w( custom agent ) ) }
|
24
|
+
let( :dash ) { make_host( 'console', :roles => %w( dashboard agent ) ) }
|
25
|
+
let( :db ) { make_host( 'db', :roles => %w( database agent ) ) }
|
26
|
+
let( :hosts ) { [ master, agent, dash, db, custom ] }
|
27
|
+
|
28
|
+
|
29
|
+
describe "#write_hiera_config_on" do
|
30
|
+
let(:hierarchy) { [ 'nodes/%{::fqdn}', 'common' ] }
|
31
|
+
it 'on FOSS host' do
|
32
|
+
host = make_host('testhost', { :platform => 'ubuntu' } )
|
33
|
+
expect(subject).to receive(:create_remote_file).with(host, host.puppet['hiera_config'], /#{host[:hieradatadir]}/)
|
34
|
+
subject.write_hiera_config_on(host, hierarchy)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'on PE host' do
|
38
|
+
host = make_host('testhost', { :platform => 'ubuntu', :type => 'pe' } )
|
39
|
+
expect(subject).to receive(:create_remote_file).with(host, host.puppet['hiera_config'], /#{host[:hieradatadir]}/)
|
40
|
+
subject.write_hiera_config_on(host, hierarchy)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#write_hiera_config" do
|
46
|
+
let(:hierarchy) { [ 'nodes/%{::fqdn}', 'common' ] }
|
47
|
+
it 'delegates to #write_hiera_config_on with the default host' do
|
48
|
+
allow( subject ).to receive( :hosts ).and_return( hosts )
|
49
|
+
expect( subject ).to receive( :write_hiera_config_on ).with( master, hierarchy).once
|
50
|
+
subject.write_hiera_config( hierarchy )
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "#copy_hiera_data_to" do
|
56
|
+
let(:path) { 'spec/fixtures/hieradata' }
|
57
|
+
it 'on FOSS host' do
|
58
|
+
host = make_host('testhost', { :platform => 'ubuntu' } )
|
59
|
+
expect(subject).to receive(:scp_to).with(host, File.expand_path(path), host[:hieradatadir])
|
60
|
+
subject.copy_hiera_data_to(host, path)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'on PE host' do
|
64
|
+
host = make_host('testhost', { :platform => 'ubuntu', :type => 'pe' } )
|
65
|
+
expect(subject).to receive(:scp_to).with(host, File.expand_path(path), host[:hieradatadir])
|
66
|
+
subject.copy_hiera_data_to(host, path)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#copy_hiera_data" do
|
71
|
+
let(:path) { 'spec/fixtures/hieradata' }
|
72
|
+
it 'delegates to #copy_hiera_data_to with the default host' do
|
73
|
+
allow( subject ).to receive( :hosts ).and_return( hosts )
|
74
|
+
expect( subject ).to receive( :copy_hiera_data_to ).with( master, path).once
|
75
|
+
subject.copy_hiera_data( path )
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '#hiera_datadir' do
|
81
|
+
it 'returns the codedir based hieradatadir for AIO' do
|
82
|
+
host = hosts[0]
|
83
|
+
host['type'] = :aio
|
84
|
+
correct_answer = File.join(host.puppet['codedir'], 'hieradata')
|
85
|
+
expect( subject.hiera_datadir(host) ).to be === correct_answer
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'returns the hieradata host value for anything not AIO (backwards compatible)' do
|
89
|
+
host_hieradatadir_value = '/home/fishing/man/pants'
|
90
|
+
host = hosts[0]
|
91
|
+
host[:hieradatadir] = host_hieradatadir_value
|
92
|
+
expect( subject.hiera_datadir(host) ).to be === host_hieradatadir_value
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
@@ -0,0 +1,413 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class ClassMixedWithDSLHelpers
|
4
|
+
include Beaker::DSL::Helpers
|
5
|
+
include Beaker::DSL::Wrappers
|
6
|
+
include Beaker::DSL::Roles
|
7
|
+
include Beaker::DSL::Patterns
|
8
|
+
|
9
|
+
def logger
|
10
|
+
RSpec::Mocks::Double.new('logger').as_null_object
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
describe ClassMixedWithDSLHelpers do
|
16
|
+
let( :opts ) { Beaker::Options::Presets.env_vars }
|
17
|
+
let( :command ){ 'ls' }
|
18
|
+
let( :host ) { double.as_null_object }
|
19
|
+
let( :result ) { Beaker::Result.new( host, command ) }
|
20
|
+
|
21
|
+
let( :master ) { make_host( 'master', :roles => %w( master agent default) ) }
|
22
|
+
let( :agent ) { make_host( 'agent', :roles => %w( agent ) ) }
|
23
|
+
let( :custom ) { make_host( 'custom', :roles => %w( custom agent ) ) }
|
24
|
+
let( :dash ) { make_host( 'console', :roles => %w( dashboard agent ) ) }
|
25
|
+
let( :db ) { make_host( 'db', :roles => %w( database agent ) ) }
|
26
|
+
let( :hosts ) { [ master, agent, dash, db, custom ] }
|
27
|
+
|
28
|
+
describe '#on' do
|
29
|
+
|
30
|
+
before :each do
|
31
|
+
result.stdout = 'stdout'
|
32
|
+
result.stderr = 'stderr'
|
33
|
+
result.exit_code = 0
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'allows the environment the command is run within to be specified' do
|
37
|
+
allow( subject ).to receive( :hosts ).and_return( hosts )
|
38
|
+
|
39
|
+
expect( Beaker::Command ).to receive( :new ).
|
40
|
+
with( 'ls ~/.bin', [], {'ENV' => { :HOME => '/tmp/test_home' }} )
|
41
|
+
|
42
|
+
subject.on( host, 'ls ~/.bin', :environment => {:HOME => '/tmp/test_home' } )
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'if the host is a String Object, finds the matching hosts with that String as role' do
|
46
|
+
allow( subject ).to receive( :hosts ).and_return( hosts )
|
47
|
+
|
48
|
+
expect( master ).to receive( :exec ).once
|
49
|
+
|
50
|
+
subject.on( 'master', 'echo hello')
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'if the host is a Symbol Object, finds the matching hsots with that Symbol as role' do
|
55
|
+
allow( subject ).to receive( :hosts ).and_return( hosts )
|
56
|
+
|
57
|
+
expect( master ).to receive( :exec ).once
|
58
|
+
|
59
|
+
subject.on( :master, 'echo hello')
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'delegates to itself for each host passed' do
|
64
|
+
allow( subject ).to receive( :hosts ).and_return( hosts )
|
65
|
+
expected = []
|
66
|
+
hosts.each_with_index do |host, i|
|
67
|
+
expected << i
|
68
|
+
expect( host ).to receive( :exec ).and_return( i )
|
69
|
+
end
|
70
|
+
|
71
|
+
results = subject.on( hosts, command )
|
72
|
+
expect( results ).to be == expected
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'upon command completion' do
|
76
|
+
before :each do
|
77
|
+
allow( subject ).to receive( :hosts ).and_return( hosts )
|
78
|
+
expect( host ).to receive( :exec ).and_return( result )
|
79
|
+
@res = subject.on( host, command )
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'returns the result of the action' do
|
83
|
+
expect( @res ).to be == result
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'provides access to stdout' do
|
87
|
+
expect( @res.stdout ).to be == 'stdout'
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'provides access to stderr' do
|
91
|
+
expect( @res.stderr ).to be == 'stderr'
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'provides access to exit_code' do
|
95
|
+
expect( @res.exit_code ).to be == 0
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'when passed a block with arity of 1' do
|
100
|
+
before :each do
|
101
|
+
allow( subject ).to receive( :hosts ).and_return( hosts )
|
102
|
+
expect( host ).to receive( :exec ).and_return( result )
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'yields result' do
|
106
|
+
subject.on host, command do |containing_class|
|
107
|
+
expect( containing_class ).
|
108
|
+
to be_an_instance_of( Beaker::Result )
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'provides access to stdout' do
|
113
|
+
subject.on host, command do |containing_class|
|
114
|
+
expect( containing_class.stdout ).to be == 'stdout'
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'provides access to stderr' do
|
119
|
+
subject.on host, command do |containing_class|
|
120
|
+
expect( containing_class.stderr ).to be == 'stderr'
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'provides access to exit_code' do
|
125
|
+
subject.on host, command do |containing_class|
|
126
|
+
expect( containing_class.exit_code ).to be == 0
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'when passed a block with arity of 0' do
|
132
|
+
before :each do
|
133
|
+
allow( subject ).to receive( :hosts ).and_return( hosts )
|
134
|
+
expect( host ).to receive( :exec ).and_return( result )
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'yields self' do
|
138
|
+
subject.on host, command do
|
139
|
+
expect( subject ).
|
140
|
+
to be_an_instance_of( ClassMixedWithDSLHelpers )
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'provides access to stdout' do
|
145
|
+
subject.on host, command do
|
146
|
+
expect( subject.stdout ).to be == 'stdout'
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'provides access to stderr' do
|
151
|
+
subject.on host, command do
|
152
|
+
expect( subject.stderr ).to be == 'stderr'
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'provides access to exit_code' do
|
157
|
+
subject.on host, command do
|
158
|
+
expect( subject.exit_code ).to be == 0
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
describe "#retry_on" do
|
166
|
+
it 'fails correctly when command never succeeds' do
|
167
|
+
result.stdout = 'stdout'
|
168
|
+
result.stderr = 'stderr'
|
169
|
+
result.exit_code = 1
|
170
|
+
|
171
|
+
retries = 5
|
172
|
+
|
173
|
+
opts = {
|
174
|
+
:max_retries => retries,
|
175
|
+
:retry_interval => 0.0001,
|
176
|
+
}
|
177
|
+
|
178
|
+
allow( subject ).to receive(:on).and_return(result)
|
179
|
+
expect( subject ).to receive(:on).exactly(retries+2)
|
180
|
+
expect { subject.retry_on(host, command, opts) }.to raise_error(RuntimeError)
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'will return success correctly if it succeeds the first time' do
|
184
|
+
result.stdout = 'stdout'
|
185
|
+
result.stderr = 'stderr'
|
186
|
+
result.exit_code = 0
|
187
|
+
|
188
|
+
opts = {
|
189
|
+
:max_retries => 5,
|
190
|
+
:retry_interval => 0.0001,
|
191
|
+
}
|
192
|
+
|
193
|
+
allow( subject ).to receive(:on).and_return(result)
|
194
|
+
expect( subject ).to receive(:on).once
|
195
|
+
|
196
|
+
result_given = subject.retry_on(host, command, opts)
|
197
|
+
expect(result_given.exit_code).to be === 0
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'will return success correctly if it succeeds after failing a few times' do
|
201
|
+
result.stdout = 'stdout'
|
202
|
+
result.stderr = 'stderr'
|
203
|
+
|
204
|
+
opts = {
|
205
|
+
:max_retries => 10,
|
206
|
+
:retry_interval => 0.1,
|
207
|
+
}
|
208
|
+
|
209
|
+
reps_num = 4
|
210
|
+
count = 0
|
211
|
+
allow( subject ).to receive(:on) do
|
212
|
+
result.exit_code = count > reps_num ? 0 : 1
|
213
|
+
count += 1
|
214
|
+
result
|
215
|
+
end
|
216
|
+
expect( subject ).to receive(:on).exactly(reps_num + 2)
|
217
|
+
|
218
|
+
result_given = subject.retry_on(host, command, opts)
|
219
|
+
expect(result_given.exit_code).to be === 0
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
describe "shell" do
|
224
|
+
it 'delegates to #on with the default host' do
|
225
|
+
allow( subject ).to receive( :hosts ).and_return( hosts )
|
226
|
+
|
227
|
+
expect( subject ).to receive( :on ).with( master, "echo hello", {}).once
|
228
|
+
|
229
|
+
subject.shell( "echo hello" )
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe '#scp_from' do
|
234
|
+
it 'delegates to the host' do
|
235
|
+
allow( subject ).to receive( :hosts ).and_return( hosts )
|
236
|
+
expect( subject ).to receive( :logger ).exactly( hosts.length ).times
|
237
|
+
expect( result ).to receive( :log ).exactly( hosts.length ).times
|
238
|
+
|
239
|
+
hosts.each do |host|
|
240
|
+
expect( host ).to receive( :do_scp_from ).and_return( result )
|
241
|
+
end
|
242
|
+
|
243
|
+
subject.scp_from( hosts, '/var/log/my.log', 'log/my.log' )
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
describe '#scp_to' do
|
248
|
+
it 'delegates to the host' do
|
249
|
+
allow( subject ).to receive( :hosts ).and_return( hosts )
|
250
|
+
expect( subject ).to receive( :logger ).exactly( hosts.length ).times
|
251
|
+
expect( result ).to receive( :log ).exactly( hosts.length ).times
|
252
|
+
|
253
|
+
hosts.each do |host|
|
254
|
+
expect( host ).to receive( :do_scp_to ).and_return( result )
|
255
|
+
end
|
256
|
+
|
257
|
+
subject.scp_to( hosts, '/var/log/my.log', 'log/my.log' )
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
describe '#rsync_to' do
|
262
|
+
it 'delegates to the host' do
|
263
|
+
allow( subject ).to receive( :hosts ).and_return( hosts )
|
264
|
+
|
265
|
+
hosts.each do |host|
|
266
|
+
expect( host ).to receive( :do_rsync_to ).and_return( result )
|
267
|
+
end
|
268
|
+
|
269
|
+
subject.rsync_to( hosts, '/var/log/my.log', 'log/my.log' )
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
describe '#create_remote_file using scp' do
|
274
|
+
it 'scps the contents passed in to the hosts' do
|
275
|
+
my_opts = { :silent => true }
|
276
|
+
tmpfile = double
|
277
|
+
|
278
|
+
expect( tmpfile ).to receive( :path ).exactly( 2 ).times.
|
279
|
+
and_return( '/local/path/to/blah' )
|
280
|
+
|
281
|
+
expect( Tempfile ).to receive( :open ).and_yield( tmpfile )
|
282
|
+
|
283
|
+
expect( File ).to receive( :open )
|
284
|
+
|
285
|
+
expect( subject ).to receive( :scp_to ).
|
286
|
+
with( hosts, '/local/path/to/blah', '/remote/path', my_opts )
|
287
|
+
|
288
|
+
subject.create_remote_file( hosts, '/remote/path', 'blah', my_opts )
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
describe '#create_remote_file using rsync' do
|
293
|
+
it 'scps the contents passed in to the hosts' do
|
294
|
+
my_opts = { :silent => true, :protocol => 'rsync' }
|
295
|
+
tmpfile = double
|
296
|
+
|
297
|
+
expect( tmpfile ).to receive( :path ).exactly( 2 ).times.
|
298
|
+
and_return( '/local/path/to/blah' )
|
299
|
+
|
300
|
+
expect( Tempfile ).to receive( :open ).and_yield( tmpfile )
|
301
|
+
|
302
|
+
expect( File ).to receive( :open )
|
303
|
+
|
304
|
+
expect( subject ).to receive( :rsync_to ).
|
305
|
+
with( hosts, '/local/path/to/blah', '/remote/path', my_opts )
|
306
|
+
|
307
|
+
subject.create_remote_file( hosts, '/remote/path', 'blah', my_opts )
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
describe '#create_tmpdir_on' do
|
312
|
+
let(:host) { {'user' => 'puppet'} }
|
313
|
+
let(:result) { double.as_null_object }
|
314
|
+
|
315
|
+
before :each do
|
316
|
+
allow(host).to receive(:result).and_return(result)
|
317
|
+
allow(result).to receive(:exit_code).and_return(0)
|
318
|
+
allow(result).to receive(:stdout).and_return('puppet')
|
319
|
+
end
|
320
|
+
|
321
|
+
context 'with no user argument' do
|
322
|
+
|
323
|
+
context 'with no path name argument' do
|
324
|
+
it 'executes chown once' do
|
325
|
+
expect(subject).to receive(:on).with(host, /^getent passwd puppet/).and_return(result)
|
326
|
+
expect(host).to receive(:tmpdir).with(/\/tmp\/beaker.*/)
|
327
|
+
expect(subject).to receive(:on).with(host, /chown puppet.puppet.*/)
|
328
|
+
subject.create_tmpdir_on(host, '/tmp/beaker')
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
context 'with path name argument' do
|
333
|
+
it 'executes chown once' do
|
334
|
+
expect(subject).to receive(:on).with(host, /^getent passwd puppet/).and_return(result)
|
335
|
+
expect(host).to receive(:tmpdir).with(/\/tmp\/bogus.*/).and_return("/tmp/bogus")
|
336
|
+
expect(subject).to receive(:on).with(host, /chown puppet.puppet \/tmp\/bogus.*/)
|
337
|
+
subject.create_tmpdir_on(host, "/tmp/bogus")
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
end
|
342
|
+
|
343
|
+
context 'with an valid user argument' do
|
344
|
+
it 'executes chown once' do
|
345
|
+
expect(subject).to receive(:on).with(host, /^getent passwd curiousgeorge/).and_return(result)
|
346
|
+
expect(host).to receive(:tmpdir).with(/\/tmp\/bogus.*/).and_return("/tmp/bogus")
|
347
|
+
expect(subject).to receive(:on).with(host, /chown curiousgeorge.curiousgeorge \/tmp\/bogus.*/)
|
348
|
+
subject.create_tmpdir_on(host, "/tmp/bogus", "curiousgeorge")
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
context 'with a invalid user argument' do
|
353
|
+
it 'executes chown once' do
|
354
|
+
allow(result).to receive(:exit_code).and_return(1)
|
355
|
+
expect(subject).to receive(:on).with(host, /^getent passwd curiousgeorge/).and_return(result)
|
356
|
+
expect{
|
357
|
+
subject.create_tmpdir_on(host, "/tmp/bogus", "curiousgeorge")
|
358
|
+
}.to raise_error(RuntimeError, /User curiousgeorge does not exist on/)
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
end
|
363
|
+
|
364
|
+
describe '#run_script_on' do
|
365
|
+
it 'scps the script to a tmpdir and executes it on host(s)' do
|
366
|
+
expect( subject ).to receive( :scp_to )
|
367
|
+
expect( subject ).to receive( :on )
|
368
|
+
subject.run_script_on( 'host', '~/.bin/make-enterprisy' )
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
describe '#run_script' do
|
373
|
+
it 'delegates to #run_script_on with the default host' do
|
374
|
+
allow( subject ).to receive( :hosts ).and_return( hosts )
|
375
|
+
|
376
|
+
expect( subject ).to receive( :run_script_on ).with( master, "/tmp/test.sh", {}).once
|
377
|
+
|
378
|
+
subject.run_script( '/tmp/test.sh' )
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
describe '#add_system32_hosts_entry' do
|
383
|
+
before do
|
384
|
+
allow( subject ).to receive(:on).and_return(Beaker::Result.new({},''))
|
385
|
+
end
|
386
|
+
context 'on debian' do
|
387
|
+
let(:platform) { 'debian-7-amd64' }
|
388
|
+
let(:host) { make_host('testbox.test.local', :platform => 'debian-7-amd64') }
|
389
|
+
it 'logs message - nothing to do on this host' do
|
390
|
+
expect( Beaker::Command ).to receive( :new ).never
|
391
|
+
|
392
|
+
expect {
|
393
|
+
subject.add_system32_hosts_entry(host, {})
|
394
|
+
}.to raise_error
|
395
|
+
end
|
396
|
+
end
|
397
|
+
context 'on windows' do
|
398
|
+
let(:platform) { 'windows-2008R2-amd64' }
|
399
|
+
let(:host) { make_host('testbox.test.local', :platform => 'windows-2008R2-amd64') }
|
400
|
+
it 'it add an entry into the /etc/hosts file' do
|
401
|
+
entry = { 'ip' => '23.251.154.122', 'name' => 'forge.puppetlabs.com' }
|
402
|
+
expect(subject).to receive(:on) do |host, command|
|
403
|
+
expect(command.command).to eq('powershell.exe')
|
404
|
+
expect(command.args).to eq(["-ExecutionPolicy Bypass", "-InputFormat None", "-NoLogo", "-NoProfile", "-NonInteractive", "-Command $text = \\\"23.251.154.122`t`tforge.puppetlabs.com\\\"; Add-Content -path 'C:\\Windows\\System32\\Drivers\\etc\\hosts' -value $text"])
|
405
|
+
end
|
406
|
+
|
407
|
+
|
408
|
+
subject.add_system32_hosts_entry(host, entry)
|
409
|
+
end
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
end
|