beaker 2.46.0 → 2.47.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -41,3 +41,9 @@ Do not output any logging for this command. Defaults to `false`.
41
41
  Specifies standard input to be provided to the command post execution. Defaults to `nil`.
42
42
 
43
43
  on host, "this command takes input", {:stdin => "hiya"}
44
+
45
+ ## [:run_in_parallel](runner/run_in_parallel.md)
46
+
47
+ Execute the command against all hosts in parallel
48
+
49
+ on hosts, puppet( 'agent -t' ), :run_in_parallel => true
@@ -0,0 +1,62 @@
1
+ # run_in_parallel global and command options
2
+
3
+ ## run_in_parallel global option
4
+ The run_in_parallel global option is an array with the following possible values: ['configure', 'install']
5
+ It defaults to an empty array []
6
+ It can be set in an options file, or overriden by the BEAKER_RUN_IN_PARALLEL environment variable
7
+ example:
8
+
9
+ export BEAKER_RUN_IN_PARALLEL=configure,install
10
+
11
+ Including 'configure' causes timesync to execute in parallel (if timesync=true for any host)
12
+
13
+ Including 'install' causes as much of the puppet install to happen in parallel as possible.
14
+
15
+ ## run_in_parallel command option
16
+ The run_in_parallel command option is a boolean value, specifying whether to execute each iteration (usually of hosts)
17
+ in parallel, or not. The block_on method is the primary method accepting the run_in_parallel command option,
18
+ however many methods that call into block_on respect it as well:
19
+ - on
20
+ - run_block_on
21
+ - block_on
22
+ - install_puppet_agent_on
23
+ - apply_manifest_on
24
+ - stop_agent_on
25
+ - execute_powershell_script_on
26
+
27
+ ## Using InParallel in your test scripts
28
+ In addition to the options, you can use InParallel within your test scripts as well.
29
+
30
+ Examples:
31
+ ```ruby
32
+ include InParallel
33
+
34
+ test_name('test_test')
35
+
36
+ # Example 1
37
+ hosts.each_in_parallel{ |host|
38
+ # Do something on each host
39
+ }
40
+
41
+ def some_method_call
42
+ return "some_method_call"
43
+ end
44
+
45
+ def some_method_call
46
+ return "some_other_method_call"
47
+ end
48
+
49
+ # Example 2
50
+ # Runs each method within the block in parallel in a forked process
51
+ run_in_parallel{
52
+ @result = some_method_call
53
+ @result_2 = some_other_method_call
54
+ }
55
+
56
+ # results in 'some_method_callsome_other_method_call'
57
+ puts @result + @result_2
58
+ ```
59
+
60
+ **_Note:_** While you can return a result from a forked process to an instance variable, any values assigned to local variables, or other changes to global state will not persist from the child process to the parent process.
61
+
62
+ Further documentation on the usage of [InParallel](http://github/puppetlabs/in-parallel/readme.md)
data/lib/beaker.rb CHANGED
@@ -29,7 +29,10 @@ module Beaker
29
29
  #
30
30
  # Common setup and testing steps
31
31
  #require 'beaker/steps'
32
- #
32
+
33
+ # InParallel, for executing in parallel
34
+ require 'in_parallel'
35
+
33
36
  # Shared methods and helpers
34
37
  require 'beaker/shared'
35
38
 
data/lib/beaker/cli.rb CHANGED
@@ -14,6 +14,7 @@ module Beaker
14
14
  @options_parser = Beaker::Options::Parser.new
15
15
  @options = @options_parser.parse_args
16
16
  @logger = Beaker::Logger.new(@options)
17
+ InParallel::InParallelExecutor.logger = @logger
17
18
  @options[:logger] = @logger
18
19
  @options[:timestamp] = @timestamp
19
20
  @options[:beaker_version] = Beaker::Version::STRING
data/lib/beaker/dsl.rb CHANGED
@@ -56,8 +56,8 @@ module Beaker
56
56
  # require 'spec_helper'
57
57
  #
58
58
  # describe 'A Test With RSpec' do
59
- # let(:hosts) { Host.new('blah', 'blah', 'not helpful' }
60
- # let(:logger) { Where.is('the', 'rspec', 'logger') }
59
+ # let(:hosts) { Host.new('blah', 'blah', 'not helpful') }
60
+ # let(:logger) { Where.is('the', 'rspec', 'logger') }
61
61
  #
62
62
  # after do
63
63
  # on master, puppet('resource mything ensure=absent')
@@ -24,7 +24,7 @@ module Beaker
24
24
  # @option opts [Hash{String=>String}] :environment ({}) These will be
25
25
  # treated as extra environment variables that should be set before
26
26
  # running the command.
27
- #
27
+ # @option opts [Boolean] :run_in_parallel Whether to run on each host in parallel.
28
28
 
29
29
  # The primary method for executing commands *on* some set of hosts.
30
30
  #
@@ -60,7 +60,7 @@ module Beaker
60
60
  # @return [Result] An object representing the outcome of *command*.
61
61
  # @raise [FailTest] Raises an exception if *command* obviously fails.
62
62
  def on(host, command, opts = {}, &block)
63
- block_on host do | host |
63
+ block_on host, opts do | host |
64
64
  if command.is_a? String
65
65
  cmd_opts = {}
66
66
  #add any additional environment variables to the command
@@ -280,10 +280,12 @@ module Beaker
280
280
  # that responds like
281
281
  # {Beaker::Host#do_scp_from}.
282
282
  # @param [String] powershell_script A string describing a set of powershell actions
283
+ # @param [Hash{Symbol=>String}] opts Options to alter execution.
284
+ # @option opts [Boolean] :run_in_parallel Whether to run on each host in parallel.
283
285
  #
284
286
  # @return [Result] Returns the result of the powershell command execution
285
287
  def execute_powershell_script_on(hosts, powershell_script, opts = {})
286
- block_on hosts do |host|
288
+ block_on hosts, opts do |host|
287
289
  script_path = "beaker_powershell_script_#{Time.now.to_i}.ps1"
288
290
  create_remote_file(host, script_path, powershell_script, opts)
289
291
  native_path = script_path.gsub(/\//, "\\")
@@ -397,6 +397,7 @@ module Beaker
397
397
  # @option opts [String] :debug (false) If this option exists,
398
398
  # the "--debug" command line parameter
399
399
  # will be passed to the 'puppet apply' command.
400
+ # @option opts [Boolean] :run_in_parallel Whether to run on each host in parallel.
400
401
  #
401
402
  # @param [Block] block This method will yield to a block of code passed
402
403
  # by the caller; this can be used for additional
@@ -405,7 +406,7 @@ module Beaker
405
406
  # @return [Array<Result>, Result, nil] An array of results, a result object,
406
407
  # or nil. Check {#run_block_on} for more details on this.
407
408
  def apply_manifest_on(host, manifest, opts = {}, &block)
408
- block_on host do | host |
409
+ block_on host, opts do | host |
409
410
  on_options = {}
410
411
  on_options[:acceptable_exit_codes] = Array(opts[:acceptable_exit_codes])
411
412
 
@@ -658,12 +659,14 @@ module Beaker
658
659
  #stops the puppet agent running on the host
659
660
  # @param [Host, Array<Host>, String, Symbol] agent One or more hosts to act upon,
660
661
  # or a role (String or Symbol) that identifies one or more hosts.
661
- def stop_agent_on(agent)
662
- block_on agent do | host |
663
- vardir = agent.puppet_configprint['vardir']
662
+ # @param [Hash{Symbol=>String}] opts Options to alter execution.
663
+ # @option opts [Boolean] :run_in_parallel Whether to run on each host in parallel.
664
+ def stop_agent_on(agent, opts = {})
665
+ block_on agent, opts do | host |
666
+ vardir = host.puppet_configprint['vardir']
664
667
  agent_running = true
665
668
  while agent_running
666
- agent_running = agent.file_exist?("#{vardir}/state/agent_catalog_run.lock")
669
+ agent_running = host.file_exist?("#{vardir}/state/agent_catalog_run.lock")
667
670
  if agent_running
668
671
  sleep 2
669
672
  end
@@ -671,26 +674,26 @@ module Beaker
671
674
 
672
675
  # In 4.0 this was changed to just be `puppet`
673
676
  agent_service = 'puppet'
674
- if !aio_version?(agent)
677
+ if !aio_version?(host)
675
678
  # The agent service is `pe-puppet` everywhere EXCEPT certain linux distros on PE 2.8
676
679
  # In all the case that it is different, this init script will exist. So we can assume
677
680
  # that if the script doesn't exist, we should just use `pe-puppet`
678
681
  agent_service = 'pe-puppet-agent'
679
- agent_service = 'pe-puppet' unless agent.file_exist?('/etc/init.d/pe-puppet-agent')
682
+ agent_service = 'pe-puppet' unless host.file_exist?('/etc/init.d/pe-puppet-agent')
680
683
  end
681
684
 
682
685
  # Under a number of stupid circumstances, we can't stop the
683
686
  # agent using puppet. This is usually because of issues with
684
687
  # the init script or system on that particular configuration.
685
688
  avoid_puppet_at_all_costs = false
686
- avoid_puppet_at_all_costs ||= agent['platform'] =~ /el-4/
687
- avoid_puppet_at_all_costs ||= agent['pe_ver'] && version_is_less(agent['pe_ver'], '3.2') && agent['platform'] =~ /sles/
689
+ avoid_puppet_at_all_costs ||= host['platform'] =~ /el-4/
690
+ avoid_puppet_at_all_costs ||= host['pe_ver'] && version_is_less(host['pe_ver'], '3.2') && host['platform'] =~ /sles/
688
691
 
689
692
  if avoid_puppet_at_all_costs
690
693
  # When upgrading, puppet is already stopped. On EL4, this causes an exit code of '1'
691
- on agent, "/etc/init.d/#{agent_service} stop", :acceptable_exit_codes => [0, 1]
694
+ on host, "/etc/init.d/#{agent_service} stop", :acceptable_exit_codes => [0, 1]
692
695
  else
693
- on agent, puppet_resource('service', agent_service, 'ensure=stopped')
696
+ on host, puppet_resource('service', agent_service, 'ensure=stopped')
694
697
  end
695
698
  end
696
699
  end
@@ -714,35 +717,52 @@ module Beaker
714
717
 
715
718
  # Ensure the host has requested a cert, then sign it
716
719
  #
717
- # @param [Host, Array<Host>, String, Symbol] host One or more hosts to act upon,
718
- # or a role (String or Symbol) that identifies one or more hosts.
720
+ # @param [Host, Array<Host>, String, Symbol] host One or more hosts, or a role (String or Symbol)
721
+ # that identifies one or more hosts to validate certificate signing.
722
+ # No argument, or an empty array means no validation of success
723
+ # for specific hosts will be performed. This will always execute
724
+ # 'cert --sign --all --allow-dns-alt-names' even for a single host.
719
725
  #
720
726
  # @return nil
721
727
  # @raise [FailTest] if process times out
722
- def sign_certificate_for(host)
723
- block_on host do | host |
724
- if [master, dashboard, database].include? host
728
+ def sign_certificate_for(host = [])
729
+ hostnames = []
730
+ hosts = host.is_a?(Array) ? host : [host]
731
+ hosts.each{ |current_host|
732
+ if [master, dashboard, database].include? current_host
725
733
 
726
- on host, puppet( 'agent -t' ), :acceptable_exit_codes => [0,1,2]
727
- on master, puppet( "cert --allow-dns-alt-names sign #{host}" ), :acceptable_exit_codes => [0,24]
734
+ on current_host, puppet( 'agent -t' ), :acceptable_exit_codes => [0,1,2]
735
+ on master, puppet( "cert --allow-dns-alt-names sign #{current_host}" ), :acceptable_exit_codes => [0,24]
728
736
 
729
737
  else
730
-
731
- hostname = Regexp.escape host.node_name
732
-
733
- last_sleep = 0
734
- next_sleep = 1
735
- (0..10).each do |i|
736
- fail_test("Failed to sign cert for #{hostname}") if i == 10
737
-
738
- on master, puppet("cert --sign --all --allow-dns-alt-names"), :acceptable_exit_codes => [0,24]
739
- break if on(master, puppet("cert --list --all")).stdout =~ /\+ "?#{hostname}"?/
740
- sleep next_sleep
741
- (last_sleep, next_sleep) = next_sleep, last_sleep+next_sleep
738
+ hostnames << Regexp.escape( current_host.node_name )
739
+ end
740
+ }
741
+ if hostnames.size < 1
742
+ on master, puppet("cert --sign --all --allow-dns-alt-names"),
743
+ :acceptable_exit_codes => [0,24]
744
+ return
745
+ end
746
+ while hostnames.size > 0
747
+ last_sleep = 0
748
+ next_sleep = 1
749
+ (0..10).each do |i|
750
+ if i == 10
751
+ fail_test("Failed to sign cert for #{hostnames}")
752
+ hostnames.clear
753
+ end
754
+ on master, puppet("cert --sign --all --allow-dns-alt-names"), :acceptable_exit_codes => [0,24]
755
+ out = on(master, puppet("cert --list --all")).stdout
756
+ if hostnames.all? { |hostname| out =~ /\+ "?#{hostname}"?/ }
757
+ hostnames.clear
758
+ break
742
759
  end
743
760
 
761
+ sleep next_sleep
762
+ (last_sleep, next_sleep) = next_sleep, last_sleep+next_sleep
744
763
  end
745
764
  end
765
+ host
746
766
  end
747
767
 
748
768
  #prompt the master to sign certs then check to confirm the cert for the default host is signed
@@ -245,6 +245,7 @@ module Beaker
245
245
  # @option opts [String] :puppet_agent_version Version of puppet agent to download
246
246
  # @option opts [String] :mac_download_url Url to download msi pattern of %url%/puppet-%version%.msi
247
247
  # @option opts [String] :win_download_url Url to download dmg pattern of %url%/(puppet|hiera|facter)-%version%.msi
248
+ # @option opts [Boolean] :run_in_parallel Whether to install on all hosts in parallel. Defaults to false.
248
249
  #
249
250
  # @return nil
250
251
  # @raise [StandardError] When encountering an unsupported platform by default, or if gem cannot be found when default_action => 'gem_install'
@@ -257,9 +258,13 @@ module Beaker
257
258
  # backwards compatability
258
259
  opts[:puppet_agent_version] ||= opts[:version]
259
260
  install_puppet_agent_on(hosts, opts)
260
-
261
261
  else
262
- block_on hosts do |host|
262
+ # Use option specified in the method call, otherwise check whether the global
263
+ # run_in_parallel option includes install
264
+ run_in_parallel = opts[:run_in_parallel]
265
+ run_in_parallel = ((@options && @options[:run_in_parallel].is_a?(Array)) ?
266
+ @options[:run_in_parallel].include?('install') : false) if run_in_parallel.nil?
267
+ block_on hosts, { :run_in_parallel => run_in_parallel} do |host|
263
268
  if host['platform'] =~ /el-(5|6|7)/
264
269
  relver = $1
265
270
  install_puppet_from_rpm_on(host, opts.merge(:release => relver, :family => 'el'))
@@ -325,6 +330,7 @@ module Beaker
325
330
  # @option opts [String] :mac_download_url Url to download msi pattern of %url%/puppet-agent-%version%.msi
326
331
  # @option opts [String] :win_download_url Url to download dmg pattern of %url%/puppet-agent-%version%.msi
327
332
  # @option opts [String] :puppet_collection Defaults to 'pc1'
333
+ # @option opts [Boolean] :run_in_parallel Whether to run on each host in parallel.
328
334
  #
329
335
  # @return nil
330
336
  # @raise [StandardError] When encountering an unsupported platform by default, or if gem cannot be found when default_action => 'gem_install'
@@ -334,7 +340,10 @@ module Beaker
334
340
  opts[:puppet_collection] ||= 'pc1' #hi! i'm case sensitive! be careful!
335
341
  opts[:puppet_agent_version] ||= opts[:version] #backwards compatability with old parameter name
336
342
 
337
- block_on hosts do |host|
343
+ run_in_parallel = opts[:run_in_parallel]
344
+ run_in_parallel = ((@options && @options[:run_in_parallel].is_a?(Array)) ?
345
+ @options[:run_in_parallel].include?('install') : false) if run_in_parallel.nil?
346
+ block_on hosts, { :run_in_parallel => run_in_parallel } do |host|
338
347
  add_role(host, 'aio') #we are installing agent, so we want aio role
339
348
  package_name = nil
340
349
  case host['platform']
@@ -379,6 +388,7 @@ module Beaker
379
388
  # @param [Hash{Symbol=>String}] opts
380
389
  # @option opts [Hash{String=>String}] :main configure the main section of puppet.conf
381
390
  # @option opts [Hash{String=>String}] :agent configure the agent section of puppet.conf
391
+ # @option opts [Boolean] :run_in_parallel Whether to run on each host in parallel.
382
392
  #
383
393
  # @example will configure /etc/puppet.conf on the puppet master.
384
394
  # config = {
@@ -407,7 +417,7 @@ module Beaker
407
417
  puppet_conf_text << "\n"
408
418
  end
409
419
  logger.debug( "setting config '#{puppet_conf_text}' on hosts #{hosts}" )
410
- block_on hosts do |host|
420
+ block_on hosts, opts do |host|
411
421
  puppet_conf_path = host.puppet['config']
412
422
  create_remote_file(host, puppet_conf_path, puppet_conf_text)
413
423
  end
@@ -16,7 +16,7 @@ module Beaker
16
16
  # The directories in the module directory that will not be scp-ed to the test system when using
17
17
  # `copy_module_to`
18
18
  PUPPET_MODULE_INSTALL_IGNORE = ['.bundle', '.git', '.idea', '.vagrant', '.vendor', 'vendor', 'acceptance',
19
- 'bundle', 'spec', 'tests', 'log']
19
+ 'bundle', 'spec', 'tests', 'log', '.svn', 'junit', 'pkg', 'example']
20
20
 
21
21
  # Install the desired module on all hosts using either the PMT or a
22
22
  # staging forge
@@ -17,11 +17,13 @@ module Beaker
17
17
  # as a String that can be used to search for
18
18
  # a set of Hosts, or a {Host}
19
19
  # or Array<{Host}> to run the block against
20
+ # @param [Hash{Symbol=>String}] opts Options to alter execution.
21
+ # @option opts [Boolean] :run_in_parallel Whether to run on each host in parallel.
20
22
  # @param [Block] block This method will yield to a block of code passed by the caller
21
23
  #
22
24
  # @return [Array<Result>, Result, nil] An array of results, a result object, or nil.
23
25
  # Check {#run_block_on} for more details on this.
24
- def block_on hosts_or_filter, &block
26
+ def block_on hosts_or_filter, opts={}, &block
25
27
  block_hosts = nil
26
28
  if defined? hosts
27
29
  block_hosts = hosts
@@ -32,7 +34,7 @@ module Beaker
32
34
  else
33
35
  block_hosts = hosts_or_filter
34
36
  end
35
- run_block_on block_hosts, filter, &block
37
+ run_block_on block_hosts, filter, opts, &block
36
38
  end
37
39
 
38
40
  end
@@ -52,7 +52,7 @@ module Beaker
52
52
  when host['platform'] =~ /sles-/
53
53
  ntp_command = "sntp #{ntp_server}"
54
54
  else
55
- ntp_command = "ntpdate -t 20 #{ntp_server}"
55
+ ntp_command = "ntpdate -u -t 20 #{ntp_server}"
56
56
  end
57
57
  success=false
58
58
  try = 0
@@ -71,6 +71,7 @@ module Beaker
71
71
  end
72
72
  end
73
73
  end
74
+ nil
74
75
  rescue => e
75
76
  report_and_raise(logger, e, "timesync (--ntp)")
76
77
  end
@@ -101,9 +101,10 @@ module Beaker
101
101
 
102
102
  #Default configuration steps to be run for a given hypervisor. Any additional configuration to be done
103
103
  #to the provided SUT for test execution to be successful.
104
- def configure
104
+ def configure(opts = {})
105
105
  return unless @options[:configure]
106
- block_on @hosts do |host|
106
+ block_on @hosts, { :run_in_parallel => (@options && @options[:run_in_parallel].is_a?(Array)) ?
107
+ @options[:run_in_parallel].include?('configure') : false} do |host|
107
108
  if host[:timesync]
108
109
  timesync(host, @options)
109
110
  end
@@ -36,6 +36,7 @@ module Beaker
36
36
  :vbguest_plugin => ['BEAKER_VB_GUEST_PLUGIN', 'BEAKER_vb_guest_plugin'],
37
37
  :tag_includes => ['BEAKER_TAG'],
38
38
  :tag_excludes => ['BEAKER_EXCLUDE_TAG'],
39
+ :run_in_parallel => ['BEAKER_RUN_IN_PARALLEL'],
39
40
  }
40
41
 
41
42
  # Select all environment variables whose name matches provided regex
@@ -86,6 +87,9 @@ module Beaker
86
87
 
87
88
  found_env_vars[:type] = type
88
89
  end
90
+ if found_env_vars[:run_in_parallel]
91
+ found_env_vars[:run_in_parallel] = found_env_vars[:run_in_parallel].split(',')
92
+ end
89
93
 
90
94
  found_env_vars[:pe_version_file_win] = found_env_vars[:pe_version_file]
91
95
  found_env_vars
@@ -188,6 +192,7 @@ module Beaker
188
192
  :nodeclassifier_port => 4433,
189
193
  :cache_files_locally => true, # TODO change to false in next major version
190
194
  :aws_keyname_modifier => rand(10 ** 10).to_s.rjust(10,'0'), # 10 digit random number string
195
+ :run_in_parallel => [],
191
196
  :ssh => {
192
197
  :config => false,
193
198
  :paranoid => false,
@@ -72,6 +72,8 @@ module Beaker
72
72
  #
73
73
  # @param [Array<Host>, Host] hosts The host or hosts to run the provided block against
74
74
  # @param [String, Symbol] filter Optional filter to apply to provided hosts - limits by name or role
75
+ # @param [Hash{Symbol=>String}] opts
76
+ # @option opts [Boolean] :run_in_parallel Whether to run on each host in parallel.
75
77
  # @param [Block] block This method will yield to a block of code passed by the caller
76
78
  #
77
79
  # @todo (beaker3.0:BKR-571): simplify return types to Array<Result> only
@@ -82,7 +84,7 @@ module Beaker
82
84
  # Else, a result object is returned. If filtering makes it such that only
83
85
  # one host is left, then it's passed as a host object (not in an array),
84
86
  # and thus a result object is returned.
85
- def run_block_on hosts = [], filter = nil, &block
87
+ def run_block_on hosts = [], filter = nil, opts = {}, &block
86
88
  result = nil
87
89
  block_hosts = hosts #the hosts to apply the block to after any filtering
88
90
  if filter
@@ -100,8 +102,18 @@ module Beaker
100
102
  end
101
103
  if block_hosts.is_a? Array
102
104
  if block_hosts.length > 0
103
- result = block_hosts.map do |h|
104
- run_block_on h, nil, &block
105
+ if opts[:run_in_parallel]
106
+ # Pass caller[1] - the line that called block_on - for logging purposes.
107
+ result = block_hosts.map.each_in_parallel(caller[1]) do |h|
108
+ run_block_on h, &block
109
+ end
110
+ hosts.each{|host| host.close}# For some reason, I have to close the SSH connection
111
+ # after spawning a process and running commands on a host,
112
+ # or else it gets into a broken state for the next call.
113
+ else
114
+ result = block_hosts.map do |h|
115
+ run_block_on h, &block
116
+ end
105
117
  end
106
118
  else
107
119
  # there are no matching hosts to execute against