kitchen-puppet 0.0.10 → 0.0.11

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.
@@ -1,5 +1,5 @@
1
- module Kitchen
2
- module Puppet
3
- VERSION = "0.0.10"
4
- end
5
- end
1
+ module Kitchen
2
+ module Puppet
3
+ VERSION = "0.0.11"
4
+ end
5
+ end
@@ -1,83 +1,83 @@
1
- # -*- encoding: utf-8 -*-
2
- #
3
- # Author:: Fletcher Nichol (<fnichol@nichol.ca>) Neill Turner (<neillwturner@gmail.com>)
4
- #
5
- # Copyright (C) 2013, Fletcher Nichol, Neill Turner
6
- #
7
- # Licensed under the Apache License, Version 2.0 (the "License");
8
- # you may not use this file except in compliance with the License.
9
- # You may obtain a copy of the License at
10
- #
11
- # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
- # Unless required by applicable law or agreed to in writing, software
14
- # distributed under the License is distributed on an "AS IS" BASIS,
15
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
- # See the License for the specific language governing permissions and
17
- # limitations under the License.
18
-
19
- require 'kitchen/errors'
20
- require 'kitchen/logging'
21
-
22
- module Kitchen
23
-
24
- module Provisioner
25
-
26
- module Puppet
27
-
28
- # Puppet module resolver that uses Librarian-Puppet and a Puppetfile to
29
- # calculate # dependencies.
30
- #
31
- class Librarian
32
-
33
- include Logging
34
-
35
-
36
- def initialize(puppetfile, path, logger = Kitchen.logger)
37
- @puppetfile = puppetfile
38
- @path = path
39
- @logger = logger
40
- end
41
-
42
- def self.load!(logger = Kitchen.logger)
43
- load_librarian!(logger)
44
- end
45
-
46
- def resolve
47
- version = ::Librarian::Puppet::VERSION
48
- info("Resolving module dependencies with Librarian-Puppet #{version}...")
49
- debug("Using Puppetfile from #{puppetfile}")
50
-
51
- env = ::Librarian::Puppet::Environment.new(
52
- :project_path => File.dirname(puppetfile))
53
- env.config_db.local["path"] = path
54
- ::Librarian::Action::Resolve.new(env).run
55
- ::Librarian::Action::Install.new(env).run
56
- end
57
-
58
- attr_reader :puppetfile, :path, :logger
59
-
60
- def self.load_librarian!(logger)
61
- first_load = require 'librarian/puppet'
62
- require 'librarian/puppet/environment'
63
- require 'librarian/action/resolve'
64
- require 'librarian/action/install'
65
-
66
- version = ::Librarian::Puppet::VERSION
67
- if first_load
68
- logger.debug("Librarian-Puppet #{version} library loaded")
69
- else
70
- logger.debug("Librarian-Puppet #{version} previously loaded")
71
- end
72
- rescue LoadError => e
73
- logger.fatal("The `librarian-puppet' gem is missing and must be installed" +
74
- " or cannot be properly activated. Run" +
75
- " `gem install librarian-puppet` or add the following to your" +
76
- " Gemfile if you are using Bundler: `gem 'librarian-puppet'`.")
77
- raise UserError,
78
- "Could not load or activate Librarian-Puppet (#{e.message})"
79
- end
80
- end
81
- end
82
- end
83
- end
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>) Neill Turner (<neillwturner@gmail.com>)
4
+ #
5
+ # Copyright (C) 2013, Fletcher Nichol, Neill Turner
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require 'kitchen/errors'
20
+ require 'kitchen/logging'
21
+
22
+ module Kitchen
23
+
24
+ module Provisioner
25
+
26
+ module Puppet
27
+
28
+ # Puppet module resolver that uses Librarian-Puppet and a Puppetfile to
29
+ # calculate # dependencies.
30
+ #
31
+ class Librarian
32
+
33
+ include Logging
34
+
35
+
36
+ def initialize(puppetfile, path, logger = Kitchen.logger)
37
+ @puppetfile = puppetfile
38
+ @path = path
39
+ @logger = logger
40
+ end
41
+
42
+ def self.load!(logger = Kitchen.logger)
43
+ load_librarian!(logger)
44
+ end
45
+
46
+ def resolve
47
+ version = ::Librarian::Puppet::VERSION
48
+ info("Resolving module dependencies with Librarian-Puppet #{version}...")
49
+ debug("Using Puppetfile from #{puppetfile}")
50
+
51
+ env = ::Librarian::Puppet::Environment.new(
52
+ :project_path => File.dirname(puppetfile))
53
+ env.config_db.local["path"] = path
54
+ ::Librarian::Action::Resolve.new(env).run
55
+ ::Librarian::Action::Install.new(env).run
56
+ end
57
+
58
+ attr_reader :puppetfile, :path, :logger
59
+
60
+ def self.load_librarian!(logger)
61
+ first_load = require 'librarian/puppet'
62
+ require 'librarian/puppet/environment'
63
+ require 'librarian/action/resolve'
64
+ require 'librarian/action/install'
65
+
66
+ version = ::Librarian::Puppet::VERSION
67
+ if first_load
68
+ logger.debug("Librarian-Puppet #{version} library loaded")
69
+ else
70
+ logger.debug("Librarian-Puppet #{version} previously loaded")
71
+ end
72
+ rescue LoadError => e
73
+ logger.fatal("The `librarian-puppet' gem is missing and must be installed" +
74
+ " or cannot be properly activated. Run" +
75
+ " `gem install librarian-puppet` or add the following to your" +
76
+ " Gemfile if you are using Bundler: `gem 'librarian-puppet'`.")
77
+ raise UserError,
78
+ "Could not load or activate Librarian-Puppet (#{e.message})"
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -1,473 +1,502 @@
1
- # -*- encoding: utf-8 -*-
2
- #
3
- # Author:: Chris Lundquist (<chris.lundquist@github.com>) Neill Turner (<neillwturner@gmail.com>)
4
- #
5
- # Copyright (C) 2013,2014 Chris Lundquist, Neill Turner
6
- #
7
- # Licensed under the Apache License, Version 2.0 (the "License");
8
- # you may not use this file except in compliance with the License.
9
- # You may obtain a copy of the License at
10
- #
11
- # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
- # Unless required by applicable law or agreed to in writing, software
14
- # distributed under the License is distributed on an "AS IS" BASIS,
15
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
- # See the License for the specific language governing permissions and
17
- # limitations under the License.
18
- #
19
- # See https://github.com/neillturner/kitchen-puppet/blob/master/provisioner_options.md
20
- # for documentation configuration parameters with puppet_apply provisioner.
21
- #
22
-
23
- require 'json'
24
- require 'kitchen/provisioner/base'
25
- require 'kitchen/provisioner/puppet/librarian'
26
-
27
- module Kitchen
28
-
29
- module Provisioner
30
- #
31
- # Puppet Apply provisioner.
32
- #
33
- class PuppetApply < Base
34
- attr_accessor :tmp_dir
35
-
36
- default_config :require_puppet_omnibus, false
37
- # TODO use something like https://github.com/fnichol/omnibus-puppet
38
- default_config :puppet_omnibus_url, nil
39
- default_config :puppet_omnibus_remote_path, '/opt/puppet'
40
- default_config :puppet_version, nil
41
- default_config :require_puppet_repo, true
42
- default_config :puppet_apt_repo, "http://apt.puppetlabs.com/puppetlabs-release-precise.deb"
43
- default_config :puppet_yum_repo, "https://yum.puppetlabs.com/puppetlabs-release-el-6.noarch.rpm"
44
- default_config :chef_bootstrap_url, "https://www.getchef.com/chef/install.sh"
45
-
46
- default_config :hiera_data_remote_path, '/var/lib/hiera'
47
- default_config :manifest, 'site.pp'
48
-
49
- default_config :manifests_path do |provisioner|
50
- provisioner.calculate_path('manifests') or
51
- raise 'No manifests_path detected. Please specify one in .kitchen.yml'
52
- end
53
-
54
- default_config :modules_path do |provisioner|
55
- provisioner.calculate_path('modules') or
56
- raise 'No modules_path detected. Please specify one in .kitchen.yml'
57
- end
58
-
59
- default_config :files_path do |provisioner|
60
- provisioner.calculate_path('files')
61
- end
62
-
63
- default_config :hiera_data_path do |provisioner|
64
- provisioner.calculate_path('hiera')
65
- end
66
-
67
- default_config :hiera_config_path do |provisioner|
68
- provisioner.calculate_path('hiera.yaml', :file)
69
- end
70
-
71
- default_config :fileserver_config_path do |provisioner|
72
- provisioner.calculate_path('fileserver.conf', :file)
73
- end
74
-
75
- default_config :puppetfile_path do |provisioner|
76
- provisioner.calculate_path('Puppetfile', :file)
77
- end
78
-
79
- default_config :modulefile_path do |provisioner|
80
- provisioner.calculate_path('Modulefile', :file)
81
- end
82
-
83
- default_config :metadata_json_path do |provisioner|
84
- provisioner.calculate_path('metadata.json', :file)
85
- end
86
-
87
- default_config :puppet_debug, false
88
- default_config :puppet_verbose, false
89
- default_config :puppet_noop, false
90
- default_config :puppet_platform, ''
91
- default_config :update_package_repos, true
92
- default_config :custom_facts, {}
93
-
94
- def calculate_path(path, type = :directory)
95
- base = File.join(config[:kitchen_root], 'puppet')
96
- candidates = []
97
- candidates << File.join(base, instance.suite.name, path)
98
- candidates << File.join(base, path)
99
- candidates << File.join(Dir.pwd, path)
100
-
101
- candidates.find do |c|
102
- type == :directory ? File.directory?(c) : File.file?(c)
103
- end
104
- end
105
-
106
- def install_command
107
- return unless config[:require_puppet_omnibus] or config[:require_puppet_repo]
108
- if config[:require_puppet_omnibus]
109
- info("Installing puppet using puppet omnibus")
110
- version = if !config[:puppet_version].nil?
111
- "-v #{config[:puppet_version]}"
112
- else
113
- ""
114
- end
115
- <<-INSTALL
116
- #{Util.shell_helpers}
117
-
118
- if [ ! -d "#{config[:puppet_omnibus_remote_path]}" ]; then
119
- echo "-----> Installing Puppet Omnibus"
120
- do_download #{config[:puppet_omnibus_url]} /tmp/puppet_install.sh
121
- #{sudo('sh')} /tmp/puppet_install.sh #{version}
122
- fi
123
- #{install_busser}
124
- INSTALL
125
- else
126
- case puppet_platform
127
- when "debian", "ubuntu"
128
- info("Installing puppet on #{puppet_platform}")
129
- <<-INSTALL
130
- if [ ! $(which puppet) ]; then
131
- #{sudo('wget')} #{puppet_apt_repo}
132
- #{sudo('dpkg')} -i #{puppet_apt_repo_file}
133
- #{update_packages_debian_cmd}
134
- #{sudo('apt-get')} -y install puppet#{puppet_debian_version}
135
- fi
136
- #{install_busser}
137
- INSTALL
138
- when "redhat", "centos", "fedora"
139
- info("Installing puppet on #{puppet_platform}")
140
- <<-INSTALL
141
- if [ ! $(which puppet) ]; then
142
- #{sudo('rpm')} -ivh #{puppet_yum_repo}
143
- #{update_packages_redhat_cmd}
144
- #{sudo('yum')} -y install puppet#{puppet_redhat_version}
145
- fi
146
- #{install_busser}
147
- INSTALL
148
- else
149
- info("Installing puppet, will try to determine platform os")
150
- <<-INSTALL
151
- if [ ! $(which puppet) ]; then
152
- if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
153
- #{sudo('rpm')} -ivh #{puppet_yum_repo}
154
- #{update_packages_redhat_cmd}
155
- #{sudo('yum')} -y install puppet#{puppet_redhat_version}
156
- else
157
- #{sudo('wget')} #{puppet_apt_repo}
158
- #{sudo('dpkg')} -i #{puppet_apt_repo_file}
159
- #{update_packages_debian_cmd}
160
- #{sudo('apt-get')} -y install puppet#{puppet_debian_version}
161
- fi
162
- fi
163
- #{install_busser}
164
- INSTALL
165
- end
166
- end
167
- end
168
-
169
- def install_busser
170
- <<-INSTALL
171
- #{Util.shell_helpers}
172
- # install chef omnibus so that busser works as this is needed to run tests :(
173
- # TODO: work out how to install enough ruby
174
- # and set busser: { :ruby_bindir => '/usr/bin/ruby' } so that we dont need the
175
- # whole chef client
176
- if [ ! -d "/opt/chef" ]
177
- then
178
- echo "-----> Installing Chef Omnibus to install busser to run tests"
179
- do_download #{chef_url} /tmp/install.sh
180
- #{sudo('sh')} /tmp/install.sh
181
- fi
182
- INSTALL
183
- end
184
-
185
- def init_command
186
- dirs = %w{modules manifests files hiera hiera.yaml}.
187
- map { |dir| File.join(config[:root_path], dir) }.join(" ")
188
- cmd = "#{sudo('rm')} -rf #{dirs} #{hiera_data_remote_path} /etc/hiera.yaml /etc/puppet/hiera.yaml /etc/puppet/fileserver.conf;"
189
- cmd = cmd+" mkdir -p #{config[:root_path]}"
190
- debug(cmd)
191
- cmd
192
- end
193
-
194
- def create_sandbox
195
- super
196
- debug("Creating local sandbox in #{sandbox_path}")
197
-
198
- yield if block_given?
199
-
200
- prepare_modules
201
- prepare_manifests
202
- prepare_files
203
- prepare_hiera_config
204
- prepare_fileserver_config
205
- prepare_hiera_data
206
- info('Finished Preparing files for transfer')
207
-
208
- end
209
-
210
- def cleanup_sandbox
211
- return if sandbox_path.nil?
212
- debug("Cleaning up local sandbox in #{sandbox_path}")
213
- FileUtils.rmtree(sandbox_path)
214
- end
215
-
216
- def prepare_command
217
- commands = []
218
-
219
- if hiera_config
220
- commands << [
221
- sudo('cp'), File.join(config[:root_path],'hiera.yaml'), '/etc/',
222
- ].join(' ')
223
-
224
- commands << [
225
- sudo('cp'), File.join(config[:root_path],'hiera.yaml'), '/etc/puppet/',
226
- ].join(' ')
227
- end
228
-
229
- if fileserver_config
230
- commands << [
231
- sudo('cp'),
232
- File.join(config[:root_path], 'fileserver.conf'),
233
- '/etc/puppet',
234
- ].join(' ')
235
- end
236
-
237
- if hiera_data and hiera_data_remote_path == '/var/lib/hiera'
238
- commands << [
239
- sudo('cp -r'), File.join(config[:root_path], 'hiera'), '/var/lib/'
240
- ].join(' ')
241
- end
242
-
243
- if hiera_data and hiera_data_remote_path != '/var/lib/hiera'
244
- commands << [
245
- sudo('mkdir -p'), hiera_data_remote_path
246
- ].join(' ')
247
- commands << [
248
- sudo('cp -r'), File.join(config[:root_path], 'hiera/*'), hiera_data_remote_path
249
- ].join(' ')
250
- end
251
-
252
- command = commands.join(' && ')
253
- debug(command)
254
- command
255
- end
256
-
257
- def run_command
258
- [
259
- custom_facts,
260
- sudo('puppet'),
261
- 'apply',
262
- File.join(config[:root_path], 'manifests', manifest),
263
- "--modulepath=#{File.join(config[:root_path], 'modules')}",
264
- "--manifestdir=#{File.join(config[:root_path], 'manifests')}",
265
- "--fileserverconfig=#{File.join(config[:root_path], 'fileserver.conf')}",
266
- puppet_noop_flag,
267
- puppet_verbose_flag,
268
- puppet_debug_flag,
269
- ].join(" ")
270
- end
271
-
272
- protected
273
-
274
- def load_needed_dependencies!
275
- if File.exists?(puppetfile)
276
- debug("Puppetfile found at #{puppetfile}, loading Librarian-Puppet")
277
- Puppet::Librarian.load!(logger)
278
- end
279
- end
280
-
281
- def tmpmodules_dir
282
- File.join(sandbox_path, 'modules')
283
- end
284
-
285
- def puppetfile
286
- config[:puppetfile_path] or ''
287
- end
288
-
289
- def modulefile
290
- config[:modulefile_path] or ''
291
- end
292
-
293
- def metadata_json
294
- config[:metadata_json_path] or ''
295
- end
296
-
297
- def manifest
298
- config[:manifest]
299
- end
300
-
301
- def manifests
302
- config[:manifests_path]
303
- end
304
-
305
- def modules
306
- config[:modules_path]
307
- end
308
-
309
- def files
310
- config[:files_path]
311
- end
312
-
313
- def hiera_config
314
- config[:hiera_config_path]
315
- end
316
-
317
- def fileserver_config
318
- config[:fileserver_config_path]
319
- end
320
-
321
- def hiera_data
322
- config[:hiera_data_path]
323
- end
324
-
325
- def hiera_data_remote_path
326
- config[:hiera_data_remote_path]
327
- end
328
-
329
- def puppet_debian_version
330
- config[:puppet_version] ? "=#{config[:puppet_version]}" : nil
331
- end
332
-
333
- def puppet_redhat_version
334
- config[:puppet_version] ? "-#{config[:puppet_version]}" : nil
335
- end
336
-
337
- def puppet_noop_flag
338
- config[:puppet_noop] ? '--noop' : nil
339
- end
340
-
341
- def puppet_debug_flag
342
- config[:puppet_debug] ? '-d' : nil
343
- end
344
-
345
- def puppet_verbose_flag
346
- config[:puppet_verbose] ? '-v' : nil
347
- end
348
-
349
- def puppet_platform
350
- config[:puppet_platform].to_s.downcase
351
- end
352
-
353
- def update_packages_debian_cmd
354
- config[:update_package_repos] ? "#{sudo('apt-get')} update" : nil
355
- end
356
-
357
- def update_packages_redhat_cmd
358
- config[:update_package_repos] ? "#{sudo('yum')} makecache" : nil
359
- end
360
-
361
- def custom_facts
362
- return nil if config[:custom_facts].none?
363
- bash_vars = config[:custom_facts].map { |k,v| "FACTER_#{k}=#{v}" }.join(" ")
364
- bash_vars = "export #{bash_vars};"
365
- debug(bash_vars)
366
- bash_vars
367
- end
368
-
369
- def puppet_apt_repo
370
- config[:puppet_apt_repo]
371
- end
372
-
373
- def puppet_apt_repo_file
374
- config[:puppet_apt_repo].split('/').last
375
- end
376
-
377
- def puppet_yum_repo
378
- config[:puppet_yum_repo]
379
- end
380
-
381
- def chef_url
382
- config[:chef_bootstrap_url]
383
- end
384
-
385
- def prepare_manifests
386
- info('Preparing manifests')
387
- debug("Using manifests from #{manifests}")
388
-
389
- tmp_manifests_dir = File.join(sandbox_path, 'manifests')
390
- FileUtils.mkdir_p(tmp_manifests_dir)
391
- FileUtils.cp_r(Dir.glob("#{manifests}/*"), tmp_manifests_dir)
392
- end
393
-
394
- def prepare_files
395
- info('Preparing files')
396
- debug("Using files from #{files}")
397
-
398
- tmp_files_dir = File.join(sandbox_path, 'files')
399
- FileUtils.mkdir_p(tmp_files_dir)
400
- FileUtils.cp_r(Dir.glob("#{files}/*"), tmp_files_dir)
401
- end
402
-
403
- def prepare_modules
404
- info('Preparing modules')
405
- if File.exists?(puppetfile)
406
- resolve_with_librarian
407
- end
408
-
409
- debug("Using modules from #{modules}")
410
-
411
- tmp_modules_dir = File.join(sandbox_path, 'modules')
412
- FileUtils.mkdir_p(tmp_modules_dir)
413
- FileUtils.cp_r(Dir.glob("#{modules}/*"), tmp_modules_dir,
414
- :remove_destination => true)
415
-
416
- if File.exists?(modulefile)
417
- warn("Modulefile found but this is depricated, ignoring it, see https://tickets.puppetlabs.com/browse/PUP-1188")
418
- end
419
-
420
- if File.exists?(metadata_json)
421
- module_name = nil
422
- begin
423
- module_name = JSON.parse( IO.read(metadata_json) )['name'].split("/").last
424
- rescue
425
- error("not able to load or parse #{metadata_json_path} for the name of the module")
426
- end
427
-
428
- if module_name
429
- module_target_path = File.join(tmp_modules_dir,module_name)
430
- FileUtils.mkdir_p(module_target_path)
431
- FileUtils.cp_r(Dir.glob("*").reject{|entry| entry =~ /modules/}, module_target_path,
432
- :remove_destination => true)
433
-
434
- end
435
- end
436
- end
437
-
438
- def prepare_hiera_config
439
- return unless hiera_config
440
-
441
- info('Preparing hiera')
442
- debug("Using hiera from #{hiera_config}")
443
-
444
- FileUtils.cp_r(hiera_config, File.join(sandbox_path, 'hiera.yaml'))
445
- end
446
-
447
- def prepare_fileserver_config
448
- return unless fileserver_config
449
-
450
- info('Preparing fileserver')
451
- debug("Using fileserver config from #{fileserver_config}")
452
-
453
- FileUtils.cp_r(fileserver_config, File.join(sandbox_path, 'fileserver.conf'))
454
- end
455
-
456
- def prepare_hiera_data
457
- return unless hiera_data
458
- info('Preparing hiera data')
459
- debug("Using hiera data from #{hiera_data}")
460
-
461
- tmp_hiera_dir = File.join(sandbox_path, 'hiera')
462
- FileUtils.mkdir_p(tmp_hiera_dir)
463
- FileUtils.cp_r(Dir.glob("#{hiera_data}/*"), tmp_hiera_dir)
464
- end
465
-
466
- def resolve_with_librarian
467
- Kitchen.mutex.synchronize do
468
- Puppet::Librarian.new(puppetfile, tmpmodules_dir, logger).resolve
469
- end
470
- end
471
- end
472
- end
473
- end
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Chris Lundquist (<chris.lundquist@github.com>) Neill Turner (<neillwturner@gmail.com>)
4
+ #
5
+ # Copyright (C) 2013,2014 Chris Lundquist, Neill Turner
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+ # See https://github.com/neillturner/kitchen-puppet/blob/master/provisioner_options.md
20
+ # for documentation configuration parameters with puppet_apply provisioner.
21
+ #
22
+
23
+ require 'json'
24
+ require 'kitchen/provisioner/base'
25
+ require 'kitchen/provisioner/puppet/librarian'
26
+
27
+ module Kitchen
28
+
29
+ class Busser
30
+
31
+ def non_suite_dirs
32
+ %w{data data_bags environments nodes roles puppet}
33
+ end
34
+ end
35
+
36
+ module Provisioner
37
+ #
38
+ # Puppet Apply provisioner.
39
+ #
40
+ class PuppetApply < Base
41
+ attr_accessor :tmp_dir
42
+
43
+ default_config :require_puppet_omnibus, false
44
+ # TODO use something like https://github.com/fnichol/omnibus-puppet
45
+ default_config :puppet_omnibus_url, nil
46
+ default_config :puppet_omnibus_remote_path, '/opt/puppet'
47
+ default_config :puppet_version, nil
48
+ default_config :require_puppet_repo, true
49
+ default_config :puppet_apt_repo, "http://apt.puppetlabs.com/puppetlabs-release-precise.deb"
50
+ default_config :puppet_yum_repo, "https://yum.puppetlabs.com/puppetlabs-release-el-6.noarch.rpm"
51
+ default_config :chef_bootstrap_url, "https://www.getchef.com/chef/install.sh"
52
+
53
+ default_config :hiera_data_remote_path, '/var/lib/hiera'
54
+ default_config :manifest, 'site.pp'
55
+
56
+ default_config :manifests_path do |provisioner|
57
+ provisioner.calculate_path('manifests') or
58
+ raise 'No manifests_path detected. Please specify one in .kitchen.yml'
59
+ end
60
+
61
+ default_config :modules_path do |provisioner|
62
+ modules_path = provisioner.calculate_path('modules')
63
+ if modules_path.nil? && provisioner.calculate_path('Puppetfile', :file).nil?
64
+ raise 'No modules_path detected. Please specify one in .kitchen.yml'
65
+ end
66
+ modules_path
67
+ end
68
+
69
+ default_config :files_path do |provisioner|
70
+ provisioner.calculate_path('files') || 'files'
71
+ end
72
+
73
+ default_config :hiera_data_path do |provisioner|
74
+ provisioner.calculate_path('hiera')
75
+ end
76
+
77
+ default_config :hiera_config_path do |provisioner|
78
+ provisioner.calculate_path('hiera.yaml', :file)
79
+ end
80
+
81
+ default_config :fileserver_config_path do |provisioner|
82
+ provisioner.calculate_path('fileserver.conf', :file)
83
+ end
84
+
85
+ default_config :puppetfile_path do |provisioner|
86
+ provisioner.calculate_path('Puppetfile', :file)
87
+ end
88
+
89
+ default_config :modulefile_path do |provisioner|
90
+ provisioner.calculate_path('Modulefile', :file)
91
+ end
92
+
93
+ default_config :metadata_json_path do |provisioner|
94
+ provisioner.calculate_path('metadata.json', :file)
95
+ end
96
+
97
+ default_config :manifests_path do |provisioner|
98
+ provisioner.calculate_path('manifests', :directory)
99
+ end
100
+
101
+
102
+ default_config :puppet_debug, false
103
+ default_config :puppet_verbose, false
104
+ default_config :puppet_noop, false
105
+ default_config :puppet_platform, ''
106
+ default_config :update_package_repos, true
107
+ default_config :custom_facts, {}
108
+
109
+ def calculate_path(path, type = :directory)
110
+ base = config[:test_base_path]
111
+ candidates = []
112
+ candidates << File.join(base, instance.suite.name, 'puppet', path)
113
+ candidates << File.join(base, instance.suite.name, path)
114
+ candidates << File.join(base, path)
115
+ candidates << File.join(Dir.pwd, path)
116
+
117
+ candidates.find do |c|
118
+ type == :directory ? File.directory?(c) : File.file?(c)
119
+ end
120
+ end
121
+
122
+ def install_command
123
+ return unless config[:require_puppet_omnibus] or config[:require_puppet_repo]
124
+ if config[:require_puppet_omnibus]
125
+ info("Installing puppet using puppet omnibus")
126
+ version = if !config[:puppet_version].nil?
127
+ "-v #{config[:puppet_version]}"
128
+ else
129
+ ""
130
+ end
131
+ <<-INSTALL
132
+ #{Util.shell_helpers}
133
+
134
+ if [ ! -d "#{config[:puppet_omnibus_remote_path]}" ]; then
135
+ echo "-----> Installing Puppet Omnibus"
136
+ do_download #{config[:puppet_omnibus_url]} /tmp/puppet_install.sh
137
+ #{sudo('sh')} /tmp/puppet_install.sh #{version}
138
+ fi
139
+ #{install_busser}
140
+ INSTALL
141
+ else
142
+ case puppet_platform
143
+ when "debian", "ubuntu"
144
+ info("Installing puppet on #{puppet_platform}")
145
+ <<-INSTALL
146
+ if [ ! $(which puppet) ]; then
147
+ #{sudo('wget')} #{puppet_apt_repo}
148
+ #{sudo('dpkg')} -i #{puppet_apt_repo_file}
149
+ #{update_packages_debian_cmd}
150
+ #{sudo('apt-get')} -y install puppet#{puppet_debian_version}
151
+ fi
152
+ #{install_busser}
153
+ INSTALL
154
+ when "redhat", "centos", "fedora"
155
+ info("Installing puppet on #{puppet_platform}")
156
+ <<-INSTALL
157
+ if [ ! $(which puppet) ]; then
158
+ #{sudo('rpm')} -ivh #{puppet_yum_repo}
159
+ #{update_packages_redhat_cmd}
160
+ #{sudo('yum')} -y install puppet#{puppet_redhat_version}
161
+ fi
162
+ #{install_busser}
163
+ INSTALL
164
+ else
165
+ info("Installing puppet, will try to determine platform os")
166
+ <<-INSTALL
167
+ if [ ! $(which puppet) ]; then
168
+ if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
169
+ #{sudo('rpm')} -ivh #{puppet_yum_repo}
170
+ #{update_packages_redhat_cmd}
171
+ #{sudo('yum')} -y install puppet#{puppet_redhat_version}
172
+ else
173
+ #{sudo('wget')} #{puppet_apt_repo}
174
+ #{sudo('dpkg')} -i #{puppet_apt_repo_file}
175
+ #{update_packages_debian_cmd}
176
+ #{sudo('apt-get')} -y install puppet#{puppet_debian_version}
177
+ fi
178
+ fi
179
+ #{install_busser}
180
+ INSTALL
181
+ end
182
+ end
183
+ end
184
+
185
+ def install_busser
186
+ <<-INSTALL
187
+ #{Util.shell_helpers}
188
+ # install chef omnibus so that busser works as this is needed to run tests :(
189
+ # TODO: work out how to install enough ruby
190
+ # and set busser: { :ruby_bindir => '/usr/bin/ruby' } so that we dont need the
191
+ # whole chef client
192
+ if [ ! -d "/opt/chef" ]
193
+ then
194
+ echo "-----> Installing Chef Omnibus to install busser to run tests"
195
+ do_download #{chef_url} /tmp/install.sh
196
+ #{sudo('sh')} /tmp/install.sh
197
+ fi
198
+ INSTALL
199
+ end
200
+
201
+ def init_command
202
+ dirs = %w{modules manifests files hiera hiera.yaml}.
203
+ map { |dir| File.join(config[:root_path], dir) }.join(" ")
204
+ cmd = "#{sudo('rm')} -rf #{dirs} #{hiera_data_remote_path} /etc/hiera.yaml /etc/puppet/hiera.yaml /etc/puppet/fileserver.conf;"
205
+ cmd = cmd+" mkdir -p #{config[:root_path]}"
206
+ debug(cmd)
207
+ cmd
208
+ end
209
+
210
+ def create_sandbox
211
+ super
212
+ debug("Creating local sandbox in #{sandbox_path}")
213
+
214
+ yield if block_given?
215
+
216
+ prepare_modules
217
+ prepare_manifests
218
+ prepare_files
219
+ prepare_hiera_config
220
+ prepare_fileserver_config
221
+ prepare_hiera_data
222
+ info('Finished Preparing files for transfer')
223
+
224
+ end
225
+
226
+ def cleanup_sandbox
227
+ return if sandbox_path.nil?
228
+ debug("Cleaning up local sandbox in #{sandbox_path}")
229
+ FileUtils.rmtree(sandbox_path)
230
+ end
231
+
232
+ def prepare_command
233
+ commands = []
234
+
235
+ if hiera_config
236
+ commands << [
237
+ sudo('cp'), File.join(config[:root_path],'hiera.yaml'), '/etc/',
238
+ ].join(' ')
239
+
240
+ commands << [
241
+ sudo('cp'), File.join(config[:root_path],'hiera.yaml'), '/etc/puppet/',
242
+ ].join(' ')
243
+ end
244
+
245
+ if fileserver_config
246
+ commands << [
247
+ sudo('cp'),
248
+ File.join(config[:root_path], 'fileserver.conf'),
249
+ '/etc/puppet',
250
+ ].join(' ')
251
+ end
252
+
253
+ if hiera_data and hiera_data_remote_path == '/var/lib/hiera'
254
+ commands << [
255
+ sudo('cp -r'), File.join(config[:root_path], 'hiera'), '/var/lib/'
256
+ ].join(' ')
257
+ end
258
+
259
+ if hiera_data and hiera_data_remote_path != '/var/lib/hiera'
260
+ commands << [
261
+ sudo('mkdir -p'), hiera_data_remote_path
262
+ ].join(' ')
263
+ commands << [
264
+ sudo('cp -r'), File.join(config[:root_path], 'hiera/*'), hiera_data_remote_path
265
+ ].join(' ')
266
+ end
267
+
268
+ command = commands.join(' && ')
269
+ debug(command)
270
+ command
271
+ end
272
+
273
+ def run_command
274
+ [
275
+ custom_facts,
276
+ sudo('puppet'),
277
+ 'apply',
278
+ File.join(config[:root_path], 'manifests', manifest),
279
+ "--modulepath=#{File.join(config[:root_path], 'modules')}",
280
+ "--manifestdir=#{File.join(config[:root_path], 'manifests')}",
281
+ "--fileserverconfig=#{File.join(config[:root_path], 'fileserver.conf')}",
282
+ puppet_noop_flag,
283
+ puppet_verbose_flag,
284
+ puppet_debug_flag,
285
+ ].join(" ")
286
+ end
287
+
288
+ protected
289
+
290
+ def load_needed_dependencies!
291
+ if File.exists?(puppetfile)
292
+ debug("Puppetfile found at #{puppetfile}, loading Librarian-Puppet")
293
+ Puppet::Librarian.load!(logger)
294
+ end
295
+ end
296
+
297
+ def tmpmodules_dir
298
+ File.join(sandbox_path, 'modules')
299
+ end
300
+
301
+ def puppetfile
302
+ config[:puppetfile_path] or ''
303
+ end
304
+
305
+ def modulefile
306
+ config[:modulefile_path] or ''
307
+ end
308
+
309
+ def metadata_json
310
+ config[:metadata_json_path] or ''
311
+ end
312
+
313
+ def manifest
314
+ config[:manifest]
315
+ end
316
+
317
+ def manifests
318
+ config[:manifests_path]
319
+ end
320
+
321
+ def modules
322
+ config[:modules_path]
323
+ end
324
+
325
+ def files
326
+ config[:files_path] || 'files'
327
+ end
328
+
329
+ def hiera_config
330
+ config[:hiera_config_path]
331
+ end
332
+
333
+ def fileserver_config
334
+ config[:fileserver_config_path]
335
+ end
336
+
337
+ def hiera_data
338
+ config[:hiera_data_path]
339
+ end
340
+
341
+ def hiera_data_remote_path
342
+ config[:hiera_data_remote_path]
343
+ end
344
+
345
+ def puppet_debian_version
346
+ config[:puppet_version] ? "=#{config[:puppet_version]}" : nil
347
+ end
348
+
349
+ def puppet_redhat_version
350
+ config[:puppet_version] ? "-#{config[:puppet_version]}" : nil
351
+ end
352
+
353
+ def puppet_noop_flag
354
+ config[:puppet_noop] ? '--noop' : nil
355
+ end
356
+
357
+ def puppet_debug_flag
358
+ config[:puppet_debug] ? '-d' : nil
359
+ end
360
+
361
+ def puppet_verbose_flag
362
+ config[:puppet_verbose] ? '-v' : nil
363
+ end
364
+
365
+ def puppet_platform
366
+ config[:puppet_platform].to_s.downcase
367
+ end
368
+
369
+ def update_packages_debian_cmd
370
+ config[:update_package_repos] ? "#{sudo('apt-get')} update" : nil
371
+ end
372
+
373
+ def update_packages_redhat_cmd
374
+ config[:update_package_repos] ? "#{sudo('yum')} makecache" : nil
375
+ end
376
+
377
+ def custom_facts
378
+ return nil if config[:custom_facts].none?
379
+ bash_vars = config[:custom_facts].map { |k,v| "FACTER_#{k}=#{v}" }.join(" ")
380
+ bash_vars = "export #{bash_vars};"
381
+ debug(bash_vars)
382
+ bash_vars
383
+ end
384
+
385
+ def puppet_apt_repo
386
+ config[:puppet_apt_repo]
387
+ end
388
+
389
+ def puppet_apt_repo_file
390
+ config[:puppet_apt_repo].split('/').last
391
+ end
392
+
393
+ def puppet_yum_repo
394
+ config[:puppet_yum_repo]
395
+ end
396
+
397
+ def chef_url
398
+ config[:chef_bootstrap_url]
399
+ end
400
+
401
+ def prepare_manifests
402
+ info('Preparing manifests')
403
+ debug("Using manifests from #{manifests}")
404
+
405
+ tmp_manifests_dir = File.join(sandbox_path, 'manifests')
406
+ FileUtils.mkdir_p(tmp_manifests_dir)
407
+ FileUtils.cp_r(Dir.glob("#{manifests}/*"), tmp_manifests_dir)
408
+ end
409
+
410
+ def prepare_files
411
+ info('Preparing files')
412
+
413
+ unless File.directory?(files)
414
+ info 'nothing to do for files'
415
+ return
416
+ end
417
+
418
+ debug("Using files from #{files}")
419
+
420
+ tmp_files_dir = File.join(sandbox_path, 'files')
421
+ FileUtils.mkdir_p(tmp_files_dir)
422
+ FileUtils.cp_r(Dir.glob("#{files}/*"), tmp_files_dir)
423
+ end
424
+
425
+ def prepare_modules
426
+ info('Preparing modules')
427
+ resolve_with_librarian if File.exists?(puppetfile)
428
+
429
+ tmp_modules_dir = File.join(sandbox_path, 'modules')
430
+ FileUtils.mkdir_p(tmp_modules_dir)
431
+
432
+ if modules && File.directory?(modules)
433
+ debug("Using modules from #{modules}")
434
+ FileUtils.cp_r(Dir.glob("#{modules}/*"), tmp_modules_dir, remove_destination: true)
435
+ else
436
+ info 'nothing to do for modules'
437
+ end
438
+
439
+ copy_self_as_module
440
+ end
441
+
442
+ def copy_self_as_module
443
+ if File.exists?(modulefile)
444
+ warn('Modulefile found but this is depricated, ignoring it, see https://tickets.puppetlabs.com/browse/PUP-1188')
445
+ end
446
+
447
+ if File.exists?(metadata_json)
448
+ module_name = nil
449
+ begin
450
+ module_name = JSON.parse(IO.read(metadata_json))['name'].split('/').last
451
+ rescue
452
+ error("not able to load or parse #{metadata_json_path} for the name of the module")
453
+ end
454
+
455
+ if module_name
456
+ module_target_path = File.join(sandbox_path, 'modules', module_name)
457
+ FileUtils.mkdir_p(module_target_path)
458
+ FileUtils.cp_r(
459
+ Dir.glob(File.join(config[:kitchen_root], '*')).reject { |entry| entry =~ /modules/ },
460
+ module_target_path,
461
+ remove_destination: true
462
+ )
463
+ end
464
+ end
465
+ end
466
+
467
+ def prepare_hiera_config
468
+ return unless hiera_config
469
+
470
+ info('Preparing hiera')
471
+ debug("Using hiera from #{hiera_config}")
472
+
473
+ FileUtils.cp_r(hiera_config, File.join(sandbox_path, 'hiera.yaml'))
474
+ end
475
+
476
+ def prepare_fileserver_config
477
+ return unless fileserver_config
478
+
479
+ info('Preparing fileserver')
480
+ debug("Using fileserver config from #{fileserver_config}")
481
+
482
+ FileUtils.cp_r(fileserver_config, File.join(sandbox_path, 'fileserver.conf'))
483
+ end
484
+
485
+ def prepare_hiera_data
486
+ return unless hiera_data
487
+ info('Preparing hiera data')
488
+ debug("Using hiera data from #{hiera_data}")
489
+
490
+ tmp_hiera_dir = File.join(sandbox_path, 'hiera')
491
+ FileUtils.mkdir_p(tmp_hiera_dir)
492
+ FileUtils.cp_r(Dir.glob("#{hiera_data}/*"), tmp_hiera_dir)
493
+ end
494
+
495
+ def resolve_with_librarian
496
+ Kitchen.mutex.synchronize do
497
+ Puppet::Librarian.new(puppetfile, tmpmodules_dir, logger).resolve
498
+ end
499
+ end
500
+ end
501
+ end
502
+ end