beaker 2.18.3 → 2.19.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 (63) hide show
  1. checksums.yaml +8 -8
  2. data/HISTORY.md +439 -2
  3. data/acceptance/lib/beaker/acceptance/install_utils.rb +58 -0
  4. data/acceptance/pre_suite/puppet_git/install.rb +6 -65
  5. data/acceptance/tests/foss_utils/clone_git_repo_on.rb +49 -0
  6. data/beaker.gemspec +2 -0
  7. data/lib/beaker/dsl/helpers/web_helpers.rb +2 -1
  8. data/lib/beaker/dsl/install_utils/aio_defaults.rb +0 -2
  9. data/lib/beaker/dsl/install_utils/foss_utils.rb +97 -60
  10. data/lib/beaker/dsl/install_utils/pe_utils.rb +30 -53
  11. data/lib/beaker/dsl/install_utils/puppet_utils.rb +43 -0
  12. data/lib/beaker/dsl/install_utils/windows_utils.rb +144 -0
  13. data/lib/beaker/dsl/roles.rb +20 -3
  14. data/lib/beaker/dsl/structure.rb +14 -3
  15. data/lib/beaker/host.rb +24 -3
  16. data/lib/beaker/host/unix/pkg.rb +9 -0
  17. data/lib/beaker/host/windows/exec.rb +3 -0
  18. data/lib/beaker/host_prebuilt_steps.rb +5 -9
  19. data/lib/beaker/hypervisor/aws_sdk.rb +22 -18
  20. data/lib/beaker/hypervisor/docker.rb +7 -0
  21. data/lib/beaker/hypervisor/vmpooler.rb +4 -0
  22. data/lib/beaker/logger.rb +12 -1
  23. data/lib/beaker/options/command_line_parser.rb +9 -0
  24. data/lib/beaker/options/options_hash.rb +3 -296
  25. data/lib/beaker/options/parser.rb +12 -0
  26. data/lib/beaker/options/presets.rb +0 -1
  27. data/lib/beaker/ssh_connection.rb +48 -23
  28. data/lib/beaker/test_case.rb +1 -1
  29. data/lib/beaker/version.rb +1 -1
  30. data/spec/beaker/dsl/helpers/web_helpers_spec.rb +10 -1
  31. data/spec/beaker/dsl/install_utils/foss_utils_spec.rb +194 -49
  32. data/spec/beaker/dsl/install_utils/pe_utils_spec.rb +112 -22
  33. data/spec/beaker/dsl/install_utils/puppet_utils_spec.rb +57 -0
  34. data/spec/beaker/dsl/install_utils/windows_utils_spec.rb +132 -0
  35. data/spec/beaker/dsl/roles_spec.rb +36 -5
  36. data/spec/beaker/dsl/structure_spec.rb +9 -2
  37. data/spec/beaker/host/unix/pkg_spec.rb +26 -6
  38. data/spec/beaker/host_prebuilt_steps_spec.rb +3 -2
  39. data/spec/beaker/host_spec.rb +18 -0
  40. data/spec/beaker/hypervisor/aixer_spec.rb +1 -1
  41. data/spec/beaker/hypervisor/aws_sdk_spec.rb +595 -58
  42. data/spec/beaker/hypervisor/docker_spec.rb +2 -1
  43. data/spec/beaker/hypervisor/solaris_spec.rb +1 -0
  44. data/spec/beaker/hypervisor/vagrant_spec.rb +2 -1
  45. data/spec/beaker/logger_spec.rb +39 -0
  46. data/spec/beaker/options/command_line_parser_spec.rb +2 -2
  47. data/spec/beaker/options/options_hash_spec.rb +1 -102
  48. data/spec/beaker/options/parser_spec.rb +19 -0
  49. data/spec/beaker/options/pe_version_scaper_spec.rb +11 -1
  50. data/spec/beaker/options/presets_spec.rb +8 -0
  51. data/spec/beaker/ssh_connection_spec.rb +39 -21
  52. data/spec/helpers.rb +9 -3
  53. data/spec/mocks.rb +2 -0
  54. metadata +34 -11
  55. data/lib/beaker/answers.rb +0 -143
  56. data/lib/beaker/answers/version20.rb +0 -120
  57. data/lib/beaker/answers/version28.rb +0 -121
  58. data/lib/beaker/answers/version30.rb +0 -227
  59. data/lib/beaker/answers/version32.rb +0 -44
  60. data/lib/beaker/answers/version34.rb +0 -51
  61. data/lib/beaker/answers/version38.rb +0 -29
  62. data/lib/beaker/answers/version40.rb +0 -44
  63. data/spec/beaker/answers_spec.rb +0 -547
@@ -1,6 +1,7 @@
1
- [ 'aio_defaults', 'pe_defaults', 'puppet_utils' ].each do |lib|
1
+ [ 'aio_defaults', 'pe_defaults', 'puppet_utils', 'windows_utils' ].each do |lib|
2
2
  require "beaker/dsl/install_utils/#{lib}"
3
3
  end
4
+ require "beaker-answers"
4
5
  module Beaker
5
6
  module DSL
6
7
  module InstallUtils
@@ -18,26 +19,7 @@ module Beaker
18
19
  include AIODefaults
19
20
  include PEDefaults
20
21
  include PuppetUtils
21
-
22
- # Set defaults and PATH for these hosts to be either pe or aio, have host['type'] == aio for aio settings, defaults
23
- # to pe.
24
- #
25
- # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
26
- # or a role (String or Symbol) that identifies one or more hosts.
27
- def configure_pe_defaults_on( hosts )
28
- block_on hosts do |host|
29
- if host[:pe_ver] && aio_version?(host) or (host['type'] && host['type'] =~ /aio/)
30
- add_aio_defaults_on(host)
31
- # provide a sane default here for puppetservice
32
- host['puppetservice'] ||= 'pe-puppetserver'
33
- else
34
- add_pe_defaults_on(host)
35
- end
36
- # add pathing env
37
- add_puppet_paths_on(host)
38
- end
39
- end
40
-
22
+ include WindowsUtils
41
23
 
42
24
  # @!macro [new] common_opts
43
25
  # @param [Hash{Symbol=>String}] opts Options to alter execution.
@@ -60,6 +42,7 @@ module Beaker
60
42
  # running the command.
61
43
 
62
44
  #Sort array of hosts so that it has the correct order for PE installation based upon each host's role
45
+ #@param subset [Array<Host>] An array of hosts to sort, defaults to global 'hosts' object
63
46
  # @example
64
47
  # h = sorted_hosts
65
48
  #
@@ -70,12 +53,13 @@ module Beaker
70
53
  # Fourth: everything else
71
54
  #
72
55
  # @!visibility private
73
- def sorted_hosts
56
+ def sorted_hosts subset = hosts
74
57
  special_nodes = []
75
58
  [master, database, dashboard].uniq.each do |host|
76
- special_nodes << host if host != nil
59
+ special_nodes << host if host != nil && subset.include?(host)
77
60
  end
78
61
  real_agents = agents - special_nodes
62
+ real_agents = real_agents.delete_if{ |host| !subset.include?(host) }
79
63
  special_nodes + real_agents
80
64
  end
81
65
 
@@ -83,8 +67,6 @@ module Beaker
83
67
  # @param [Host] host The host that PE is to be installed on
84
68
  # For UNIX machines using the full PE installer, the host object must have the 'pe_installer' field set correctly.
85
69
  # @param [Hash{Symbol=>String}] opts The options
86
- # @option opts [String] :pe_ver_win Default PE version to install or upgrade to on Windows hosts
87
- # (Othersie uses individual Windows hosts pe_ver)
88
70
  # @option opts [String] :pe_ver Default PE version to install or upgrade to
89
71
  # (Otherwise uses individual hosts pe_ver)
90
72
  # @option opts [Boolean] :pe_debug (false) Should we run the installer in debug mode?
@@ -93,16 +75,9 @@ module Beaker
93
75
  # @api private
94
76
  def installer_cmd(host, opts)
95
77
  version = host['pe_ver'] || opts[:pe_ver]
96
- if host['platform'] =~ /windows/
97
- log_file = "#{File.basename(host['working_dir'])}.log"
98
- # cat may not be available with strictly Windows environments
99
- # Prefer `type` as an alternative to `cat` if non-cygwin
100
- win_cat = host.is_cygwin? ? "cat" : "type"
101
- pe_debug = host[:pe_debug] || opts[:pe_debug] ? " && #{win_cat} #{log_file}" : ''
102
- "cd #{host['working_dir']} && cmd /C 'start /w msiexec.exe /qn /L*V #{log_file} /i #{host['dist']}.msi PUPPET_MASTER_SERVER=#{master} PUPPET_AGENT_CERTNAME=#{host}'#{pe_debug}"
103
78
  # Frictionless install didn't exist pre-3.2.0, so in that case we fall
104
79
  # through and do a regular install.
105
- elsif host['roles'].include? 'frictionless' and ! version_is_less(version, '3.2.0')
80
+ if host['roles'].include? 'frictionless' and ! version_is_less(version, '3.2.0')
106
81
  # PE 3.4 introduced the ability to pass in config options to the bash script in the form
107
82
  # of <section>:<key>=<value>
108
83
  frictionless_install_opts = []
@@ -419,14 +394,18 @@ module Beaker
419
394
  :puppet_agent_sha => host[:puppet_agent_sha] || opts[:puppet_agent_sha],
420
395
  :pe_ver => host[:pe_ver] || opts[:pe_ver],
421
396
  :puppet_collection => host[:puppet_collection] || opts[:puppet_collection] })
422
- setup_defaults_and_config_helper_on(host, master, [0, 1])
397
+ # 1 since no certificate found and waitforcert disabled
398
+ acceptable_exit_codes = [0, 1]
399
+ acceptable_exit_codes << 2 if opts[:type] == :upgrade
400
+ setup_defaults_and_config_helper_on(host, master, acceptable_exit_codes)
423
401
  elsif host['platform'] =~ /windows/
424
- on host, installer_cmd(host, opts)
425
- configure_pe_defaults_on(host)
426
- if not host.is_cygwin?
427
- # HACK: for some reason, post install we need to refresh the connection to make puppet available for execution
428
- host.close
429
- end
402
+ opts = { :debug => host[:pe_debug] || opts[:pe_debug] }
403
+ msi_path = "#{host['working_dir']}\\#{host['dist']}.msi"
404
+ install_msi_on(host, msi_path, {}, opts)
405
+
406
+ # 1 since no certificate found and waitforcert disabled
407
+ acceptable_exit_codes = 1
408
+ setup_defaults_and_config_helper_on(host, master, acceptable_exit_codes)
430
409
  else
431
410
  # We only need answers if we're using the classic installer
432
411
  version = host['pe_ver'] || opts[:pe_ver]
@@ -437,17 +416,17 @@ module Beaker
437
416
  deploy_frictionless_to_master(host)
438
417
  end
439
418
  on host, installer_cmd(host, opts)
440
- configure_pe_defaults_on(host)
419
+ configure_type_defaults_on(host)
441
420
  elsif host['platform'] =~ /osx|eos/
442
421
  # If we're not frictionless, we need to run the OSX special-case
443
422
  on host, installer_cmd(host, opts)
444
423
  acceptable_codes = host['platform'] =~ /osx/ ? [1] : [0, 1]
445
424
  setup_defaults_and_config_helper_on(host, master, acceptable_codes)
446
425
  else
447
- answers = Beaker::Answers.create(opts[:pe_ver] || host['pe_ver'], hosts, opts)
426
+ answers = BeakerAnswers::Answers.create(opts[:pe_ver] || host['pe_ver'], hosts, opts)
448
427
  create_remote_file host, "#{host['working_dir']}/answers", answers.answer_string(host)
449
428
  on host, installer_cmd(host, opts)
450
- configure_pe_defaults_on(host)
429
+ configure_type_defaults_on(host)
451
430
  end
452
431
  end
453
432
 
@@ -535,7 +514,7 @@ module Beaker
535
514
  # @return nil
536
515
  # @api private
537
516
  def setup_defaults_and_config_helper_on(host, master, acceptable_exit_codes=nil)
538
- configure_pe_defaults_on(host)
517
+ configure_type_defaults_on(host)
539
518
  #set the certname and master
540
519
  on host, puppet("config set server #{master}")
541
520
  on host, puppet("config set certname #{host}")
@@ -551,8 +530,7 @@ module Beaker
551
530
 
552
531
  #Install PE based upon host configuration and options
553
532
  #
554
- # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
555
- # or a role (String or Symbol) that identifies one or more hosts.
533
+ # @param [Host, Array<Host>] install_hosts One or more hosts to act upon
556
534
  # @!macro common_opts
557
535
  # @option opts [Boolean] :masterless Are we performing a masterless installation?
558
536
  # @option opts [String] :puppet_agent_version Version of puppet-agent to install. Required for PE agent
@@ -569,10 +547,10 @@ module Beaker
569
547
  # Install file names are assumed to be of the format puppet-enterprise-VERSION-PLATFORM.(tar)|(tar.gz)
570
548
  # for Unix like systems and puppet-enterprise-VERSION.msi for Windows systems.
571
549
  #
572
- def install_pe_on(hosts, opts)
573
- #process the version files if necessary
574
- confine_block(:to, {}, hosts) do
550
+ def install_pe_on(install_hosts, opts)
551
+ confine_block(:to, {}, install_hosts) do
575
552
  sorted_hosts.each do |host|
553
+ #process the version files if necessary
576
554
  host['pe_dir'] ||= opts[:pe_dir]
577
555
  if host['platform'] =~ /windows/
578
556
  # we don't need the pe_version if:
@@ -598,8 +576,7 @@ module Beaker
598
576
  end
599
577
 
600
578
  #Upgrade PE based upon host configuration and options
601
- # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
602
- # or a role (String or Symbol) that identifies one or more hosts.
579
+ # @param [Host, Array<Host>] upgrade_hosts One or more hosts to act upon
603
580
  # @!macro common_opts
604
581
  # @param [String] path A path (either local directory or a URL to a listing of PE builds).
605
582
  # Will contain a LATEST file indicating the latest build to install.
@@ -610,8 +587,8 @@ module Beaker
610
587
  #
611
588
  # @note Install file names are assumed to be of the format puppet-enterprise-VERSION-PLATFORM.(tar)|(tar.gz)
612
589
  # for Unix like systems and puppet-enterprise-VERSION.msi for Windows systems.
613
- def upgrade_pe_on hosts, opts, path=nil
614
- confine_block(:to, {}, hosts) do
590
+ def upgrade_pe_on upgrade_hosts, opts, path=nil
591
+ confine_block(:to, {}, upgrade_hosts) do
615
592
  set_console_password = false
616
593
  # if we are upgrading from something lower than 3.4 then we need to set the pe console password
617
594
  if (dashboard[:pe_ver] ? version_is_less(dashboard[:pe_ver], "3.4.0") : true)
@@ -65,6 +65,46 @@ module Beaker
65
65
  end
66
66
  end
67
67
 
68
+ # Configure the provided hosts to be of their host[:type], it host[type] == nil do nothing
69
+ def configure_type_defaults_on( hosts )
70
+ block_on hosts do |host|
71
+ has_defaults = false
72
+ if host[:type]
73
+ host_type = host[:type]
74
+ # clean up the naming conventions here (some teams use foss-package, git-whatever, we need
75
+ # to correctly handle that
76
+ # don't worry about aio, that happens in the aio_version? check
77
+ host_type = case host_type
78
+ when /(\A|-)(git)|(foss)(\Z|-)/
79
+ 'foss'
80
+ when /(\A|-)pe(\Z|-)/
81
+ 'pe'
82
+ else
83
+ nil
84
+ end
85
+ if host_type
86
+ add_method = "add_#{host_type}_defaults_on"
87
+ if self.respond_to?(add_method, host)
88
+ self.send(add_method, host)
89
+ else
90
+ raise "cannot add defaults of type #{host_type} for host #{host.name} (#{add_method} not present)"
91
+ end
92
+ has_defaults = true
93
+ end
94
+ end
95
+ if aio_version?(host)
96
+ add_aio_defaults_on(host)
97
+ has_defaults = true
98
+ end
99
+ # add pathing env
100
+ if has_defaults
101
+ add_puppet_paths_on(host)
102
+ end
103
+ end
104
+ end
105
+ alias_method :configure_foss_defaults_on, :configure_type_defaults_on
106
+ alias_method :configure_pe_defaults_on, :configure_type_defaults_on
107
+
68
108
  #If the host is associated with a type remove all defaults and environment associated with that type.
69
109
  # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
70
110
  # or a role (String or Symbol) that identifies one or more hosts.
@@ -78,6 +118,9 @@ module Beaker
78
118
  else
79
119
  raise "cannot remove defaults of type #{host['type']} associated with host #{host.name} (#{remove_method} not present)"
80
120
  end
121
+ if aio_version?(host)
122
+ remove_aio_defaults_on(host)
123
+ end
81
124
  end
82
125
  end
83
126
  end
@@ -0,0 +1,144 @@
1
+ module Beaker
2
+ module DSL
3
+ module InstallUtils
4
+ #
5
+ # This module contains methods useful for Windows installs
6
+ #
7
+ module WindowsUtils
8
+
9
+ # Given a host, returns it's system TEMP path
10
+ # @param [Host] host An object implementing {Beaker::Hosts}'s interface.
11
+ def get_temp_path(host)
12
+ # under CYGWIN %TEMP% may not be set
13
+ tmp_path = on(host, Command.new('ECHO %SYSTEMROOT%', [], { :cmdexe => true }))
14
+ tmp_path.output.gsub(/\n/, '') + '\\TEMP'
15
+ end
16
+
17
+ # Generates commands to be inserted into a Windows batch file to launch an MSI install
18
+ # @param [String] msi_path The path of the MSI - can be a local Windows style file path like
19
+ # c:\temp\puppet.msi OR a url like https://download.com/puppet.msi or file://c:\temp\puppet.msi
20
+ # @param [Hash{String=>String}] msi_opts MSI installer options
21
+ # See https://docs.puppetlabs.com/guides/install_puppet/install_windows.html#msi-properties
22
+ # @param [String] log_path The path to write the MSI log - must be a local Windows style file path
23
+ #
24
+ # @api private
25
+ def msi_install_script(msi_path, msi_opts, log_path)
26
+ # msiexec requires backslashes in file paths launched under cmd.exe start /w
27
+ url_pattern = /^(https?|file):\/\//
28
+ msi_path = msi_path.gsub(/\//, "\\") if msi_path !~ url_pattern
29
+
30
+ msi_params = msi_opts.map{|k, v| "#{k}=#{v}"}.join(' ')
31
+
32
+ # msiexec requires quotes around paths with backslashes - c:\ or file://c:\
33
+ # not strictly needed for http:// but it simplifies this code
34
+ batch_contents = <<-BATCH
35
+ start /w msiexec.exe /i \"#{msi_path}\" /qn /L*V #{log_path} #{msi_params}
36
+ exit /B %errorlevel%
37
+ BATCH
38
+ end
39
+
40
+ # Given a host, path to MSI and MSI options, will create a batch file
41
+ # on the host, returning the path to the randomized batch file and
42
+ # the randomized log file
43
+ # @param [Host] host An object implementing {Beaker::Hosts}'s interface.
44
+ # @param [String] msi_path The path of the MSI - can be a local Windows style file path like
45
+ # c:\temp\puppet.msi OR a url like https://download.com/puppet.msi or file://c:\temp\puppet.msi
46
+ # @param [Hash{String=>String}] msi_opts MSI installer options
47
+ # See https://docs.puppetlabs.com/guides/install_puppet/install_windows.html#msi-properties
48
+ # @api private
49
+ def create_install_msi_batch_on(host, msi_path, msi_opts)
50
+ timestamp = Time.new.strftime('%Y-%m-%d_%H.%M.%S')
51
+ tmp_path = get_temp_path(host)
52
+
53
+ batch_name = "install-puppet-msi-#{timestamp}.bat"
54
+ batch_path = "#{tmp_path}\\#{batch_name}"
55
+
56
+ log_path = "#{tmp_path}\\install-puppet-#{timestamp}.log"
57
+
58
+ Tempfile.open(batch_name) do |tmp_file|
59
+ batch_contents = msi_install_script(msi_path, msi_opts, log_path)
60
+
61
+ File.open(tmp_file.path, 'w') { |file| file.puts(batch_contents) }
62
+ host.do_scp_to(tmp_file.path, batch_path, {})
63
+ end
64
+
65
+ return batch_path, log_path
66
+ end
67
+
68
+ # Given hosts construct a PATH that includes puppetbindir, facterbindir and hierabindir
69
+ # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
70
+ # or a role (String or Symbol) that identifies one or more hosts.
71
+ # @param [String] msi_path The path of the MSI - can be a local Windows style file path like
72
+ # c:\temp\puppet.msi OR a url like https://download.com/puppet.msi or file://c:\temp\puppet.msi
73
+ # @param [Hash{String=>String}] msi_opts MSI installer options
74
+ # See https://docs.puppetlabs.com/guides/install_puppet/install_windows.html#msi-properties
75
+ # @option msi_opts [String] INSTALLIDIR Where Puppet and its dependencies should be installed.
76
+ # (Defaults vary based on operating system and intaller architecture)
77
+ # Requires Puppet 2.7.12 / PE 2.5.0
78
+ # @option msi_opts [String] PUPPET_MASTER_SERVER The hostname where the puppet master server can be reached.
79
+ # (Defaults to puppet)
80
+ # Requires Puppet 2.7.12 / PE 2.5.0
81
+ # @option msi_opts [String] PUPPET_CA_SERVER The hostname where the CA puppet master server can be reached, if you are using multiple masters and only one of them is acting as the CA.
82
+ # (Defaults the value of PUPPET_MASTER_SERVER)
83
+ # Requires Puppet 2.7.12 / PE 2.5.0
84
+ # @option msi_opts [String] PUPPET_AGENT_CERTNAME The node’s certificate name, and the name it uses when requesting catalogs. This will set a value for
85
+ # (Defaults to the node's fqdn as discovered by facter fqdn)
86
+ # Requires Puppet 2.7.12 / PE 2.5.0
87
+ # @option msi_opts [String] PUPPET_AGENT_ENVIRONMENT The node’s environment.
88
+ # (Defaults to production)
89
+ # Requires Puppet 3.3.1 / PE 3.1.0
90
+ # @option msi_opts [String] PUPPET_AGENT_STARTUP_MODE Whether the puppet agent service should run (or be allowed to run)
91
+ # (Defaults to Manual - valid values are Automatic, Manual or Disabled)
92
+ # Requires Puppet 3.4.0 / PE 3.2.0
93
+ # @option msi_opts [String] PUPPET_AGENT_ACCOUNT_USER Whether the puppet agent service should run (or be allowed to run)
94
+ # (Defaults to LocalSystem)
95
+ # Requires Puppet 3.4.0 / PE 3.2.0
96
+ # @option msi_opts [String] PUPPET_AGENT_ACCOUNT_PASSWORD The password to use for puppet agent’s user account
97
+ # (No default)
98
+ # Requires Puppet 3.4.0 / PE 3.2.0
99
+ # @option msi_opts [String] PUPPET_AGENT_ACCOUNT_DOMAIN The domain of puppet agent’s user account.
100
+ # (Defaults to .)
101
+ # Requires Puppet 3.4.0 / PE 3.2.0
102
+ # @option opts [Boolean] :debug output the MSI installation log when set to true
103
+ # otherwise do not output log (false; default behavior)
104
+ #
105
+ # @example
106
+ # install_msi_on(hosts, 'c:\puppet.msi', {:debug => true})
107
+ #
108
+ # @api private
109
+ def install_msi_on(hosts, msi_path, msi_opts = {}, opts = {})
110
+ block_on hosts do | host |
111
+ msi_opts['PUPPET_AGENT_STARTUP_MODE'] ||= 'Manual'
112
+ batch_path, log_file = create_install_msi_batch_on(host, msi_path, msi_opts)
113
+
114
+ # begin / rescue here so that we can reuse existing error msg propagation
115
+ begin
116
+ # 1641 = ERROR_SUCCESS_REBOOT_INITIATED
117
+ # 3010 = ERROR_SUCCESS_REBOOT_REQUIRED
118
+ on host, Command.new("\"#{batch_path}\"", [], { :cmdexe => true }), :acceptable_exit_codes => [0, 1641, 3010]
119
+ rescue
120
+ on host, Command.new("type \"#{log_file}\"", [], { :cmdexe => true })
121
+ raise
122
+ end
123
+
124
+ if opts[:debug]
125
+ on host, Command.new("type \"#{log_file}\"", [], { :cmdexe => true })
126
+ end
127
+
128
+ if !host.is_cygwin?
129
+ # HACK: for some reason, post install we need to refresh the connection to make puppet available for execution
130
+ host.close
131
+ end
132
+
133
+ # verify service status post install
134
+ # if puppet service exists, then pe-puppet is not queried
135
+ # if puppet service does not exist, pe-puppet is queried and that exit code is used
136
+ # therefore, this command will always exit 0 if either service is installed
137
+ on host, Command.new("sc query puppet || sc query pe-puppet", [], { :cmdexe => true })
138
+ end
139
+ end
140
+
141
+ end
142
+ end
143
+ end
144
+ end
@@ -119,16 +119,25 @@ module Beaker
119
119
  host['roles'].length == 1 && host['roles'].include?('agent')
120
120
  end
121
121
 
122
- # Determine whether a host has an AIO version or not. If a host :pe_ver
122
+ # Determine whether a host has an AIO version or not. If a host :pe_ver or :version
123
123
  # is not specified, then it is open-ended, and as such, can be an AIO
124
124
  # version depending on the context.
125
125
  #
126
+ # True when any of the following cases are true
127
+ # * has PE version (:pe_ver) >= 4.0
128
+ # * has FOSS version (:version) >= 4.0
129
+ # * host has role 'aio'
130
+ # * host as the type 'aio'
131
+ #
126
132
  # @note aio version is just a base-line condition. If you want to check
127
133
  # that a host is an aio agent, refer to {#aio_agent?}.
128
134
  #
129
135
  # @return [Boolean] whether or not a host is AIO-capable
130
136
  def aio_version?(host)
131
- return !( host[:pe_ver] && version_is_less(host[:pe_ver], '4.0') )
137
+ return (( host[:pe_ver] && !version_is_less(host[:pe_ver], '4.0') ) ||
138
+ ( host[:version] && !version_is_less(host[:version], '4.0') ) ||
139
+ ( host[:roles] && host[:roles].include?('aio')) ||
140
+ ( host[:type] && !!(host[:type] =~ /(\A|-)aio(\Z|-)/ ))) == true
132
141
  end
133
142
 
134
143
  # Determine if the host is an AIO agent
@@ -140,6 +149,14 @@ module Beaker
140
149
  aio_version?(host) && agent_only(host)
141
150
  end
142
151
 
152
+ # Add the provided role to the host
153
+ #
154
+ # @param [Host] host Host to add role to
155
+ # @param [String] role The role to add to host
156
+ def add_role(host, role)
157
+ host[:roles] = host[:roles] | [role]
158
+ end
159
+
143
160
  #Create a new role method for a given arbitrary role name. Makes it possible to be able to run
144
161
  #commands without having to refer to role by String or Symbol. Will not add a new method
145
162
  #definition if the name is already in use.
@@ -156,7 +173,7 @@ module Beaker
156
173
  else
157
174
  if not respond_to? role
158
175
  if role !~ /\A[[:alpha:]]+[a-zA-Z0-9_]*[!?=]?\Z/
159
- raise "Role name format error for '#{role}'. Allowed characters are: \na-Z\n0-9 (as long as not at the beginning of name)\n'_'\n'?', '!' and '=' (only as individual last character at end of name)"
176
+ raise ArgumentError, "Role name format error for '#{role}'. Allowed characters are: \na-Z\n0-9 (as long as not at the beginning of name)\n'_'\n'?', '!' and '=' (only as individual last character at end of name)"
160
177
  end
161
178
  self.class.send :define_method, role.to_s do
162
179
  hosts_with_role = hosts_as role.to_sym
@@ -167,18 +167,29 @@ module Beaker
167
167
  # @example Confining to an already defined subset of hosts
168
168
  # confine :to, {}, agents
169
169
  #
170
+ # @example Confining from an already defined subset of hosts
171
+ # confine :except, {}, agents
172
+ #
173
+ #
170
174
  # @return [Array<Host>] Returns an array of hosts that are still valid
171
175
  # targets for this tests case.
172
176
  # @raise [SkipTest] Raises skip test if there are no valid hosts for
173
177
  # this test case after confinement.
174
178
  def confine(type, criteria, host_array = nil, &block)
175
- hosts_to_modify = host_array || hosts
179
+ hosts_to_modify = Array( host_array || hosts )
176
180
  case type
177
181
  when :except
178
- hosts_to_modify = hosts_to_modify - select_hosts(criteria, hosts_to_modify, &block)
182
+ if criteria and ( not criteria.empty? )
183
+ hosts_to_modify = hosts_to_modify - select_hosts(criteria, hosts_to_modify, &block)
184
+ else
185
+ # confining to all hosts *except* provided array of hosts
186
+ hosts_to_modify = hosts - host_array
187
+ end
179
188
  when :to
180
189
  if criteria and ( not criteria.empty? )
181
190
  hosts_to_modify = select_hosts(criteria, hosts_to_modify, &block)
191
+ else
192
+ # confining to only hosts in provided array of hosts
182
193
  end
183
194
  else
184
195
  raise "Unknown option #{type}"
@@ -198,7 +209,7 @@ module Beaker
198
209
  # @see #confine
199
210
  def confine_block(type, criteria, host_array = nil, &block)
200
211
  begin
201
- host_array ||= hosts
212
+ host_array = Array( host_array || hosts )
202
213
  original_hosts = self.hosts.dup
203
214
  confine(type, criteria, host_array)
204
215