beaker 2.7.1 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +8 -8
  2. data/HISTORY.md +121 -2
  3. data/lib/beaker/dsl.rb +2 -2
  4. data/lib/beaker/dsl/helpers.rb +13 -1429
  5. data/lib/beaker/dsl/helpers/facter_helpers.rb +48 -0
  6. data/lib/beaker/dsl/helpers/hiera_helpers.rb +71 -0
  7. data/lib/beaker/dsl/helpers/host_helpers.rb +506 -0
  8. data/lib/beaker/dsl/helpers/puppet_helpers.rb +698 -0
  9. data/lib/beaker/dsl/helpers/tk_helpers.rb +101 -0
  10. data/lib/beaker/dsl/helpers/web_helpers.rb +115 -0
  11. data/lib/beaker/dsl/install_utils.rb +8 -1570
  12. data/lib/beaker/dsl/install_utils/ezbake_utils.rb +256 -0
  13. data/lib/beaker/dsl/install_utils/module_utils.rb +237 -0
  14. data/lib/beaker/dsl/install_utils/pe_utils.rb +518 -0
  15. data/lib/beaker/dsl/install_utils/puppet_utils.rb +722 -0
  16. data/lib/beaker/dsl/outcomes.rb +0 -4
  17. data/lib/beaker/dsl/roles.rb +0 -3
  18. data/lib/beaker/dsl/structure.rb +127 -4
  19. data/lib/beaker/dsl/wrappers.rb +0 -4
  20. data/lib/beaker/host.rb +23 -0
  21. data/lib/beaker/host/unix/pkg.rb +4 -4
  22. data/lib/beaker/host_prebuilt_steps.rb +11 -5
  23. data/lib/beaker/hypervisor/vagrant.rb +1 -0
  24. data/lib/beaker/hypervisor/vmpooler.rb +38 -0
  25. data/lib/beaker/logger.rb +10 -4
  26. data/lib/beaker/network_manager.rb +5 -4
  27. data/lib/beaker/options/command_line_parser.rb +7 -0
  28. data/lib/beaker/shared.rb +2 -1
  29. data/lib/beaker/shared/semvar.rb +41 -0
  30. data/lib/beaker/test_suite.rb +20 -6
  31. data/lib/beaker/version.rb +1 -1
  32. data/spec/beaker/dsl/helpers/facter_helpers_spec.rb +59 -0
  33. data/spec/beaker/dsl/helpers/hiera_helpers_spec.rb +96 -0
  34. data/spec/beaker/dsl/helpers/host_helpers_spec.rb +413 -0
  35. data/spec/beaker/dsl/{helpers_spec.rb → helpers/puppet_helpers_spec.rb} +2 -611
  36. data/spec/beaker/dsl/helpers/tk_helpers_spec.rb +83 -0
  37. data/spec/beaker/dsl/helpers/web_helpers_spec.rb +60 -0
  38. data/spec/beaker/dsl/install_utils/module_utils_spec.rb +241 -0
  39. data/spec/beaker/dsl/install_utils/pe_utils_spec.rb +475 -0
  40. data/spec/beaker/dsl/install_utils/puppet_utils_spec.rb +523 -0
  41. data/spec/beaker/dsl/structure_spec.rb +108 -0
  42. data/spec/beaker/host_prebuilt_steps_spec.rb +44 -0
  43. data/spec/beaker/host_spec.rb +41 -0
  44. data/spec/beaker/hypervisor/vagrant_spec.rb +2 -1
  45. data/spec/beaker/logger_spec.rb +9 -2
  46. data/spec/beaker/network_manager_spec.rb +7 -1
  47. data/spec/beaker/options/command_line_parser_spec.rb +3 -2
  48. data/spec/beaker/shared/semvar_spec.rb +36 -0
  49. data/spec/beaker/test_suite_spec.rb +48 -0
  50. data/spec/mocks.rb +10 -0
  51. metadata +23 -5
  52. data/lib/beaker/dsl/ezbake_utils.rb +0 -259
  53. data/spec/beaker/dsl/install_utils_spec.rb +0 -1242
@@ -0,0 +1,518 @@
1
+ module Beaker
2
+ module DSL
3
+ module InstallUtils
4
+ #
5
+ # This module contains methods to help installing/upgrading PE builds - including Higgs installs
6
+ #
7
+ # To mix this is into a class you need the following:
8
+ # * a method *hosts* that yields any hosts implementing
9
+ # {Beaker::Host}'s interface to act upon.
10
+ # * a method *options* that provides an options hash, see {Beaker::Options::OptionsHash}
11
+ # * the module {Beaker::DSL::Roles} that provides access to the various hosts implementing
12
+ # {Beaker::Host}'s interface to act upon
13
+ # * the module {Beaker::DSL::Wrappers} the provides convenience methods for {Beaker::DSL::Command} creation
14
+ module PEUtils
15
+
16
+ #Sort array of hosts so that it has the correct order for PE installation based upon each host's role
17
+ # @example
18
+ # h = sorted_hosts
19
+ #
20
+ # @note Order for installation should be
21
+ # First : master
22
+ # Second: database host (if not same as master)
23
+ # Third: dashboard (if not same as master or database)
24
+ # Fourth: everything else
25
+ #
26
+ # @!visibility private
27
+ def sorted_hosts
28
+ special_nodes = []
29
+ [master, database, dashboard].uniq.each do |host|
30
+ special_nodes << host if host != nil
31
+ end
32
+ real_agents = agents - special_nodes
33
+ special_nodes + real_agents
34
+ end
35
+
36
+ #Create the PE install command string based upon the host and options settings
37
+ # @param [Host] host The host that PE is to be installed on
38
+ # For UNIX machines using the full PE installer, the host object must have the 'pe_installer' field set correctly.
39
+ # @param [Hash{Symbol=>String}] opts The options
40
+ # @option opts [String] :pe_ver_win Default PE version to install or upgrade to on Windows hosts
41
+ # (Othersie uses individual Windows hosts pe_ver)
42
+ # @option opts [String] :pe_ver Default PE version to install or upgrade to
43
+ # (Otherwise uses individual hosts pe_ver)
44
+ # @option opts [Boolean] :pe_debug (false) Should we run the installer in debug mode?
45
+ # @example
46
+ # on host, "#{installer_cmd(host, opts)} -a #{host['working_dir']}/answers"
47
+ # @api private
48
+ def installer_cmd(host, opts)
49
+ version = host['pe_ver'] || opts[:pe_ver]
50
+ if host['platform'] =~ /windows/
51
+ log_file = "#{File.basename(host['working_dir'])}.log"
52
+ pe_debug = host[:pe_debug] || opts[:pe_debug] ? " && cat #{log_file}" : ''
53
+ if host.is_cygwin?
54
+ "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}"
55
+ else
56
+ "cd #{host['working_dir']} && msiexec.exe /qn /L*V #{log_file} /i #{host['dist']}.msi PUPPET_MASTER_SERVER=#{master} PUPPET_AGENT_CERTNAME=#{host}#{pe_debug}"
57
+ end
58
+ # Frictionless install didn't exist pre-3.2.0, so in that case we fall
59
+ # through and do a regular install.
60
+ elsif host['roles'].include? 'frictionless' and ! version_is_less(version, '3.2.0')
61
+ # PE 3.4 introduced the ability to pass in config options to the bash script in the form
62
+ # of <section>:<key>=<value>
63
+ frictionless_install_opts = []
64
+ if host.has_key?('frictionless_options') and ! version_is_less(version, '3.4.0')
65
+ # since we have options to pass in, we need to tell the bash script
66
+ host['frictionless_options'].each do |section, settings|
67
+ settings.each do |key, value|
68
+ frictionless_install_opts << "#{section}:#{key}=#{value}"
69
+ end
70
+ end
71
+ end
72
+
73
+ pe_debug = host[:pe_debug] || opts[:pe_debug] ? ' -x' : ''
74
+ "cd #{host['working_dir']} && curl --tlsv1 -kO https://#{master}:8140/packages/#{version}/install.bash && bash#{pe_debug} install.bash #{frictionless_install_opts.join(' ')}".strip
75
+ elsif host['platform'] =~ /osx/
76
+ version = host['pe_ver'] || opts[:pe_ver]
77
+ pe_debug = host[:pe_debug] || opts[:pe_debug] ? ' -verboseR' : ''
78
+ "cd #{host['working_dir']} && hdiutil attach #{host['dist']}.dmg && installer#{pe_debug} -pkg /Volumes/puppet-enterprise-#{version}/puppet-enterprise-installer-#{version}.pkg -target /"
79
+ elsif host['platform'] =~ /eos/
80
+ commands = ['enable', "extension puppet-enterprise-#{version}-#{host['platform']}.swix"]
81
+ command = commands.join("\n")
82
+ "Cli -c '#{command}'"
83
+ else
84
+ pe_debug = host[:pe_debug] || opts[:pe_debug] ? ' -D' : ''
85
+ "cd #{host['working_dir']}/#{host['dist']} && ./#{host['pe_installer']}#{pe_debug} -a #{host['working_dir']}/answers"
86
+ end
87
+ end
88
+
89
+ #Determine the PE package to download/upload on a mac host, download/upload that package onto the host.
90
+ # Assumed file name format: puppet-enterprise-3.3.0-rc1-559-g97f0833-osx-10.9-x86_64.dmg.
91
+ # @param [Host] host The mac host to download/upload and unpack PE onto
92
+ # @param [Hash{Symbol=>Symbol, String}] opts The options
93
+ # @option opts [String] :pe_dir Default directory or URL to pull PE package from
94
+ # (Otherwise uses individual hosts pe_dir)
95
+ # @api private
96
+ def fetch_pe_on_mac(host, opts)
97
+ path = host['pe_dir'] || opts[:pe_dir]
98
+ local = File.directory?(path)
99
+ filename = "#{host['dist']}"
100
+ extension = ".dmg"
101
+ if local
102
+ if not File.exists?("#{path}/#{filename}#{extension}")
103
+ raise "attempting installation on #{host}, #{path}/#{filename}#{extension} does not exist"
104
+ end
105
+ scp_to host, "#{path}/#{filename}#{extension}", "#{host['working_dir']}/#{filename}#{extension}"
106
+ else
107
+ if not link_exists?("#{path}/#{filename}#{extension}")
108
+ raise "attempting installation on #{host}, #{path}/#{filename}#{extension} does not exist"
109
+ end
110
+ on host, "cd #{host['working_dir']}; curl -O #{path}/#{filename}#{extension}"
111
+ end
112
+ end
113
+
114
+ #Determine the PE package to download/upload on a windows host, download/upload that package onto the host.
115
+ #Assumed file name format: puppet-enterprise-3.3.0-rc1-559-g97f0833.msi
116
+ # @param [Host] host The windows host to download/upload and unpack PE onto
117
+ # @param [Hash{Symbol=>Symbol, String}] opts The options
118
+ # @option opts [String] :pe_dir Default directory or URL to pull PE package from
119
+ # (Otherwise uses individual hosts pe_dir)
120
+ # @option opts [String] :pe_ver_win Default PE version to install or upgrade to
121
+ # (Otherwise uses individual hosts pe_ver)
122
+ # @api private
123
+ def fetch_pe_on_windows(host, opts)
124
+ path = host['pe_dir'] || opts[:pe_dir]
125
+ local = File.directory?(path)
126
+ version = host['pe_ver'] || opts[:pe_ver_win]
127
+ filename = "#{host['dist']}"
128
+ extension = ".msi"
129
+ if local
130
+ if not File.exists?("#{path}/#{filename}#{extension}")
131
+ raise "attempting installation on #{host}, #{path}/#{filename}#{extension} does not exist"
132
+ end
133
+ scp_to host, "#{path}/#{filename}#{extension}", "#{host['working_dir']}/#{filename}#{extension}"
134
+ else
135
+ if not link_exists?("#{path}/#{filename}#{extension}")
136
+ raise "attempting installation on #{host}, #{path}/#{filename}#{extension} does not exist"
137
+ end
138
+ if host.is_cygwin?
139
+ on host, "cd #{host['working_dir']}; curl -O #{path}/#{filename}#{extension}"
140
+ else
141
+ on host, powershell("$webclient = New-Object System.Net.WebClient; $webclient.DownloadFile('#{path}/#{filename}#{extension}','#{host['wor
142
+ king_dir']}\\#{filename}#{extension}')")
143
+ end
144
+ end
145
+ end
146
+
147
+ #Determine the PE package to download/upload on a unix style host, download/upload that package onto the host
148
+ #and unpack it.
149
+ # @param [Host] host The unix style host to download/upload and unpack PE onto
150
+ # @param [Hash{Symbol=>Symbol, String}] opts The options
151
+ # @option opts [String] :pe_dir Default directory or URL to pull PE package from
152
+ # (Otherwise uses individual hosts pe_dir)
153
+ # @api private
154
+ def fetch_pe_on_unix(host, opts)
155
+ path = host['pe_dir'] || opts[:pe_dir]
156
+ local = File.directory?(path)
157
+ filename = "#{host['dist']}"
158
+ if local
159
+ extension = File.exists?("#{path}/#{filename}.tar.gz") ? ".tar.gz" : ".tar"
160
+ if not File.exists?("#{path}/#{filename}#{extension}")
161
+ raise "attempting installation on #{host}, #{path}/#{filename}#{extension} does not exist"
162
+ end
163
+ scp_to host, "#{path}/#{filename}#{extension}", "#{host['working_dir']}/#{filename}#{extension}"
164
+ if extension =~ /gz/
165
+ on host, "cd #{host['working_dir']}; gunzip #{filename}#{extension}"
166
+ end
167
+ if extension =~ /tar/
168
+ on host, "cd #{host['working_dir']}; tar -xvf #{filename}.tar"
169
+ end
170
+ else
171
+ if host['platform'] =~ /eos/
172
+ extension = '.swix'
173
+ else
174
+ extension = link_exists?("#{path}/#{filename}.tar.gz") ? ".tar.gz" : ".tar"
175
+ end
176
+ if not link_exists?("#{path}/#{filename}#{extension}")
177
+ raise "attempting installation on #{host}, #{path}/#{filename}#{extension} does not exist"
178
+ end
179
+
180
+ if host['platform'] =~ /eos/
181
+ commands = ['enable', "copy #{path}/#{filename}#{extension} extension:"]
182
+ command = commands.join("\n")
183
+ on host, "Cli -c '#{command}'"
184
+ else
185
+ unpack = 'tar -xvf -'
186
+ unpack = extension =~ /gz/ ? 'gunzip | ' + unpack : unpack
187
+ on host, "cd #{host['working_dir']}; curl #{path}/#{filename}#{extension} | #{unpack}"
188
+ end
189
+ end
190
+ end
191
+
192
+ #Determine the PE package to download/upload per-host, download/upload that package onto the host
193
+ #and unpack it.
194
+ # @param [Array<Host>] hosts The hosts to download/upload and unpack PE onto
195
+ # @param [Hash{Symbol=>Symbol, String}] opts The options
196
+ # @option opts [String] :pe_dir Default directory or URL to pull PE package from
197
+ # (Otherwise uses individual hosts pe_dir)
198
+ # @option opts [String] :pe_ver Default PE version to install or upgrade to
199
+ # (Otherwise uses individual hosts pe_ver)
200
+ # @option opts [String] :pe_ver_win Default PE version to install or upgrade to on Windows hosts
201
+ # (Otherwise uses individual Windows hosts pe_ver)
202
+ # @api private
203
+ def fetch_pe(hosts, opts)
204
+ hosts.each do |host|
205
+ # We install Puppet from the master for frictionless installs, so we don't need to *fetch* anything
206
+ next if host['roles'].include?('frictionless') && (! version_is_less(opts[:pe_ver] || host['pe_ver'], '3.2.0'))
207
+
208
+ if host['platform'] =~ /windows/
209
+ fetch_pe_on_windows(host, opts)
210
+ elsif host['platform'] =~ /osx/
211
+ fetch_pe_on_mac(host, opts)
212
+ else
213
+ fetch_pe_on_unix(host, opts)
214
+ end
215
+ end
216
+ end
217
+
218
+ #Classify the master so that it can deploy frictionless packages for a given host.
219
+ # @param [Host] host The host to install pacakges for
220
+ # @api private
221
+ def deploy_frictionless_to_master(host)
222
+ klass = host['platform'].gsub(/-/, '_').gsub(/\./,'')
223
+ klass = "pe_repo::platform::#{klass}"
224
+ on dashboard, "cd /opt/puppet/share/puppet-dashboard && /opt/puppet/bin/bundle exec /opt/puppet/bin/rake nodeclass:add[#{klass},skip]"
225
+ on dashboard, "cd /opt/puppet/share/puppet-dashboard && /opt/puppet/bin/bundle exec /opt/puppet/bin/rake node:add[#{master},,,skip]"
226
+ on dashboard, "cd /opt/puppet/share/puppet-dashboard && /opt/puppet/bin/bundle exec /opt/puppet/bin/rake node:addclass[#{master},#{klass}]"
227
+ on master, puppet("agent -t"), :acceptable_exit_codes => [0,2]
228
+ end
229
+
230
+ #Perform a Puppet Enterprise upgrade or install
231
+ # @param [Array<Host>] hosts The hosts to install or upgrade PE on
232
+ # @param [Hash{Symbol=>Symbol, String}] opts The options
233
+ # @option opts [String] :pe_dir Default directory or URL to pull PE package from
234
+ # (Otherwise uses individual hosts pe_dir)
235
+ # @option opts [String] :pe_ver Default PE version to install or upgrade to
236
+ # (Otherwise uses individual hosts pe_ver)
237
+ # @option opts [String] :pe_ver_win Default PE version to install or upgrade to on Windows hosts
238
+ # (Otherwise uses individual Windows hosts pe_ver)
239
+ # @option opts [Symbol] :type (:install) One of :upgrade or :install
240
+ # @option opts [Boolean] :set_console_password Should we set the PE console password in the answers file? Used during upgrade only.
241
+ # @option opts [Hash<String>] :answers Pre-set answers based upon ENV vars and defaults
242
+ # (See {Beaker::Options::Presets.env_vars})
243
+ #
244
+ # @example
245
+ # do_install(hosts, {:type => :upgrade, :pe_dir => path, :pe_ver => version, :pe_ver_win => version_win})
246
+ #
247
+ # @api private
248
+ #
249
+ def do_install hosts, opts = {}
250
+ masterless = (defined? options) ? options[:masterless] : false
251
+ opts[:masterless] = masterless # has to pass masterless down for answer generation awareness
252
+ opts[:type] = opts[:type] || :install
253
+ unless masterless
254
+ pre30database = version_is_less(opts[:pe_ver] || database['pe_ver'], '3.0')
255
+ pre30master = version_is_less(opts[:pe_ver] || master['pe_ver'], '3.0')
256
+
257
+ unless version_is_less(opts[:pe_ver] || master['pe_ver'], '3.4')
258
+ master['puppetservice'] = 'pe-puppetserver'
259
+ end
260
+ end
261
+
262
+ # Set PE distribution for all the hosts, create working dir
263
+ use_all_tar = ENV['PE_USE_ALL_TAR'] == 'true'
264
+ hosts.each do |host|
265
+ host['pe_installer'] ||= 'puppet-enterprise-installer'
266
+ if host['platform'] !~ /windows|osx/
267
+ platform = use_all_tar ? 'all' : host['platform']
268
+ version = host['pe_ver'] || opts[:pe_ver]
269
+ host['dist'] = "puppet-enterprise-#{version}-#{platform}"
270
+ elsif host['platform'] =~ /osx/
271
+ version = host['pe_ver'] || opts[:pe_ver]
272
+ host['dist'] = "puppet-enterprise-#{version}-#{host['platform']}"
273
+ elsif host['platform'] =~ /windows/
274
+ version = host[:pe_ver] || opts['pe_ver_win']
275
+ should_install_64bit = !(version_is_less(version, '3.4')) && host.is_x86_64? && !host['install_32'] && !opts['install_32']
276
+ #only install 64bit builds if
277
+ # - we are on pe version 3.4+
278
+ # - we do not have install_32 set on host
279
+ # - we do not have install_32 set globally
280
+ if !(version_is_less(version, '4.0'))
281
+ if should_install_64bit
282
+ host['dist'] = "puppet-agent-#{version}-x64"
283
+ else
284
+ host['dist'] = "puppet-agent-#{version}-x86"
285
+ end
286
+ elsif should_install_64bit
287
+ host['dist'] = "puppet-enterprise-#{version}-x64"
288
+ else
289
+ host['dist'] = "puppet-enterprise-#{version}"
290
+ end
291
+ end
292
+ host['working_dir'] = host.tmpdir(Time.new.strftime("%Y-%m-%d_%H.%M.%S"))
293
+ end
294
+
295
+ fetch_pe(hosts, opts)
296
+
297
+ install_hosts = hosts.dup
298
+ unless masterless
299
+ # If we're installing a database version less than 3.0, ignore the database host
300
+ install_hosts.delete(database) if pre30database and database != master and database != dashboard
301
+ end
302
+
303
+ install_hosts.each do |host|
304
+ if host['platform'] =~ /windows/
305
+ on host, installer_cmd(host, opts)
306
+ if not host.is_cygwin?
307
+ # HACK: for some reason, post install we need to refresh the connection to make puppet available for execution
308
+ host.close
309
+ end
310
+ else
311
+ # We only need answers if we're using the classic installer
312
+ version = host['pe_ver'] || opts[:pe_ver]
313
+ if host['roles'].include?('frictionless') && (! version_is_less(version, '3.2.0'))
314
+ # If We're *not* running the classic installer, we want
315
+ # to make sure the master has packages for us.
316
+ deploy_frictionless_to_master(host)
317
+ on host, installer_cmd(host, opts)
318
+ elsif host['platform'] =~ /osx|eos/
319
+ # If we're not frictionless, we need to run the OSX special-case
320
+ on host, installer_cmd(host, opts)
321
+ #set the certname and master
322
+ on host, puppet("config set server #{master}")
323
+ on host, puppet("config set certname #{host}")
324
+ #run once to request cert
325
+ acceptable_codes = host['platform'] =~ /osx/ ? [1] : [0, 1]
326
+ on host, puppet_agent('-t'), :acceptable_exit_codes => acceptable_codes
327
+ else
328
+ answers = Beaker::Answers.create(opts[:pe_ver] || host['pe_ver'], hosts, opts)
329
+ create_remote_file host, "#{host['working_dir']}/answers", answers.answer_string(host)
330
+ on host, installer_cmd(host, opts)
331
+ end
332
+ end
333
+
334
+ # On each agent, we ensure the certificate is signed then shut down the agent
335
+ sign_certificate_for(host) unless masterless
336
+ stop_agent_on(host)
337
+ end
338
+
339
+ unless masterless
340
+ # Wait for PuppetDB to be totally up and running (post 3.0 version of pe only)
341
+ sleep_until_puppetdb_started(database) unless pre30database
342
+
343
+ # Run the agent once to ensure everything is in the dashboard
344
+ install_hosts.each do |host|
345
+ on host, puppet_agent('-t'), :acceptable_exit_codes => [0,2]
346
+
347
+ # Workaround for PE-1105 when deploying 3.0.0
348
+ # The installer did not respect our database host answers in 3.0.0,
349
+ # and would cause puppetdb to be bounced by the agent run. By sleeping
350
+ # again here, we ensure that if that bounce happens during an upgrade
351
+ # test we won't fail early in the install process.
352
+ if host['pe_ver'] == '3.0.0' and host == database
353
+ sleep_until_puppetdb_started(database)
354
+ end
355
+ end
356
+
357
+ install_hosts.each do |host|
358
+ wait_for_host_in_dashboard(host)
359
+ end
360
+
361
+ if pre30master
362
+ task = 'nodegroup:add_all_nodes group=default'
363
+ else
364
+ task = 'defaultgroup:ensure_default_group'
365
+ end
366
+ on dashboard, "/opt/puppet/bin/rake -sf /opt/puppet/share/puppet-dashboard/Rakefile #{task} RAILS_ENV=production"
367
+
368
+ # Now that all hosts are in the dashbaord, run puppet one more
369
+ # time to configure mcollective
370
+ on install_hosts, puppet_agent('-t'), :acceptable_exit_codes => [0,2]
371
+ end
372
+ end
373
+
374
+ #Install PE based upon host configuration and options
375
+ # @example
376
+ # install_pe
377
+ #
378
+ # @note Either pe_ver and pe_dir should be set in the ENV or each host should have pe_ver and pe_dir set individually.
379
+ # Install file names are assumed to be of the format puppet-enterprise-VERSION-PLATFORM.(tar)|(tar.gz)
380
+ # for Unix like systems and puppet-enterprise-VERSION.msi for Windows systems.
381
+ #
382
+ def install_pe
383
+ #process the version files if necessary
384
+ hosts.each do |host|
385
+ host['pe_dir'] ||= options[:pe_dir]
386
+ if host['platform'] =~ /windows/
387
+ host['pe_ver'] = host['pe_ver'] || options['pe_ver'] ||
388
+ Beaker::Options::PEVersionScraper.load_pe_version(host[:pe_dir] || options[:pe_dir], options[:pe_version_file_win])
389
+ else
390
+ host['pe_ver'] = host['pe_ver'] || options['pe_ver'] ||
391
+ Beaker::Options::PEVersionScraper.load_pe_version(host[:pe_dir] || options[:pe_dir], options[:pe_version_file])
392
+ end
393
+ end
394
+ #send in the global options hash
395
+ do_install sorted_hosts, options
396
+ end
397
+
398
+ #Upgrade PE based upon host configuration and options
399
+ # @param [String] path A path (either local directory or a URL to a listing of PE builds).
400
+ # Will contain a LATEST file indicating the latest build to install.
401
+ # This is ignored if a pe_upgrade_ver and pe_upgrade_dir are specified
402
+ # in the host configuration file.
403
+ # @example
404
+ # upgrade_pe("http://neptune.puppetlabs.lan/3.0/ci-ready/")
405
+ #
406
+ # @note Install file names are assumed to be of the format puppet-enterprise-VERSION-PLATFORM.(tar)|(tar.gz)
407
+ # for Unix like systems and puppet-enterprise-VERSION.msi for Windows systems.
408
+ def upgrade_pe path=nil
409
+ set_console_password = false
410
+ # if we are upgrading from something lower than 3.4 then we need to set the pe console password
411
+ if (dashboard[:pe_ver] ? version_is_less(dashboard[:pe_ver], "3.4.0") : true)
412
+ set_console_password = true
413
+ end
414
+ # get new version information
415
+ hosts.each do |host|
416
+ host['pe_dir'] = host['pe_upgrade_dir'] || path
417
+ if host['platform'] =~ /windows/
418
+ host['pe_ver'] = host['pe_upgrade_ver'] || options['pe_upgrade_ver'] ||
419
+ Options::PEVersionScraper.load_pe_version(host['pe_dir'], options[:pe_version_file_win])
420
+ else
421
+ host['pe_ver'] = host['pe_upgrade_ver'] || options['pe_upgrade_ver'] ||
422
+ Options::PEVersionScraper.load_pe_version(host['pe_dir'], options[:pe_version_file])
423
+ end
424
+ if version_is_less(host['pe_ver'], '3.0')
425
+ host['pe_installer'] ||= 'puppet-enterprise-upgrader'
426
+ end
427
+ end
428
+ # send in the global options hash
429
+ do_install(sorted_hosts, options.merge({:type => :upgrade, :set_console_password => set_console_password}))
430
+ options['upgrade'] = true
431
+ end
432
+
433
+ #Create the Higgs install command string based upon the host and options settings. Installation command will be run as a
434
+ #background process. The output of the command will be stored in the provided host['higgs_file'].
435
+ # @param [Host] host The host that Higgs is to be installed on
436
+ # The host object must have the 'working_dir', 'dist' and 'pe_installer' field set correctly.
437
+ # @api private
438
+ def higgs_installer_cmd host
439
+
440
+ "cd #{host['working_dir']}/#{host['dist']} ; nohup ./#{host['pe_installer']} <<<Y > #{host['higgs_file']} 2>&1 &"
441
+
442
+ end
443
+
444
+ #Perform a Puppet Enterprise Higgs install up until web browser interaction is required, runs on linux hosts only.
445
+ # @param [Host] host The host to install higgs on
446
+ # @param [Hash{Symbol=>Symbol, String}] opts The options
447
+ # @option opts [String] :pe_dir Default directory or URL to pull PE package from
448
+ # (Otherwise uses individual hosts pe_dir)
449
+ # @option opts [String] :pe_ver Default PE version to install
450
+ # (Otherwise uses individual hosts pe_ver)
451
+ # @raise [StandardError] When installation times out
452
+ #
453
+ # @example
454
+ # do_higgs_install(master, {:pe_dir => path, :pe_ver => version})
455
+ #
456
+ # @api private
457
+ #
458
+ def do_higgs_install host, opts
459
+ use_all_tar = ENV['PE_USE_ALL_TAR'] == 'true'
460
+ platform = use_all_tar ? 'all' : host['platform']
461
+ version = host['pe_ver'] || opts[:pe_ver]
462
+ host['dist'] = "puppet-enterprise-#{version}-#{platform}"
463
+
464
+ use_all_tar = ENV['PE_USE_ALL_TAR'] == 'true'
465
+ host['pe_installer'] ||= 'puppet-enterprise-installer'
466
+ host['working_dir'] = host.tmpdir(Time.new.strftime("%Y-%m-%d_%H.%M.%S"))
467
+
468
+ fetch_pe([host], opts)
469
+
470
+ host['higgs_file'] = "higgs_#{File.basename(host['working_dir'])}.log"
471
+ on host, higgs_installer_cmd(host), opts
472
+
473
+ #wait for output to host['higgs_file']
474
+ #we're all done when we find this line in the PE installation log
475
+ higgs_re = /Please\s+go\s+to\s+https:\/\/.*\s+in\s+your\s+browser\s+to\s+continue\s+installation/m
476
+ res = Result.new(host, 'tmp cmd')
477
+ tries = 10
478
+ attempts = 0
479
+ prev_sleep = 0
480
+ cur_sleep = 1
481
+ while (res.stdout !~ higgs_re) and (attempts < tries)
482
+ res = on host, "cd #{host['working_dir']}/#{host['dist']} && cat #{host['higgs_file']}", :acceptable_exit_codes => (0..255)
483
+ attempts += 1
484
+ sleep( cur_sleep )
485
+ prev_sleep = cur_sleep
486
+ cur_sleep = cur_sleep + prev_sleep
487
+ end
488
+
489
+ if attempts >= tries
490
+ raise "Failed to kick off PE (Higgs) web installation"
491
+ end
492
+ end
493
+
494
+ #Install Higgs up till the point where you need to continue installation in a web browser, defaults to execution
495
+ #on the master node.
496
+ #@param [Host] higgs_host The host to install Higgs on (supported on linux platform only)
497
+ # @example
498
+ # install_higgs
499
+ #
500
+ # @note Either pe_ver and pe_dir should be set in the ENV or each host should have pe_ver and pe_dir set individually.
501
+ # Install file names are assumed to be of the format puppet-enterprise-VERSION-PLATFORM.(tar)|(tar.gz).
502
+ #
503
+ def install_higgs( higgs_host = master )
504
+ #process the version files if necessary
505
+ master['pe_dir'] ||= options[:pe_dir]
506
+ master['pe_ver'] = master['pe_ver'] || options['pe_ver'] ||
507
+ Beaker::Options::PEVersionScraper.load_pe_version(master[:pe_dir] || options[:pe_dir], options[:pe_version_file])
508
+ if higgs_host['platform'] =~ /osx|windows/
509
+ raise "Attempting higgs installation on host #{higgs_host.name} with unsupported platform #{higgs_host['platform']}"
510
+ end
511
+ #send in the global options hash
512
+ do_higgs_install higgs_host, options
513
+ end
514
+
515
+ end
516
+ end
517
+ end
518
+ end