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,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