beaker-puppet 0.1.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 (52) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +25 -0
  3. data/.simplecov +9 -0
  4. data/Gemfile +25 -0
  5. data/HISTORY.md +8 -0
  6. data/LICENSE +202 -0
  7. data/README.md +55 -0
  8. data/Rakefile +299 -0
  9. data/acceptance/config/acceptance-options.rb +6 -0
  10. data/acceptance/config/gem/acceptance-options.rb +9 -0
  11. data/acceptance/config/git/acceptance-options.rb +9 -0
  12. data/acceptance/config/nodes/vagrant-ubuntu-1404.yml +8 -0
  13. data/acceptance/config/pkg/acceptance-options.rb +8 -0
  14. data/acceptance/lib/beaker/acceptance/install_utils.rb +58 -0
  15. data/acceptance/pre_suite/gem/install.rb +8 -0
  16. data/acceptance/pre_suite/git/install.rb +97 -0
  17. data/acceptance/pre_suite/pkg/install.rb +9 -0
  18. data/acceptance/tests/README.md +3 -0
  19. data/acceptance/tests/backwards_compatible.rb +19 -0
  20. data/acceptance/tests/install_smoke_test.rb +21 -0
  21. data/acceptance/tests/stub_host.rb +47 -0
  22. data/acceptance/tests/web_helpers_test.rb +54 -0
  23. data/acceptance/tests/with_puppet_running_on.rb +26 -0
  24. data/beaker-puppet.gemspec +38 -0
  25. data/bin/beaker-puppet +32 -0
  26. data/lib/beaker-puppet.rb +46 -0
  27. data/lib/beaker-puppet/helpers/facter_helpers.rb +57 -0
  28. data/lib/beaker-puppet/helpers/puppet_helpers.rb +865 -0
  29. data/lib/beaker-puppet/helpers/tk_helpers.rb +89 -0
  30. data/lib/beaker-puppet/install_utils/aio_defaults.rb +93 -0
  31. data/lib/beaker-puppet/install_utils/ezbake_utils.rb +256 -0
  32. data/lib/beaker-puppet/install_utils/foss_defaults.rb +211 -0
  33. data/lib/beaker-puppet/install_utils/foss_utils.rb +1309 -0
  34. data/lib/beaker-puppet/install_utils/module_utils.rb +244 -0
  35. data/lib/beaker-puppet/install_utils/puppet_utils.rb +157 -0
  36. data/lib/beaker-puppet/version.rb +3 -0
  37. data/lib/beaker-puppet/wrappers.rb +93 -0
  38. data/lib/beaker/dsl/helpers/facter_helpers.rb +1 -0
  39. data/lib/beaker/dsl/helpers/puppet_helpers.rb +1 -0
  40. data/lib/beaker/dsl/helpers/tk_helpers.rb +1 -0
  41. data/lib/beaker/dsl/install_utils/aio_defaults.rb +1 -0
  42. data/lib/beaker/dsl/install_utils/ezbake_utils.rb +1 -0
  43. data/lib/beaker/dsl/install_utils/foss_defaults.rb +1 -0
  44. data/lib/beaker/dsl/install_utils/foss_utils.rb +1 -0
  45. data/lib/beaker/dsl/install_utils/module_utils.rb +1 -0
  46. data/lib/beaker/dsl/install_utils/puppet_utils.rb +1 -0
  47. data/spec/beaker-puppet/helpers/facter_helpers_spec.rb +64 -0
  48. data/spec/beaker-puppet/helpers/puppet_helpers_spec.rb +1287 -0
  49. data/spec/beaker-puppet/helpers/tk_helpers_spec.rb +86 -0
  50. data/spec/helpers.rb +109 -0
  51. data/spec/spec_helper.rb +23 -0
  52. metadata +249 -0
@@ -0,0 +1,1309 @@
1
+ require "beaker/dsl/install_utils/windows_utils"
2
+ [ 'aio', 'foss' ].each do |lib|
3
+ require "beaker-puppet/install_utils/#{lib}_defaults"
4
+ end
5
+ require "beaker-puppet/install_utils/puppet_utils"
6
+ module Beaker
7
+ module DSL
8
+ module InstallUtils
9
+ #
10
+ # This module contains methods to install FOSS puppet from various sources
11
+ #
12
+ # To mix this is into a class you need the following:
13
+ # * a method *hosts* that yields any hosts implementing
14
+ # {Beaker::Host}'s interface to act upon.
15
+ # * a method *options* that provides an options hash, see {Beaker::Options::OptionsHash}
16
+ # * the module {Beaker::DSL::Roles} that provides access to the various hosts implementing
17
+ # {Beaker::Host}'s interface to act upon
18
+ # * the module {Beaker::DSL::Wrappers} the provides convenience methods for {Beaker::DSL::Command} creation
19
+ module FOSSUtils
20
+ include AIODefaults
21
+ include FOSSDefaults
22
+ include PuppetUtils
23
+ include WindowsUtils
24
+
25
+ # The default install path
26
+ SourcePath = "/opt/puppet-git-repos"
27
+
28
+ # A regex to know if the uri passed is pointing to a git repo
29
+ GitURI = %r{^(git|https?|file)://|^git@|^gitmirror@}
30
+
31
+ # Github's ssh signature for cloning via ssh
32
+ GitHubSig = 'github.com,207.97.227.239 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ=='
33
+
34
+ # lookup project-specific git environment variables
35
+ # PROJECT_VAR or VAR otherwise return the default
36
+ #
37
+ # @!visibility private
38
+ def lookup_in_env(env_variable_name, project_name=nil, default=nil)
39
+ env_variable_name = "#{env_variable_name.upcase.gsub('-','_')}"
40
+ project_specific_name = "#{project_name.upcase.gsub('-','_')}_#{env_variable_name}" if project_name
41
+ project_name && ENV[project_specific_name] || ENV[env_variable_name] || default
42
+ end
43
+
44
+ # @param [String] project_name
45
+ # @param [String] git_fork When not provided will use PROJECT_FORK environment variable
46
+ # @param [String] git_server When not provided will use PROJECT_SERVER environment variable
47
+ # @param [String] git_protocol 'git','ssh','https'
48
+ #
49
+ # @return [String] Returns a git-usable url
50
+ #
51
+ # TODO: enable other protocols, clarify, http://git-scm.com/book/ch4-1.html
52
+ def build_git_url(project_name, git_fork = nil, git_server = nil, git_protocol='https')
53
+ git_fork ||= lookup_in_env('FORK', project_name, 'puppetlabs')
54
+ git_server ||= lookup_in_env('SERVER', project_name, 'github.com')
55
+
56
+ case git_protocol
57
+ when /(ssh|git)/
58
+ git_protocol = 'git@'
59
+ when /https/
60
+ git_protocol = 'https://'
61
+ end
62
+
63
+ repo = (git_server == 'github.com') ? "#{git_fork}/#{project_name}.git" : "#{git_fork}-#{project_name}.git"
64
+ return git_protocol == 'git@' ? "#{git_protocol}#{git_server}:#{repo}" : "#{git_protocol}#{git_server}/#{repo}"
65
+ end
66
+ alias_method :build_giturl, :build_git_url
67
+
68
+ # @param [String] uri A uri in the format of <git uri>#<revision>
69
+ # the `git://`, `http://`, `https://`, and ssh
70
+ # (if cloning as the remote git user) protocols
71
+ # are valid for <git uri>
72
+ #
73
+ # @example Usage
74
+ # project = extract_repo_info_from 'git@github.com:puppetlabs/SuperSecretSauce#what_is_justin_doing'
75
+ #
76
+ # puts project[:name]
77
+ # #=> 'SuperSecretSauce'
78
+ #
79
+ # puts project[:rev]
80
+ # #=> 'what_is_justin_doing'
81
+ #
82
+ # @return [Hash{Symbol=>String}] Returns a hash containing the project
83
+ # name, repository path, and revision
84
+ # (defaults to HEAD)
85
+ #
86
+ def extract_repo_info_from uri
87
+ require 'pathname'
88
+ project = {}
89
+ repo, rev = uri.split('#', 2)
90
+ project[:name] = Pathname.new(repo).basename('.git').to_s
91
+ project[:path] = repo
92
+ project[:rev] = rev || 'HEAD'
93
+ return project
94
+ end
95
+
96
+ # Takes an array of package info hashes (like that returned from
97
+ # {#extract_repo_info_from}) and sorts the `puppet`, `facter`, `hiera`
98
+ # packages so that puppet's dependencies will be installed first.
99
+ #
100
+ # @!visibility private
101
+ def order_packages packages_array
102
+ puppet = packages_array.select {|e| e[:name] == 'puppet' }
103
+ puppet_depends_on = packages_array.select do |e|
104
+ e[:name] == 'hiera' or e[:name] == 'facter'
105
+ end
106
+ depends_on_puppet = (packages_array - puppet) - puppet_depends_on
107
+ [puppet_depends_on, puppet, depends_on_puppet].flatten
108
+ end
109
+
110
+ # @param [Host] host An object implementing {Beaker::Hosts}'s
111
+ # interface.
112
+ # @param [String] path The path on the remote [host] to the repository
113
+ # @param [Hash{Symbol=>String}] repository A hash representing repo
114
+ # info like that emitted by
115
+ # {#extract_repo_info_from}
116
+ #
117
+ # @example Getting multiple project versions
118
+ # versions = [puppet_repo, facter_repo, hiera_repo].inject({}) do |vers, repo_info|
119
+ # vers.merge(find_git_repo_versions(host, '/opt/git-puppet-repos', repo_info) )
120
+ # end
121
+ # @return [Hash] Executes git describe on [host] and returns a Hash
122
+ # with the key of [repository[:name]] and value of
123
+ # the output from git describe.
124
+ #
125
+ # @note This requires the helper methods:
126
+ # * {Beaker::DSL::Helpers#on}
127
+ #
128
+ def find_git_repo_versions host, path, repository
129
+ logger.notify("\n * Grab version for #{repository[:name]}")
130
+
131
+ version = {}
132
+ on host, "cd #{path}/#{repository[:name]} && " +
133
+ "git describe || true" do
134
+ version[repository[:name]] = stdout.chomp
135
+ end
136
+
137
+ version
138
+ end
139
+
140
+ # @param [Host] host An object implementing {Beaker::Hosts}'s
141
+ # interface.
142
+ # @param [String] path The path on the remote [host] to the repository
143
+ # @param [Hash{Symbol=>String}] repository A hash representing repo
144
+ # info like that emitted by
145
+ # {#extract_repo_info_from}
146
+ #
147
+ # @note This requires the helper methods:
148
+ # * {Beaker::DSL::Helpers#on}
149
+ #
150
+ def clone_git_repo_on host, path, repository, opts = {}
151
+ opts = {:accept_all_exit_codes => true}.merge(opts)
152
+ name = repository[:name]
153
+ repo = repository[:path]
154
+ rev = repository[:rev]
155
+ depth = repository[:depth]
156
+ depth_branch = repository[:depth_branch]
157
+ target = "#{path}/#{name}"
158
+
159
+ if (depth_branch.nil?)
160
+ depth_branch = rev
161
+ end
162
+
163
+ clone_cmd = "git clone #{repo} #{target}"
164
+ if (depth)
165
+ clone_cmd = "git clone --branch #{depth_branch} --depth #{depth} #{repo} #{target}"
166
+ end
167
+
168
+ logger.notify("\n * Clone #{repo} if needed")
169
+
170
+ on host, "test -d #{path} || mkdir -p #{path}", opts
171
+ on host, "test -d #{target} || #{clone_cmd}", opts
172
+
173
+ logger.notify("\n * Update #{name} and check out revision #{rev}")
174
+ commands = ["cd #{target}",
175
+ "remote rm origin",
176
+ "remote add origin #{repo}",
177
+ "fetch origin +refs/pull/*:refs/remotes/origin/pr/* +refs/heads/*:refs/remotes/origin/*",
178
+ "clean -fdx",
179
+ "checkout -f #{rev}"]
180
+ on host, commands.join(" && git "), opts
181
+ end
182
+
183
+ # @see #find_git_repo_versions
184
+ # @note This assumes the target repository application
185
+ # can be installed via an install.rb ruby script.
186
+ def install_from_git_on host, path, repository, opts = {}
187
+ opts = {:accept_all_exit_codes => true}.merge(opts)
188
+ clone_git_repo_on host, path, repository, opts
189
+ name = repository[:name]
190
+ logger.notify("\n * Install #{name} on the system")
191
+ # The solaris ruby IPS package has bindir set to /usr/ruby/1.8/bin.
192
+ # However, this is not the path to which we want to deliver our
193
+ # binaries. So if we are using solaris, we have to pass the bin and
194
+ # sbin directories to the install.rb
195
+ target = "#{path}/#{name}"
196
+ install_opts = ''
197
+ install_opts = '--bindir=/usr/bin --sbindir=/usr/sbin' if host['platform'].include? 'solaris'
198
+
199
+ on host, "cd #{target} && " +
200
+ "if [ -f install.rb ]; then " +
201
+ "ruby ./install.rb #{install_opts}; " +
202
+ "else true; fi", opts
203
+ end
204
+ alias_method :install_from_git, :install_from_git_on
205
+
206
+ # @deprecated Use {#install_puppet_on} instead.
207
+ def install_puppet(opts = {})
208
+ #send in the global hosts!
209
+ install_puppet_on(hosts, opts)
210
+ end
211
+
212
+ #Install FOSS based on specified hosts using provided options
213
+ # @example will install puppet 3.6.1 from native puppetlabs provided packages wherever possible and will fail over to gem installation when impossible
214
+ # install_puppet_on(hosts, {
215
+ # :version => '3.6.1',
216
+ # :facter_version => '2.0.1',
217
+ # :hiera_version => '1.3.3',
218
+ # :default_action => 'gem_install',
219
+ # })
220
+ #
221
+ # @example will install puppet 4 from native puppetlabs provided puppet-agent 1.x package wherever possible and will fail over to gem installation when impossible
222
+ # install_puppet({
223
+ # :version => '4',
224
+ # :default_action => 'gem_install'
225
+ # })
226
+ #
227
+ # @example will install puppet 4.1.0 from native puppetlabs provided puppet-agent 1.1.0 package wherever possible and will fail over to gem installation when impossible
228
+ # install_puppet({
229
+ # :version => '4.1.0',
230
+ # :puppet_agent_version => '1.1.0',
231
+ # :default_action => 'gem_install'
232
+ # })
233
+ #
234
+ #
235
+ #
236
+ # @example Will install latest packages on Enterprise Linux and Debian based distros and fail hard on all othere platforms.
237
+ # install_puppet_on(hosts)
238
+ #
239
+ # @note This will attempt to add a repository for apt.puppetlabs.com on
240
+ # Debian, Ubuntu, or Cumulus machines, or yum.puppetlabs.com on EL or Fedora
241
+ # machines, then install the package 'puppet' or 'puppet-agent'.
242
+ #
243
+ # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
244
+ # or a role (String or Symbol) that identifies one or more hosts.
245
+ # @param [Hash{Symbol=>String}] opts
246
+ # @option opts [String] :version Version of puppet to download
247
+ # @option opts [String] :puppet_agent_version Version of puppet agent to download
248
+ # @option opts [String] :mac_download_url Url to download msi pattern of %url%/puppet-%version%.msi
249
+ # @option opts [String] :win_download_url Url to download dmg pattern of %url%/(puppet|hiera|facter)-%version%.msi
250
+ # @option opts [Boolean] :run_in_parallel Whether to install on all hosts in parallel. Defaults to false.
251
+ #
252
+ # @return nil
253
+ # @raise [StandardError] When encountering an unsupported platform by default, or if gem cannot be found when default_action => 'gem_install'
254
+ # @raise [FailTest] When error occurs during the actual installation process
255
+ def install_puppet_on(hosts, opts={})
256
+ opts = FOSS_DEFAULT_DOWNLOAD_URLS.merge(opts)
257
+
258
+ # If version isn't specified assume the latest in the 3.x series
259
+ if opts[:version] and not version_is_less(opts[:version], '4.0.0')
260
+ # backwards compatability
261
+ opts[:puppet_agent_version] ||= opts[:version]
262
+ install_puppet_agent_on(hosts, opts)
263
+ else
264
+ # Use option specified in the method call, otherwise check whether the global
265
+ # run_in_parallel option includes install
266
+ run_in_parallel = run_in_parallel? opts, @options, 'install'
267
+ block_on hosts, { :run_in_parallel => run_in_parallel } do |host|
268
+ if host['platform'] =~ /el-(5|6|7)/
269
+ relver = $1
270
+ install_puppet_from_rpm_on(host, opts.merge(:release => relver, :family => 'el'))
271
+ elsif host['platform'] =~ /fedora-(\d+)/
272
+ relver = $1
273
+ install_puppet_from_rpm_on(host, opts.merge(:release => relver, :family => 'fedora'))
274
+ elsif host['platform'] =~ /(ubuntu|debian|cumulus|huaweios)/
275
+ install_puppet_from_deb_on(host, opts)
276
+ elsif host['platform'] =~ /windows/
277
+ relver = opts[:version]
278
+ install_puppet_from_msi_on(host, opts)
279
+ elsif host['platform'] =~ /osx/
280
+ install_puppet_from_dmg_on(host, opts)
281
+ elsif host['platform'] =~ /openbsd/
282
+ install_puppet_from_openbsd_packages_on(host, opts)
283
+ elsif host['platform'] =~ /freebsd/
284
+ install_puppet_from_freebsd_ports_on(host, opts)
285
+ elsif host['platform'] =~ /archlinux/
286
+ install_puppet_from_pacman_on(host, opts)
287
+ else
288
+ if opts[:default_action] == 'gem_install'
289
+ opts[:version] ||= '~> 3.x'
290
+ install_puppet_from_gem_on(host, opts)
291
+ else
292
+ raise "install_puppet() called for unsupported platform '#{host['platform']}' on '#{host.name}'"
293
+ end
294
+ end
295
+
296
+ host[:version] = opts[:version]
297
+
298
+ # Certain install paths may not create the config dirs/files needed
299
+ host.mkdir_p host['puppetpath'] unless host[:type] =~ /aio/
300
+
301
+ if ((host['platform'] =~ /windows/) and not host.is_cygwin?)
302
+ # Do nothing
303
+ else
304
+ on host, "echo '' >> #{host.puppet['hiera_config']}"
305
+ end
306
+ end
307
+ end
308
+
309
+ nil
310
+ end
311
+
312
+ #Install Puppet Agent based on specified hosts using provided options
313
+ # @example will install puppet-agent 1.1.0 from native puppetlabs provided packages wherever possible and will fail over to gem installing latest puppet
314
+ # install_puppet_agent_on(hosts, {
315
+ # :puppet_agent_version => '1.1.0',
316
+ # :default_action => 'gem_install',
317
+ # })
318
+ #
319
+ #
320
+ # @example Will install latest packages on Enterprise Linux, Debian based distros, Windows, OSX and fail hard on all othere platforms.
321
+ # install_puppet_agent_on(hosts)
322
+ #
323
+ # @note This will attempt to add a repository for apt.puppetlabs.com on
324
+ # Debian, Ubuntu, or Cumulus machines, or yum.puppetlabs.com on EL or Fedora
325
+ # machines, then install the package 'puppet-agent'.
326
+ #
327
+ # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
328
+ # or a role (String or Symbol) that identifies one or more hosts.
329
+ # @param [Hash{Symbol=>String}] opts
330
+ # @option opts [String] :puppet_agent_version Version of puppet to download
331
+ # @option opts [String] :puppet_gem_version Version of puppet to install via gem if no puppet-agent package is available
332
+ # @option opts [String] :mac_download_url Url to download msi pattern of %url%/puppet-agent-%version%.msi
333
+ # @option opts [String] :win_download_url Url to download dmg pattern of %url%/puppet-agent-%version%.msi
334
+ # @option opts [String] :puppet_collection Defaults to 'pc1'
335
+ # @option opts [Boolean] :run_in_parallel Whether to run on each host in parallel.
336
+ #
337
+ # @return nil
338
+ # @raise [StandardError] When encountering an unsupported platform by default, or if gem cannot be found when default_action => 'gem_install'
339
+ # @raise [FailTest] When error occurs during the actual installation process
340
+ def install_puppet_agent_on(hosts, opts = {})
341
+ opts = FOSS_DEFAULT_DOWNLOAD_URLS.merge(opts)
342
+ opts[:puppet_collection] ||= 'pc1' #hi! i'm case sensitive! be careful!
343
+ opts[:puppet_agent_version] ||= opts[:version] #backwards compatability with old parameter name
344
+
345
+ run_in_parallel = run_in_parallel? opts, @options, 'install'
346
+ block_on hosts, { :run_in_parallel => run_in_parallel } do |host|
347
+ add_role(host, 'aio') #we are installing agent, so we want aio role
348
+ package_name = nil
349
+ case host['platform']
350
+ when /el-|fedora|sles|centos|cisco_/
351
+ package_name = 'puppet-agent'
352
+ package_name << "-#{opts[:puppet_agent_version]}" if opts[:puppet_agent_version]
353
+ when /debian|ubuntu|cumulus|huaweios/
354
+ package_name = 'puppet-agent'
355
+ package_name << "=#{opts[:puppet_agent_version]}-1#{host['platform'].codename}" if opts[:puppet_agent_version]
356
+ when /windows/
357
+ install_puppet_agent_from_msi_on(host, opts)
358
+ when /osx/
359
+ install_puppet_agent_from_dmg_on(host, opts)
360
+ else
361
+ if opts[:default_action] == 'gem_install'
362
+ opts[:version] = opts[:puppet_gem_version]
363
+ install_puppet_from_gem_on(host, opts)
364
+ on host, "echo '' >> #{host.puppet['hiera_config']}"
365
+ else
366
+ raise "install_puppet_agent_on() called for unsupported " +
367
+ "platform '#{host['platform']}' on '#{host.name}'"
368
+ end
369
+ end
370
+
371
+ if package_name
372
+ install_puppetlabs_release_repo( host, opts[:puppet_collection] )
373
+ host.install_package( package_name )
374
+ end
375
+ end
376
+ end
377
+
378
+ # @deprecated Use {#configure_puppet_on} instead.
379
+ def configure_puppet(opts={})
380
+ hosts.each do |host|
381
+ configure_puppet_on(host,opts)
382
+ end
383
+ end
384
+
385
+ # Configure puppet.conf on the given host(s) based upon a provided hash
386
+ # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
387
+ # or a role (String or Symbol) that identifies one or more hosts.
388
+ # @param [Hash{Symbol=>String}] opts
389
+ # @option opts [Hash{String=>String}] :main configure the main section of puppet.conf
390
+ # @option opts [Hash{String=>String}] :agent configure the agent section of puppet.conf
391
+ # @option opts [Boolean] :run_in_parallel Whether to run on each host in parallel.
392
+ #
393
+ # @example will configure /etc/puppet.conf on the puppet master.
394
+ # config = {
395
+ # 'main' => {
396
+ # 'server' => 'testbox.test.local',
397
+ # 'certname' => 'testbox.test.local',
398
+ # 'logdir' => '/var/log/puppet',
399
+ # 'vardir' => '/var/lib/puppet',
400
+ # 'ssldir' => '/var/lib/puppet/ssl',
401
+ # 'rundir' => '/var/run/puppet'
402
+ # },
403
+ # 'agent' => {
404
+ # 'environment' => 'dev'
405
+ # }
406
+ # }
407
+ # configure_puppet_on(master, config)
408
+ #
409
+ # @return nil
410
+ def configure_puppet_on(hosts, opts = {})
411
+ puppet_conf_text = ''
412
+ opts.each do |section,options|
413
+ puppet_conf_text << "[#{section}]\n"
414
+ options.each do |option,value|
415
+ puppet_conf_text << "#{option}=#{value}\n"
416
+ end
417
+ puppet_conf_text << "\n"
418
+ end
419
+ logger.debug( "setting config '#{puppet_conf_text}' on hosts #{hosts}" )
420
+ block_on hosts, opts do |host|
421
+ puppet_conf_path = host.puppet['config']
422
+ create_remote_file(host, puppet_conf_path, puppet_conf_text)
423
+ end
424
+ end
425
+
426
+ # Installs Puppet and dependencies using rpm on provided host(s).
427
+ #
428
+ # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
429
+ # or a role (String or Symbol) that identifies one or more hosts.
430
+ # @param [Hash{Symbol=>String}] opts An options hash
431
+ # @option opts [String] :version The version of Puppet to install, if nil installs latest version
432
+ # @option opts [String] :facter_version The version of Facter to install, if nil installs latest version
433
+ # @option opts [String] :hiera_version The version of Hiera to install, if nil installs latest version
434
+ # @option opts [String] :release The major release of the OS
435
+ # @option opts [String] :family The OS family (one of 'el' or 'fedora')
436
+ #
437
+ # @return nil
438
+ # @api private
439
+ def install_puppet_from_rpm_on( hosts, opts )
440
+ block_on hosts do |host|
441
+ if host[:type] == 'aio'
442
+ install_puppetlabs_release_repo(host,'pc1',opts)
443
+ else
444
+ install_puppetlabs_release_repo(host,nil,opts)
445
+ end
446
+
447
+ if opts[:facter_version]
448
+ host.install_package("facter-#{opts[:facter_version]}")
449
+ end
450
+
451
+ if opts[:hiera_version]
452
+ host.install_package("hiera-#{opts[:hiera_version]}")
453
+ end
454
+
455
+ puppet_pkg = opts[:version] ? "puppet-#{opts[:version]}" : 'puppet'
456
+ host.install_package("#{puppet_pkg}")
457
+ configure_type_defaults_on( host )
458
+ end
459
+ end
460
+ alias_method :install_puppet_from_rpm, :install_puppet_from_rpm_on
461
+
462
+ # Installs Puppet and dependencies from deb on provided host(s).
463
+ #
464
+ # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
465
+ # or a role (String or Symbol) that identifies one or more hosts.
466
+ # @param [Hash{Symbol=>String}] opts An options hash
467
+ # @option opts [String] :version The version of Puppet to install, if nil installs latest version
468
+ # @option opts [String] :facter_version The version of Facter to install, if nil installs latest version
469
+ # @option opts [String] :hiera_version The version of Hiera to install, if nil installs latest version
470
+ #
471
+ # @return nil
472
+ # @api private
473
+ def install_puppet_from_deb_on( hosts, opts )
474
+ block_on hosts do |host|
475
+ install_puppetlabs_release_repo(host)
476
+
477
+ if opts[:facter_version]
478
+ host.install_package("facter=#{opts[:facter_version]}-1puppetlabs1")
479
+ end
480
+
481
+ if opts[:hiera_version]
482
+ host.install_package("hiera=#{opts[:hiera_version]}-1puppetlabs1")
483
+ end
484
+
485
+ if opts[:version]
486
+ host.install_package("puppet-common=#{opts[:version]}-1puppetlabs1")
487
+ host.install_package("puppet=#{opts[:version]}-1puppetlabs1")
488
+ else
489
+ host.install_package('puppet')
490
+ end
491
+ configure_type_defaults_on( host )
492
+ end
493
+ end
494
+ alias_method :install_puppet_from_deb, :install_puppet_from_deb_on
495
+
496
+ # Installs Puppet and dependencies from msi on provided host(s).
497
+ #
498
+ # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
499
+ # or a role (String or Symbol) that identifies one or more hosts.
500
+ # @param [Hash{Symbol=>String}] opts An options hash
501
+ # @option opts [String] :version The version of Puppet to install
502
+ # @option opts [String] :puppet_agent_version The version of the
503
+ # puppet-agent package to install, required if version is 4.0.0 or greater
504
+ # @option opts [String] :win_download_url The url to download puppet from
505
+ #
506
+ # @note on windows, the +:ruby_arch+ host parameter can determine in addition
507
+ # to other settings whether the 32 or 64bit install is used
508
+ def install_puppet_from_msi_on( hosts, opts )
509
+ block_on hosts do |host|
510
+ version = opts[:version]
511
+
512
+ if version && !version_is_less(version, '4.0.0')
513
+ if opts[:puppet_agent_version].nil?
514
+ raise "You must specify the version of puppet agent you " +
515
+ "want to install if you want to install Puppet 4.0 " +
516
+ "or greater on Windows"
517
+ end
518
+
519
+ opts[:version] = opts[:puppet_agent_version]
520
+ install_puppet_agent_from_msi_on(host, opts)
521
+
522
+ else
523
+ compute_puppet_msi_name(host, opts)
524
+ install_a_puppet_msi_on(host, opts)
525
+
526
+ end
527
+ configure_type_defaults_on( host )
528
+ end
529
+ end
530
+ alias_method :install_puppet_from_msi, :install_puppet_from_msi_on
531
+
532
+ # @api private
533
+ def compute_puppet_msi_name(host, opts)
534
+ version = opts[:version]
535
+ install_32 = host['install_32'] || opts['install_32']
536
+ less_than_3_dot_7 = version && version_is_less(version, '3.7')
537
+
538
+ # If there's no version declared, install the latest in the 3.x series
539
+ if not version
540
+ if !host.is_x86_64? || install_32
541
+ host['dist'] = 'puppet-latest'
542
+ else
543
+ host['dist'] = 'puppet-x64-latest'
544
+ end
545
+
546
+ # Install Puppet 3.x with the x86 installer if:
547
+ # - we are on puppet < 3.7, or
548
+ # - we are less than puppet 4.0 and on an x86 host, or
549
+ # - we have install_32 set on host or globally
550
+ # Install Puppet 3.x with the x64 installer if:
551
+ # - we are otherwise trying to install Puppet 3.x on a x64 host
552
+ elsif less_than_3_dot_7 or not host.is_x86_64? or install_32
553
+ host['dist'] = "puppet-#{version}"
554
+
555
+ elsif host.is_x86_64?
556
+ host['dist'] = "puppet-#{version}-x64"
557
+
558
+ else
559
+ raise "I don't understand how to install Puppet version: #{version}"
560
+ end
561
+ end
562
+
563
+ # Installs Puppet Agent and dependencies from msi on provided host(s).
564
+ #
565
+ # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
566
+ # or a role (String or Symbol) that identifies one or more hosts.
567
+ # @param [Hash{Symbol=>String}] opts An options hash
568
+ # @option opts [String] :puppet_agent_version The version of Puppet Agent to install
569
+ # @option opts [String] :win_download_url The url to download puppet from
570
+ #
571
+ # @note on windows, the +:ruby_arch+ host parameter can determine in addition
572
+ # to other settings whether the 32 or 64bit install is used
573
+ def install_puppet_agent_from_msi_on(hosts, opts)
574
+ block_on hosts do |host|
575
+
576
+ add_role(host, 'aio') #we are installing agent, so we want aio role
577
+ is_config_32 = true == (host['ruby_arch'] == 'x86') || host['install_32'] || opts['install_32']
578
+ should_install_64bit = host.is_x86_64? && !is_config_32
579
+ arch = should_install_64bit ? 'x64' : 'x86'
580
+
581
+ # If we don't specify a version install the latest MSI for puppet-agent
582
+ if opts[:puppet_agent_version]
583
+ host['dist'] = "puppet-agent-#{opts[:puppet_agent_version]}-#{arch}"
584
+ else
585
+ host['dist'] = "puppet-agent-#{arch}-latest"
586
+ end
587
+
588
+ install_a_puppet_msi_on(host, opts)
589
+ end
590
+ end
591
+
592
+ # @api private
593
+ def install_a_puppet_msi_on(hosts, opts)
594
+ block_on hosts do |host|
595
+ link = "#{opts[:win_download_url]}/#{host['dist']}.msi"
596
+ if not link_exists?( link )
597
+ raise "Puppet MSI at #{link} does not exist!"
598
+ end
599
+
600
+
601
+ msi_download_path = "#{host.system_temp_path}\\#{host['dist']}.msi"
602
+
603
+ if host.is_cygwin?
604
+ # NOTE: it is critical that -o be before -O on Windows
605
+ on host, "curl -o \"#{msi_download_path}\" -O #{link}"
606
+
607
+ #Because the msi installer doesn't add Puppet to the environment path
608
+ #Add both potential paths for simplicity
609
+ #NOTE - this is unnecessary if the host has been correctly identified as 'foss' during set up
610
+ puppetbin_path = "\"/cygdrive/c/Program Files (x86)/Puppet Labs/Puppet/bin\":\"/cygdrive/c/Program Files/Puppet Labs/Puppet/bin\""
611
+ on host, %Q{ echo 'export PATH=$PATH:#{puppetbin_path}' > /etc/bash.bashrc }
612
+ else
613
+ on host, powershell("$webclient = New-Object System.Net.WebClient; $webclient.DownloadFile('#{link}','#{msi_download_path}')")
614
+ end
615
+
616
+ opts = { :debug => host[:pe_debug] || opts[:pe_debug] }
617
+ install_msi_on(host, msi_download_path, {}, opts)
618
+
619
+ configure_type_defaults_on( host )
620
+ if not host.is_cygwin?
621
+ host.mkdir_p host['distmoduledir']
622
+ end
623
+ end
624
+ end
625
+
626
+ # Installs Puppet and dependencies from FreeBSD ports
627
+ #
628
+ # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
629
+ # or a role (String or Symbol) that identifies one or more hosts.
630
+ # @param [Hash{Symbol=>String}] opts An options hash
631
+ # @option opts [String] :version The version of Puppet to install (shows warning)
632
+ #
633
+ # @return nil
634
+ # @api private
635
+ def install_puppet_from_freebsd_ports_on( hosts, opts )
636
+ if (opts[:version])
637
+ logger.warn "If you wish to choose a specific Puppet version, use `install_puppet_from_gem_on('~> 3.*')`"
638
+ end
639
+
640
+ block_on hosts do |host|
641
+ if host['platform'] =~ /freebsd-9/
642
+ host.install_package("puppet")
643
+ else
644
+ host.install_package("sysutils/puppet")
645
+ end
646
+ end
647
+
648
+ end
649
+ alias_method :install_puppet_from_freebsd_ports, :install_puppet_from_freebsd_ports_on
650
+
651
+ # Installs Puppet and dependencies from dmg on provided host(s).
652
+ #
653
+ # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
654
+ # or a role (String or Symbol) that identifies one or more hosts.
655
+ # @param [Hash{Symbol=>String}] opts An options hash
656
+ # @option opts [String] :version The version of Puppet to install
657
+ # @option opts [String] :puppet_version The version of puppet-agent to install
658
+ # @option opts [String] :facter_version The version of Facter to install
659
+ # @option opts [String] :hiera_version The version of Hiera to install
660
+ # @option opts [String] :mac_download_url Url to download msi pattern of %url%/puppet-%version%.msi
661
+ #
662
+ # @return nil
663
+ # @api private
664
+ def install_puppet_from_dmg_on( hosts, opts )
665
+ block_on hosts do |host|
666
+ # install puppet-agent if puppet version > 4.0 OR not puppet version is provided
667
+ if (opts[:version] && !version_is_less(opts[:version], '4.0.0')) || !opts[:version]
668
+ if opts[:puppet_agent_version].nil?
669
+ raise "You must specify the version of puppet-agent you " +
670
+ "want to install if you want to install Puppet 4.0 " +
671
+ "or greater on OSX"
672
+ end
673
+
674
+ install_puppet_agent_from_dmg_on(host, opts)
675
+
676
+ else
677
+ puppet_ver = opts[:version] || 'latest'
678
+ facter_ver = opts[:facter_version] || 'latest'
679
+ hiera_ver = opts[:hiera_version] || 'latest'
680
+
681
+ if [puppet_ver, facter_ver, hiera_ver].include?(nil)
682
+ 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',})"
683
+ end
684
+
685
+ on host, "curl -O #{opts[:mac_download_url]}/puppet-#{puppet_ver}.dmg"
686
+ on host, "curl -O #{opts[:mac_download_url]}/facter-#{facter_ver}.dmg"
687
+ on host, "curl -O #{opts[:mac_download_url]}/hiera-#{hiera_ver}.dmg"
688
+
689
+ host.install_package("puppet-#{puppet_ver}")
690
+ host.install_package("facter-#{facter_ver}")
691
+ host.install_package("hiera-#{hiera_ver}")
692
+
693
+ configure_type_defaults_on( host )
694
+ end
695
+ end
696
+ end
697
+ alias_method :install_puppet_from_dmg, :install_puppet_from_dmg_on
698
+
699
+ # Installs puppet-agent and dependencies from dmg on provided host(s).
700
+ #
701
+ # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
702
+ # or a role (String or Symbol) that identifies one or more hosts.
703
+ # @param [Hash{Symbol=>String}] opts An options hash
704
+ # @option opts [String] :puppet_agent_version The version of Puppet Agent to install, defaults to latest
705
+ # @option opts [String] :mac_download_url Url to download msi pattern of %url%/puppet-%version%.dmg
706
+ # @option opts [String] :puppet_collection Defaults to 'PC1'
707
+ #
708
+ # @return nil
709
+ # @api private
710
+ def install_puppet_agent_from_dmg_on(hosts, opts)
711
+ opts[:puppet_collection] ||= 'PC1'
712
+ opts[:puppet_collection] = opts[:puppet_collection].upcase #needs to be upcase, more lovely consistency
713
+ block_on hosts do |host|
714
+
715
+ add_role(host, 'aio') #we are installing agent, so we want aio role
716
+
717
+ variant, version, arch, codename = host['platform'].to_array
718
+
719
+ download_url = "#{opts[:mac_download_url]}/#{version}/#{opts[:puppet_collection]}/#{arch}"
720
+
721
+ latest = get_latest_puppet_agent_build_from_url(download_url)
722
+
723
+ agent_version = opts[:puppet_agent_version] || latest
724
+ unless agent_version.length > 0
725
+ raise "no puppet-agent version specified or found on at #{download_url}"
726
+ end
727
+
728
+ pkg_name = "puppet-agent-#{agent_version}*"
729
+ dmg_name = "puppet-agent-#{agent_version}-1.osx#{version}.dmg"
730
+ on host, "curl -O #{download_url}/#{dmg_name}"
731
+
732
+ host.install_package(pkg_name)
733
+
734
+ configure_type_defaults_on( host )
735
+ end
736
+ end
737
+
738
+ # Returns the latest puppet-agent version number from a given url.
739
+ #
740
+ # @param [String] url URL containing list of puppet-agent packages.
741
+ # Example: https://downloads.puppetlabs.com/mac/10.11/PC1/x86_64
742
+ #
743
+ # @return [String] version puppet-agent version number (e.g. 1.4.1)
744
+ # Empty string if none found.
745
+ # @api private
746
+ def get_latest_puppet_agent_build_from_url(url)
747
+ require 'nokogiri'
748
+ require 'open-uri'
749
+ page = Nokogiri::HTML(open("#{url}/?C=M;O=A"))
750
+ agents = page.css('a').children.select{ |link| link.to_s.include? 'puppet-agent' }
751
+ re = /puppet-agent-(.*)-1/
752
+ latest_match = agents[-1].to_s.match re
753
+ if latest_match
754
+ latest = latest_match[1]
755
+ else
756
+ latest = ''
757
+ end
758
+ end
759
+
760
+ # Installs Puppet and dependencies from OpenBSD packages
761
+ #
762
+ # @param [Host, Array<Host>, String, Symbol] hosts The host to install packages on
763
+ # @param [Hash{Symbol=>String}] opts An options hash
764
+ # @option opts [String] :version The version of Puppet to install (shows warning)
765
+ #
766
+ # @return nil
767
+ # @api private
768
+ def install_puppet_from_openbsd_packages_on(hosts, opts)
769
+ if (opts[:version])
770
+ logger.warn "If you wish to choose a specific Puppet version, use `install_puppet_from_gem_on('~> 3.*')`"
771
+ end
772
+
773
+ block_on hosts do |host|
774
+ host.install_package('puppet')
775
+
776
+ configure_type_defaults_on(host)
777
+ end
778
+ end
779
+
780
+ # Installs Puppet and dependencies from Arch Linux Pacman
781
+ #
782
+ # @param [Host, Array<Host>, String, Symbol] hosts The host to install packages on
783
+ # @param [Hash{Symbol=>String}] opts An options hash
784
+ # @option opts [String] :version The version of Puppet to install (shows warning)
785
+ #
786
+ # @return nil
787
+ # @api private
788
+ def install_puppet_from_pacman_on(hosts, opts)
789
+ if (opts[:version])
790
+ # Arch is rolling release, only the latest package versions are supported
791
+ logger.warn "If you wish to choose a specific Puppet version, use `install_puppet_from_gem_on('~> 3.*')`"
792
+ end
793
+
794
+ block_on hosts do |host|
795
+ host.install_package('puppet')
796
+
797
+ configure_type_defaults_on(host)
798
+ end
799
+ end
800
+
801
+ # Installs Puppet and dependencies from gem on provided host(s)
802
+ #
803
+ # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
804
+ # or a role (String or Symbol) that identifies one or more hosts.
805
+ # @param [Hash{Symbol=>String}] opts An options hash
806
+ # @option opts [String] :version The version of Puppet to install, if nil installs latest
807
+ # @option opts [String] :facter_version The version of Facter to install, if nil installs latest
808
+ # @option opts [String] :hiera_version The version of Hiera to install, if nil installs latest
809
+ #
810
+ # @return nil
811
+ # @raise [StandardError] if gem does not exist on target host
812
+ # @api private
813
+ def install_puppet_from_gem_on( hosts, opts )
814
+ block_on hosts do |host|
815
+ # There are a lot of special things to do for Solaris and Solaris 10.
816
+ # This is easier than checking host['platform'] every time.
817
+ is_solaris10 = host['platform'] =~ /solaris-10/
818
+ is_solaris = host['platform'] =~ /solaris/
819
+
820
+ # Hosts may be provisioned with csw but pkgutil won't be in the
821
+ # PATH by default to avoid changing the behavior for Puppet's tests
822
+ if is_solaris10
823
+ on host, 'ln -s /opt/csw/bin/pkgutil /usr/bin/pkgutil'
824
+ end
825
+
826
+ # Solaris doesn't necessarily have this, but gem needs it
827
+ if is_solaris
828
+ on host, 'mkdir -p /var/lib'
829
+ end
830
+
831
+ unless host.check_for_command( 'gem' )
832
+ gempkg = case host['platform']
833
+ when /solaris-11/ then 'ruby-18'
834
+ when /ubuntu-14/ then 'ruby'
835
+ when /solaris-10|ubuntu|debian|el-|cumulus|huaweios/ then 'rubygems'
836
+ when /openbsd/ then 'ruby'
837
+ else
838
+ raise "install_puppet() called with default_action " +
839
+ "'gem_install' but program `gem' is " +
840
+ "not installed on #{host.name}"
841
+ end
842
+
843
+ host.install_package gempkg
844
+ end
845
+
846
+ # Link 'gem' to /usr/bin instead of adding /opt/csw/bin to PATH.
847
+ if is_solaris10
848
+ on host, 'ln -s /opt/csw/bin/gem /usr/bin/gem'
849
+ end
850
+
851
+ if host['platform'] =~ /debian|ubuntu|solaris|cumulus|huaweios/
852
+ gem_env = YAML.load( on( host, 'gem environment' ).stdout )
853
+ gem_paths_array = gem_env['RubyGems Environment'].find {|h| h['GEM PATHS'] != nil }['GEM PATHS']
854
+ path_with_gem = 'export PATH=' + gem_paths_array.join(':') + ':${PATH}'
855
+ on host, "echo '#{path_with_gem}' >> ~/.bashrc"
856
+ end
857
+
858
+ gemflags = '--no-ri --no-rdoc --no-format-executable'
859
+
860
+ if opts[:facter_version]
861
+ on host, "gem install facter -v'#{opts[:facter_version]}' #{gemflags}"
862
+ end
863
+
864
+ if opts[:hiera_version]
865
+ on host, "gem install hiera -v'#{opts[:hiera_version]}' #{gemflags}"
866
+ end
867
+
868
+ ver_cmd = opts[:version] ? "-v '#{opts[:version]}'" : ''
869
+ on host, "gem install puppet #{ver_cmd} #{gemflags}"
870
+
871
+ # Similar to the treatment of 'gem' above.
872
+ # This avoids adding /opt/csw/bin to PATH.
873
+ if is_solaris
874
+ gem_env = YAML.load( on( host, 'gem environment' ).stdout )
875
+ # This is the section we want - this has the dir where gem executables go.
876
+ env_sect = 'EXECUTABLE DIRECTORY'
877
+ # Get the directory where 'gem' installs executables.
878
+ # On Solaris 10 this is usually /opt/csw/bin
879
+ gem_exec_dir = gem_env['RubyGems Environment'].find {|h| h[env_sect] != nil }[env_sect]
880
+
881
+ on host, "ln -s #{gem_exec_dir}/hiera /usr/bin/hiera"
882
+ on host, "ln -s #{gem_exec_dir}/facter /usr/bin/facter"
883
+ on host, "ln -s #{gem_exec_dir}/puppet /usr/bin/puppet"
884
+ end
885
+
886
+ # A gem install might not necessarily create these
887
+ ['confdir', 'logdir', 'codedir'].each do |key|
888
+ host.mkdir_p host.puppet[key] if host.puppet.has_key?(key)
889
+ end
890
+
891
+ configure_type_defaults_on( host )
892
+ end
893
+ end
894
+ alias_method :install_puppet_from_gem, :install_puppet_from_gem_on
895
+ alias_method :install_puppet_agent_from_gem_on, :install_puppet_from_gem_on
896
+
897
+ # Install official puppetlabs release repository configuration on host(s).
898
+ #
899
+ # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
900
+ # or a role (String or Symbol) that identifies one or more hosts.
901
+ #
902
+ # @note This method only works on redhat-like and debian-like hosts.
903
+ #
904
+ def install_puppetlabs_release_repo_on( hosts, repo = nil, opts = options )
905
+ block_on hosts do |host|
906
+ variant, version, arch, codename = host['platform'].to_array
907
+ repo_name = repo.nil? ? '' : '-' + repo
908
+ opts = FOSS_DEFAULT_DOWNLOAD_URLS.merge(opts)
909
+
910
+ case variant
911
+ when /^(fedora|el|centos|sles|cisco_nexus|cisco_ios_xr)$/
912
+ variant_url_value = (($1 == 'centos') ? 'el' : $1)
913
+ if variant == 'cisco_nexus'
914
+ variant_url_value = 'cisco-wrlinux'
915
+ version = '5'
916
+ end
917
+ if variant == 'cisco_ios_xr'
918
+ variant_url_value = 'cisco-wrlinux'
919
+ version = '7'
920
+ end
921
+ remote = "%s/puppetlabs-release%s-%s-%s.noarch.rpm" %
922
+ [opts[:release_yum_repo_url], repo_name, variant_url_value, version]
923
+
924
+ if variant == 'cisco_nexus'
925
+ # cisco nexus requires using yum to install the repo
926
+ host.install_package( remote )
927
+ elsif variant == 'cisco_ios_xr'
928
+ # cisco ios xr requires using yum to localinstall the repo
929
+ on host, "yum -y localinstall #{remote}"
930
+ else
931
+ opts[:package_proxy] ||= false
932
+ host.install_package_with_rpm( remote, '--replacepkgs',
933
+ { :package_proxy => opts[:package_proxy] } )
934
+ end
935
+
936
+ when /^(debian|ubuntu|cumulus|huaweios)$/
937
+ deb = "puppetlabs-release%s-%s.deb" % [repo_name, codename]
938
+
939
+ remote = URI.join( opts[:release_apt_repo_url], deb )
940
+
941
+ on host, "wget -O /tmp/puppet.deb #{remote}"
942
+ on host, "dpkg -i --force-all /tmp/puppet.deb"
943
+ on host, "apt-get update"
944
+ else
945
+ raise "No repository installation step for #{variant} yet..."
946
+ end
947
+ configure_type_defaults_on( host )
948
+ end
949
+ end
950
+ alias_method :install_puppetlabs_release_repo, :install_puppetlabs_release_repo_on
951
+
952
+ # Installs the repo configs on a given host
953
+ #
954
+ # @param [Beaker::Host] host Host to install configs on
955
+ # @param [String] buildserver_url URL of the buildserver
956
+ # @param [String] package_name Name of the package
957
+ # @param [String] build_version Version of the package
958
+ # @param [String] copy_dir Local directory to fetch files into & SCP out of
959
+ #
960
+ # @return nil
961
+ def install_repo_configs(host, buildserver_url, package_name, build_version, copy_dir)
962
+ repo_filename = host.repo_filename( package_name, build_version )
963
+ repo_config_folder_url = "%s/%s/%s/repo_configs/%s/" %
964
+ [ buildserver_url, package_name, build_version, host.repo_type ]
965
+
966
+ repo = fetch_http_file( repo_config_folder_url,
967
+ repo_filename,
968
+ copy_dir )
969
+
970
+ if host[:platform] =~ /cisco_nexus/
971
+ to_path = "#{host.package_config_dir}/#{File.basename(repo)}"
972
+ else
973
+ to_path = host.package_config_dir
974
+ end
975
+ scp_to( host, repo, to_path )
976
+
977
+ on( host, 'apt-get update' ) if host['platform'] =~ /ubuntu-|debian-|cumulus-|huaweios-/
978
+ nil
979
+ end
980
+
981
+ # Install development repository on the given host. This method pushes all
982
+ # repository information including package files for the specified
983
+ # package_name to the host and modifies the repository configuration file
984
+ # to point at the new repository. This is particularly useful for
985
+ # installing development packages on hosts that can't access the builds
986
+ # server.
987
+ #
988
+ # @param [Host] host An object implementing {Beaker::Hosts}'s
989
+ # interface.
990
+ # @param [String] package_name The name of the package whose repository is
991
+ # being installed.
992
+ # @param [String] build_version A string identifying the output of a
993
+ # packaging job for use in looking up
994
+ # repository directory information
995
+ # @param [String] repo_configs_dir A local directory where repository files will be
996
+ # stored as an intermediate step before
997
+ # pushing them to the given host.
998
+ # @param [Hash{Symbol=>String}] opts Options to alter execution.
999
+ # @option opts [String] :dev_builds_url The URL to look for dev builds.
1000
+ # @option opts [String, Array<String>] :dev_builds_repos The repo(s)
1001
+ # to check for dev builds in.
1002
+ #
1003
+ # @note puppet-agent requires :dev_builds_repos to be set to the
1004
+ # puppet collection(s) to set the build server URL appropriately.
1005
+ #
1006
+ # @note This method only works on redhat-like and debian-like hosts.
1007
+ #
1008
+ def install_puppetlabs_dev_repo ( host, package_name, build_version,
1009
+ repo_configs_dir = nil,
1010
+ opts = options )
1011
+ variant, version, arch, codename = host['platform'].to_array
1012
+ if variant !~ /^(fedora|el|centos|debian|ubuntu|cumulus|huaweios|cisco_nexus|cisco_ios_xr|sles)$/
1013
+ raise "No repository installation step for #{variant} yet..."
1014
+ end
1015
+ repo_configs_dir ||= 'tmp/repo_configs'
1016
+
1017
+ platform_configs_dir = File.join(repo_configs_dir, variant)
1018
+ opts = FOSS_DEFAULT_DOWNLOAD_URLS.merge(opts)
1019
+
1020
+ # some of the uses of dev_builds_url below can't include protocol info,
1021
+ # plus this opens up possibility of switching the behavior on provided
1022
+ # url type
1023
+ _, protocol, hostname = opts[:dev_builds_url].partition /.*:\/\//
1024
+ dev_builds_url = protocol + hostname
1025
+ dev_builds_url = opts[:dev_builds_url] if variant =~ /^(fedora|el|centos)$/
1026
+
1027
+ install_repo_configs( host, dev_builds_url, package_name,
1028
+ build_version, platform_configs_dir )
1029
+
1030
+ configure_type_defaults_on( host )
1031
+ end
1032
+
1033
+ # Installs packages from the local development repository on the given host
1034
+ #
1035
+ # @param [Host] host An object implementing {Beaker::Hosts}'s
1036
+ # interface.
1037
+ # @param [Regexp] package_name The name of the package whose repository is
1038
+ # being installed.
1039
+ #
1040
+ # @note This method only works on redhat-like and debian-like hosts.
1041
+ # @note This method is paired to be run directly after {#install_puppetlabs_dev_repo}
1042
+ #
1043
+ def install_packages_from_local_dev_repo( host, package_name )
1044
+ if host['platform'] =~ /debian|ubuntu|cumulus|huaweios/
1045
+ find_filename = '*.deb'
1046
+ find_command = 'dpkg -i'
1047
+ elsif host['platform'] =~ /fedora|el|centos/
1048
+ find_filename = '*.rpm'
1049
+ find_command = 'rpm -ivh'
1050
+ else
1051
+ raise "No repository installation step for #{host['platform']} yet..."
1052
+ end
1053
+ find_command = "find /root/#{package_name} -type f -name '#{find_filename}' -exec #{find_command} {} \\;"
1054
+ on host, find_command
1055
+ configure_type_defaults_on( host )
1056
+ end
1057
+
1058
+ # Install development repo of the puppet-agent on the given host(s). Downloaded from
1059
+ # location of the form DEV_BUILDS_URL/puppet-agent/AGENT_VERSION/repos
1060
+ #
1061
+ # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
1062
+ # or a role (String or Symbol) that identifies one or more hosts.
1063
+ # @param [Hash{Symbol=>String}] opts An options hash
1064
+ # @option opts [String] :puppet_agent_version The version of puppet-agent to install. This
1065
+ # parameter is used by puppet with the +SUITE_VERSION+ environment
1066
+ # variable to provide a `git describe` value to beaker to create a
1067
+ # build server URL. Note that +puppet_agent_sha+ will still be used
1068
+ # instead of this if a value is provided for that option
1069
+ # @option opts [String] :puppet_agent_sha The sha of puppet-agent to install, defaults to provided
1070
+ # puppet_agent_version
1071
+ # @option opts [String] :copy_base_local Directory where puppet-agent artifact
1072
+ # will be stored locally
1073
+ # (default: 'tmp/repo_configs')
1074
+ # @option opts [String] :copy_dir_external Directory where puppet-agent
1075
+ # artifact will be pushed to on the external machine
1076
+ # (default: '/root')
1077
+ # @option opts [String] :puppet_collection Defaults to 'PC1'
1078
+ # @option opts [String] :dev_builds_url Base URL to pull artifacts from
1079
+ # @option opts [String] :copy_base_local Directory where puppet-agent artifact
1080
+ # will be stored locally
1081
+ # (default: 'tmp/repo_configs')
1082
+ # @option opts [String] :copy_dir_external Directory where puppet-agent
1083
+ # artifact will be pushed to on the external machine
1084
+ # (default: '/root')
1085
+ #
1086
+ # @note on windows, the +:ruby_arch+ host parameter can determine in addition
1087
+ # to other settings whether the 32 or 64bit install is used
1088
+ #
1089
+ # @example
1090
+ # install_puppet_agent_dev_repo_on(host, { :puppet_agent_sha => 'd3377feaeac173aada3a2c2cedd141eb610960a7', :puppet_agent_version => '1.1.1.225.gd3377fe' })
1091
+ #
1092
+ # @return nil
1093
+ def install_puppet_agent_dev_repo_on( hosts, opts )
1094
+
1095
+ opts[:puppet_agent_version] ||= opts[:version] #backward compatability
1096
+ if not opts[:puppet_agent_version]
1097
+ raise "must provide :puppet_agent_version (puppet-agent version) for install_puppet_agent_dev_repo_on"
1098
+ end
1099
+ # TODO consolidate these values as they serve no purpose from beaker's side
1100
+ # you could provide any values you could to one to the other
1101
+ puppet_agent_version = opts[:puppet_agent_sha] || opts[:puppet_agent_version]
1102
+
1103
+ opts = FOSS_DEFAULT_DOWNLOAD_URLS.merge(opts)
1104
+ opts[:download_url] = "#{opts[:dev_builds_url]}/puppet-agent/#{ puppet_agent_version }/repos/"
1105
+ opts[:copy_base_local] ||= File.join('tmp', 'repo_configs')
1106
+ opts[:puppet_collection] ||= 'PC1'
1107
+ release_path = opts[:download_url]
1108
+
1109
+ block_on hosts do |host|
1110
+ variant, version, arch, codename = host['platform'].to_array
1111
+ add_role(host, 'aio') #we are installing agent, so we want aio role
1112
+ copy_dir_local = File.join(opts[:copy_base_local], variant)
1113
+ onhost_copy_base = opts[:copy_dir_external] || host.external_copy_base
1114
+
1115
+ case variant
1116
+ when /^(fedora|el|centos|debian|ubuntu|cumulus|huaweios|cisco_nexus|cisco_ios_xr)$/
1117
+ if arch == 's390x'
1118
+ logger.trace("#install_puppet_agent_dev_repo_on: s390x arch detected for host #{host}. using dev package")
1119
+ else
1120
+ opts[:dev_builds_repos] ||= [ opts[:puppet_collection] ]
1121
+ install_puppetlabs_dev_repo( host, 'puppet-agent', puppet_agent_version, nil, opts )
1122
+ host.install_package('puppet-agent')
1123
+ logger.trace("#install_puppet_agent_dev_repo_on: install_puppetlabs_dev_repo finished")
1124
+ next
1125
+ end
1126
+ when /^(eos|osx|windows|solaris|sles|aix)$/
1127
+ # Download installer package file & run install manually.
1128
+ # Done below, so that el hosts with s390x arch can use this
1129
+ # workflow as well
1130
+ else
1131
+ raise "No repository installation step for #{variant} yet..."
1132
+ end
1133
+
1134
+ release_path_end, release_file = host.puppet_agent_dev_package_info(
1135
+ opts[:puppet_collection], opts[:puppet_agent_version], opts )
1136
+ release_path << release_path_end
1137
+ logger.trace("#install_puppet_agent_dev_repo_on: dev_package_info, continuing...")
1138
+
1139
+ if variant =~ /eos/
1140
+ host.get_remote_file( "#{release_path}/#{release_file}" )
1141
+ else
1142
+ onhost_copied_file = File.join(onhost_copy_base, release_file)
1143
+ fetch_http_file( release_path, release_file, copy_dir_local)
1144
+ scp_to host, File.join(copy_dir_local, release_file), onhost_copy_base
1145
+ end
1146
+
1147
+ case variant
1148
+ when /^eos/
1149
+ host.install_from_file( release_file )
1150
+ when /^(sles|aix|el)$/
1151
+ # NOTE: AIX does not support repo management. This block assumes
1152
+ # that the desired rpm has been mirrored to the 'repos' location.
1153
+ # NOTE: the AIX 7.1 package will only install on 7.2 with
1154
+ # --ignoreos. This is a bug in package building on AIX 7.1's RPM
1155
+ if variant == "aix" and version == "7.2"
1156
+ aix_72_ignoreos_hack = "--ignoreos"
1157
+ end
1158
+ on host, "rpm -ivh #{aix_72_ignoreos_hack} #{onhost_copied_file}"
1159
+ when /^windows$/
1160
+ result = on host, "echo #{onhost_copied_file}"
1161
+ onhost_copied_file = result.raw_output.chomp
1162
+ msi_opts = { :debug => host[:pe_debug] || opts[:pe_debug] }
1163
+ install_msi_on(host, onhost_copied_file, {}, msi_opts)
1164
+ when /^osx$/
1165
+ host.install_package("puppet-agent-#{opts[:puppet_agent_version]}*")
1166
+ when /^solaris$/
1167
+ host.solaris_install_local_package( release_file, onhost_copy_base )
1168
+ end
1169
+ configure_type_defaults_on( host )
1170
+ end
1171
+ end
1172
+ alias_method :install_puppetagent_dev_repo, :install_puppet_agent_dev_repo_on
1173
+
1174
+ # Install shared repo of the puppet-agent on the given host(s). Downloaded from
1175
+ # location of the form PE_PROMOTED_BUILDS_URL/PE_VER/puppet-agent/AGENT_VERSION/repo
1176
+ #
1177
+ # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
1178
+ # or a role (String or Symbol) that identifies one or more hosts.
1179
+ # @param [Hash{Symbol=>String}] opts An options hash
1180
+ # @option opts [String] :puppet_agent_version The version of puppet-agent to install, defaults to 'latest'
1181
+ # @option opts [String] :pe_ver The version of PE (will also use host['pe_ver']), defaults to '4.0'
1182
+ # @option opts [String] :copy_base_local Directory where puppet-agent artifact
1183
+ # will be stored locally
1184
+ # (default: 'tmp/repo_configs')
1185
+ # @option opts [String] :copy_dir_external Directory where puppet-agent
1186
+ # artifact will be pushed to on the external machine
1187
+ # (default: '/root')
1188
+ # @option opts [String] :puppet_collection Defaults to 'PC1'
1189
+ # @option opts [String] :pe_promoted_builds_url Base URL to pull artifacts from
1190
+ #
1191
+ # @note on windows, the +:ruby_arch+ host parameter can determine in addition
1192
+ # to other settings whether the 32 or 64bit install is used
1193
+ #
1194
+ # @example
1195
+ # install_puppet_agent_pe_promoted_repo_on(host, { :puppet_agent_version => '1.1.0.227', :pe_ver => '4.0.0-rc1'})
1196
+ #
1197
+ # @return nil
1198
+ def install_puppet_agent_pe_promoted_repo_on( hosts, opts )
1199
+ opts[:puppet_agent_version] ||= 'latest'
1200
+
1201
+ block_on hosts do |host|
1202
+ pe_ver = host[:pe_ver] || opts[:pe_ver] || '4.0.0-rc1'
1203
+ opts = FOSS_DEFAULT_DOWNLOAD_URLS.merge(opts)
1204
+ opts[:download_url] = "#{opts[:pe_promoted_builds_url]}/puppet-agent/#{ pe_ver }/#{ opts[:puppet_agent_version] }/repos"
1205
+ opts[:copy_base_local] ||= File.join('tmp', 'repo_configs')
1206
+ opts[:copy_dir_external] ||= host.external_copy_base
1207
+ opts[:puppet_collection] ||= 'PC1'
1208
+ add_role(host, 'aio') #we are installing agent, so we want aio role
1209
+ release_path = opts[:download_url]
1210
+ variant, version, arch, codename = host['platform'].to_array
1211
+ copy_dir_local = File.join(opts[:copy_base_local], variant)
1212
+ onhost_copy_base = opts[:copy_dir_external]
1213
+
1214
+ release_path_end, release_file, download_file =
1215
+ host.pe_puppet_agent_promoted_package_info(
1216
+ opts[:puppet_collection], opts
1217
+ )
1218
+ release_path << release_path_end
1219
+
1220
+ onhost_copied_download = File.join(onhost_copy_base, download_file)
1221
+ onhost_copied_file = File.join(onhost_copy_base, release_file)
1222
+ fetch_http_file( release_path, download_file, copy_dir_local)
1223
+ scp_to host, File.join(copy_dir_local, download_file), onhost_copy_base
1224
+
1225
+ if variant == 'windows'
1226
+ result = on host, "echo #{onhost_copied_file}"
1227
+ onhost_copied_file = result.raw_output.chomp
1228
+ opts = { :debug => host[:pe_debug] || opts[:pe_debug] }
1229
+ # couldn't pull this out, because it's relying on
1230
+ # {Beaker::DSL::InstallUtils::WindowsUtils} methods,
1231
+ # which I didn't want to attack right now. TODO
1232
+ install_msi_on(host, onhost_copied_file, {}, opts)
1233
+ else
1234
+ host.pe_puppet_agent_promoted_package_install(
1235
+ onhost_copy_base, onhost_copied_download,
1236
+ onhost_copied_file, download_file, opts
1237
+ )
1238
+ end
1239
+ configure_type_defaults_on( host )
1240
+ end
1241
+ end
1242
+
1243
+ # This method will install a pem file certificate on a windows host
1244
+ #
1245
+ # @param [Host] host A host object
1246
+ # @param [String] cert_name The name of the pem file
1247
+ # @param [String] cert The contents of the certificate
1248
+ #
1249
+ def install_cert_on_windows(host, cert_name, cert)
1250
+ create_remote_file(host, "C:\\Windows\\Temp\\#{cert_name}.pem", cert)
1251
+ on host, "certutil -v -addstore Root C:\\Windows\\Temp\\#{cert_name}.pem"
1252
+ end
1253
+
1254
+ # Ensures Puppet and dependencies are no longer installed on host(s).
1255
+ #
1256
+ # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
1257
+ # or a role (String or Symbol) that identifies one or more hosts.
1258
+ #
1259
+ # @return nil
1260
+ # @api public
1261
+ def remove_puppet_on( hosts )
1262
+ block_on hosts do |host|
1263
+ cmdline_args = ''
1264
+ # query packages
1265
+ case host[:platform]
1266
+ when /cumulus|huaweios/
1267
+ pkgs = on(host, "dpkg-query -l | awk '{print $2}' | grep -E '(^pe-|puppet)'", :acceptable_exit_codes => [0,1]).stdout.chomp.split(/\n+/)
1268
+ when /aix|sles|el|redhat|centos|oracle|scientific/
1269
+ pkgs = on(host, "rpm -qa | grep -E '(^pe-|puppet)'", :acceptable_exit_codes => [0,1]).stdout.chomp.split(/\n+/)
1270
+ when /solaris-10/
1271
+ cmdline_args = '-a noask'
1272
+ pkgs = on(host, "pkginfo | egrep '(^pe-|puppet)' | cut -f2 -d ' '", :acceptable_exit_codes => [0,1]).stdout.chomp.split(/\n+/)
1273
+ when /solaris-11/
1274
+ pkgs = on(host, "pkg list | egrep '(^pe-|puppet)' | awk '{print $1}'", :acceptable_exit_codes => [0,1]).stdout.chomp.split(/\n+/)
1275
+ else
1276
+ raise "remove_puppet_on() called for unsupported " +
1277
+ "platform '#{host['platform']}' on '#{host.name}'"
1278
+ end
1279
+
1280
+ # uninstall packages
1281
+ host.uninstall_package(pkgs.join(' '), cmdline_args) if pkgs.length > 0
1282
+
1283
+ if host[:platform] =~ /solaris-11/ then
1284
+ # FIXME: This leaves things in a state where Puppet Enterprise (3.x) cannot be cleanly installed
1285
+ # but is required to put things in a state that puppet-agent can be installed
1286
+ # extra magic for expunging left over publisher
1287
+ publishers = ['puppetlabs.com', 'com.puppetlabs']
1288
+ publishers.each do |publisher|
1289
+ if on(host, "pkg publisher #{publisher}", :acceptable_exit_codes => [0,1]).exit_code == 0 then
1290
+ # First, try to remove the publisher altogether
1291
+ if on(host, "pkg unset-publisher #{publisher}", :acceptable_exit_codes => [0,1]).exit_code == 1 then
1292
+ # If that doesn't work, we're in a non-global zone and the
1293
+ # publisher is from a global zone. As such, just remove any
1294
+ # references to the non-global zone uri.
1295
+ on(host, "pkg set-publisher -G '*' #{publisher}", :acceptable_exit_codes => [0,1])
1296
+ end
1297
+ end
1298
+ end
1299
+ end
1300
+
1301
+ # delete any residual files
1302
+ on(host, 'find / -name "*puppet*" -print | xargs rm -rf')
1303
+
1304
+ end
1305
+ end
1306
+ end
1307
+ end
1308
+ end
1309
+ end