beaker 2.18.3 → 2.19.0

Sign up to get free protection for your applications and to get access to all the features.
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