kitchen-puppet 0.0.11 → 0.0.12

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,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,502 +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
- 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
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
+
428
+ FileUtils.mkdir_p(tmpmodules_dir)
429
+
430
+ if modules && File.directory?(modules)
431
+ debug("Using modules from #{modules}")
432
+ FileUtils.cp_r(Dir.glob("#{modules}/*"), tmpmodules_dir, remove_destination: true)
433
+ else
434
+ info 'nothing to do for modules'
435
+ end
436
+
437
+ resolve_with_librarian if File.exists?(puppetfile)
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