beaker 1.16.0 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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