beaker-puppet 0.1.0

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