beaker 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -40,7 +40,7 @@ module Beaker
40
40
  if not @compute_client
41
41
  raise "Unable to create OpenStack Compute instance (api key: #{@options[:openstack_api_key]}, username: #{@options[:openstack_username]}, auth_url: #{@options[:openstack_auth_url]}, tenant: #{@options[:openstack_tenant]})"
42
42
  end
43
- @network_client || Fog::Network.new(
43
+ @network_client ||= Fog::Network.new(
44
44
  :provider => :openstack,
45
45
  :openstack_api_key => @options[:openstack_api_key],
46
46
  :openstack_username => @options[:openstack_username],
@@ -132,6 +132,8 @@ module Beaker
132
132
  :project => @options[:project].to_s })
133
133
  @vms << vm
134
134
 
135
+ #enable root if user is not root
136
+ enable_root_on_hosts()
135
137
  end
136
138
  end
137
139
 
@@ -150,5 +152,28 @@ module Beaker
150
152
  end
151
153
  end
152
154
 
155
+ # Enables root for instances with custom username like ubuntu-amis
156
+ #
157
+ # @return [void]
158
+ # @api private
159
+ def enable_root_on_hosts
160
+ @hosts.each do |host|
161
+ enable_root(host)
162
+ end
163
+ end
164
+
165
+ # Enables root access for a host when username is not root
166
+ #
167
+ # @return [void]
168
+ # @api private
169
+ def enable_root(host)
170
+ if host['user'] != 'root'
171
+ copy_ssh_to_root(host, @options)
172
+ enable_root_login(host, @options)
173
+ host['user'] = 'root'
174
+ host.close
175
+ end
176
+ end
177
+
153
178
  end
154
179
  end
@@ -31,6 +31,7 @@ module Beaker
31
31
  v_file << " v.vm.box_url = '#{host['box_url']}'\n" unless host['box_url'].nil?
32
32
  v_file << " v.vm.box_version = '#{host['box_version']}'\n" unless host['box_version'].nil?
33
33
  v_file << " v.vm.box_check_update = '#{host['box_check_update'] ||= 'true'}'\n"
34
+ v_file << " v.vm.synced_folder '.', '/vagrant', disabled: true\n" if host['synced_folder'] == 'disabled'
34
35
  v_file << " v.vm.network :private_network, ip: \"#{host['ip'].to_s}\", :netmask => \"#{host['netmask'] ||= "255.255.0.0"}\", :mac => \"#{randmac}\"\n"
35
36
 
36
37
  if /windows/i.match(host['platform'])
@@ -39,6 +40,11 @@ module Beaker
39
40
  v_file << " v.vm.guest = :windows"
40
41
  end
41
42
 
43
+ if /osx/i.match(host['platform'])
44
+ v_file << " v.vm.network 'private_network', ip: '10.0.1.10'\n"
45
+ v_file << " v.vm.synced_folder '.', '/vagrant', :nfs => true\n"
46
+ end
47
+
42
48
  v_file << self.class.provider_vfile_section(host, options)
43
49
 
44
50
  v_file << " end\n"
@@ -163,12 +169,12 @@ module Beaker
163
169
  @logger.info(line)
164
170
  end
165
171
  if not wait_thr.value.success?
166
- raise "Failed to exec 'vagrant #{args}'"
172
+ raise "Failed to exec 'vagrant #{args}'. Error was #{stderr.read}"
167
173
  end
168
174
  exit_status = wait_thr.value
169
175
  }
170
176
  if exit_status != 0
171
- raise "Failed to execute vagrant_cmd ( #{args} )"
177
+ raise "Failed to execute vagrant_cmd ( #{args} ). Error was #{stderr.read}"
172
178
  end
173
179
  end
174
180
  end
@@ -18,6 +18,8 @@ class Beaker::VagrantVirtualbox < Beaker::Vagrant
18
18
  provider_section << " vb.customize ['storageattach', :id, '--storagectl', 'SATA Controller', '--port', 1, '--device', 0, '--type', 'hdd', '--medium','#{host['disk_path']}']\n"
19
19
  provider_section << " vb.customize [\"modifyvm\", :id, \"--natdnshostresolver1\", \"#{host['natdns']}\"]\n" unless host['natdns'].nil?
20
20
  provider_section << " vb.customize [\"modifyvm\", :id, \"--natdnsproxy1\", \"#{host['natdns']}\"]\n" unless host['natdns'].nil?
21
+ provider_section << " vb.gui = true\n" unless host['vb_gui'].nil?
22
+ provider_section << " [\"modifyvm\", :id, \"--cpuidset\", \"1\",\"000206a7\",\"02100800\",\"1fbae3bf\",\"bfebfbff\"\]" if /osx/i.match(host['platform'])
21
23
  end
22
24
  provider_section << " end\n"
23
25
 
@@ -119,6 +119,7 @@ module Beaker
119
119
  :log_level => 'info',
120
120
  :trace_limit => 10,
121
121
  :"master-start-curl-retries" => 120,
122
+ :masterless => false,
122
123
  :options_file => nil,
123
124
  :type => 'pe',
124
125
  :provision => true,
@@ -46,6 +46,27 @@ module Beaker
46
46
  a_host.first
47
47
  end
48
48
 
49
+ # Find at most a single host with the role provided. Raise an error if
50
+ # more than one host is found to have the provided role.
51
+ # @param [Array<Host>] hosts The hosts to examine
52
+ # @param [String] role The host returned will have this role in its role list
53
+ # @return [Host] The single host with the desired role in its roles list
54
+ # or nil if no host is found
55
+ # @raise [ArgumentError] Raised if more than one host has the given role defined
56
+ def find_at_most_one_host_with_role(hosts, role)
57
+ role_hosts = hosts_with_role(hosts, role)
58
+ host_with_role = nil
59
+ case role_hosts.length
60
+ when 0
61
+ when 1
62
+ host_with_role = role_hosts[0]
63
+ else
64
+ host_string = ( role_hosts.map { |host| host.name } ).join( ', ')
65
+ raise ArgumentError, "There should be only one host with #{role} defined, but I found #{role_hosts.length} (#{host_string})"
66
+ end
67
+ host_with_role
68
+ end
69
+
49
70
  #Execute a block selecting the hosts that match with the provided criteria
50
71
  #@param [Array<Host>, Host] hosts The host or hosts to run the provided block against
51
72
  #@param [String, Symbol] filter Optional filter to apply to provided hosts - limits by name or role
@@ -1,5 +1,5 @@
1
1
  module Beaker
2
2
  module Version
3
- STRING = '2.2.0'
3
+ STRING = '2.3.0'
4
4
  end
5
5
  end
@@ -50,6 +50,44 @@ module Beaker
50
50
  end
51
51
  end
52
52
 
53
+ describe "Masterless Setup" do
54
+ let( :ver ) { @ver || '3.0' }
55
+ let( :options ) { options = Beaker::Options::Presets.new.presets
56
+ options[:masterless] = true
57
+ options }
58
+ let( :hosts ) { make_hosts({}, 1) }
59
+ let( :host ) { hosts[0] }
60
+ let( :answers ) { Beaker::Answers.create(ver, hosts, options) }
61
+ let( :host_answers ) { answers.answers[host.name] }
62
+
63
+
64
+ it 'adds the correct answers' do
65
+ expect( host_answers[:q_puppetagent_server] ).to be === host_answers[:q_puppetagent_certname]
66
+ expect( host_answers[:q_continue_or_reenter_master_hostname]).to be === 'c'
67
+ end
68
+
69
+ it 'skips the correct answers' do
70
+ expect( host_answers[:q_puppetmaster_install]).to be === 'n'
71
+ expect( host_answers[:q_puppet_enterpriseconsole_install] ).to be === 'n'
72
+ expect( host_answers[:q_puppetdb_install] ).to be === 'n'
73
+ end
74
+
75
+ it '3.0: never calls #only_host_with_role in #generate_answers' do
76
+ expect( answers.generate_answers ).to_not receive( :only_host_with_role )
77
+ end
78
+
79
+ it '3.2: never calls #only_host_with_role in #generate_answers' do
80
+ @ver = '3.2'
81
+ expect( answers.generate_answers ).to_not receive( :only_host_with_role )
82
+ end
83
+
84
+ it '3.4: never calls #only_host_with_role in #generate_answers' do
85
+ @ver = '3.4'
86
+ expect( answers.generate_answers ).to_not receive( :only_host_with_role )
87
+ end
88
+
89
+ end
90
+
53
91
  describe Version34 do
54
92
  let( :options ) { Beaker::Options::Presets.new.presets }
55
93
  let( :basic_hosts ) { make_hosts( {'pe_ver' => @ver } ) }
@@ -1294,4 +1294,56 @@ describe ClassMixedWithDSLHelpers do
1294
1294
  end
1295
1295
  end
1296
1296
  end
1297
+
1298
+ describe "#write_hiera_config_on" do
1299
+ let(:hierarchy) { [ 'nodes/%{::fqdn}', 'common' ] }
1300
+ it 'on FOSS host' do
1301
+ host = make_host('testhost', { :platform => 'ubuntu' } )
1302
+ expect(subject).to receive(:create_remote_file).with(host, host[:hieraconf], /#{host[:hieradatadir]}/)
1303
+ subject.write_hiera_config_on(host, hierarchy)
1304
+ end
1305
+
1306
+ it 'on PE host' do
1307
+ host = make_host('testhost', { :platform => 'ubuntu', :type => 'pe' } )
1308
+ expect(subject).to receive(:create_remote_file).with(host, host[:hieraconf], /#{host[:hieradatadir]}/)
1309
+ subject.write_hiera_config_on(host, hierarchy)
1310
+ end
1311
+
1312
+ end
1313
+
1314
+ describe "#write_hiera_config" do
1315
+ let(:hierarchy) { [ 'nodes/%{::fqdn}', 'common' ] }
1316
+ it 'delegates to #write_hiera_config_on with the default host' do
1317
+ allow( subject ).to receive( :hosts ).and_return( hosts )
1318
+ expect( subject ).to receive( :write_hiera_config_on ).with( master, hierarchy).once
1319
+ subject.write_hiera_config( hierarchy )
1320
+ end
1321
+
1322
+ end
1323
+
1324
+ describe "#copy_hiera_data_to" do
1325
+ let(:path) { 'spec/fixtures/hieradata' }
1326
+ it 'on FOSS host' do
1327
+ host = make_host('testhost', { :platform => 'ubuntu' } )
1328
+ expect(subject).to receive(:scp_to).with(host, File.expand_path(path), host[:hieradatadir])
1329
+ subject.copy_hiera_data_to(host, path)
1330
+ end
1331
+
1332
+ it 'on PE host' do
1333
+ host = make_host('testhost', { :platform => 'ubuntu', :type => 'pe' } )
1334
+ expect(subject).to receive(:scp_to).with(host, File.expand_path(path), host[:hieradatadir])
1335
+ subject.copy_hiera_data_to(host, path)
1336
+ end
1337
+ end
1338
+
1339
+ describe "#copy_hiera_data" do
1340
+ let(:path) { 'spec/fixtures/hieradata' }
1341
+ it 'delegates to #copy_hiera_data_to with the default host' do
1342
+ allow( subject ).to receive( :hosts ).and_return( hosts )
1343
+ expect( subject ).to receive( :copy_hiera_data_to ).with( master, path).once
1344
+ subject.copy_hiera_data( path )
1345
+ end
1346
+
1347
+ end
1348
+
1297
1349
  end
@@ -154,6 +154,13 @@ describe ClassMixedWithDSLInstallUtils do
154
154
  allow( subject ).to receive( :hosts ).and_return( hosts )
155
155
  expect( subject.sorted_hosts ).to be === hosts
156
156
  end
157
+
158
+ it 'does not allow nil entries' do
159
+ allow( subject ).to receive( :options ).and_return( { :masterless => true } )
160
+ masterless_host = [basic_hosts[0]]
161
+ allow( subject ).to receive( :hosts ).and_return( masterless_host )
162
+ expect( subject.sorted_hosts ).to be === masterless_host
163
+ end
157
164
  end
158
165
 
159
166
  describe 'installer_cmd' do
@@ -372,7 +379,7 @@ describe ClassMixedWithDSLInstallUtils do
372
379
  expect( subject ).to receive( :on ).with( hosts[2], /puppet config set certname/ ).once
373
380
  expect( subject ).to receive( :on ).with( hosts[3], /puppet config set certname/ ).once
374
381
  expect( subject ).to receive( :on ).with( hosts[2], /puppet agent -t/, :acceptable_exit_codes => [1] ).once
375
- expect( subject ).to receive( :on ).with( hosts[3], /puppet agent -t/, :acceptable_exit_codes => [1] ).once
382
+ expect( subject ).to receive( :on ).with( hosts[3], /puppet agent -t/, :acceptable_exit_codes => [0, 1] ).once
376
383
  #sign certificate per-host
377
384
  expect( subject ).to receive( :sign_certificate_for ).with( hosts[0] ).once
378
385
  expect( subject ).to receive( :sign_certificate_for ).with( hosts[1] ).once
@@ -397,6 +404,30 @@ describe ClassMixedWithDSLInstallUtils do
397
404
  expect( subject ).to receive( :on ).with( hosts, /puppet agent/, :acceptable_exit_codes => [0,2] ).once
398
405
  subject.do_install( hosts, opts )
399
406
  end
407
+
408
+ it 'can perform a masterless installation' do
409
+ hosts = make_hosts({
410
+ :pe_ver => '3.0',
411
+ :roles => ['agent']
412
+ }, 1)
413
+
414
+ allow( subject ).to receive( :hosts ).and_return( hosts )
415
+ allow( subject ).to receive( :options ).and_return({ :masterless => true })
416
+ allow( subject ).to receive( :on ).and_return( Beaker::Result.new( {}, '' ) )
417
+ allow( subject ).to receive( :fetch_puppet ).and_return( true )
418
+ allow( subject ).to receive( :create_remote_file ).and_return( true )
419
+ allow( subject ).to receive( :stop_agent_on ).and_return( true )
420
+ allow( subject ).to receive( :version_is_less ).with(anything, '3.2.0').exactly(hosts.length + 1).times.and_return( false )
421
+
422
+ expect( subject ).to receive( :on ).with( hosts[0], /puppet-enterprise-installer/ ).once
423
+ expect( subject ).to receive( :create_remote_file ).with( hosts[0], /answers/, /q/ ).once
424
+ expect( subject ).to_not receive( :sign_certificate_for )
425
+ expect( subject ).to receive( :stop_agent_on ).with( hosts[0] ).once
426
+ expect( subject ).to_not receive( :sleep_until_puppetdb_started )
427
+ expect( subject ).to_not receive( :wait_for_host_in_dashboard )
428
+ expect( subject ).to_not receive( :on ).with( hosts[0], /puppet agent -t/, :acceptable_exit_codes => [0,2] )
429
+ subject.do_install( hosts, opts)
430
+ end
400
431
  end
401
432
 
402
433
  describe 'do_higgs_install' do
@@ -812,6 +843,32 @@ describe ClassMixedWithDSLInstallUtils do
812
843
 
813
844
  end
814
845
 
846
+ describe '#install_packages_from_local_dev_repo' do
847
+ let( :package_name ) { 'puppet-agent' }
848
+ let( :platform ) { @platform || 'other' }
849
+ let( :host ) do
850
+ FakeHost.create('fakvm', platform, opts)
851
+ end
852
+
853
+ it 'sets the find command correctly for el-based systems' do
854
+ @platform = 'el-1-3'
855
+ expect( subject ).to receive( :on ).with( host, /\*\.rpm.+rpm\s-ivh/ )
856
+ subject.install_packages_from_local_dev_repo( host, package_name )
857
+ end
858
+
859
+ it 'sets the find command correctly for debian-based systems' do
860
+ @platform = 'debian-1-3'
861
+ expect( subject ).to receive( :on ).with( host, /\*\.deb.+dpkg\s-i/ )
862
+ subject.install_packages_from_local_dev_repo( host, package_name )
863
+ end
864
+
865
+ it 'fails correctly for systems not accounted for' do
866
+ @platform = 'eos-1-3'
867
+ expect{ subject.install_packages_from_local_dev_repo( host, package_name ) }.to raise_error RuntimeError
868
+ end
869
+
870
+ end
871
+
815
872
  describe '#install_puppetagent_dev_repo' do
816
873
 
817
874
  it 'raises an exception when host platform is unsupported' do
@@ -9,6 +9,7 @@ end
9
9
  describe ClassMixedWithDSLRoles do
10
10
 
11
11
  let( :hosts ) { @hosts || Hash.new }
12
+ let( :options ) { @options || Hash.new }
12
13
  let( :agent1 ) { make_host( 'agent1', { :roles => [ 'agent' ] } ) }
13
14
  let( :agent2 ) { make_host( 'agent2', { :roles => [ 'agent' ] } ) }
14
15
  let( :a_and_dash ) { make_host( 'a_and_dash', { :roles => [ 'agent', 'dashboard' ] } ) }
@@ -42,6 +43,12 @@ describe ClassMixedWithDSLRoles do
42
43
  expect( subject ).to receive( :hosts ).exactly( 1 ).times.and_return( hosts )
43
44
  expect { subject.master }.to raise_error Beaker::DSL::FailTest
44
45
  end
46
+ it 'returns nil if no master and masterless is set' do
47
+ @options = { :masterless => true }
48
+ expect( subject ).to receive( :hosts ).and_return( hosts )
49
+ expect( subject ).to receive( :options ).and_return( options )
50
+ expect( subject.master ).to be_nil
51
+ end
45
52
  end
46
53
  describe '#dashboard' do
47
54
  it 'returns the dashboard if there is one' do
@@ -59,6 +66,12 @@ describe ClassMixedWithDSLRoles do
59
66
  expect( subject ).to receive( :hosts ).and_return( hosts )
60
67
  expect { subject.dashboard }.to raise_error Beaker::DSL::FailTest
61
68
  end
69
+ it 'returns nil if no dashboard and masterless is set' do
70
+ @options = { :masterless => true }
71
+ expect( subject ).to receive( :hosts ).and_return( hosts )
72
+ expect( subject ).to receive( :options ).and_return( options )
73
+ expect( subject.dashboard ).to be_nil
74
+ end
62
75
  end
63
76
  describe '#database' do
64
77
  it 'returns the database if there is one' do
@@ -76,6 +89,12 @@ describe ClassMixedWithDSLRoles do
76
89
  expect( subject ).to receive( :hosts ).and_return( hosts )
77
90
  expect { subject.database }.to raise_error Beaker::DSL::FailTest
78
91
  end
92
+ it 'returns nil if no database and masterless is set' do
93
+ @options = { :masterless => true }
94
+ expect( subject ).to receive( :hosts ).and_return( hosts )
95
+ expect( subject ).to receive( :options ).and_return( options )
96
+ expect( subject.database ).to be_nil
97
+ end
79
98
  end
80
99
  describe '#default' do
81
100
  it 'returns the default host when one is specified' do
@@ -86,12 +105,18 @@ describe ClassMixedWithDSLRoles do
86
105
  it 'raises an error if there is more than one default' do
87
106
  @hosts = [ db, monolith, default, default ]
88
107
  expect( subject ).to receive( :hosts ).and_return( hosts )
89
- expect { subject.database }.to raise_error Beaker::DSL::FailTest
108
+ expect { subject.default }.to raise_error Beaker::DSL::FailTest
90
109
  end
91
110
  it 'and raises an error if there is no default' do
92
111
  @hosts = [ agent1, agent2, custom ]
93
112
  expect( subject ).to receive( :hosts ).and_return( hosts )
94
- expect { subject.database }.to raise_error Beaker::DSL::FailTest
113
+ expect { subject.default }.to raise_error Beaker::DSL::FailTest
114
+ end
115
+ it 'returns nil if no default and masterless is set' do
116
+ @options = { :masterless => true }
117
+ expect( subject ).to receive( :hosts ).and_return( hosts )
118
+ expect( subject ).to receive( :options ).and_return( options )
119
+ expect( subject.default ).to be_nil
95
120
  end
96
121
  end
97
122
  describe '#add_role_def' do
@@ -56,6 +56,24 @@ module Beaker
56
56
  expect(host.is_using_passenger?).to be_truthy
57
57
  expect(host.graceful_restarts?).to be_truthy
58
58
  end
59
+
60
+ it 'can be an AIO host' do
61
+ options['type'] = 'aio'
62
+ expect(host.is_pe?).to be_falsy
63
+ expect(host.use_service_scripts?).to be_falsy
64
+ expect(host.is_using_passenger?).to be_falsy
65
+ end
66
+
67
+ it 'sets the paths correctly for an AIO agent host' do
68
+ options['type'] = 'aio'
69
+ expect(host['puppetvardir']).to be === Unix::Host::aio_defaults[:puppetvardir]
70
+ end
71
+
72
+ it 'sets the paths correctly for an AIO non-agent host' do
73
+ options['type'] = 'aio'
74
+ options['roles'] = ['master']
75
+ expect(host['puppetvardir']).to be === Unix::Host::foss_defaults[:puppetvardir]
76
+ end
59
77
  end
60
78
 
61
79
  describe "uses_passenger!" do
@@ -79,6 +79,17 @@ EOF
79
79
  expect( vagrantfile ).to match(/(ssh.forward_agent = true)/)
80
80
  end
81
81
 
82
+ it "can make a Vagrantfile with synced_folder disabled" do
83
+ path = vagrant.instance_variable_get( :@vagrant_path )
84
+ allow( vagrant ).to receive( :randmac ).and_return( "0123456789" )
85
+
86
+ hosts = make_hosts({:synced_folder => 'disabled'},1)
87
+ vagrant.make_vfile( hosts, options )
88
+
89
+ vagrantfile = File.read( File.expand_path( File.join( path, "Vagrantfile")))
90
+ expect( vagrantfile ).to match(/v.vm.synced_folder .* disabled: true/)
91
+ end
92
+
82
93
  it "generates a valid windows config" do
83
94
  path = vagrant.instance_variable_get( :@vagrant_path )
84
95
  allow( vagrant ).to receive( :randmac ).and_return( "0123456789" )
@@ -56,6 +56,26 @@ module Beaker
56
56
  end
57
57
  end
58
58
 
59
+ context "find_at_most_one_host_with_role" do
60
+ it "can find the single master in a set of hosts" do
61
+
62
+ expect( host_handler.find_at_most_one_host_with_role( hosts, 'master' ) ).to be === hosts[1]
63
+
64
+ end
65
+
66
+ it "throws an error when more than one host with matching role is found" do
67
+
68
+ expect{ host_handler.find_at_most_one_host_with_role( hosts, 'agent' ) }.to raise_error(ArgumentError)
69
+
70
+ end
71
+
72
+ it "returns nil when no host is found matching the role" do
73
+
74
+ expect( host_handler.find_at_most_one_host_with_role( hosts, 'surprise' ) ).to be_nil
75
+
76
+ end
77
+ end
78
+
59
79
  context "run_block_on" do
60
80
  it "can execute a block against hosts identified by a string" do
61
81
  myhosts = host_handler.run_block_on( hosts, role0 ) do |hosts|