beaker 1.16.0 → 1.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +8 -8
  2. data/CONTRIBUTING.md +90 -0
  3. data/HISTORY.md +654 -2
  4. data/beaker.gemspec +1 -0
  5. data/lib/beaker/answers/version34.rb +4 -0
  6. data/lib/beaker/cli.rb +49 -2
  7. data/lib/beaker/dsl/helpers.rb +356 -196
  8. data/lib/beaker/dsl/install_utils.rb +135 -16
  9. data/lib/beaker/dsl/patterns.rb +37 -0
  10. data/lib/beaker/dsl/roles.rb +29 -0
  11. data/lib/beaker/dsl.rb +2 -1
  12. data/lib/beaker/host/unix.rb +14 -10
  13. data/lib/beaker/host/windows.rb +2 -0
  14. data/lib/beaker/host.rb +96 -1
  15. data/lib/beaker/host_prebuilt_steps.rb +41 -51
  16. data/lib/beaker/hypervisor/aws_sdk.rb +80 -16
  17. data/lib/beaker/hypervisor/ec2_helper.rb +1 -1
  18. data/lib/beaker/logger.rb +17 -0
  19. data/lib/beaker/options/command_line_parser.rb +3 -0
  20. data/lib/beaker/options/hosts_file_parser.rb +7 -4
  21. data/lib/beaker/options/options_hash.rb +2 -2
  22. data/lib/beaker/options/parser.rb +1 -1
  23. data/lib/beaker/options/presets.rb +128 -83
  24. data/lib/beaker/perf.rb +58 -0
  25. data/lib/beaker/shared/host_manager.rb +81 -0
  26. data/lib/beaker/shared.rb +2 -2
  27. data/lib/beaker/ssh_connection.rb +14 -7
  28. data/lib/beaker/test_case.rb +13 -0
  29. data/lib/beaker/test_suite.rb +23 -5
  30. data/lib/beaker/version.rb +1 -1
  31. data/lib/beaker.rb +1 -1
  32. data/spec/beaker/answers_spec.rb +13 -8
  33. data/spec/beaker/dsl/ezbake_utils_spec.rb +8 -9
  34. data/spec/beaker/dsl/helpers_spec.rb +299 -51
  35. data/spec/beaker/dsl/install_utils_spec.rb +75 -10
  36. data/spec/beaker/dsl/roles_spec.rb +36 -1
  37. data/spec/beaker/host_prebuilt_steps_spec.rb +21 -5
  38. data/spec/beaker/host_spec.rb +187 -23
  39. data/spec/beaker/hypervisor/ec2_helper_spec.rb +4 -4
  40. data/spec/beaker/hypervisor/vagrant_spec.rb +1 -1
  41. data/spec/beaker/options/hosts_file_parser_spec.rb +5 -0
  42. data/spec/beaker/options/options_hash_spec.rb +2 -2
  43. data/spec/beaker/options/parser_spec.rb +6 -0
  44. data/spec/beaker/options/presets_spec.rb +18 -2
  45. data/spec/beaker/perf_spec.rb +87 -0
  46. data/spec/beaker/shared/{host_role_parser_spec.rb → host_manager_spec.rb} +36 -5
  47. data/spec/beaker/test_suite_spec.rb +4 -3
  48. data/spec/matchers.rb +31 -3
  49. data/spec/mocks.rb +31 -25
  50. metadata +24 -5
  51. data/lib/beaker/shared/host_role_parser.rb +0 -36
@@ -3,6 +3,9 @@ require 'resolv'
3
3
  require 'inifile'
4
4
  require 'timeout'
5
5
  require 'beaker/dsl/outcomes'
6
+ require 'beaker/options'
7
+ require 'hocon'
8
+ require 'hocon/config_error'
6
9
 
7
10
  module Beaker
8
11
  module DSL
@@ -74,19 +77,16 @@ module Beaker
74
77
  # @return [Result] An object representing the outcome of *command*.
75
78
  # @raise [FailTest] Raises an exception if *command* obviously fails.
76
79
  def on(host, command, opts = {}, &block)
77
- unless command.is_a? Command
80
+ block_on host do | host |
81
+ if command.is_a? Command
82
+ command = command.cmd_line(host)
83
+ end
78
84
  cmd_opts = {}
85
+ #add any additional environment variables to the command
79
86
  if opts[:environment]
80
87
  cmd_opts['ENV'] = opts[:environment]
81
88
  end
82
89
  command = Command.new(command.to_s, [], cmd_opts)
83
- end
84
- if host.is_a? String or host.is_a? Symbol
85
- host = hosts_as(host) #check by role
86
- end
87
- if host.is_a? Array
88
- host.map { |h| on h, command, opts, &block }
89
- else
90
90
  @result = host.exec(command, opts)
91
91
 
92
92
  # Also, let additional checking be performed by the caller.
@@ -100,8 +100,7 @@ module Beaker
100
100
  yield @result
101
101
  end
102
102
  end
103
-
104
- return @result
103
+ @result
105
104
  end
106
105
  end
107
106
 
@@ -179,11 +178,10 @@ module Beaker
179
178
  #
180
179
  # @return [Result] Returns the result of the SCP operation
181
180
  def scp_from host, from_path, to_path, opts = {}
182
- if host.is_a? Array
183
- host.each { |h| scp_from h, from_path, to_path, opts }
184
- else
181
+ block_on host do | host |
185
182
  @result = host.do_scp_from(from_path, to_path, opts)
186
183
  @result.log logger
184
+ @result
187
185
  end
188
186
  end
189
187
 
@@ -201,11 +199,10 @@ module Beaker
201
199
  #
202
200
  # @return [Result] Returns the result of the SCP operation
203
201
  def scp_to host, from_path, to_path, opts = {}
204
- if host.is_a? Array
205
- host.each { |h| scp_to h, from_path, to_path, opts }
206
- else
202
+ block_on host do | host |
207
203
  @result = host.do_scp_to(from_path, to_path, opts)
208
204
  @result.log logger
205
+ @result
209
206
  end
210
207
  end
211
208
 
@@ -349,7 +346,7 @@ module Beaker
349
346
  # @option opts [String] :source The location on the test runners box where the files are found
350
347
  # @option opts [String] :module_name The name of the module to be copied over
351
348
  def puppet_module_install_on(host, opts = {})
352
- Array(host).each do |h|
349
+ block_on host do | h |
353
350
  on h, puppet("module install #{opts[:module_name]}")
354
351
  end
355
352
  end
@@ -405,31 +402,14 @@ module Beaker
405
402
  # @raise [SkipTest] Raises skip test if there are no valid hosts for
406
403
  # this test case after confinement.
407
404
  def confine(type, criteria, host_array = nil, &block)
408
- provided_hosts = host_array ? true : false
409
405
  hosts_to_modify = host_array || hosts
410
- criteria.each_pair do |property, value|
411
- case type
412
- when :except
413
- hosts_to_modify = hosts_to_modify.reject do |host|
414
- inspect_host host, property, value
415
- end
416
- if block_given?
417
- hosts_to_modify = hosts_to_modify.reject do |host|
418
- yield host
419
- end
420
- end
421
- when :to
422
- hosts_to_modify = hosts_to_modify.select do |host|
423
- inspect_host host, property, value
424
- end
425
- if block_given?
426
- hosts_to_modify = hosts_to_modify.select do |host|
427
- yield host
428
- end
429
- end
430
- else
431
- raise "Unknown option #{type}"
432
- end
406
+ case type
407
+ when :except
408
+ hosts_to_modify = hosts_to_modify - select_hosts(criteria, hosts_to_modify, &block)
409
+ when :to
410
+ hosts_to_modify = select_hosts(criteria, hosts_to_modify, &block)
411
+ else
412
+ raise "Unknown option #{type}"
433
413
  end
434
414
  if hosts_to_modify.empty?
435
415
  logger.warn "No suitable hosts with: #{criteria.inspect}"
@@ -456,6 +436,59 @@ module Beaker
456
436
  end
457
437
  end
458
438
 
439
+ #Return a set of hosts that meet the given criteria
440
+ # @param [Hash{Symbol,String=>String,Regexp,Array<String,Regexp>}]
441
+ # criteria Specify the criteria with which a host should be
442
+ # considered for inclusion. The key is any attribute
443
+ # of the host that will be yielded by {Beaker::Host#[]}.
444
+ # The value can be any string/regex or array of strings/regexp.
445
+ # The values are compared using [Enumerable#any?] so that if one
446
+ # value of an array matches the host is considered a match for that
447
+ # criteria.
448
+ # @param [Array<Host>] host_array This creatively named parameter is
449
+ # an optional array of hosts to confine to. If not passed in, this
450
+ # method will modify {Beaker::TestCase#hosts} in place.
451
+ # @param [Proc] block Addition checks to determine suitability of hosts
452
+ # for selection. Each host that is still valid after checking
453
+ # *criteria* is then passed in turn into this block. The block
454
+ # should return true if the host matches this additional criteria.
455
+ #
456
+ # @return [Array<Host>] Returns an array of hosts that meet the provided criteria
457
+ def select_hosts(criteria, host_array = nil, &block)
458
+ hosts_to_select_from = host_array || hosts
459
+ criteria.each_pair do |property, value|
460
+ hosts_to_select_from = hosts_to_select_from.select do |host|
461
+ inspect_host host, property, value
462
+ end
463
+ end
464
+ if block_given?
465
+ hosts_to_select_from = hosts_to_select_from.select do |host|
466
+ yield host
467
+ end
468
+ end
469
+ hosts_to_select_from
470
+ end
471
+
472
+ # Return the name of the puppet user.
473
+ #
474
+ # @param [Host] host One object that acts like a Beaker::Host
475
+ #
476
+ # @note This method assumes puppet is installed on the host.
477
+ #
478
+ def puppet_user(host)
479
+ return host.puppet('master')['group']
480
+ end
481
+
482
+ # Return the name of the puppet group.
483
+ #
484
+ # @param [Host] host One object that acts like a Beaker::Host
485
+ #
486
+ # @note This method assumes puppet is installed on the host.
487
+ #
488
+ def puppet_group(host)
489
+ return host.puppet('master')['user']
490
+ end
491
+
459
492
  # @!visibility private
460
493
  def inspect_host(host, property, one_or_more_values)
461
494
  values = Array(one_or_more_values)
@@ -489,16 +522,24 @@ module Beaker
489
522
  # specified, if no section is specified the
490
523
  # a puppet.conf file will be written with the
491
524
  # options put in a section named after [mode]
492
- #
493
- # There is a special setting for command_line
494
- # arguments such as --debug or --logdest, which
495
- # cannot be set in puppet.conf. For example:
525
+ # @option conf_opts [String] :__commandline_args__ A special setting for
526
+ # command_line arguments such as --debug or
527
+ # --logdest, which cannot be set in
528
+ # puppet.conf. For example:
496
529
  #
497
530
  # :__commandline_args__ => '--logdest /tmp/a.log'
498
531
  #
499
532
  # These will only be applied when starting a FOSS
500
533
  # master, as a pe master is just bounced.
501
- #
534
+ # @option conf_opts [Hash] :__service_args__ A special setting of options
535
+ # for controlling how the puppet master service is
536
+ # handled. The only setting currently is
537
+ # :bypass_service_script, which if set true will
538
+ # force stopping and starting a webrick master
539
+ # using the start_puppet_from_source_* methods,
540
+ # even if it seems the host has passenger.
541
+ # This is needed in FOSS tests to initialize
542
+ # SSL.
502
543
  # @param [File] testdir The temporary directory which will hold backup
503
544
  # configuration, and other test artifacts.
504
545
  #
@@ -524,16 +565,43 @@ module Beaker
524
565
  def with_puppet_running_on host, conf_opts, testdir = host.tmpdir(File.basename(@path)), &block
525
566
  raise(ArgumentError, "with_puppet_running_on's conf_opts must be a Hash. You provided a #{conf_opts.class}: '#{conf_opts}'") if !conf_opts.kind_of?(Hash)
526
567
  cmdline_args = conf_opts[:__commandline_args__]
527
- conf_opts = conf_opts.reject { |k,v| k == :__commandline_args__ }
568
+ service_args = conf_opts[:__service_args__] || {}
569
+ conf_opts = conf_opts.reject { |k,v| [:__commandline_args__, :__service_args__].include?(k) }
528
570
 
529
571
  curl_retries = host['master-start-curl-retries'] || options['master-start-curl-retries']
530
572
  logger.debug "Setting curl retries to #{curl_retries}"
531
573
 
574
+ if options[:is_jvm_puppet]
575
+ confdir = host.puppet('master')['confdir']
576
+ vardir = host.puppet('master')['vardir']
577
+
578
+ if cmdline_args
579
+ split_args = cmdline_args.split()
580
+
581
+ split_args.each do |arg|
582
+ case arg
583
+ when /--confdir=(.*)/
584
+ confdir = $1
585
+ when /--vardir=(.*)/
586
+ vardir = $1
587
+ end
588
+ end
589
+ end
590
+
591
+ jvm_puppet_opts = { "jruby-puppet" => {
592
+ "master-conf-dir" => confdir,
593
+ "master-var-dir" => vardir,
594
+ }}
595
+
596
+ jvm_puppet_conf = File.join("#{host['jvm-puppet-confdir']}", "jvm-puppet.conf")
597
+ modify_tk_config(host, jvm_puppet_conf, jvm_puppet_opts)
598
+ end
599
+
532
600
  begin
533
601
  backup_file = backup_the_file(host, host['puppetpath'], testdir, 'puppet.conf')
534
602
  lay_down_new_puppet_conf host, conf_opts, testdir
535
603
 
536
- if host['puppetservice']
604
+ if host.use_service_scripts? && !service_args[:bypass_service_script]
537
605
  bounce_service( host, host['puppetservice'], curl_retries )
538
606
  else
539
607
  puppet_master_started = start_puppet_from_source_on!( host, cmdline_args )
@@ -547,9 +615,9 @@ module Beaker
547
615
 
548
616
  ensure
549
617
  begin
550
- restore_puppet_conf_from_backup( host, backup_file )
551
618
 
552
- if host['puppetservice']
619
+ if host.use_service_scripts? && !service_args[:bypass_service_script]
620
+ restore_puppet_conf_from_backup( host, backup_file )
553
621
  bounce_service( host, host['puppetservice'], curl_retries )
554
622
  else
555
623
  if puppet_master_started
@@ -557,6 +625,7 @@ module Beaker
557
625
  else
558
626
  dump_puppet_log(host)
559
627
  end
628
+ restore_puppet_conf_from_backup( host, backup_file )
560
629
  end
561
630
 
562
631
  rescue Exception => teardown_exception
@@ -655,7 +724,7 @@ module Beaker
655
724
  # @!visibility private
656
725
  def dump_puppet_log(host)
657
726
  syslogfile = case host['platform']
658
- when /fedora|centos|el/ then '/var/log/messages'
727
+ when /fedora|centos|el|redhat|scientific/ then '/var/log/messages'
659
728
  when /ubuntu|debian/ then '/var/log/syslog'
660
729
  else return
661
730
  end
@@ -687,10 +756,89 @@ module Beaker
687
756
  new_conf
688
757
  end
689
758
 
759
+ # Modify the given TrapperKeeper config file.
760
+ #
761
+ # @param [Host] host A host object
762
+ # @param [OptionsHash] options_hash New hash which will be merged into
763
+ # the given TrapperKeeper config.
764
+ # @param [String] config_file_path Path to the TrapperKeeper config on
765
+ # the given host which is to be
766
+ # modified.
767
+ # @param [Bool] replace If set true, instead of updating the existing
768
+ # TrapperKeeper configuration, replace it entirely
769
+ # with the contents of the given hash.
770
+ #
771
+ # @note TrapperKeeper config files can be HOCON, JSON, or Ini. We don't
772
+ # particularly care which of these the file named by `config_file_path` on
773
+ # the SUT actually is, just that the contents can be parsed into a map.
774
+ #
775
+ def modify_tk_config(host, config_file_path, options_hash, replace=false)
776
+ if options_hash.empty?
777
+ return nil
778
+ end
779
+
780
+ new_hash = Beaker::Options::OptionsHash.new
781
+
782
+ if replace
783
+ new_hash.merge!(options_hash)
784
+ else
785
+ if not host.file_exist?( config_file_path )
786
+ raise "Error: #{config_file_path} does not exist on #{host}"
787
+ end
788
+ file_string = host.exec( Command.new( "cat #{config_file_path}" )).stdout
789
+
790
+ begin
791
+ tk_conf_hash = read_tk_config_string(file_string)
792
+ rescue RuntimeError
793
+ raise "Error reading trapperkeeper config: #{config_file_path} at host: #{host}"
794
+ end
795
+
796
+ new_hash.merge!(tk_conf_hash)
797
+ new_hash.merge!(options_hash)
798
+ end
799
+
800
+ file_string = JSON.dump(new_hash)
801
+ create_remote_file host, config_file_path, file_string
802
+ end
803
+
804
+ # The Trapperkeeper config service will accept HOCON (aka typesafe), JSON,
805
+ # or Ini configuration files which means we need to safely handle the the
806
+ # exceptions that might come from parsing the given string with the wrong
807
+ # parser and fall back to the next valid parser in turn. We finally raise
808
+ # a RuntimeException if none of the parsers succeed.
809
+ #
810
+ # @!visibility private
811
+ def read_tk_config_string( string )
812
+ begin
813
+ return Hocon.parse(string)
814
+ rescue Hocon::ConfigError
815
+ nil
816
+ end
817
+
818
+ begin
819
+ return JSON.parse(string)
820
+ rescue JSON::JSONError
821
+ nil
822
+ end
823
+
824
+ begin
825
+ return IniFile.new(string)
826
+ rescue IniFile::Error
827
+ nil
828
+ end
829
+
830
+ raise "Failed to read TrapperKeeper config!"
831
+ end
832
+
690
833
  # @!visibility private
691
834
  def bounce_service host, service, curl_retries = 120
692
- host.exec puppet_resource( 'service', service, 'ensure=stopped' )
693
- host.exec puppet_resource( 'service', service, 'ensure=running' )
835
+ if host.graceful_restarts?
836
+ apachectl_path = host.is_pe? ? "#{host['puppetsbindir']}/apache2ctl" : 'apache2ctl'
837
+ host.exec(Command.new("#{apachectl_path} graceful"))
838
+ else
839
+ host.exec puppet_resource('service', service, 'ensure=stopped')
840
+ host.exec puppet_resource('service', service, 'ensure=running')
841
+ end
694
842
  curl_with_retries(" #{service} ", host, "https://localhost:8140", [35, 60], curl_retries)
695
843
  end
696
844
 
@@ -769,79 +917,76 @@ module Beaker
769
917
  # validation, etc.
770
918
  #
771
919
  def apply_manifest_on(host, manifest, opts = {}, &block)
772
- if host.is_a?(Array)
773
- return host.map do |h|
774
- apply_manifest_on(h, manifest, opts, &block)
920
+ block_on host do | host |
921
+
922
+ on_options = {}
923
+ on_options[:acceptable_exit_codes] = Array(opts[:acceptable_exit_codes])
924
+
925
+ puppet_apply_opts = {}
926
+ puppet_apply_opts[:verbose] = nil
927
+ puppet_apply_opts[:parseonly] = nil if opts[:parseonly]
928
+ puppet_apply_opts[:trace] = nil if opts[:trace]
929
+ puppet_apply_opts[:parser] = 'future' if opts[:future_parser]
930
+ puppet_apply_opts[:modulepath] = opts[:modulepath] if opts[:modulepath]
931
+ puppet_apply_opts[:noop] = nil if opts[:noop]
932
+
933
+ # From puppet help:
934
+ # "... an exit code of '2' means there were changes, an exit code of
935
+ # '4' means there were failures during the transaction, and an exit
936
+ # code of '6' means there were both changes and failures."
937
+ if [opts[:catch_changes],opts[:catch_failures],opts[:expect_failures],opts[:expect_changes]].compact.length > 1
938
+ raise(ArgumentError,
939
+ 'Cannot specify more than one of `catch_failures`, ' +
940
+ '`catch_changes`, `expect_failures`, or `expect_changes` ' +
941
+ 'for a single manifest')
775
942
  end
776
- end
777
943
 
778
- on_options = {}
779
- on_options[:acceptable_exit_codes] = Array(opts[:acceptable_exit_codes])
780
-
781
- puppet_apply_opts = {}
782
- puppet_apply_opts[:verbose] = nil
783
- puppet_apply_opts[:parseonly] = nil if opts[:parseonly]
784
- puppet_apply_opts[:trace] = nil if opts[:trace]
785
- puppet_apply_opts[:parser] = 'future' if opts[:future_parser]
786
- puppet_apply_opts[:modulepath] = opts[:modulepath] if opts[:modulepath]
787
- puppet_apply_opts[:noop] = nil if opts[:noop]
788
-
789
- # From puppet help:
790
- # "... an exit code of '2' means there were changes, an exit code of
791
- # '4' means there were failures during the transaction, and an exit
792
- # code of '6' means there were both changes and failures."
793
- if [opts[:catch_changes],opts[:catch_failures],opts[:expect_failures],opts[:expect_changes]].compact.length > 1
794
- raise(ArgumentError,
795
- 'Cannot specify more than one of `catch_failures`, ' +
796
- '`catch_changes`, `expect_failures`, or `expect_changes` ' +
797
- 'for a single manifest')
798
- end
944
+ if opts[:catch_changes]
945
+ puppet_apply_opts['detailed-exitcodes'] = nil
799
946
 
800
- if opts[:catch_changes]
801
- puppet_apply_opts['detailed-exitcodes'] = nil
947
+ # We're after idempotency so allow exit code 0 only.
948
+ on_options[:acceptable_exit_codes] |= [0]
949
+ elsif opts[:catch_failures]
950
+ puppet_apply_opts['detailed-exitcodes'] = nil
802
951
 
803
- # We're after idempotency so allow exit code 0 only.
804
- on_options[:acceptable_exit_codes] |= [0]
805
- elsif opts[:catch_failures]
806
- puppet_apply_opts['detailed-exitcodes'] = nil
952
+ # We're after only complete success so allow exit codes 0 and 2 only.
953
+ on_options[:acceptable_exit_codes] |= [0, 2]
954
+ elsif opts[:expect_failures]
955
+ puppet_apply_opts['detailed-exitcodes'] = nil
807
956
 
808
- # We're after only complete success so allow exit codes 0 and 2 only.
809
- on_options[:acceptable_exit_codes] |= [0, 2]
810
- elsif opts[:expect_failures]
811
- puppet_apply_opts['detailed-exitcodes'] = nil
957
+ # We're after failures specifically so allow exit codes 1, 4, and 6 only.
958
+ on_options[:acceptable_exit_codes] |= [1, 4, 6]
959
+ elsif opts[:expect_changes]
960
+ puppet_apply_opts['detailed-exitcodes'] = nil
812
961
 
813
- # We're after failures specifically so allow exit codes 1, 4, and 6 only.
814
- on_options[:acceptable_exit_codes] |= [1, 4, 6]
815
- elsif opts[:expect_changes]
816
- puppet_apply_opts['detailed-exitcodes'] = nil
962
+ # We're after changes specifically so allow exit code 2 only.
963
+ on_options[:acceptable_exit_codes] |= [2]
964
+ else
965
+ # Either use the provided acceptable_exit_codes or default to [0]
966
+ on_options[:acceptable_exit_codes] |= [0]
967
+ end
817
968
 
818
- # We're after changes specifically so allow exit code 2 only.
819
- on_options[:acceptable_exit_codes] |= [2]
820
- else
821
- # Either use the provided acceptable_exit_codes or default to [0]
822
- on_options[:acceptable_exit_codes] |= [0]
823
- end
969
+ # Not really thrilled with this implementation, might want to improve it
970
+ # later. Basically, there is a magic trick in the constructor of
971
+ # PuppetCommand which allows you to pass in a Hash for the last value in
972
+ # the *args Array; if you do so, it will be treated specially. So, here
973
+ # we check to see if our caller passed us a hash of environment variables
974
+ # that they want to set for the puppet command. If so, we set the final
975
+ # value of *args to a new hash with just one entry (the value of which
976
+ # is our environment variables hash)
977
+ if opts.has_key?(:environment)
978
+ puppet_apply_opts['ENV'] = opts[:environment]
979
+ end
824
980
 
825
- # Not really thrilled with this implementation, might want to improve it
826
- # later. Basically, there is a magic trick in the constructor of
827
- # PuppetCommand which allows you to pass in a Hash for the last value in
828
- # the *args Array; if you do so, it will be treated specially. So, here
829
- # we check to see if our caller passed us a hash of environment variables
830
- # that they want to set for the puppet command. If so, we set the final
831
- # value of *args to a new hash with just one entry (the value of which
832
- # is our environment variables hash)
833
- if opts.has_key?(:environment)
834
- puppet_apply_opts['ENV'] = opts[:environment]
835
- end
981
+ file_path = host.tmpfile('apply_manifest.pp')
982
+ create_remote_file(host, file_path, manifest + "\n")
836
983
 
837
- file_path = host.tmpfile('apply_manifest.pp')
838
- create_remote_file(host, file_path, manifest + "\n")
984
+ if host[:default_apply_opts].respond_to? :merge
985
+ puppet_apply_opts = host[:default_apply_opts].merge( puppet_apply_opts )
986
+ end
839
987
 
840
- if host[:default_apply_opts].respond_to? :merge
841
- puppet_apply_opts = host[:default_apply_opts].merge( puppet_apply_opts )
988
+ on host, puppet('apply', file_path, puppet_apply_opts), on_options, &block
842
989
  end
843
-
844
- on host, puppet('apply', file_path, puppet_apply_opts), on_options, &block
845
990
  end
846
991
 
847
992
  # Runs 'puppet apply' on default host, piping manifest through stdin
@@ -853,9 +998,7 @@ module Beaker
853
998
  # @deprecated
854
999
  def run_agent_on(host, arg='--no-daemonize --verbose --onetime --test',
855
1000
  options={}, &block)
856
- if host.is_a? Array
857
- host.each { |h| run_agent_on h, arg, options, &block }
858
- else
1001
+ block_on host do | host |
859
1002
  on host, puppet_agent(arg), options, &block
860
1003
  end
861
1004
  end
@@ -863,32 +1006,34 @@ module Beaker
863
1006
  # FIX: this should be moved into host/platform
864
1007
  # @visibility private
865
1008
  def run_cron_on(host, action, user, entry="", &block)
866
- platform = host['platform']
867
- if platform.include?('solaris') || platform.include?('aix') then
868
- case action
869
- when :list then args = '-l'
870
- when :remove then args = '-r'
871
- when :add
872
- on( host,
873
- "echo '#{entry}' > /var/spool/cron/crontabs/#{user}",
874
- &block )
875
- end
1009
+ block_on host do | host |
1010
+ platform = host['platform']
1011
+ if platform.include?('solaris') || platform.include?('aix') then
1012
+ case action
1013
+ when :list then args = '-l'
1014
+ when :remove then args = '-r'
1015
+ when :add
1016
+ on( host,
1017
+ "echo '#{entry}' > /var/spool/cron/crontabs/#{user}",
1018
+ &block )
1019
+ end
876
1020
 
877
- else # default for GNU/Linux platforms
878
- case action
879
- when :list then args = '-l -u'
880
- when :remove then args = '-r -u'
881
- when :add
882
- on( host,
883
- "echo '#{entry}' > /tmp/#{user}.cron && " +
884
- "crontab -u #{user} /tmp/#{user}.cron",
885
- &block )
1021
+ else # default for GNU/Linux platforms
1022
+ case action
1023
+ when :list then args = '-l -u'
1024
+ when :remove then args = '-r -u'
1025
+ when :add
1026
+ on( host,
1027
+ "echo '#{entry}' > /tmp/#{user}.cron && " +
1028
+ "crontab -u #{user} /tmp/#{user}.cron",
1029
+ &block )
1030
+ end
886
1031
  end
887
- end
888
1032
 
889
- if args
890
- case action
891
- when :list, :remove then on(host, "crontab #{args} #{user}", &block)
1033
+ if args
1034
+ case action
1035
+ when :list, :remove then on(host, "crontab #{args} #{user}", &block)
1036
+ end
892
1037
  end
893
1038
  end
894
1039
  end
@@ -899,23 +1044,24 @@ module Beaker
899
1044
  # A teardown step is also added to make sure unstubbing of the host is
900
1045
  # removed always.
901
1046
  #
902
- # @param machine [String] the host to execute this stub
1047
+ # @param [Host, Array<Host>, String, Symbol] machine One or more hosts to act upon,
1048
+ # or a role (String or Symbol) that identifies one or more hosts.
903
1049
  # @param ip_spec [Hash{String=>String}] a hash containing the host to ip
904
1050
  # mappings
905
1051
  # @example Stub puppetlabs.com on the master to 127.0.0.1
906
1052
  # stub_hosts_on(master, 'puppetlabs.com' => '127.0.0.1')
907
1053
  def stub_hosts_on(machine, ip_spec)
908
- ip_spec.each do |host, ip|
909
- logger.notify("Stubbing host #{host} to IP #{ip} on machine #{machine}")
910
- on( machine,
911
- puppet('resource', 'host', host, 'ensure=present', "ip=#{ip}") )
912
- end
1054
+ block_on machine do | host |
1055
+ ip_spec.each do |address, ip|
1056
+ logger.notify("Stubbing address #{address} to IP #{ip} on machine #{host}")
1057
+ on( host, puppet('resource', 'host', address, 'ensure=present', "ip=#{ip}") )
1058
+ end
913
1059
 
914
- teardown do
915
- ip_spec.each do |host, ip|
916
- logger.notify("Unstubbing host #{host} to IP #{ip} on machine #{machine}")
917
- on( machine,
918
- puppet('resource', 'host', host, 'ensure=absent') )
1060
+ teardown do
1061
+ ip_spec.each do |address, ip|
1062
+ logger.notify("Unstubbing address #{address} to IP #{ip} on machine #{host}")
1063
+ on( host, puppet('resource', 'host', address, 'ensure=absent') )
1064
+ end
919
1065
  end
920
1066
  end
921
1067
  end
@@ -943,8 +1089,10 @@ module Beaker
943
1089
  #use global options hash
944
1090
  forge_host ||= options[:forge_host]
945
1091
  @forge_ip ||= Resolv.getaddress(forge_host)
946
- stub_hosts_on(machine, 'forge.puppetlabs.com' => @forge_ip)
947
- stub_hosts_on(machine, 'forgeapi.puppetlabs.com' => @forge_ip)
1092
+ block_on machine do | host |
1093
+ stub_hosts_on(host, 'forge.puppetlabs.com' => @forge_ip)
1094
+ stub_hosts_on(host, 'forgeapi.puppetlabs.com' => @forge_ip)
1095
+ end
948
1096
  end
949
1097
 
950
1098
  # This wraps the method `stub_hosts` and makes the stub specific to
@@ -1024,32 +1172,36 @@ module Beaker
1024
1172
  end
1025
1173
 
1026
1174
  #stops the puppet agent running on the host
1175
+ # @param [Host, Array<Host>, String, Symbol] agent One or more hosts to act upon,
1176
+ # or a role (String or Symbol) that identifies one or more hosts.
1027
1177
  def stop_agent_on(agent)
1028
- vardir = agent.puppet['vardir']
1029
- agent_running = true
1030
- while agent_running
1031
- result = on agent, "[ -e '#{vardir}/state/agent_catalog_run.lock' ]", :acceptable_exit_codes => [0,1]
1032
- agent_running = (result.exit_code == 0)
1033
- sleep 2 unless agent_running
1034
- end
1178
+ block_on agent do | host |
1179
+ vardir = agent.puppet['vardir']
1180
+ agent_running = true
1181
+ while agent_running
1182
+ result = on host, "[ -e '#{vardir}/state/agent_catalog_run.lock' ]", :acceptable_exit_codes => [0,1]
1183
+ agent_running = (result.exit_code == 0)
1184
+ sleep 2 unless agent_running
1185
+ end
1035
1186
 
1036
- # The agent service is `pe-puppet` everywhere EXCEPT certain linux distros on PE 2.8
1037
- # In all the case that it is different, this init script will exist. So we can assume
1038
- # that if the script doesn't exist, we should just use `pe-puppet`
1039
- result = on agent, "[ -e /etc/init.d/pe-puppet-agent ]", :acceptable_exit_codes => [0,1]
1040
- agent_service = (result.exit_code == 0) ? 'pe-puppet-agent' : 'pe-puppet'
1041
-
1042
- # Under a number of stupid circumstances, we can't stop the
1043
- # agent using puppet. This is usually because of issues with
1044
- # the init script or system on that particular configuration.
1045
- avoid_puppet_at_all_costs = false
1046
- avoid_puppet_at_all_costs ||= agent['platform'] =~ /el-4/
1047
- avoid_puppet_at_all_costs ||= agent['pe_ver'] && version_is_less(agent['pe_ver'], '3.2') && agent['platform'] =~ /sles/
1048
-
1049
- if avoid_puppet_at_all_costs
1050
- on agent, "/etc/init.d/#{agent_service} stop"
1051
- else
1052
- on agent, puppet_resource('service', agent_service, 'ensure=stopped')
1187
+ # The agent service is `pe-puppet` everywhere EXCEPT certain linux distros on PE 2.8
1188
+ # In all the case that it is different, this init script will exist. So we can assume
1189
+ # that if the script doesn't exist, we should just use `pe-puppet`
1190
+ result = on agent, "[ -e /etc/init.d/pe-puppet-agent ]", :acceptable_exit_codes => [0,1]
1191
+ agent_service = (result.exit_code == 0) ? 'pe-puppet-agent' : 'pe-puppet'
1192
+
1193
+ # Under a number of stupid circumstances, we can't stop the
1194
+ # agent using puppet. This is usually because of issues with
1195
+ # the init script or system on that particular configuration.
1196
+ avoid_puppet_at_all_costs = false
1197
+ avoid_puppet_at_all_costs ||= agent['platform'] =~ /el-4/
1198
+ avoid_puppet_at_all_costs ||= agent['pe_ver'] && version_is_less(agent['pe_ver'], '3.2') && agent['platform'] =~ /sles/
1199
+
1200
+ if avoid_puppet_at_all_costs
1201
+ on agent, "/etc/init.d/#{agent_service} stop"
1202
+ else
1203
+ on agent, puppet_resource('service', agent_service, 'ensure=stopped')
1204
+ end
1053
1205
  end
1054
1206
  end
1055
1207
 
@@ -1068,31 +1220,34 @@ module Beaker
1068
1220
 
1069
1221
  # Ensure the host has requested a cert, then sign it
1070
1222
  #
1071
- # @param [Host] host The host to sign for
1223
+ # @param [Host, Array<Host>, String, Symbol] host One or more hosts to act upon,
1224
+ # or a role (String or Symbol) that identifies one or more hosts.
1072
1225
  #
1073
1226
  # @return nil
1074
1227
  # @raise [FailTest] if process times out
1075
1228
  def sign_certificate_for(host)
1076
- if [master, dashboard, database].include? host
1229
+ block_on host do | host |
1230
+ if [master, dashboard, database].include? host
1077
1231
 
1078
- on host, puppet( 'agent -t' ), :acceptable_exit_codes => [0,1,2]
1079
- on master, puppet( "cert --allow-dns-alt-names sign #{host}" ), :acceptable_exit_codes => [0,24]
1232
+ on host, puppet( 'agent -t' ), :acceptable_exit_codes => [0,1,2]
1233
+ on master, puppet( "cert --allow-dns-alt-names sign #{host}" ), :acceptable_exit_codes => [0,24]
1080
1234
 
1081
- else
1235
+ else
1082
1236
 
1083
- hostname = Regexp.escape host.node_name
1237
+ hostname = Regexp.escape host.node_name
1084
1238
 
1085
- last_sleep = 0
1086
- next_sleep = 1
1087
- (0..10).each do |i|
1088
- fail_test("Failed to sign cert for #{hostname}") if i == 10
1239
+ last_sleep = 0
1240
+ next_sleep = 1
1241
+ (0..10).each do |i|
1242
+ fail_test("Failed to sign cert for #{hostname}") if i == 10
1089
1243
 
1090
- on master, puppet("cert --sign --all"), :acceptable_exit_codes => [0,24]
1091
- break if on(master, puppet("cert --list --all")).stdout =~ /\+ "?#{hostname}"?/
1092
- sleep next_sleep
1093
- (last_sleep, next_sleep) = next_sleep, last_sleep+next_sleep
1094
- end
1244
+ on master, puppet("cert --sign --all"), :acceptable_exit_codes => [0,24]
1245
+ break if on(master, puppet("cert --list --all")).stdout =~ /\+ "?#{hostname}"?/
1246
+ sleep next_sleep
1247
+ (last_sleep, next_sleep) = next_sleep, last_sleep+next_sleep
1248
+ end
1095
1249
 
1250
+ end
1096
1251
  end
1097
1252
  end
1098
1253
 
@@ -1104,7 +1259,8 @@ module Beaker
1104
1259
 
1105
1260
  # Get a facter fact from a provided host
1106
1261
  #
1107
- # @param [Host] host The host to query the fact for
1262
+ # @param [Host, Array<Host>, String, Symbol] host One or more hosts to act upon,
1263
+ # or a role (String or Symbol) that identifies one or more hosts.
1108
1264
  # @param [String] name The name of the fact to query for
1109
1265
  # @!macro common_opts
1110
1266
  #
@@ -1112,7 +1268,11 @@ module Beaker
1112
1268
  # @raise [FailTest] Raises an exception if call to facter fails
1113
1269
  def fact_on(host, name, opts = {})
1114
1270
  result = on host, facter(name, opts)
1115
- result.stdout.chomp if result.stdout
1271
+ if result.kind_of?(Array)
1272
+ result.map { |res| res.stdout.chomp }
1273
+ else
1274
+ result.stdout.chomp
1275
+ end
1116
1276
  end
1117
1277
 
1118
1278
  # Get a facter fact from the default host
@@ -1200,7 +1360,7 @@ module Beaker
1200
1360
  module_name = nil
1201
1361
  if File.exists?("#{root_module_dir}/metadata.json")
1202
1362
  logger.debug "Attempting to parse Modulename from metadata.json"
1203
- module_json = JSON.parse (File.read "#{root_module_dir}/metadata.json")
1363
+ module_json = JSON.parse(File.read "#{root_module_dir}/metadata.json")
1204
1364
  if(module_json.has_key?('name'))
1205
1365
  module_name = get_module_name(module_json['name'])
1206
1366
  end