beaker 0.0.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +8 -8
  2. data/.travis.yml +8 -0
  3. data/README.md +6 -6
  4. data/beaker.gemspec +6 -2
  5. data/lib/beaker.rb +1 -1
  6. data/lib/beaker/answers.rb +34 -7
  7. data/lib/beaker/answers/version20.rb +124 -0
  8. data/lib/beaker/answers/version28.rb +21 -0
  9. data/lib/beaker/answers/version30.rb +24 -5
  10. data/lib/beaker/cli.rb +55 -41
  11. data/lib/beaker/command.rb +2 -2
  12. data/lib/beaker/dsl/helpers.rb +320 -106
  13. data/lib/beaker/dsl/install_utils.rb +202 -81
  14. data/lib/beaker/dsl/roles.rb +40 -0
  15. data/lib/beaker/host.rb +28 -20
  16. data/lib/beaker/host/unix.rb +7 -4
  17. data/lib/beaker/host/unix/pkg.rb +42 -12
  18. data/lib/beaker/host/windows.rb +9 -5
  19. data/lib/beaker/host/windows/group.rb +1 -1
  20. data/lib/beaker/host/windows/pkg.rb +41 -8
  21. data/lib/beaker/hypervisor.rb +23 -10
  22. data/lib/beaker/hypervisor/aixer.rb +15 -19
  23. data/lib/beaker/hypervisor/blimper.rb +71 -72
  24. data/lib/beaker/hypervisor/fusion.rb +11 -10
  25. data/lib/beaker/hypervisor/solaris.rb +17 -23
  26. data/lib/beaker/hypervisor/vagrant.rb +27 -12
  27. data/lib/beaker/hypervisor/vcloud.rb +154 -138
  28. data/lib/beaker/hypervisor/vcloud_pooled.rb +97 -0
  29. data/lib/beaker/hypervisor/vsphere.rb +8 -5
  30. data/lib/beaker/hypervisor/vsphere_helper.rb +43 -33
  31. data/lib/beaker/network_manager.rb +16 -12
  32. data/lib/beaker/options/command_line_parser.rb +199 -0
  33. data/lib/beaker/options/hosts_file_parser.rb +39 -0
  34. data/lib/beaker/options/options_file_parser.rb +45 -0
  35. data/lib/beaker/options/options_hash.rb +294 -0
  36. data/lib/beaker/options/parser.rb +288 -0
  37. data/lib/beaker/options/pe_version_scraper.rb +35 -0
  38. data/lib/beaker/options/presets.rb +70 -0
  39. data/lib/beaker/shared.rb +2 -1
  40. data/lib/beaker/shared/host_handler.rb +7 -2
  41. data/lib/beaker/shared/repetition.rb +1 -0
  42. data/lib/beaker/shared/timed.rb +14 -0
  43. data/lib/beaker/test_case.rb +2 -38
  44. data/lib/beaker/test_suite.rb +11 -25
  45. data/lib/beaker/utils/repo_control.rb +6 -8
  46. data/lib/beaker/utils/setup_helper.rb +9 -20
  47. data/spec/beaker/answers_spec.rb +109 -0
  48. data/spec/beaker/command_spec.rb +2 -2
  49. data/spec/beaker/dsl/assertions_spec.rb +1 -3
  50. data/spec/beaker/dsl/helpers_spec.rb +519 -84
  51. data/spec/beaker/dsl/install_utils_spec.rb +265 -16
  52. data/spec/beaker/dsl/roles_spec.rb +31 -10
  53. data/spec/beaker/host/windows/group_spec.rb +55 -0
  54. data/spec/beaker/host_spec.rb +130 -40
  55. data/spec/beaker/hypervisor/aixer_spec.rb +34 -0
  56. data/spec/beaker/hypervisor/blimper_spec.rb +77 -0
  57. data/spec/beaker/hypervisor/fusion_spec.rb +26 -0
  58. data/spec/beaker/hypervisor/hypervisor_spec.rb +66 -0
  59. data/spec/beaker/hypervisor/solaris_spec.rb +39 -0
  60. data/spec/beaker/hypervisor/vagrant_spec.rb +105 -0
  61. data/spec/beaker/hypervisor/vcloud_pooled_spec.rb +60 -0
  62. data/spec/beaker/hypervisor/vcloud_spec.rb +70 -0
  63. data/spec/beaker/hypervisor/vsphere_helper_spec.rb +162 -0
  64. data/spec/beaker/hypervisor/vsphere_spec.rb +76 -0
  65. data/spec/beaker/options/command_line_parser_spec.rb +25 -0
  66. data/spec/beaker/options/data/LATEST +1 -0
  67. data/spec/beaker/options/data/badyaml.cfg +21 -0
  68. data/spec/beaker/options/data/hosts.cfg +21 -0
  69. data/spec/beaker/options/data/opts.txt +6 -0
  70. data/spec/beaker/options/hosts_file_parser_spec.rb +30 -0
  71. data/spec/beaker/options/options_file_parser_spec.rb +23 -0
  72. data/spec/beaker/options/options_hash_spec.rb +111 -0
  73. data/spec/beaker/options/parser_spec.rb +172 -0
  74. data/spec/beaker/options/pe_version_scaper_spec.rb +15 -0
  75. data/spec/beaker/options/presets_spec.rb +24 -0
  76. data/spec/beaker/puppet_command_spec.rb +54 -21
  77. data/spec/beaker/shared/error_handler_spec.rb +40 -0
  78. data/spec/beaker/shared/host_handler_spec.rb +104 -0
  79. data/spec/beaker/shared/repetition_spec.rb +72 -0
  80. data/spec/beaker/test_suite_spec.rb +3 -16
  81. data/spec/beaker/utils/ntp_control_spec.rb +42 -0
  82. data/spec/beaker/utils/repo_control_spec.rb +168 -0
  83. data/spec/beaker/utils/setup_helper_spec.rb +82 -0
  84. data/spec/beaker/utils/validator_spec.rb +58 -0
  85. data/spec/helpers.rb +97 -0
  86. data/spec/matchers.rb +39 -0
  87. data/spec/mock_blimpy.rb +48 -0
  88. data/spec/mock_fission.rb +60 -0
  89. data/spec/mock_vsphere.rb +310 -0
  90. data/spec/mock_vsphere_helper.rb +183 -0
  91. data/spec/mocks.rb +83 -0
  92. data/spec/spec_helper.rb +8 -1
  93. metadata +106 -13
  94. data/beaker.rb +0 -10
  95. data/lib/beaker/options_parsing.rb +0 -323
  96. data/lib/beaker/test_config.rb +0 -148
  97. data/spec/beaker/options_parsing_spec.rb +0 -37
  98. data/spec/mocks_and_helpers.rb +0 -34
@@ -129,106 +129,159 @@ module Beaker
129
129
  end
130
130
  end
131
131
 
132
- def do_install hosts, version, path, pre_30, options = {}
133
- #convenience methods for installation
134
- ########################################################
135
- def installer_cmd(host, version, installer)
136
- if host['platform'] =~ /windows/
137
- "cd #{host['working_dir']} && msiexec.exe /qn /i puppet-enterprise-#{version}.msi"
138
- else
139
- "cd #{host['working_dir']}/#{host['dist']} && ./#{installer}"
140
- end
132
+ #Create the PE install command string based upon the host and options settings
133
+ # @param [Host] host The host that PE is to be installed on
134
+ # @param [Hash{Symbol=>String}] options The options
135
+ # @option options [String] :installer The name of the installer to use for upgrading/installing
136
+ # @option options [String] :pe_ver_win Default PE version to install or upgrade to on Windows hosts
137
+ # (Othersie uses individual Windows hosts pe_ver)
138
+ # @option options [String :pe_ver Default PE version to install or upgrade to
139
+ # (Otherwise uses individual hosts pe_ver)
140
+ # @example
141
+ # on host, "#{installer_cmd(host, options)} -a #{host['working_dir']}/answers"
142
+ # @api private
143
+ def installer_cmd(host, options)
144
+ if host['platform'] =~ /windows/
145
+ version = options[:pe_ver_win] || host['pe_ver']
146
+ "cd #{host['working_dir']} && msiexec.exe /qn /i puppet-enterprise-#{version}.msi"
147
+ else
148
+ version = options[:pe_ver] || host['pe_ver']
149
+ "cd #{host['working_dir']}/#{host['dist']} && ./#{options[:installer]}"
141
150
  end
142
- def link_exists?(link)
143
- require "net/http"
144
- require "open-uri"
145
- url = URI.parse(link)
146
- Net::HTTP.start(url.host, url.port) do |http|
147
- return http.head(url.request_uri).code == "200"
148
- end
151
+ end
152
+
153
+ #Determine is a given URL is accessible
154
+ #@param [String] link The URL to examine
155
+ #@return [Boolean] true if the URL has a '200' HTTP response code, false otherwise
156
+ #@example
157
+ # extension = link_exists?("#{URL}.tar.gz") ? ".tar.gz" : ".tar"
158
+ # @api private
159
+ def link_exists?(link)
160
+ require "net/http"
161
+ require "open-uri"
162
+ url = URI.parse(link)
163
+ Net::HTTP.start(url.host, url.port) do |http|
164
+ return http.head(url.request_uri).code == "200"
149
165
  end
150
- def fetch_puppet(hosts, version, path)
166
+ end
167
+
168
+ #Determine the PE package to download/upload per-host, download/upload that package onto the host
169
+ #and unpack it.
170
+ # @param [Array<Host>] hosts The hosts to download/upload and unpack PE onto
171
+ # @param [Hash{Symbol=>Symbol, String}] options The options
172
+ # @option options [String] :pe_dir Default directory or URL to pull PE package from
173
+ # (Otherwise uses individual hosts pe_dir)
174
+ # @option options [String] :pe_ver Default PE version to install or upgrade to
175
+ # (Otherwise uses individual hosts pe_ver)
176
+ # @option options [String] :pe_ver_win Default PE version to install or upgrade to on Windows hosts
177
+ # (Otherwise uses individual Windows hosts pe_ver)
178
+ # @api private
179
+ def fetch_puppet(hosts, options)
180
+ hosts.each do |host|
181
+ windows = host['platform'] =~ /windows/
182
+ path = options[:pe_dir] || host['pe_dir']
151
183
  local = File.directory?(path)
152
- hosts.each do |host|
153
- filename = ""
184
+ filename = ""
185
+ extension = ""
186
+ if windows
187
+ version = options[:pe_ver_win] || host['pe_ver']
188
+ filename = "puppet-enterprise-#{version}"
189
+ extension = ".msi"
190
+ else
191
+ filename = "#{host['dist']}"
154
192
  extension = ""
155
- if host['platform'] =~ /windows/
156
- filename = "puppet-enterprise-#{version}"
157
- extension = ".msi"
158
- else
159
- filename = "#{host['dist']}"
160
- extension = ""
161
- if local
162
- extension = File.exists?("#{path}/#{filename}.tar.gz") ? ".tar.gz" : ".tar"
163
- else
164
- extension = link_exists?("#{path}/#{filename}.tar.gz") ? ".tar.gz" : ".tar"
165
- end
166
- end
167
193
  if local
168
- if not File.exists?("#{path}/#{filename}#{extension}")
169
- raise "attempting installation on #{host}, #{path}/#{filename}#{extension} does not exist"
170
- end
171
- scp_to host, "#{path}/#{filename}#{extension}", "#{host['working_dir']}/#{filename}#{extension}"
194
+ extension = File.exists?("#{path}/#{filename}.tar.gz") ? ".tar.gz" : ".tar"
172
195
  else
173
- if not link_exists?("#{path}/#{filename}#{extension}")
174
- raise "attempting installation on #{host}, #{path}/#{filename}#{extension} does not exist"
175
- end
176
- on host, "cd #{host['working_dir']}; curl #{path}/#{filename}#{extension} -o #{filename}#{extension}"
177
- end
178
- if extension =~ /gz/
179
- on host, "cd #{host['working_dir']}; gunzip #{filename}#{extension}"
180
- end
181
- if extension =~ /tar/
182
- on host, "cd #{host['working_dir']}; tar -xvf #{filename}.tar"
196
+ extension = link_exists?("#{path}/#{filename}.tar.gz") ? ".tar.gz" : ".tar"
183
197
  end
184
198
  end
199
+ if local
200
+ if not File.exists?("#{path}/#{filename}#{extension}")
201
+ raise "attempting installation on #{host}, #{path}/#{filename}#{extension} does not exist"
202
+ end
203
+ scp_to host, "#{path}/#{filename}#{extension}", "#{host['working_dir']}/#{filename}#{extension}"
204
+ else
205
+ if not link_exists?("#{path}/#{filename}#{extension}")
206
+ raise "attempting installation on #{host}, #{path}/#{filename}#{extension} does not exist"
207
+ end
208
+ on host, "cd #{host['working_dir']}; curl #{path}/#{filename}#{extension} -o #{filename}#{extension}"
209
+ end
210
+ if extension =~ /gz/
211
+ on host, "cd #{host['working_dir']}; gunzip #{filename}#{extension}"
212
+ end
213
+ if extension =~ /tar/
214
+ on host, "cd #{host['working_dir']}; tar -xvf #{filename}.tar"
215
+ end
185
216
  end
186
- ########################################################
187
- #start installation steps here
188
- options[:installer] = 'puppet-enterprise-installer' unless options[:installer]
189
- options[:type] = :install unless options[:type]
217
+ end
218
+
219
+ #Perform a Puppet Enterprise upgrade or install
220
+ # @param [Array<Host>] hosts The hosts to install or upgrade PE on
221
+ # @param [Hash{Symbol=>Symbol, String}] options The options
222
+ # @option options [String] :pe_dir Default directory or URL to pull PE package from
223
+ # (Otherwise uses individual hosts pe_dir)
224
+ # @option options [String] :pe_ver Default PE version to install or upgrade to
225
+ # (Otherwise uses individual hosts pe_ver)
226
+ # @option options [String] :pe_ver_win Default PE version to install or upgrade to on Windows hosts
227
+ # (Otherwise uses individual Windows hosts pe_ver)
228
+ # @option options [String] :installer ('puppet-enterprise-installer') The name of the installer to use for upgrading/installing
229
+ # @option options [Symbol] :type (:install) One of :upgrade or :install
230
+ #
231
+ #
232
+ # @example
233
+ # do_install(hosts, {:type => :upgrade, :pe_dir => path, :pe_ver => version, :pe_ver_win => version_win})
234
+ #
235
+ # @api private
236
+ #
237
+ def do_install hosts, options = {}
238
+ options[:installer] = options[:installer] || 'puppet-enterprise-installer'
239
+ options[:type] = options[:type] || :install
190
240
  hostcert='uname | grep -i sunos > /dev/null && hostname || hostname -s'
191
241
  master_certname = on(master, hostcert).stdout.strip
192
- answers = Beaker::Answers.answers(version, hosts, master_certname, options)
193
- special_nodes = [master, database, dashboard].uniq
194
- real_agents = agents - special_nodes
242
+ pre30database = version_is_less(options[:pe_ver] || database['pe_ver'], '3.0')
243
+ pre30master = version_is_less(options[:pe_ver] || master['pe_ver'], '3.0')
195
244
 
196
245
  # Set PE distribution for all the hosts, create working dir
197
246
  use_all_tar = ENV['PE_USE_ALL_TAR'] == 'true'
198
247
  hosts.each do |host|
199
- platform = use_all_tar ? 'all' : host['platform']
200
- host['dist'] = "puppet-enterprise-#{version}-#{platform}"
248
+ if host['platform'] !~ /windows/
249
+ platform = use_all_tar ? 'all' : host['platform']
250
+ version = options[:pe_ver] || host['pe_ver']
251
+ host['dist'] = "puppet-enterprise-#{version}-#{platform}"
252
+ end
201
253
  host['working_dir'] = "/tmp/" + Time.new.strftime("%Y-%m-%d_%H.%M.%S") #unique working dirs make me happy
202
254
  on host, "mkdir #{host['working_dir']}"
203
255
  end
204
256
 
205
- fetch_puppet(hosts, version, path)
257
+ fetch_puppet(hosts, options)
206
258
 
207
259
  hosts.each do |host|
208
260
  # Database host was added in 3.0. Skip it if installing an older version
209
- next if host == database and host != master and host != dashboard and pre_30
261
+ next if host == database and host != master and host != dashboard and pre30database
210
262
  if host['platform'] =~ /windows/
211
- on host, "#{installer_cmd(host, version, options[:installer])} PUPPET_MASTER_SERVER=#{master} PUPPET_AGENT_CERTNAME=#{host}"
263
+ on host, "#{installer_cmd(host, options)} PUPPET_MASTER_SERVER=#{master} PUPPET_AGENT_CERTNAME=#{host}"
212
264
  else
265
+ answers = Beaker::Answers.answers(options[:pe_ver] || host['pe_ver'], hosts, master_certname, options)
213
266
  create_remote_file host, "#{host['working_dir']}/answers", Beaker::Answers.answer_string(host, answers)
214
267
 
215
- on host, "#{installer_cmd(host, version, options[:installer])} -a #{host['working_dir']}/answers"
268
+ on host, "#{installer_cmd(host, options)} -a #{host['working_dir']}/answers"
216
269
  end
217
270
  end
218
271
 
219
272
 
220
- # If we're installing a version less than 3.0, ignore the database host
273
+ # If we're installing a database version less than 3.0, ignore the database host
221
274
  install_hosts = hosts.dup
222
- install_hosts.delete(database) if pre_30 and database != master and database != dashboard
275
+ install_hosts.delete(database) if pre30database and database != master and database != dashboard
223
276
 
224
277
  # On each agent, we ensure the certificate is signed then shut down the agent
225
278
  install_hosts.each do |host|
226
- sign_certificate(host)
227
- stop_agent(host)
279
+ sign_certificate_for(host)
280
+ stop_agent_on(host)
228
281
  end
229
282
 
230
- # Wait for PuppetDB to be totally up and running
231
- sleep_until_puppetdb_started(database) unless pre_30
283
+ # Wait for PuppetDB to be totally up and running (post 3.0 version of pe only)
284
+ sleep_until_puppetdb_started(database) unless pre30database
232
285
 
233
286
  # Run the agent once to ensure everything is in the dashboard
234
287
  install_hosts.each do |host|
@@ -239,7 +292,7 @@ module Beaker
239
292
  # and would cause puppetdb to be bounced by the agent run. By sleeping
240
293
  # again here, we ensure that if that bounce happens during an upgrade
241
294
  # test we won't fail early in the install process.
242
- if version == '3.0.0' and host == database
295
+ if host['pe_ver'] == '3.0.0' and host == database
243
296
  sleep_until_puppetdb_started(database)
244
297
  end
245
298
  end
@@ -248,7 +301,7 @@ module Beaker
248
301
  wait_for_host_in_dashboard(host)
249
302
  end
250
303
 
251
- if pre_30
304
+ if pre30master
252
305
  task = 'nodegroup:add_all_nodes group=default'
253
306
  else
254
307
  task = 'defaultgroup:ensure_default_group'
@@ -260,37 +313,105 @@ module Beaker
260
313
  on install_hosts, puppet_agent('-t'), :acceptable_exit_codes => [0,2]
261
314
  end
262
315
 
263
- #is version a < version b
264
- #3.0.0-160-gac44cfb is greater than 3.0.0, and 2.8.2
316
+ #Is PE version a less than PE version b
317
+ #@param [String] a A PE version of the from '\d.\d.\d.*'
318
+ #@param [String] b A PE version of the form '\d.\d.\d.*'
319
+ #@return [Boolean] true if a is less than b, otherwise return false
320
+ #
321
+ #@note 3.0.0-160-gac44cfb is greater than 3.0.0, and 2.8.2
322
+ # @!visibility private
265
323
  def version_is_less a, b
266
- a = a.split('-')[0].split('.')
267
- b = b.split('-')[0].split('.')
268
- (0...a.length).each do |i|
269
- if i < b.length
270
- if a[i] < b[i]
324
+ a_nums = a.split('-')[0].split('.')
325
+ b_nums = b.split('-')[0].split('.')
326
+ (0...a_nums.length).each do |i|
327
+ if i < b_nums.length
328
+ if a_nums[i] < b_nums[i]
271
329
  return true
272
- elsif a[i] > b[i]
330
+ elsif a_nums[i] > b_nums[i]
273
331
  return false
274
332
  end
275
333
  else
276
334
  return false
277
335
  end
278
336
  end
337
+ #checks all dots, they are equal so examine the rest
338
+ a_rest = a.split('-', 2)[1]
339
+ b_rest = b.split('-', 2)[1]
340
+ if a_rest and b_rest and a_rest < b_rest
341
+ return false
342
+ elsif a_rest and not b_rest
343
+ return false
344
+ elsif not a_rest and b_rest
345
+ return true
346
+ end
279
347
  return false
280
348
  end
281
349
 
282
- def install_pe version, path
283
- pre_30 = version_is_less(version, '3.0')
284
- step "Install #{version} PE on #{path}"
285
- do_install hosts, version, path, pre_30
350
+ #Sort array of hosts so that it has the correct order for PE installation based upon each host's role
351
+ # @example
352
+ # h = sorted_hosts
353
+ #
354
+ # @note Order for installation should be
355
+ # First : master
356
+ # Second: database host (if not same as master)
357
+ # Third: dashboard (if not same as master or database)
358
+ # Fourth: everything else
359
+ #
360
+ # @!visibility private
361
+ def sorted_hosts
362
+ special_nodes = [master, database, dashboard].uniq
363
+ real_agents = agents - special_nodes
364
+ special_nodes + real_agents
286
365
  end
287
366
 
288
- def upgrade_pe version, path, from
367
+ #Install PE based upon host configuration and options
368
+ # @example
369
+ # install_pe
370
+ #
371
+ # @note Either pe_ver and pe_dir should be set in the ENV or each host should have pe_ver and pe_dir set individually.
372
+ # Install file names are assumed to be of the format puppet-enterprise-VERSION-PLATFORM.(tar)|(tar.gz)
373
+ # for Unix like systems and puppet-enterprise-VERSION.msi for Windows systems.
374
+ #
375
+ # @api dsl
376
+ def install_pe
377
+ #process the version files if necessary
378
+ hosts.each do |host|
379
+ if host['platform'] =~ /windows/
380
+ host['pe_ver'] = host['pe_ver'] ||
381
+ Beaker::Options::PEVersionScraper.load_pe_version(host[:pe_dir] || options[:pe_dir], options[:pe_version_file_win])
382
+ else
383
+ host['pe_ver'] = host['pe_ver'] ||
384
+ Beaker::Options::PEVersionScraper.load_pe_version(host[:pe_dir] || options[:pe_dir], options[:pe_version_file])
385
+ end
386
+ end
387
+ do_install sorted_hosts
388
+ end
389
+
390
+ #Upgrade PE based upon host configuration and options
391
+ # @param [String] path A path (either local directory or a URL to a listing of PE builds).
392
+ # Will contain a LATEST file indicating the latest build to install.
393
+ # @example
394
+ # upgrade_pe("http://neptune.puppetlabs.lan/3.0/ci-ready/")
395
+ #
396
+ # @note Install file names are assumed to be of the format puppet-enterprise-VERSION-PLATFORM.(tar)|(tar.gz)
397
+ # for Unix like systems and puppet-enterprise-VERSION.msi for Windows systems.
398
+ # @api dsl
399
+ def upgrade_pe path
400
+ version = Options::PEVersionScraper.load_pe_version(path, options[:pe_version_file])
401
+ version_win = Options::PEVersionScraper.load_pe_version(path, options[:pe_version_file_win])
289
402
  pre_30 = version_is_less(version, '3.0')
290
403
  if pre_30
291
- do_install(hosts, version, path, pre_30, :type => :upgrade, :installer => 'puppet-enterprise-upgrader', :from => from)
404
+ do_install(sorted_hosts, {:type => :upgrade, :pe_dir => path, :pe_ver => version, :pe_ver_win => version_win, :installer => 'puppet-enterprise-upgrader'})
292
405
  else
293
- do_install(hosts, version, path, pre_30, :type => :upgrade, :from => from)
406
+ do_install(sorted_hosts, {:type => :upgrade, :pe_dir => path, :pe_ver => version, :pe_ver_win => version_win})
407
+ end
408
+ #at this point we've completed a successful upgrade, update the host pe_ver to reflect that
409
+ hosts.each do |host|
410
+ if host['platform'] =~ /windows/
411
+ host['pe_ver'] = version_win
412
+ else
413
+ host['pe_ver'] = version
414
+ end
294
415
  end
295
416
  end
296
417
 
@@ -68,6 +68,44 @@ module Beaker
68
68
  find_only_one :dashboard
69
69
  end
70
70
 
71
+ # The default host
72
+ # - if only one host defined, then that host
73
+ # OR
74
+ # - host with 'default' as a role
75
+ # OR
76
+ # - host with 'master' as a role
77
+ #
78
+ # @return [Array<Host>]
79
+ # @raise [Beaker::DSL::Outcomes::FailTest] if no default host is found
80
+ #
81
+ # @example Basic usage
82
+ # on, default, "curl https://#{database}/nodes/#{agent}"
83
+ #
84
+ def default
85
+ if hosts.length == 1
86
+ return hosts[0]
87
+ elsif any_hosts_as? :default
88
+ return find_only_one :default
89
+ elsif any_hosts_as? :master
90
+ return find_only_one :master
91
+ else
92
+ raise DSL::Outcomes::FailTest, "no default host specified"
93
+ end
94
+ end
95
+
96
+ # Determine if there is a host or hosts with the given role defined
97
+ # @return [Boolean] True if there is a host with role, false otherwise
98
+ #
99
+ # @example Usage
100
+ # if any_hosts_as?(:master)
101
+ # puts "master is defined"
102
+ # end
103
+ #
104
+ # @api public
105
+ def any_hosts_as?(role)
106
+ hosts_as(role).length > 0
107
+ end
108
+
71
109
  # Select hosts that include a desired role from #hosts
72
110
  #
73
111
  # @param [String, Symbol] desired_role The role to select for
@@ -91,6 +129,8 @@ module Beaker
91
129
  # the specified role is NOT found.
92
130
  def find_only_one role
93
131
  only_host_with_role(hosts, role)
132
+ rescue ArgumentError => e
133
+ raise DSL::Outcomes::FailTest, e.to_s
94
134
  end
95
135
  end
96
136
  end
data/lib/beaker/host.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'socket'
2
- require 'timeout'
3
2
 
4
3
  %w(command ssh_connection).each do |lib|
5
4
  begin
@@ -11,6 +10,7 @@ end
11
10
 
12
11
  module Beaker
13
12
  class Host
13
+ SELECT_TIMEOUT = 30
14
14
 
15
15
  # This class providers array syntax for using puppet --configprint on a host
16
16
  class PuppetConfigReader
@@ -25,34 +25,34 @@ module Beaker
25
25
  end
26
26
  end
27
27
 
28
- def self.create name, options, config
29
- case config['HOSTS'][name]['platform']
28
+ def self.create name, options
29
+ case options['HOSTS'][name]['platform']
30
30
  when /windows/
31
- Windows::Host.new name, options, config
31
+ Windows::Host.new name, options
32
32
  when /aix/
33
- Aix::Host.new name, options, config
33
+ Aix::Host.new name, options
34
34
  else
35
- Unix::Host.new name, options, config
35
+ Unix::Host.new name, options
36
36
  end
37
37
  end
38
38
 
39
39
  attr_accessor :logger
40
40
  attr_reader :name, :defaults
41
- def initialize name, options, config
41
+ def initialize name, options
42
42
  @logger = options[:logger]
43
- @name, @options, @config = name, options.dup, config
43
+ @name, @options = name.to_s, options.dup
44
44
 
45
45
  # This is annoying and its because of drift/lack of enforcement/lack of having
46
46
  # a explict relationship between our defaults, our setup steps and how they're
47
47
  # related through 'type' and the differences between the assumption of our two
48
48
  # configurations we have for many of our products
49
49
  type = is_pe? ? :pe : :foss
50
- @defaults = merge_defaults_for_type @config, type
50
+ @defaults = merge_defaults_for_type @options, type
51
51
  end
52
52
 
53
- def merge_defaults_for_type config, type
53
+ def merge_defaults_for_type options, type
54
54
  defaults = self.class.send "#{type}_defaults".to_sym
55
- defaults.merge(config['CONFIG']).merge(config['HOSTS'][name])
55
+ defaults.merge(options.merge((options['HOSTS'][name])))
56
56
  end
57
57
 
58
58
  def node_name
@@ -63,18 +63,26 @@ module Beaker
63
63
  end
64
64
 
65
65
  def port_open? port
66
- Timeout.timeout 1 do
67
- begin
68
- TCPSocket.new(reachable_name, port).close
69
- return true
70
- rescue Errno::ECONNREFUSED
71
- return false
66
+ s = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
67
+ sa = Socket.sockaddr_in(port, reachable_name)
68
+
69
+ begin
70
+ s.connect_nonblock(sa)
71
+ rescue Errno::EINPROGRESS
72
+ if IO.select(nil, [s], nil, SELECT_TIMEOUT)
73
+ begin
74
+ s.connect_nonblock(sa)
75
+ rescue Errno::EISCONN
76
+ return true
77
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
78
+ return false
79
+ end
72
80
  end
73
81
  end
82
+ return false
74
83
  end
75
84
 
76
85
  def up?
77
- require 'socket'
78
86
  begin
79
87
  Socket.getaddrinfo( reachable_name, nil )
80
88
  return true
@@ -120,7 +128,7 @@ module Beaker
120
128
  end
121
129
 
122
130
  def is_pe?
123
- @config.is_pe?
131
+ @options.is_pe?
124
132
  end
125
133
 
126
134
  def connection
@@ -161,7 +169,7 @@ module Beaker
161
169
  # No, TestCase has the knowledge about whether its failed, checking acceptable
162
170
  # exit codes at the host level and then raising...
163
171
  # is it necessary to break execution??
164
- unless result.exit_code_in?(options[:acceptable_exit_codes] || [0])
172
+ unless result.exit_code_in?(Array(options[:acceptable_exit_codes] || 0))
165
173
  limit = 10
166
174
  raise "Host '#{self}' exited with #{result.exit_code} running:\n #{cmdline}\nLast #{limit} lines of output were:\n#{result.formatted_output(limit)}"
167
175
  end