kitchen-puppet 0.0.10 → 0.0.11

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