beaker 2.7.1 → 2.8.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 (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,722 @@
1
+ module Beaker
2
+ module DSL
3
+ module InstallUtils
4
+ #
5
+ # This module contains methods to install FOSS puppet from various sources
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 PuppetUtils
15
+
16
+ # The default install path
17
+ SourcePath = "/opt/puppet-git-repos"
18
+
19
+ # A regex to know if the uri passed is pointing to a git repo
20
+ GitURI = %r{^(git|https?|file)://|^git@|^gitmirror@}
21
+
22
+ # Github's ssh signature for cloning via ssh
23
+ GitHubSig = 'github.com,207.97.227.239 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ=='
24
+
25
+ # @param [String] uri A uri in the format of <git uri>#<revision>
26
+ # the `git://`, `http://`, `https://`, and ssh
27
+ # (if cloning as the remote git user) protocols
28
+ # are valid for <git uri>
29
+ #
30
+ # @example Usage
31
+ # project = extract_repo_info_from 'git@github.com:puppetlabs/SuperSecretSauce#what_is_justin_doing'
32
+ #
33
+ # puts project[:name]
34
+ # #=> 'SuperSecretSauce'
35
+ #
36
+ # puts project[:rev]
37
+ # #=> 'what_is_justin_doing'
38
+ #
39
+ # @return [Hash{Symbol=>String}] Returns a hash containing the project
40
+ # name, repository path, and revision
41
+ # (defaults to HEAD)
42
+ #
43
+ def extract_repo_info_from uri
44
+ require 'pathname'
45
+ project = {}
46
+ repo, rev = uri.split('#', 2)
47
+ project[:name] = Pathname.new(repo).basename('.git').to_s
48
+ project[:path] = repo
49
+ project[:rev] = rev || 'HEAD'
50
+ return project
51
+ end
52
+
53
+ # Takes an array of package info hashes (like that returned from
54
+ # {#extract_repo_info_from}) and sorts the `puppet`, `facter`, `hiera`
55
+ # packages so that puppet's dependencies will be installed first.
56
+ #
57
+ # @!visibility private
58
+ def order_packages packages_array
59
+ puppet = packages_array.select {|e| e[:name] == 'puppet' }
60
+ puppet_depends_on = packages_array.select do |e|
61
+ e[:name] == 'hiera' or e[:name] == 'facter'
62
+ end
63
+ depends_on_puppet = (packages_array - puppet) - puppet_depends_on
64
+ [puppet_depends_on, puppet, depends_on_puppet].flatten
65
+ end
66
+
67
+ # @param [Host] host An object implementing {Beaker::Hosts}'s
68
+ # interface.
69
+ # @param [String] path The path on the remote [host] to the repository
70
+ # @param [Hash{Symbol=>String}] repository A hash representing repo
71
+ # info like that emitted by
72
+ # {#extract_repo_info_from}
73
+ #
74
+ # @example Getting multiple project versions
75
+ # versions = [puppet_repo, facter_repo, hiera_repo].inject({}) do |vers, repo_info|
76
+ # vers.merge(find_git_repo_versions(host, '/opt/git-puppet-repos', repo_info) )
77
+ # end
78
+ # @return [Hash] Executes git describe on [host] and returns a Hash
79
+ # with the key of [repository[:name]] and value of
80
+ # the output from git describe.
81
+ #
82
+ # @note This requires the helper methods:
83
+ # * {Beaker::DSL::Structure#step}
84
+ # * {Beaker::DSL::Helpers#on}
85
+ #
86
+ def find_git_repo_versions host, path, repository
87
+ version = {}
88
+ step "Grab version for #{repository[:name]}" do
89
+ on host, "cd #{path}/#{repository[:name]} && " +
90
+ "git describe || true" do
91
+ version[repository[:name]] = stdout.chomp
92
+ end
93
+ end
94
+ version
95
+ end
96
+
97
+ #
98
+ # @see #find_git_repo_versions
99
+ def install_from_git host, path, repository
100
+ name = repository[:name]
101
+ repo = repository[:path]
102
+ rev = repository[:rev]
103
+ depth = repository[:depth]
104
+ depth_branch = repository[:depth_branch]
105
+ target = "#{path}/#{name}"
106
+
107
+ if (depth_branch.nil?)
108
+ depth_branch = rev
109
+ end
110
+
111
+ clone_cmd = "git clone #{repo} #{target}"
112
+ if (depth)
113
+ clone_cmd = "git clone --branch #{depth_branch} --depth #{depth} #{repo} #{target}"
114
+ end
115
+
116
+ step "Clone #{repo} if needed" do
117
+ on host, "test -d #{path} || mkdir -p #{path}"
118
+ on host, "test -d #{target} || #{clone_cmd}"
119
+ end
120
+
121
+ step "Update #{name} and check out revision #{rev}" do
122
+ commands = ["cd #{target}",
123
+ "remote rm origin",
124
+ "remote add origin #{repo}",
125
+ "fetch origin +refs/pull/*:refs/remotes/origin/pr/* +refs/heads/*:refs/remotes/origin/*",
126
+ "clean -fdx",
127
+ "checkout -f #{rev}"]
128
+ on host, commands.join(" && git ")
129
+ end
130
+
131
+ step "Install #{name} on the system" do
132
+ # The solaris ruby IPS package has bindir set to /usr/ruby/1.8/bin.
133
+ # However, this is not the path to which we want to deliver our
134
+ # binaries. So if we are using solaris, we have to pass the bin and
135
+ # sbin directories to the install.rb
136
+ install_opts = ''
137
+ install_opts = '--bindir=/usr/bin --sbindir=/usr/sbin' if
138
+ host['platform'].include? 'solaris'
139
+
140
+ on host, "cd #{target} && " +
141
+ "if [ -f install.rb ]; then " +
142
+ "ruby ./install.rb #{install_opts}; " +
143
+ "else true; fi"
144
+ end
145
+ end
146
+
147
+ #Install FOSS based upon host configuration and options
148
+ # @example will install puppet 3.6.1 from native puppetlabs provided packages wherever possible and will fail over to gem installation when impossible
149
+ # install_puppet({
150
+ # :version => '3.6.1',
151
+ # :facter_version => '2.0.1',
152
+ # :hiera_version => '1.3.3',
153
+ # :default_action => 'gem_install',
154
+ #
155
+ # })
156
+ #
157
+ #
158
+ # @example Will install latest packages on Enterprise Linux and Debian based distros and fail hard on all othere platforms.
159
+ # install_puppet()
160
+ #
161
+ # @note This will attempt to add a repository for apt.puppetlabs.com on
162
+ # Debian, Ubuntu, or Cumulus machines, or yum.puppetlabs.com on EL or Fedora
163
+ # machines, then install the package 'puppet'.
164
+ # @param [Hash{Symbol=>String}] opts
165
+ # @option opts [String] :version Version of puppet to download
166
+ # @option opts [String] :mac_download_url Url to download msi pattern of %url%/puppet-%version%.msi
167
+ # @option opts [String] :win_download_url Url to download dmg pattern of %url%/(puppet|hiera|facter)-%version%.msi
168
+ #
169
+ # @return nil
170
+ # @raise [StandardError] When encountering an unsupported platform by default, or if gem cannot be found when default_action => 'gem_install'
171
+ # @raise [FailTest] When error occurs during the actual installation process
172
+ def install_puppet(opts = {})
173
+ default_download_url = 'http://downloads.puppetlabs.com'
174
+ opts = {:win_download_url => "#{default_download_url}/windows",
175
+ :mac_download_url => "#{default_download_url}/mac"}.merge(opts)
176
+ hosts.each do |host|
177
+ if host['platform'] =~ /el-(5|6|7)/
178
+ relver = $1
179
+ install_puppet_from_rpm host, opts.merge(:release => relver, :family => 'el')
180
+ elsif host['platform'] =~ /fedora-(\d+)/
181
+ relver = $1
182
+ install_puppet_from_rpm host, opts.merge(:release => relver, :family => 'fedora')
183
+ elsif host['platform'] =~ /(ubuntu|debian|cumulus)/
184
+ install_puppet_from_deb host, opts
185
+ elsif host['platform'] =~ /windows/
186
+ relver = opts[:version]
187
+ install_puppet_from_msi host, opts
188
+ elsif host['platform'] =~ /osx/
189
+ install_puppet_from_dmg host, opts
190
+ else
191
+ if opts[:default_action] == 'gem_install'
192
+ install_puppet_from_gem host, opts
193
+ else
194
+ raise "install_puppet() called for unsupported platform '#{host['platform']}' on '#{host.name}'"
195
+ end
196
+ end
197
+
198
+ # Certain install paths may not create the config dirs/files needed
199
+ on host, "mkdir -p #{host['puppetpath']}" unless host[:type] =~ /aio/
200
+ on host, "echo '' >> #{host.puppet['hiera_config']}"
201
+ end
202
+ nil
203
+ end
204
+
205
+ # Configure puppet.conf for all hosts based upon a provided Hash
206
+ # @param [Hash{Symbol=>String}] opts
207
+ # @option opts [Hash{String=>String}] :main configure the main section of puppet.conf
208
+ # @option opts [Hash{String=>String}] :agent configure the agent section of puppet.conf
209
+ #
210
+ # @return nil
211
+ def configure_puppet(opts={})
212
+ hosts.each do |host|
213
+ configure_puppet_on(host,opts)
214
+ end
215
+ end
216
+
217
+ # Configure puppet.conf on the given host based upon a provided hash
218
+ # @param [Host] host The host to configure puppet.conf on
219
+ # @param [Hash{Symbol=>String}] opts
220
+ # @option opts [Hash{String=>String}] :main configure the main section of puppet.conf
221
+ # @option opts [Hash{String=>String}] :agent configure the agent section of puppet.conf
222
+ #
223
+ # @example will configure /etc/puppet.conf on the puppet master.
224
+ # config = {
225
+ # 'main' => {
226
+ # 'server' => 'testbox.test.local',
227
+ # 'certname' => 'testbox.test.local',
228
+ # 'logdir' => '/var/log/puppet',
229
+ # 'vardir' => '/var/lib/puppet',
230
+ # 'ssldir' => '/var/lib/puppet/ssl',
231
+ # 'rundir' => '/var/run/puppet'
232
+ # },
233
+ # 'agent' => {
234
+ # 'environment' => 'dev'
235
+ # }
236
+ # }
237
+ # configure_puppet(master, config)
238
+ #
239
+ # @return nil
240
+ def configure_puppet_on(host, opts = {})
241
+ if host['platform'] =~ /windows/
242
+ puppet_conf = host.puppet['config']
243
+ conf_data = ''
244
+ opts.each do |section,options|
245
+ conf_data << "[#{section}]`n"
246
+ options.each do |option,value|
247
+ conf_data << "#{option}=#{value}`n"
248
+ end
249
+ conf_data << "`n"
250
+ end
251
+ on host, powershell("\$text = \\\"#{conf_data}\\\"; Set-Content -path '#{puppet_conf}' -value \$text")
252
+ else
253
+ puppet_conf = host.puppet['config']
254
+ conf_data = ''
255
+ opts.each do |section,options|
256
+ conf_data << "[#{section}]\n"
257
+ options.each do |option,value|
258
+ conf_data << "#{option}=#{value}\n"
259
+ end
260
+ conf_data << "\n"
261
+ end
262
+ on host, "echo \"#{conf_data}\" > #{puppet_conf}"
263
+ end
264
+ end
265
+
266
+ # Installs Puppet and dependencies using rpm
267
+ #
268
+ # @param [Host] host The host to install packages on
269
+ # @param [Hash{Symbol=>String}] opts An options hash
270
+ # @option opts [String] :version The version of Puppet to install, if nil installs latest version
271
+ # @option opts [String] :facter_version The version of Facter to install, if nil installs latest version
272
+ # @option opts [String] :hiera_version The version of Hiera to install, if nil installs latest version
273
+ # @option opts [String] :default_action What to do if we don't know how to install native packages on host.
274
+ # Valid value is 'gem_install' or nil. If nil raises an exception when
275
+ # on an unsupported platform. When 'gem_install' attempts to install
276
+ # Puppet via gem.
277
+ # @option opts [String] :release The major release of the OS
278
+ # @option opts [String] :family The OS family (one of 'el' or 'fedora')
279
+ #
280
+ # @return nil
281
+ # @api private
282
+ def install_puppet_from_rpm( host, opts )
283
+ release_package_string = "http://yum.puppetlabs.com/puppetlabs-release-#{opts[:family]}-#{opts[:release]}.noarch.rpm"
284
+
285
+ on host, "rpm -q --quiet puppetlabs-release || rpm -ivh #{release_package_string}"
286
+
287
+ if opts[:facter_version]
288
+ on host, "yum install -y facter-#{opts[:facter_version]}"
289
+ end
290
+
291
+ if opts[:hiera_version]
292
+ on host, "yum install -y hiera-#{opts[:hiera_version]}"
293
+ end
294
+
295
+ puppet_pkg = opts[:version] ? "puppet-#{opts[:version]}" : 'puppet'
296
+ on host, "yum install -y #{puppet_pkg}"
297
+ end
298
+
299
+ # Installs Puppet and dependencies from deb
300
+ #
301
+ # @param [Host] host The host to install packages on
302
+ # @param [Hash{Symbol=>String}] opts An options hash
303
+ # @option opts [String] :version The version of Puppet to install, if nil installs latest version
304
+ # @option opts [String] :facter_version The version of Facter to install, if nil installs latest version
305
+ # @option opts [String] :hiera_version The version of Hiera to install, if nil installs latest version
306
+ #
307
+ # @return nil
308
+ # @api private
309
+ def install_puppet_from_deb( host, opts )
310
+ if ! host.check_for_package 'lsb-release'
311
+ host.install_package('lsb-release')
312
+ end
313
+
314
+ if ! host.check_for_command 'curl'
315
+ on host, 'apt-get install -y curl'
316
+ end
317
+
318
+ on host, 'curl -O http://apt.puppetlabs.com/puppetlabs-release-$(lsb_release -c -s).deb'
319
+ on host, 'dpkg -i puppetlabs-release-$(lsb_release -c -s).deb'
320
+ on host, 'apt-get update'
321
+
322
+ if opts[:facter_version]
323
+ on host, "apt-get install -y facter=#{opts[:facter_version]}-1puppetlabs1"
324
+ end
325
+
326
+ if opts[:hiera_version]
327
+ on host, "apt-get install -y hiera=#{opts[:hiera_version]}-1puppetlabs1"
328
+ end
329
+
330
+ if opts[:version]
331
+ on host, "apt-get install -y puppet-common=#{opts[:version]}-1puppetlabs1"
332
+ on host, "apt-get install -y puppet=#{opts[:version]}-1puppetlabs1"
333
+ else
334
+ on host, 'apt-get install -y puppet'
335
+ end
336
+ end
337
+
338
+ # Installs Puppet and dependencies from msi
339
+ #
340
+ # @param [Host] host The host to install packages on
341
+ # @param [Hash{Symbol=>String}] opts An options hash
342
+ # @option opts [String] :version The version of Puppet to install, required
343
+ # @option opts [String] :win_download_url The url to download puppet from
344
+ def install_puppet_from_msi( host, opts )
345
+ #only install 64bit builds if
346
+ # - we are on puppet version 3.7+
347
+ # - we do not have install_32 set on host
348
+ # - we do not have install_32 set globally
349
+ version = opts[:version]
350
+ if !(version_is_less(version, '3.7')) and host.is_x86_64? and not host['install_32'] and not opts['install_32']
351
+ host['dist'] = "puppet-#{version}-x64"
352
+ else
353
+ host['dist'] = "puppet-#{version}"
354
+ end
355
+ link = "#{opts[:win_download_url]}/#{host['dist']}.msi"
356
+ if not link_exists?( link )
357
+ raise "Puppet #{version} at #{link} does not exist!"
358
+ end
359
+
360
+ if host.is_cygwin?
361
+ dest = "#{host['dist']}.msi"
362
+ on host, "curl -O #{link}"
363
+
364
+ #Because the msi installer doesn't add Puppet to the environment path
365
+ #Add both potential paths for simplicity
366
+ #NOTE - this is unnecessary if the host has been correctly identified as 'foss' during set up
367
+ puppetbin_path = "\"/cygdrive/c/Program Files (x86)/Puppet Labs/Puppet/bin\":\"/cygdrive/c/Program Files/Puppet Labs/Puppet/bin\""
368
+ on host, %Q{ echo 'export PATH=$PATH:#{puppetbin_path}' > /etc/bash.bashrc }
369
+ else
370
+ dest = "C:\\Windows\\Temp\\#{host['dist']}.msi"
371
+
372
+ on host, "set PATH=\"%PATH%;#{host['puppetbindir']}\""
373
+ on host, "setx PATH \"%PATH%;#{host['puppetbindir']}\""
374
+
375
+ on host, powershell("$webclient = New-Object System.Net.WebClient; $webclient.DownloadFile('#{link}','#{dest}')")
376
+
377
+ on host, "if not exist #{host['distmoduledir']} (md #{host['distmoduledir']})"
378
+ end
379
+
380
+ on host, "cmd /C 'start /w msiexec.exe /qn /i #{dest}'"
381
+ end
382
+
383
+ # Installs Puppet and dependencies from dmg
384
+ #
385
+ # @param [Host] host The host to install packages on
386
+ # @param [Hash{Symbol=>String}] opts An options hash
387
+ # @option opts [String] :version The version of Puppet to install, required
388
+ # @option opts [String] :facter_version The version of Facter to install, required
389
+ # @option opts [String] :hiera_version The version of Hiera to install, required
390
+ # @option opts [String] :mac_download_url Url to download msi pattern of %url%/puppet-%version%.msi
391
+ #
392
+ # @return nil
393
+ # @api private
394
+ def install_puppet_from_dmg( host, opts )
395
+
396
+ puppet_ver = opts[:version]
397
+ facter_ver = opts[:facter_version]
398
+ hiera_ver = opts[:hiera_version]
399
+
400
+ if [puppet_ver, facter_ver, hiera_ver].include?(nil)
401
+ raise "You need to specify versions for OSX host\n eg. install_puppet({:version => '3.6.2',:facter_version => '2.1.0',:hiera_version => '1.3.4',})"
402
+ end
403
+
404
+ on host, "curl -O #{opts[:mac_download_url]}/puppet-#{puppet_ver}.dmg"
405
+ on host, "curl -O #{opts[:mac_download_url]}/facter-#{facter_ver}.dmg"
406
+ on host, "curl -O #{opts[:mac_download_url]}/hiera-#{hiera_ver}.dmg"
407
+
408
+ on host, "hdiutil attach puppet-#{puppet_ver}.dmg"
409
+ on host, "hdiutil attach facter-#{facter_ver}.dmg"
410
+ on host, "hdiutil attach hiera-#{hiera_ver}.dmg"
411
+
412
+ on host, "installer -pkg /Volumes/puppet-#{puppet_ver}/puppet-#{puppet_ver}.pkg -target /"
413
+ on host, "installer -pkg /Volumes/facter-#{facter_ver}/facter-#{facter_ver}.pkg -target /"
414
+ on host, "installer -pkg /Volumes/hiera-#{hiera_ver}/hiera-#{hiera_ver}.pkg -target /"
415
+ end
416
+
417
+ # Installs Puppet and dependencies from gem
418
+ #
419
+ # @param [Host] host The host to install packages on
420
+ # @param [Hash{Symbol=>String}] opts An options hash
421
+ # @option opts [String] :version The version of Puppet to install, if nil installs latest
422
+ # @option opts [String] :facter_version The version of Facter to install, if nil installs latest
423
+ # @option opts [String] :hiera_version The version of Hiera to install, if nil installs latest
424
+ #
425
+ # @return nil
426
+ # @raise [StandardError] if gem does not exist on target host
427
+ # @api private
428
+ def install_puppet_from_gem( host, opts )
429
+ # There are a lot of special things to do for Solaris and Solaris 10.
430
+ # This is easier than checking host['platform'] every time.
431
+ is_solaris10 = host['platform'] =~ /solaris-10/
432
+ is_solaris = host['platform'] =~ /solaris/
433
+
434
+ # Hosts may be provisioned with csw but pkgutil won't be in the
435
+ # PATH by default to avoid changing the behavior for Puppet's tests
436
+ if is_solaris10
437
+ on host, 'ln -s /opt/csw/bin/pkgutil /usr/bin/pkgutil'
438
+ end
439
+
440
+ # Solaris doesn't necessarily have this, but gem needs it
441
+ if is_solaris
442
+ on host, 'mkdir -p /var/lib'
443
+ end
444
+
445
+ unless host.check_for_command( 'gem' )
446
+ gempkg = case host['platform']
447
+ when /solaris-11/ then 'ruby-18'
448
+ when /ubuntu-14/ then 'ruby'
449
+ when /solaris-10|ubuntu|debian|el-|cumulus/ then 'rubygems'
450
+ else
451
+ raise "install_puppet() called with default_action " +
452
+ "'gem_install' but program `gem' is " +
453
+ "not installed on #{host.name}"
454
+ end
455
+
456
+ host.install_package gempkg
457
+ end
458
+
459
+ # Link 'gem' to /usr/bin instead of adding /opt/csw/bin to PATH.
460
+ if is_solaris10
461
+ on host, 'ln -s /opt/csw/bin/gem /usr/bin/gem'
462
+ end
463
+
464
+ if host['platform'] =~ /debian|ubuntu|solaris|cumulus/
465
+ gem_env = YAML.load( on( host, 'gem environment' ).stdout )
466
+ gem_paths_array = gem_env['RubyGems Environment'].find {|h| h['GEM PATHS'] != nil }['GEM PATHS']
467
+ path_with_gem = 'export PATH=' + gem_paths_array.join(':') + ':${PATH}'
468
+ on host, "echo '#{path_with_gem}' >> ~/.bashrc"
469
+ end
470
+
471
+ if opts[:facter_version]
472
+ on host, "gem install facter -v#{opts[:facter_version]} --no-ri --no-rdoc"
473
+ end
474
+
475
+ if opts[:hiera_version]
476
+ on host, "gem install hiera -v#{opts[:hiera_version]} --no-ri --no-rdoc"
477
+ end
478
+
479
+ ver_cmd = opts[:version] ? "-v#{opts[:version]}" : ''
480
+ on host, "gem install puppet #{ver_cmd} --no-ri --no-rdoc"
481
+
482
+ # Similar to the treatment of 'gem' above.
483
+ # This avoids adding /opt/csw/bin to PATH.
484
+ if is_solaris
485
+ gem_env = YAML.load( on( host, 'gem environment' ).stdout )
486
+ # This is the section we want - this has the dir where gem executables go.
487
+ env_sect = 'EXECUTABLE DIRECTORY'
488
+ # Get the directory where 'gem' installs executables.
489
+ # On Solaris 10 this is usually /opt/csw/bin
490
+ gem_exec_dir = gem_env['RubyGems Environment'].find {|h| h[env_sect] != nil }[env_sect]
491
+
492
+ on host, "ln -s #{gem_exec_dir}/hiera /usr/bin/hiera"
493
+ on host, "ln -s #{gem_exec_dir}/facter /usr/bin/facter"
494
+ on host, "ln -s #{gem_exec_dir}/puppet /usr/bin/puppet"
495
+ end
496
+ end
497
+
498
+ # Install official puppetlabs release repository configuration on host.
499
+ #
500
+ # @param [Host] host An object implementing {Beaker::Hosts}'s
501
+ # interface.
502
+ #
503
+ # @note This method only works on redhat-like and debian-like hosts.
504
+ #
505
+ def install_puppetlabs_release_repo ( host )
506
+ variant, version, arch, codename = host['platform'].to_array
507
+
508
+ case variant
509
+ when /^(fedora|el|centos)$/
510
+ variant = (($1 == 'centos') ? 'el' : $1)
511
+
512
+ rpm = options[:release_yum_repo_url] +
513
+ "/puppetlabs-release-%s-%s.noarch.rpm" % [variant, version]
514
+
515
+ on host, "rpm -ivh #{rpm}"
516
+
517
+ when /^(debian|ubuntu|cumulus)$/
518
+ deb = URI.join(options[:release_apt_repo_url], "puppetlabs-release-%s.deb" % codename)
519
+
520
+ on host, "wget -O /tmp/puppet.deb #{deb}"
521
+ on host, "dpkg -i --force-all /tmp/puppet.deb"
522
+ on host, "apt-get update"
523
+ else
524
+ raise "No repository installation step for #{variant} yet..."
525
+ end
526
+ end
527
+
528
+ # Install development repository on the given host. This method pushes all
529
+ # repository information including package files for the specified
530
+ # package_name to the host and modifies the repository configuration file
531
+ # to point at the new repository. This is particularly useful for
532
+ # installing development packages on hosts that can't access the builds
533
+ # server.
534
+ #
535
+ # @param [Host] host An object implementing {Beaker::Hosts}'s
536
+ # interface.
537
+ # @param [String] package_name The name of the package whose repository is
538
+ # being installed.
539
+ # @param [String] build_version A string identifying the output of a
540
+ # packaging job for use in looking up
541
+ # repository directory information
542
+ # @param [String] repo_configs_dir A local directory where repository files will be
543
+ # stored as an intermediate step before
544
+ # pushing them to the given host.
545
+ #
546
+ # @note This method only works on redhat-like and debian-like hosts.
547
+ #
548
+ def install_puppetlabs_dev_repo ( host, package_name, build_version,
549
+ repo_configs_dir = 'tmp/repo_configs' )
550
+ variant, version, arch, codename = host['platform'].to_array
551
+ platform_configs_dir = File.join(repo_configs_dir, variant)
552
+
553
+ # some of the uses of dev_builds_url below can't include protocol info,
554
+ # pluse this opens up possibility of switching the behavior on provided
555
+ # url type
556
+ _, protocol, hostname = options[:dev_builds_url].partition /.*:\/\//
557
+ dev_builds_url = protocol + hostname
558
+
559
+ on host, "mkdir -p /root/#{package_name}"
560
+
561
+ case variant
562
+ when /^(fedora|el|centos)$/
563
+ variant = (($1 == 'centos') ? 'el' : $1)
564
+ fedora_prefix = ((variant == 'fedora') ? 'f' : '')
565
+
566
+ if host.is_pe?
567
+ pattern = "pl-%s-%s-repos-pe-%s-%s%s-%s.repo"
568
+ else
569
+ pattern = "pl-%s-%s-%s-%s%s-%s.repo"
570
+ end
571
+
572
+ repo_filename = pattern % [
573
+ package_name,
574
+ build_version,
575
+ variant,
576
+ fedora_prefix,
577
+ version,
578
+ arch
579
+ ]
580
+
581
+ repo = fetch_http_file( "%s/%s/%s/repo_configs/rpm/" %
582
+ [ dev_builds_url, package_name, build_version ],
583
+ repo_filename,
584
+ platform_configs_dir)
585
+
586
+ link = "%s/%s/%s/repos/%s/%s%s/products/%s/" %
587
+ [ dev_builds_url, package_name, build_version, variant,
588
+ fedora_prefix, version, arch ]
589
+
590
+ if not link_exists?( link )
591
+ link = "%s/%s/%s/repos/%s/%s%s/devel/%s/" %
592
+ [ dev_builds_url, package_name, build_version, variant,
593
+ fedora_prefix, version, arch ]
594
+ end
595
+
596
+ if not link_exists?( link )
597
+ raise "Unable to reach a repo directory at #{link}"
598
+ end
599
+
600
+ repo_dir = fetch_http_dir( link, platform_configs_dir )
601
+
602
+ config_dir = '/etc/yum.repos.d/'
603
+ scp_to host, repo, config_dir
604
+ scp_to host, repo_dir, "/root/#{package_name}"
605
+
606
+ search = "baseurl\\s*=\\s*http:\\/\\/#{hostname}.*$"
607
+ replace = "baseurl=file:\\/\\/\\/root\\/#{package_name}\\/#{arch}"
608
+ sed_command = "sed -i 's/#{search}/#{replace}/'"
609
+ find_and_sed = "find #{config_dir} -name \"*.repo\" -exec #{sed_command} {} \\;"
610
+
611
+ on host, find_and_sed
612
+
613
+ when /^(debian|ubuntu|cumulus)$/
614
+ list = fetch_http_file( "%s/%s/%s/repo_configs/deb/" %
615
+ [ dev_builds_url, package_name, build_version ],
616
+ "pl-%s-%s-%s.list" %
617
+ [ package_name, build_version, codename ],
618
+ platform_configs_dir )
619
+
620
+ repo_dir = fetch_http_dir( "%s/%s/%s/repos/apt/%s" %
621
+ [ dev_builds_url, package_name,
622
+ build_version, codename ],
623
+ platform_configs_dir )
624
+
625
+ config_dir = '/etc/apt/sources.list.d'
626
+ scp_to host, list, config_dir
627
+ scp_to host, repo_dir, "/root/#{package_name}"
628
+
629
+ search = "deb\\s\\+http:\\/\\/#{hostname}.*$"
630
+ replace = "deb file:\\/\\/\\/root\\/#{package_name}\\/#{codename} #{codename} main"
631
+ sed_command = "sed -i 's/#{search}/#{replace}/'"
632
+ find_and_sed = "find #{config_dir} -name \"*.list\" -exec #{sed_command} {} \\;"
633
+
634
+ on host, find_and_sed
635
+ on host, "apt-get update"
636
+
637
+ else
638
+ raise "No repository installation step for #{variant} yet..."
639
+ end
640
+ end
641
+
642
+ # Installs packages from the local development repository on the given host
643
+ #
644
+ # @param [Host] host An object implementing {Beaker::Hosts}'s
645
+ # interface.
646
+ # @param [Regexp] package_name The name of the package whose repository is
647
+ # being installed.
648
+ #
649
+ # @note This method only works on redhat-like and debian-like hosts.
650
+ # @note This method is paired to be run directly after {#install_puppetlabs_dev_repo}
651
+ #
652
+ def install_packages_from_local_dev_repo( host, package_name )
653
+ if host['platform'] =~ /debian|ubuntu|cumulus/
654
+ find_filename = '*.deb'
655
+ find_command = 'dpkg -i'
656
+ elsif host['platform'] =~ /fedora|el|centos/
657
+ find_filename = '*.rpm'
658
+ find_command = 'rpm -ivh'
659
+ else
660
+ raise "No repository installation step for #{host['platform']} yet..."
661
+ end
662
+ find_command = "find /root/#{package_name} -type f -name '#{find_filename}' -exec #{find_command} {} \\;"
663
+ on host, find_command
664
+ end
665
+
666
+ # Install development repo of the puppet-agent on the given host
667
+ #
668
+ # @param [Host] host An object implementing {Beaker::Hosts}'s interface
669
+ # @param [Hash{Symbol=>String}] opts An options hash
670
+ # @option opts [String] :version The version of puppet-agent to install
671
+ # @option opts [String] :copy_base_local Directory where puppet-agent artifact
672
+ # will be stored locally
673
+ # (default: 'tmp/repo_configs')
674
+ # @option opts [String] :copy_dir_external Directory where puppet-agent
675
+ # artifact will be pushed to on the external machine
676
+ # (default: '/root')
677
+ # @return nil
678
+ def install_puppetagent_dev_repo( host, opts )
679
+ opts[:copy_base_local] ||= File.join('tmp', 'repo_configs')
680
+ opts[:copy_dir_external] ||= File.join('/', 'root')
681
+ variant, version, arch, codename = host['platform'].to_array
682
+ release_path = "#{options[:dev_builds_url]}/puppet-agent/#{opts[:version]}/artifacts/"
683
+ copy_dir_local = File.join(opts[:copy_base_local], variant)
684
+ onhost_copy_base = opts[:copy_dir_external]
685
+
686
+ case variant
687
+ when /^(fedora|el|centos)$/
688
+ release_path << "el/#{version}/products/#{arch}"
689
+ release_file = "puppet-agent-#{opts[:version]}-1.#{arch}.rpm"
690
+ when /^(debian|ubuntu|cumulus)$/
691
+ release_path << "deb/#{codename}"
692
+ release_file = "puppet-agent_#{opts[:version]}-1_#{arch}.deb"
693
+ when /^windows$/
694
+ release_path << 'windows'
695
+ onhost_copy_base = '`cygpath -smF 35`/'
696
+ arch_suffix = arch =~ /64/ ? '64' : '86'
697
+ release_file = "puppet-agent-x#{arch_suffix}.msi"
698
+ else
699
+ raise "No repository installation step for #{variant} yet..."
700
+ end
701
+
702
+ onhost_copied_file = File.join(onhost_copy_base, release_file)
703
+ fetch_http_file( release_path, release_file, copy_dir_local)
704
+ scp_to host, File.join(copy_dir_local, release_file), onhost_copy_base
705
+
706
+ case variant
707
+ when /^(fedora|el|centos)$/
708
+ on host, "rpm -ivh #{onhost_copied_file}"
709
+ when /^(debian|ubuntu|cumulus)$/
710
+ on host, "dpkg -i --force-all #{onhost_copied_file}"
711
+ on host, "apt-get update"
712
+ when /^windows$/
713
+ result = on host, "echo #{onhost_copied_file}"
714
+ onhost_copied_file = result.raw_output.chomp
715
+ on host, Command.new("start /w #{onhost_copied_file}", [], { :cmdexe => true })
716
+ end
717
+ end
718
+
719
+ end
720
+ end
721
+ end
722
+ end