kitchen-puppet 1.44.2 → 1.45.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,1207 +1,1204 @@
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 'uri'
24
- require 'json'
25
- require 'kitchen'
26
- require 'kitchen/provisioner/puppet/librarian'
27
-
28
- module Kitchen
29
- class Busser
30
- def non_suite_dirs
31
- %w(data data_bags environments nodes roles puppet)
32
- end
33
- end
34
-
35
- module Configurable
36
- def platform_name
37
- instance.platform.name
38
- end
39
- end
40
-
41
- module Provisioner
42
- #
43
- # Puppet Apply provisioner.
44
- #
45
- class PuppetApply < Base
46
- attr_accessor :tmp_dir
47
-
48
- default_config :require_puppet_collections, false
49
- default_config :puppet_yum_collections_repo, 'http://yum.puppetlabs.com/puppetlabs-release-pc1-el-6.noarch.rpm'
50
- default_config :puppet_apt_collections_repo, 'http://apt.puppetlabs.com/puppetlabs-release-pc1-wheezy.deb'
51
- default_config :puppet_coll_remote_path, '/opt/puppetlabs'
52
- default_config :puppet_version, nil
53
- default_config :facter_version, nil
54
- default_config :hiera_version, nil
55
- default_config :install_hiera, false
56
- default_config :hiera_package, 'hiera-puppet'
57
- default_config :require_puppet_repo, true
58
- default_config :require_chef_for_busser, true
59
- default_config :resolve_with_librarian_puppet, true
60
- default_config :puppet_environment, nil
61
- default_config :puppet_apt_repo, 'http://apt.puppetlabs.com/puppetlabs-release-precise.deb'
62
- default_config :puppet_yum_repo, 'https://yum.puppetlabs.com/puppetlabs-release-el-6.noarch.rpm'
63
- default_config :chef_bootstrap_url, 'https://www.getchef.com/chef/install.sh'
64
- default_config :puppet_logdest, nil
65
- default_config :custom_install_command, nil
66
- default_config :custom_pre_install_command, nil
67
- default_config :custom_pre_apply_command, nil
68
- default_config :puppet_whitelist_exit_code, nil
69
- default_config :require_puppet_omnibus, false
70
- default_config :puppet_omnibus_url, 'https://raw.githubusercontent.com/petems/puppet-install-shell/master/install_puppet.sh'
71
- default_config :puppet_enc, nil
72
- default_config :ignore_spec_fixtures, false
73
-
74
- default_config :puppet_apply_command, nil
75
-
76
- default_config :puppet_git_init, nil
77
- default_config :puppet_git_pr, nil
78
-
79
- default_config :http_proxy, nil
80
- default_config :https_proxy, nil
81
-
82
- default_config :ignored_paths_from_root, []
83
- default_config :hiera_data_remote_path, '/var/lib/hiera'
84
- default_config :manifest, 'site.pp'
85
-
86
- default_config :manifests_path do |provisioner|
87
- provisioner.calculate_path('manifests') ||
88
- raise('No manifests_path detected. Please specify one in .kitchen.yml')
89
- end
90
-
91
- default_config :modules_path do |provisioner|
92
- modules_path = provisioner.calculate_path('modules')
93
- if modules_path.nil? && provisioner.calculate_path('Puppetfile', :file).nil?
94
- raise('No modules_path detected. Please specify one in .kitchen.yml')
95
- end
96
- modules_path
97
- end
98
-
99
- default_config :files_path do |provisioner|
100
- provisioner.calculate_path('files') || 'files'
101
- end
102
-
103
- default_config :hiera_data_path do |provisioner|
104
- provisioner.calculate_path('hiera')
105
- end
106
-
107
- default_config :puppet_config_path do |provisioner|
108
- provisioner.calculate_path('puppet.conf', :file)
109
- end
110
-
111
- default_config :hiera_config_path do |provisioner|
112
- provisioner.calculate_path('hiera.yaml', :file)
113
- end
114
-
115
- default_config :fileserver_config_path do |provisioner|
116
- provisioner.calculate_path('fileserver.conf', :file)
117
- end
118
- default_config :puppetfile_path do |provisioner|
119
- provisioner.calculate_path('Puppetfile', :file)
120
- end
121
-
122
- default_config :modulefile_path do |provisioner|
123
- provisioner.calculate_path('Modulefile', :file)
124
- end
125
-
126
- default_config :metadata_json_path do |provisioner|
127
- provisioner.calculate_path('metadata.json', :file)
128
- end
129
-
130
- default_config :manifests_path do |provisioner|
131
- provisioner.calculate_path('manifests', :directory)
132
- end
133
-
134
- default_config :spec_files_path do |provisioner|
135
- provisioner.calculate_path('spec', :directory)
136
- end
137
-
138
- default_config :spec_files_remote_path, '/etc/puppet/spec'
139
-
140
- default_config :puppet_debug, false
141
- default_config :puppet_verbose, false
142
- default_config :puppet_noop, false
143
- default_config :platform, &:platform_name
144
- default_config :update_package_repos, true
145
- default_config :remove_puppet_repo, false
146
- default_config :install_custom_facts, false
147
- default_config :custom_facts, {}
148
- default_config :facterlib, nil
149
- default_config :puppet_detailed_exitcodes, nil
150
- default_config :facter_file, nil
151
- default_config :librarian_puppet_ssl_file, nil
152
-
153
- default_config :hiera_eyaml, false
154
- default_config :hiera_eyaml_key_remote_path, '/etc/puppet/secure/keys'
155
-
156
- default_config :hiera_eyaml_key_path do |provisioner|
157
- provisioner.calculate_path('hiera_keys')
158
- end
159
-
160
- default_config :hiera_deep_merge, false
161
- default_config :puppet_no_sudo, false
162
-
163
- def calculate_path(path, type = :directory)
164
- base = config[:test_base_path]
165
- candidates = []
166
- candidates << File.join(base, instance.suite.name, 'puppet', path)
167
- candidates << File.join(base, instance.suite.name, path)
168
- candidates << File.join(base, path)
169
- candidates << File.join(Dir.pwd, path)
170
-
171
- candidates.find do |c|
172
- type == :directory ? File.directory?(c) : File.file?(c)
173
- end
174
- end
175
-
176
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
177
- def install_command
178
- return unless config[:require_puppet_collections] || config[:require_puppet_repo] || config[:require_puppet_omnibus]
179
- if config[:require_puppet_omnibus]
180
- install_omnibus_command
181
- elsif config[:require_puppet_collections]
182
- install_command_collections
183
- else
184
- case puppet_platform
185
- when 'debian', 'ubuntu'
186
- info("Installing puppet on #{config[:platform]}")
187
- # need to add a CR to avoid trouble with proxy settings concatenation
188
- <<-INSTALL
189
-
190
- #{custom_pre_install_command}
191
- if [ ! $(which puppet) ]; then
192
- #{sudo('apt-get')} -y install wget
193
- #{sudo('wget')} #{wget_proxy_parm} #{puppet_apt_repo}
194
- #{sudo('dpkg')} -i #{puppet_apt_repo_file}
195
- #{update_packages_debian_cmd}
196
- #{sudo_env('apt-get')} -y install facter#{facter_debian_version}
197
- #{sudo_env('apt-get')} -y install puppet-common#{puppet_debian_version}
198
- #{sudo_env('apt-get')} -y install puppet#{puppet_debian_version}
199
- #{install_hiera}
200
- fi
201
- #{install_eyaml}
202
- #{install_deep_merge}
203
- #{install_busser}
204
- #{custom_install_command}
205
- INSTALL
206
- when 'redhat', 'centos', 'fedora', 'oracle', 'amazon'
207
- info("Installing puppet from yum on #{puppet_platform}")
208
- # need to add a CR to avoid trouble with proxy settings concatenation
209
- <<-INSTALL
210
-
211
- #{custom_pre_install_command}
212
- if [ ! $(which puppet) ]; then
213
- #{install_puppet_yum_repo}
214
- fi
215
- #{install_eyaml}
216
- #{install_deep_merge}
217
- #{install_busser}
218
- #{custom_install_command}
219
- INSTALL
220
- when /^windows.*/
221
- info("Installing puppet on #{puppet_platform}")
222
- <<-INSTALL
223
- if(Get-Command puppet -ErrorAction 0) { return; }
224
- if( [Environment]::Is64BitOperatingSystem ) {
225
- $MsiUrl = "https://downloads.puppetlabs.com/windows/puppet-#{puppet_windows_version}-x64.msi"
226
- } else {
227
- $MsiUrl = "https://downloads.puppetlabs.com/windows/puppet-#{puppet_windows_version}.msi"
228
- }
229
- $process = Start-Process -FilePath msiexec.exe -Wait -PassThru -ArgumentList '/qn', '/norestart', '/i', $MsiUrl
230
- if ($process.ExitCode -ne 0) {
231
- Write-Host "Installer failed."
232
- Exit 1
233
- }
234
-
235
- #{install_busser}
236
- INSTALL
237
- else
238
- info('Installing puppet, will try to determine platform os')
239
- # need to add a CR to avoid trouble with proxy settings concatenation
240
- <<-INSTALL
241
-
242
- #{custom_pre_install_command}
243
- if [ ! $(which puppet) ]; then
244
- if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ] || [ -f /etc/oracle-release ]; then
245
- #{install_puppet_yum_repo}
246
- else
247
- if [ -f /etc/system-release ] || [ grep -q 'Amazon Linux' /etc/system-release ]; then
248
- #{install_puppet_yum_repo}
249
- else
250
- #{sudo('apt-get')} -y install wget
251
- #{sudo('wget')} #{wget_proxy_parm} #{puppet_apt_repo}
252
- #{sudo('dpkg')} -i #{puppet_apt_repo_file}
253
- #{update_packages_debian_cmd}
254
- #{sudo_env('apt-get')} -y install facter#{facter_debian_version}
255
- #{sudo_env('apt-get')} -y install puppet-common#{puppet_debian_version}
256
- #{sudo_env('apt-get')} -y install puppet#{puppet_debian_version}
257
- #{install_hiera}
258
- fi
259
- fi
260
- fi
261
- #{install_eyaml}
262
- #{install_deep_merge}
263
- #{install_busser}
264
- #{custom_install_command}
265
- INSTALL
266
- end
267
- end
268
- end
269
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
270
-
271
- def install_command_collections
272
- case puppet_platform
273
- when 'debian', 'ubuntu'
274
- info("Installing Puppet Collections on #{puppet_platform}")
275
- <<-INSTALL
276
-
277
- #{Util.shell_helpers}
278
- #{custom_pre_install_command}
279
- if [ ! -d "#{config[:puppet_coll_remote_path]}" ]; then
280
- if [ ! -f "#{config[:puppet_apt_collections_repo]}" ]; then
281
- #{sudo('apt-get')} -y install wget
282
- #{sudo('wget')} #{wget_proxy_parm} #{config[:puppet_apt_collections_repo]}
283
- fi
284
- #{sudo('dpkg')} -i #{puppet_apt_coll_repo_file}
285
- #{sudo('apt-get')} update
286
- #{sudo_env('apt-get')} -y install puppet-agent#{puppet_debian_version}
287
- fi
288
- #{install_eyaml("#{config[:puppet_coll_remote_path]}/puppet/bin/gem")}
289
- #{install_deep_merge}
290
- #{install_busser}
291
- #{custom_install_command}
292
- INSTALL
293
- when 'redhat', 'centos', 'fedora', 'oracle', 'amazon'
294
- info("Installing Puppet Collections on #{puppet_platform}")
295
- <<-INSTALL
296
-
297
- #{Util.shell_helpers}
298
- if [ ! -d "#{config[:puppet_coll_remote_path]}" ]; then
299
- echo "-----> #{sudo_env('yum')} -y localinstall #{config[:puppet_yum_collections_repo]}"
300
- #{sudo_env('yum')} -y localinstall #{config[:puppet_yum_collections_repo]}
301
- #{sudo_env('yum')} -y install puppet-agent#{puppet_redhat_version}
302
- fi
303
- #{install_eyaml("#{config[:puppet_coll_remote_path]}/puppet/bin/gem")}
304
- #{install_deep_merge}
305
- #{install_busser}
306
- #{custom_install_command}
307
- INSTALL
308
- else
309
- info('Installing Puppet Collections, will try to determine platform os')
310
- <<-INSTALL
311
-
312
- #{Util.shell_helpers}
313
- #{custom_pre_install_command}
314
- if [ ! -d "#{config[:puppet_coll_remote_path]}" ]; then
315
- if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ] || [ -f /etc/oracle-release ] || \
316
- [ -f /etc/system-release ] || [ grep -q 'Amazon Linux' /etc/system-release ]; then
317
- echo "-----> #{sudo_env('yum')} -y localinstall #{config[:puppet_yum_collections_repo]}"
318
- #{sudo_env('yum')} -y localinstall #{config[:puppet_yum_collections_repo]}
319
- #{sudo_env('yum')} -y install puppet-agent#{puppet_redhat_version}
320
- else
321
- #{sudo('apt-get')} -y install wget
322
- #{sudo('wget')} #{wget_proxy_parm} #{config[:puppet_apt_collections_repo]}
323
- #{sudo('dpkg')} -i #{puppet_apt_coll_repo_file}
324
- #{sudo('apt-get')} update
325
- #{sudo_env('apt-get')} -y install puppet-agent#{puppet_debian_version}
326
- fi
327
- fi
328
- #{install_eyaml("#{config[:puppet_coll_remote_path]}/puppet/bin/gem")}
329
- #{install_deep_merge}
330
- #{install_busser}
331
- #{custom_install_command}
332
- INSTALL
333
- end
334
- end
335
-
336
- def install_deep_merge
337
- return unless config[:hiera_deep_merge]
338
- <<-INSTALL
339
- # Support for hash merge lookups to recursively merge hash keys
340
- if [[ $(#{sudo('gem')} list deep_merge -i) == 'false' ]]; then
341
- echo '-----> Installing deep_merge to provide deep_merge of hiera hashes'
342
- #{sudo('gem')} install #{gem_proxy_parm} --no-ri --no-rdoc deep_merge
343
- fi
344
- INSTALL
345
- end
346
-
347
- def install_eyaml(gem_cmd = 'gem')
348
- return unless config[:hiera_eyaml]
349
- <<-INSTALL
350
- # A backend for Hiera that provides per-value asymmetric encryption of sensitive data
351
- if [[ $(#{sudo(gem_cmd)} list hiera-eyaml -i) == 'false' ]]; then
352
- echo '-----> Installing hiera-eyaml to provide encryption of hiera data'
353
- #{sudo(gem_cmd)} install #{gem_proxy_parm} --no-ri --no-rdoc highline -v 1.6.21
354
- #{sudo(gem_cmd)} install #{gem_proxy_parm} --no-ri --no-rdoc hiera-eyaml
355
- fi
356
- INSTALL
357
- end
358
-
359
- def install_busser
360
- return unless config[:require_chef_for_busser]
361
- info("Install busser on #{puppet_platform}")
362
- case puppet_platform
363
- when /^windows.*/
364
- # https://raw.githubusercontent.com/opscode/knife-windows/master/lib/chef/knife/bootstrap/windows-chef-client-msi.erb
365
- <<-INSTALL
366
- $webclient = New-Object System.Net.WebClient; $webclient.DownloadFile('https://opscode-omnibus-packages.s3.amazonaws.com/windows/2008r2/x86_64/chef-windows-11.12.8-1.windows.msi','chef-windows-11.12.8-1.windows.msi')
367
- msiexec /qn /i chef-windows-11.12.8-1.windows.msi
368
-
369
- cmd.exe /C "SET PATH=%PATH%;`"C:\\opscode\\chef\\embedded\\bin`";`"C:\\tmp\\busser\\gems\\bin`""
370
-
371
- INSTALL
372
- else
373
- <<-INSTALL
374
- #{Util.shell_helpers}
375
- # install chef omnibus so that busser works as this is needed to run tests :(
376
- # TODO: work out how to install enough ruby
377
- # and set busser: { :ruby_bindir => '/usr/bin/ruby' } so that we dont need the
378
- # whole chef client
379
- if [ ! -d "/opt/chef" ]
380
- then
381
- echo '-----> Installing Chef Omnibus to install busser to run tests'
382
- #{export_http_proxy_parm}
383
- #{export_https_proxy_parm}
384
- do_download #{chef_url} /tmp/install.sh
385
- #{sudo('sh')} /tmp/install.sh
386
- fi
387
- INSTALL
388
- end
389
- end
390
-
391
- def install_omnibus_command
392
- info('Installing puppet using puppet omnibus')
393
-
394
- version = ''
395
- version = "-v #{config[:puppet_version]}" unless config[:puppet_version].nil?
396
-
397
- <<-INSTALL
398
- #{Util.shell_helpers}
399
- if [ ! $(which puppet) ]; then
400
- echo "-----> Installing Puppet Omnibus"
401
- #{export_http_proxy_parm}
402
- #{export_https_proxy_parm}
403
- do_download #{config[:puppet_omnibus_url]} /tmp/install_puppet.sh
404
- #{sudo_env('sh')} /tmp/install_puppet.sh #{version}
405
- fi
406
- INSTALL
407
- end
408
-
409
- def install_hiera
410
- return unless config[:install_hiera]
411
- <<-INSTALL
412
- #{sudo_env('apt-get')} -y install #{hiera_package}
413
- INSTALL
414
- end
415
-
416
- def hiera_package
417
- "#{config[:hiera_package]}#{puppet_hiera_debian_version}"
418
- end
419
-
420
- # /bin/wget -P /etc/pki/rpm-gpg/ http://yum.puppetlabs.com/RPM-GPG-KEY-puppetlabs
421
- # changed to curl
422
-
423
- def install_puppet_yum_repo
424
- <<-INSTALL
425
- rhelversion=$(cat /etc/redhat-release | grep 'release 7')
426
- # For CentOS7/RHEL7 the rdo release contains puppetlabs repo, creating conflict. Create temp-repo
427
- #{sudo_env('curl')} -o /etc/pki/rpm-gpg/RPM-GPG-KEY-puppetlabs http://yum.puppetlabs.com/RPM-GPG-KEY-puppetlabs
428
- if [ -n "$rhelversion" ]; then
429
- echo '[puppettemp-products]
430
- name=Puppet Labs Products - \$basearch
431
- baseurl=http://yum.puppetlabs.com/el/7/products/\$basearch
432
- gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-puppetlabs
433
- enabled=0
434
- gpgcheck=1
435
- [puppettemp-deps]
436
- name=Puppet Labs Dependencies - \$basearch
437
- baseurl=http://yum.puppetlabs.com/el/7/dependencies/\$basearch
438
- gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-puppetlabs
439
- enabled=0
440
- gpgcheck=1' | sudo tee /etc/yum.repos.d/puppettemp.repo > /dev/null
441
- sudo sed -i 's/^[ \t]*//' /etc/yum.repos.d/puppettemp.repo
442
- #{update_packages_redhat_cmd}
443
- #{sudo_env('yum')} -y --enablerepo=puppettemp-products --enablerepo=puppettemp-deps install puppet#{puppet_redhat_version}
444
- # Clean up temporary puppet repo
445
- sudo rm -rf /etc/pki/rpm-gpg/RPM-GPG-KEY-puppetlabs
446
- sudo rm -rf /etc/yum.repos.d/puppettemp.repo
447
- else
448
- #{sudo('rpm')} -ivh #{proxy_parm} #{puppet_yum_repo}
449
- #{update_packages_redhat_cmd}
450
- #{sudo_env('yum')} -y install puppet#{puppet_redhat_version}
451
- fi
452
- INSTALL
453
- end
454
-
455
- def custom_pre_install_command
456
- <<-INSTALL
457
- #{config[:custom_pre_install_command]}
458
- INSTALL
459
- end
460
-
461
- def custom_install_command
462
- <<-INSTALL
463
- #{config[:custom_install_command]}
464
- INSTALL
465
- end
466
-
467
- def init_command
468
- todelete = %w(modules manifests files hiera hiera.yaml facter spec enc)
469
- .map { |dir| File.join(config[:root_path], dir) }
470
- todelete += [hiera_data_remote_path,
471
- '/etc/hiera.yaml',
472
- "#{puppet_dir}/hiera.yaml",
473
- spec_files_remote_path.to_s,
474
- "#{puppet_dir}/fileserver.conf"]
475
- todelete << File.join(puppet_dir, config[:puppet_environment]) if config[:puppet_environment]
476
- cmd = "#{sudo(rm_command_paths(todelete))};"
477
- cmd += " #{mkdir_command} #{config[:root_path]};"
478
- cmd += " #{sudo(mkdir_command)} #{puppet_dir}"
479
- debug(cmd)
480
- cmd
481
- end
482
-
483
- def create_sandbox
484
- super
485
- debug("Creating local sandbox in #{sandbox_path}")
486
- yield if block_given?
487
- prepare_modules
488
- prepare_manifests
489
- prepare_files
490
- prepare_facter_file
491
- prepare_facts
492
- prepare_puppet_config
493
- prepare_hiera_config
494
- prepare_fileserver_config
495
- prepare_hiera_data
496
- prepare_enc
497
- prepare_spec_files
498
- info('Finished Preparing files for transfer')
499
- end
500
-
501
- def cleanup_sandbox
502
- return if sandbox_path.nil?
503
- debug("Cleaning up local sandbox in #{sandbox_path}")
504
- FileUtils.rmtree(sandbox_path)
505
- return if remove_repo.nil?
506
- debug("Cleaning up remote sandbox: #{remove_repo}")
507
- instance.remote_exec remove_repo
508
- end
509
-
510
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
511
- def prepare_command
512
- commands = []
513
- if puppet_git_init
514
- commands << [
515
- sudo('rm -rf'), '/etc/puppet'
516
- ].join(' ')
517
-
518
- commands << [
519
- sudo('git clone'), puppet_git_init, '/etc/puppet'
520
- ].join(' ')
521
- end
522
-
523
- if puppet_git_pr
524
- commands << [
525
- sudo('git'),
526
- '--git-dir=/etc/puppet/.git/',
527
- 'fetch -f',
528
- 'origin',
529
- "pull/#{puppet_git_pr}/head:pr_#{puppet_git_pr}"
530
- ].join(' ')
531
-
532
- commands << [
533
- sudo('git'),
534
- '--git-dir=/etc/puppet/.git/',
535
- '--work-tree=/etc/puppet/',
536
- 'checkout',
537
- "pr_#{puppet_git_pr}"
538
- ].join(' ')
539
- end
540
-
541
- if puppet_config
542
- commands << [
543
- sudo(cp_command),
544
- File.join(config[:root_path], 'puppet.conf'),
545
- puppet_dir
546
- ].join(' ')
547
- end
548
-
549
- if hiera_config
550
- commands << [
551
- sudo(cp_command), File.join(config[:root_path], 'hiera.yaml'), '/etc/'
552
- ].join(' ')
553
-
554
- commands << [
555
- sudo(cp_command), File.join(config[:root_path], 'hiera.yaml'), hiera_config_dir
556
- ].join(' ')
557
- end
558
-
559
- if fileserver_config
560
- commands << [
561
- sudo(cp_command),
562
- File.join(config[:root_path], 'fileserver.conf'),
563
- puppet_dir
564
- ].join(' ')
565
- end
566
-
567
- if hiera_data && hiera_data_remote_path == '/var/lib/hiera'
568
- commands << [
569
- sudo("#{cp_command} -r"), File.join(config[:root_path], 'hiera'), '/var/lib/'
570
- ].join(' ')
571
- end
572
-
573
- if hiera_data && hiera_data_remote_path != '/var/lib/hiera'
574
- commands << [
575
- sudo(mkdir_command), hiera_data_remote_path
576
- ].join(' ')
577
- commands << [
578
- sudo("#{cp_command} -r"), File.join(config[:root_path], 'hiera/*'), hiera_data_remote_path
579
- ].join(' ')
580
- end
581
-
582
- if hiera_eyaml
583
- commands << [
584
- sudo(mkdir_command), hiera_eyaml_key_remote_path
585
- ].join(' ')
586
- commands << [
587
- sudo("#{cp_command} -r"), File.join(config[:root_path], 'hiera_keys/*'), hiera_eyaml_key_remote_path
588
- ].join(' ')
589
- end
590
-
591
- if puppet_environment
592
- commands << [
593
- sudo('ln -s '), config[:root_path], File.join(puppet_dir, config[:puppet_environment])
594
- ].join(' ')
595
- end
596
-
597
- if spec_files_path && spec_files_remote_path
598
- commands << [
599
- sudo(mkdir_command), spec_files_remote_path
600
- ].join(' ')
601
- commands << [
602
- sudo("#{cp_command} -r"), File.join(config[:root_path], 'spec/*'), spec_files_remote_path
603
- ].join(' ')
604
- end
605
-
606
- if config[:puppet_enc]
607
- commands << [
608
- sudo('chmod 755'), File.join("#{config[:root_path]}/enc", File.basename(config[:puppet_enc]))
609
- ].join(' ')
610
- end
611
-
612
- command = powershell_shell? ? commands.join('; ') : commands.join(' && ')
613
- debug(command)
614
- command
615
- end
616
-
617
- def run_command
618
- if !config[:puppet_apply_command].nil?
619
- return config[:puppet_apply_command]
620
- else
621
- result = [
622
- facterlib,
623
- custom_facts,
624
- puppet_manifestdir,
625
- puppet_cmd,
626
- 'apply',
627
- File.join(config[:root_path], 'manifests', manifest),
628
- "--modulepath=#{File.join(config[:root_path], 'modules')}",
629
- "--fileserverconfig=#{File.join(config[:root_path], 'fileserver.conf')}",
630
- custom_options,
631
- puppet_environment_flag,
632
- puppet_noop_flag,
633
- puppet_enc_flag,
634
- puppet_detailed_exitcodes_flag,
635
- puppet_verbose_flag,
636
- puppet_debug_flag,
637
- puppet_logdest_flag,
638
- puppet_whitelist_exit_code
639
- ].join(' ')
640
- if config[:custom_post_apply_command]
641
- custom_post_apply_trap = <<-TRAP
642
- function custom_post_apply_command {
643
- #{config[:custom_post_apply_command]}
644
- }
645
- trap custom_post_apply_command EXIT
646
- TRAP
647
- end
648
- result = <<-RUN
649
- #{config[:custom_pre_apply_command]}
650
- #{custom_post_apply_trap}
651
- #{result}
652
- RUN
653
- info("Going to invoke puppet apply with: #{result}")
654
- result
655
- end
656
- end
657
-
658
- protected
659
-
660
- def load_needed_dependencies!
661
- return unless File.exist?(puppetfile)
662
- return unless config[:resolve_with_librarian_puppet]
663
- debug("Puppetfile found at #{puppetfile}, loading Librarian-Puppet")
664
- Puppet::Librarian.load!(logger)
665
- end
666
-
667
- def tmpmodules_dir
668
- File.join(sandbox_path, 'modules')
669
- end
670
-
671
- def puppetfile
672
- config[:puppetfile_path] || ''
673
- end
674
-
675
- def modulefile
676
- config[:modulefile_path] || ''
677
- end
678
-
679
- def metadata_json
680
- config[:metadata_json_path] || ''
681
- end
682
-
683
- def manifest
684
- config[:manifest]
685
- end
686
-
687
- def manifests
688
- config[:manifests_path]
689
- end
690
-
691
- def modules
692
- config[:modules_path]
693
- end
694
-
695
- def files
696
- config[:files_path] || 'files'
697
- end
698
-
699
- def puppet_config
700
- config[:puppet_config_path]
701
- end
702
-
703
- def puppet_environment
704
- config[:puppet_environment]
705
- end
706
-
707
- def puppet_git_init
708
- config[:puppet_git_init]
709
- end
710
-
711
- def puppet_git_pr
712
- config[:puppet_git_pr]
713
- end
714
-
715
- def hiera_config
716
- config[:hiera_config_path]
717
- end
718
-
719
- def fileserver_config
720
- config[:fileserver_config_path]
721
- end
722
-
723
- def hiera_data
724
- config[:hiera_data_path]
725
- end
726
-
727
- def hiera_data_remote_path
728
- config[:hiera_data_remote_path]
729
- end
730
-
731
- def hiera_eyaml
732
- config[:hiera_eyaml]
733
- end
734
-
735
- def hiera_eyaml_key_path
736
- config[:hiera_eyaml_key_path]
737
- end
738
-
739
- def hiera_eyaml_key_remote_path
740
- config[:hiera_eyaml_key_remote_path]
741
- end
742
-
743
- def hiera_deep_merge
744
- config[:hiera_deep_merge]
745
- end
746
-
747
- def librarian_puppet_ssl_file
748
- config[:librarian_puppet_ssl_file]
749
- end
750
-
751
- def puppet_cmd
752
- puppet_bin = powershell_shell? ? '& "C:\Program Files\Puppet Labs\Puppet\bin\puppet"' : 'puppet'
753
- if config[:require_puppet_collections]
754
- puppet_bin = "#{config[:puppet_coll_remote_path]}/bin/puppet"
755
- end
756
-
757
- if config[:puppet_no_sudo]
758
- puppet_bin
759
- else
760
- sudo_env(puppet_bin)
761
- end
762
- end
763
-
764
- def puppet_dir
765
- return '/etc/puppetlabs/puppet' if config[:require_puppet_collections]
766
- return '/etc/puppet' unless powershell_shell?
767
- 'C:/ProgramData/PuppetLabs/puppet/etc'
768
- end
769
-
770
- def hiera_config_dir
771
- return '/etc/puppetlabs/code' if config[:require_puppet_collections]
772
- return '/etc/puppet' unless powershell_shell?
773
- 'C:/ProgramData/PuppetLabs/puppet/etc'
774
- end
775
-
776
- def puppet_debian_version
777
- config[:puppet_version] ? "=#{config[:puppet_version]}" : nil
778
- end
779
-
780
- def facter_debian_version
781
- config[:facter_version] ? "=#{config[:facter_version]}" : nil
782
- end
783
-
784
- def puppet_hiera_debian_version
785
- config[:hiera_version] ? "=#{config[:hiera_version]}" : nil
786
- end
787
-
788
- def puppet_redhat_version
789
- if puppet_platform == 'amazon'
790
- config[:puppet_version]
791
- else
792
- config[:puppet_version] ? "-#{config[:puppet_version]}" : nil
793
- end
794
- end
795
-
796
- def puppet_windows_version
797
- config[:puppet_version] ? config[:puppet_version].to_s : '3.8.6'
798
- end
799
-
800
- def puppet_environment_flag
801
- if config[:puppet_version] =~ /^2/
802
- config[:puppet_environment] ? "--environment=#{config[:puppet_environment]}" : nil
803
- else
804
- config[:puppet_environment] ? "--environment=#{config[:puppet_environment]} --environmentpath=#{puppet_dir}" : nil
805
- end
806
- end
807
-
808
- def puppet_manifestdir
809
- return nil if config[:require_puppet_collections]
810
- return nil if config[:puppet_environment]
811
- return nil if powershell_shell?
812
- bash_vars = "export MANIFESTDIR='#{File.join(config[:root_path], 'manifests')}';"
813
- debug(bash_vars)
814
- bash_vars
815
- end
816
-
817
- def custom_options
818
- config[:custom_options] || ''
819
- end
820
-
821
- def puppet_noop_flag
822
- config[:puppet_noop] ? '--noop' : nil
823
- end
824
-
825
- def puppet_debug_flag
826
- config[:puppet_debug] ? '-d' : nil
827
- end
828
-
829
- def puppet_verbose_flag
830
- config[:puppet_verbose] ? '-v' : nil
831
- end
832
-
833
- def puppet_logdest_flag
834
- return nil unless config[:puppet_logdest]
835
- destinations = ''
836
- config[:puppet_logdest].each do |dest|
837
- destinations << "--logdest #{dest} "
838
- end
839
- destinations
840
- end
841
-
842
- def puppet_platform
843
- config[:platform].gsub(/-.*/, '')
844
- end
845
-
846
- def update_packages_debian_cmd
847
- config[:update_package_repos] ? "#{sudo_env('apt-get')} update" : nil
848
- end
849
-
850
- def update_packages_redhat_cmd
851
- # #{sudo('yum')}
852
- config[:update_package_repos] ? "#{sudo_env('yum')} makecache" : nil
853
- end
854
-
855
- def sudo_env(pm)
856
- s = https_proxy ? "https_proxy=#{https_proxy}" : nil
857
- p = http_proxy ? "http_proxy=#{http_proxy}" : nil
858
- p || s ? "#{sudo('env')} #{p} #{s} #{pm}" : sudo(pm).to_s
859
- end
860
-
861
- def remove_puppet_repo
862
- config[:remove_puppet_repo]
863
- end
864
-
865
- def spec_files_path
866
- config[:spec_files_path]
867
- end
868
-
869
- def spec_files_remote_path
870
- config[:spec_files_remote_path]
871
- end
872
-
873
- def facterlib
874
- factpath = nil
875
- factpath = File.join(config[:root_path], 'facter').to_s if config[:install_custom_facts] && !config[:custom_facts].none?
876
- factpath = File.join(config[:root_path], 'facter').to_s if config[:facter_file]
877
- factpath = "#{factpath}:" if config[:facterlib] && !factpath.nil?
878
- factpath = "#{factpath}#{config[:facterlib]}" if config[:facterlib]
879
- return nil if factpath.nil?
880
- bash_vars = "export FACTERLIB='#{factpath}';"
881
- debug(bash_vars)
882
- bash_vars
883
- end
884
-
885
- def custom_facts
886
- return nil if config[:custom_facts].none?
887
- return nil if config[:install_custom_facts]
888
- if powershell_shell?
889
- environment_vars = config[:custom_facts].map { |k, v| "$env:FACTER_#{k}='#{v}'" }.join('; ')
890
- environment_vars = "#{environment_vars};"
891
- else
892
- environment_vars = config[:custom_facts].map { |k, v| "FACTER_#{k}=#{v}" }.join(' ')
893
- environment_vars = "export #{environment_vars};"
894
- end
895
- debug(environment_vars)
896
- environment_vars
897
- end
898
-
899
- def puppet_enc_flag
900
- config[:puppet_enc] ? "--node_terminus=exec --external_nodes=#{config[:root_path]}/enc/#{File.basename(config[:puppet_enc])}" : nil
901
- end
902
-
903
- def puppet_detailed_exitcodes_flag
904
- config[:puppet_detailed_exitcodes] ? '--detailed-exitcodes' : nil
905
- end
906
-
907
- def remove_repo
908
- remove_puppet_repo ? "#{sudo('rm')} -rf /tmp/kitchen #{hiera_data_remote_path} #{hiera_eyaml_key_remote_path} #{puppet_dir}/* " : nil
909
- end
910
-
911
- def puppet_whitelist_exit_code
912
- if config[:puppet_whitelist_exit_code].nil?
913
- return powershell_shell? ? '; exit $LASTEXITCODE' : nil
914
- elsif powershell_shell?
915
- return "; if(@(#{[config[:puppet_whitelist_exit_code]].join(', ')}) -contains $LASTEXITCODE) {exit 0} else {exit $LASTEXITCODE}"
916
- else
917
- return "; [ $? -eq #{config[:puppet_whitelist_exit_code]} ] && exit 0"
918
- end
919
- end
920
-
921
- def puppet_apt_repo
922
- platform_version = config[:platform].partition('-')[2]
923
- case puppet_platform
924
- when 'ubuntu'
925
- case platform_version
926
- when '14.10'
927
- # Utopic Repo
928
- 'https://apt.puppetlabs.com/puppetlabs-release-utopic.deb'
929
- when '14.04'
930
- # Trusty Repo
931
- 'https://apt.puppetlabs.com/puppetlabs-release-trusty.deb'
932
- when '12.04'
933
- # Precise Repo
934
- 'https://apt.puppetlabs.com/puppetlabs-release-precise.deb'
935
- else
936
- # Configured Repo
937
- config[:puppet_apt_repo]
938
- end
939
- when 'debian'
940
- case platform_version.gsub(/\..*/, '')
941
- when '8'
942
- # Debian Jessie
943
- 'https://apt.puppetlabs.com/puppetlabs-release-jessie.deb'
944
- when '7'
945
- # Debian Wheezy
946
- 'https://apt.puppetlabs.com/puppetlabs-release-wheezy.deb'
947
- when '6'
948
- # Debian Squeeze
949
- 'https://apt.puppetlabs.com/puppetlabs-release-squeeze.deb'
950
- else
951
- # Configured Repo
952
- config[:puppet_apt_repo]
953
- end
954
- else
955
- debug("Apt repo detection failed with platform - #{config[:platform]}")
956
- false
957
- end
958
- end
959
-
960
- def puppet_apt_repo_file
961
- puppet_apt_repo.split('/').last if puppet_apt_repo
962
- end
963
-
964
- def puppet_apt_coll_repo_file
965
- config[:puppet_apt_collections_repo].split('/').last
966
- end
967
-
968
- def puppet_yum_repo
969
- config[:puppet_yum_repo]
970
- end
971
-
972
- def proxy_parm
973
- http_proxy ? "--httpproxy #{URI.parse(http_proxy).host.downcase} --httpport #{URI.parse(http_proxy).port} " : nil
974
- end
975
-
976
- def gem_proxy_parm
977
- http_proxy ? "--http-proxy #{http_proxy}" : nil
978
- end
979
-
980
- def wget_proxy_parm
981
- p = http_proxy ? "-e http_proxy=#{http_proxy}" : nil
982
- s = https_proxy ? "-e https_proxy=#{https_proxy}" : nil
983
- p || s ? "-e use_proxy=yes #{p} #{s}" : nil
984
- end
985
-
986
- def export_http_proxy_parm
987
- http_proxy ? "export http_proxy=#{http_proxy}" : nil
988
- end
989
-
990
- def export_https_proxy_parm
991
- https_proxy ? "export https_proxy=#{https_proxy}" : nil
992
- end
993
-
994
- def http_proxy
995
- config[:http_proxy]
996
- end
997
-
998
- def https_proxy
999
- config[:https_proxy]
1000
- end
1001
-
1002
- def chef_url
1003
- config[:chef_bootstrap_url]
1004
- end
1005
-
1006
- def prepare_manifests
1007
- info('Preparing manifests')
1008
- debug("Using manifests from #{manifests}")
1009
-
1010
- tmp_manifests_dir = File.join(sandbox_path, 'manifests')
1011
- FileUtils.mkdir_p(tmp_manifests_dir)
1012
- FileUtils.cp_r(Dir.glob("#{manifests}/*"), tmp_manifests_dir)
1013
- end
1014
-
1015
- def prepare_files
1016
- info('Preparing files')
1017
- unless File.directory?(files)
1018
- info 'nothing to do for files'
1019
- return
1020
- end
1021
-
1022
- debug("Using files from #{files}")
1023
-
1024
- tmp_files_dir = File.join(sandbox_path, 'files')
1025
- FileUtils.mkdir_p(tmp_files_dir)
1026
- FileUtils.cp_r(Dir.glob("#{files}/*"), tmp_files_dir)
1027
- end
1028
-
1029
- def prepare_facter_file
1030
- return unless config[:facter_file]
1031
- info 'Copying facter file'
1032
- facter_dir = File.join(sandbox_path, 'facter')
1033
- FileUtils.mkdir_p(facter_dir)
1034
- FileUtils.cp_r(config[:facter_file], facter_dir)
1035
- end
1036
-
1037
- def prepare_facts
1038
- return unless config[:install_custom_facts]
1039
- return unless config[:custom_facts]
1040
- info 'Installing custom facts'
1041
- facter_dir = File.join(sandbox_path, 'facter')
1042
- FileUtils.mkdir_p(facter_dir)
1043
- tmp_facter_file = File.join(facter_dir, 'kitchen.rb')
1044
- facter_facts = Hash[config[:custom_facts].map { |k, v| [k.to_s, v.to_s] }]
1045
- File.open(tmp_facter_file, 'a') do |out|
1046
- facter_facts.each do |k, v|
1047
- out.write "\nFacter.add(:#{k}) do\n"
1048
- out.write " setcode do\n"
1049
- out.write " \"#{v}\"\n"
1050
- out.write " end\n"
1051
- out.write "end\n"
1052
- end
1053
- end
1054
- end
1055
-
1056
- def prepare_modules
1057
- info('Preparing modules')
1058
-
1059
- FileUtils.mkdir_p(tmpmodules_dir)
1060
- resolve_with_librarian if File.exist?(puppetfile) && config[:resolve_with_librarian_puppet]
1061
-
1062
- if modules && modules.include?(':')
1063
- debug('Found multiple directories in module path merging.....')
1064
- modules_array = modules.split(':')
1065
- modules_array.each do |m|
1066
- copy_modules(m, tmpmodules_dir)
1067
- end
1068
- elsif modules
1069
- copy_modules(modules, tmpmodules_dir)
1070
- else
1071
- info 'nothing to do for modules'
1072
- end
1073
-
1074
- copy_self_as_module
1075
- end
1076
-
1077
- def copy_modules(source, destination)
1078
- return unless File.directory?(source)
1079
-
1080
- debug("Copying modules from #{source} to #{destination}")
1081
-
1082
- excluded_paths = %w(modules spec pkg) + config[:ignored_paths_from_root]
1083
-
1084
- Dir.glob("#{source}/*").each do |f|
1085
- module_name = File.basename(f)
1086
- target = "#{destination}/#{module_name}"
1087
- FileUtils.mkdir_p(target) unless File.exist? target
1088
- FileUtils.cp_r(Dir.glob("#{source}/#{module_name}/*").reject { |entry| entry =~ /#{excluded_paths.join('$|')}$/ }, target, remove_destination: true)
1089
- end
1090
- end
1091
-
1092
- def copy_self_as_module
1093
- if File.exist?(modulefile)
1094
- warn('Modulefile found but this is depricated, ignoring it, see https://tickets.puppetlabs.com/browse/PUP-1188')
1095
- end
1096
-
1097
- return unless File.exist?(metadata_json)
1098
- module_name = nil
1099
- begin
1100
- module_name = JSON.parse(IO.read(metadata_json))['name'].split('-').last
1101
- rescue
1102
- error("not able to load or parse #{metadata_json_path} for the name of the module")
1103
- end
1104
-
1105
- return unless module_name
1106
- module_target_path = File.join(sandbox_path, 'modules', module_name)
1107
- FileUtils.mkdir_p(module_target_path)
1108
-
1109
- excluded_paths = %w(modules spec pkg) + config[:ignored_paths_from_root]
1110
-
1111
- FileUtils.cp_r(
1112
- Dir.glob(File.join(config[:kitchen_root], '*')).reject { |entry| entry =~ /#{excluded_paths.join('$|')}$/ },
1113
- module_target_path,
1114
- remove_destination: true
1115
- )
1116
- end
1117
-
1118
- def prepare_puppet_config
1119
- return unless puppet_config
1120
-
1121
- info('Preparing puppet.conf')
1122
- debug("Using puppet config from #{puppet_config}")
1123
-
1124
- FileUtils.cp_r(puppet_config, File.join(sandbox_path, 'puppet.conf'))
1125
- end
1126
-
1127
- def prepare_enc
1128
- return unless config[:puppet_enc]
1129
- info 'Copying enc file'
1130
- enc_dir = File.join(sandbox_path, 'enc')
1131
- FileUtils.mkdir_p(enc_dir)
1132
- FileUtils.cp_r(config[:puppet_enc], File.join(enc_dir, '/'))
1133
- end
1134
-
1135
- def prepare_hiera_config
1136
- return unless hiera_config
1137
-
1138
- info('Preparing hiera')
1139
- debug("Using hiera from #{hiera_config}")
1140
-
1141
- FileUtils.cp_r(hiera_config, File.join(sandbox_path, 'hiera.yaml'))
1142
- end
1143
-
1144
- def prepare_fileserver_config
1145
- return unless fileserver_config
1146
-
1147
- info('Preparing fileserver')
1148
- debug("Using fileserver config from #{fileserver_config}")
1149
-
1150
- FileUtils.cp_r(fileserver_config, File.join(sandbox_path, 'fileserver.conf'))
1151
- end
1152
-
1153
- def prepare_hiera_data
1154
- return unless hiera_data
1155
- info('Preparing hiera data')
1156
- tmp_hiera_dir = File.join(sandbox_path, 'hiera')
1157
- debug("Copying hiera data from #{hiera_data} to #{tmp_hiera_dir}")
1158
- FileUtils.mkdir_p(tmp_hiera_dir)
1159
- FileUtils.cp_r(Dir.glob("#{hiera_data}/*"), tmp_hiera_dir)
1160
- return unless hiera_eyaml_key_path
1161
- tmp_hiera_key_dir = File.join(sandbox_path, 'hiera_keys')
1162
- debug("Copying hiera eyaml keys from #{hiera_eyaml_key_path} to #{tmp_hiera_key_dir}")
1163
- FileUtils.mkdir_p(tmp_hiera_key_dir)
1164
- FileUtils.cp_r(Dir.glob("#{hiera_eyaml_key_path}/*"), tmp_hiera_key_dir)
1165
- end
1166
-
1167
- def prepare_spec_files
1168
- return unless spec_files_path
1169
- info('Preparing spec files')
1170
- tmp_spec_dir = File.join(sandbox_path, 'spec')
1171
- debug("Copying specs from #{spec_files_path} to #{tmp_spec_dir}")
1172
- FileUtils.mkdir_p(tmp_spec_dir)
1173
- FileUtils.cp_r(Dir.glob(File.join(spec_files_path, '*')).reject { |entry| entry =~ /fixtures$/ }, tmp_spec_dir) if config[:ignore_spec_fixtures]
1174
- FileUtils.cp_r(Dir.glob("#{spec_files_path}/*"), tmp_spec_dir) unless config[:ignore_spec_fixtures]
1175
- end
1176
-
1177
- def resolve_with_librarian
1178
- Kitchen.mutex.synchronize do
1179
- ENV['SSL_CERT_FILE'] = librarian_puppet_ssl_file if librarian_puppet_ssl_file
1180
- Puppet::Librarian.new(puppetfile, tmpmodules_dir, logger).resolve
1181
- ENV['SSL_CERT_FILE'] = '' if librarian_puppet_ssl_file
1182
- end
1183
- end
1184
-
1185
- def cp_command
1186
- return 'cp -force' if powershell_shell?
1187
- 'cp'
1188
- end
1189
-
1190
- def rm_command
1191
- return 'rm -force -recurse' if powershell_shell?
1192
- 'rm -rf'
1193
- end
1194
-
1195
- def mkdir_command
1196
- return 'mkdir -force -path' if powershell_shell?
1197
- 'mkdir -p'
1198
- end
1199
-
1200
- def rm_command_paths(paths)
1201
- return :nil if paths.length.zero?
1202
- return "#{rm_command} \"#{paths.join('", "')}\"" if powershell_shell?
1203
- "#{rm_command} #{paths.join(' ')}"
1204
- end
1205
- end
1206
- end
1207
- 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 'uri'
24
+ require 'json'
25
+ require 'kitchen'
26
+ require 'kitchen/provisioner/puppet/librarian'
27
+
28
+ module Kitchen
29
+ class Busser
30
+ def non_suite_dirs
31
+ %w(data data_bags environments nodes roles puppet)
32
+ end
33
+ end
34
+
35
+ module Configurable
36
+ def platform_name
37
+ instance.platform.name
38
+ end
39
+ end
40
+
41
+ module Provisioner
42
+ #
43
+ # Puppet Apply provisioner.
44
+ #
45
+ class PuppetApply < Base
46
+ attr_accessor :tmp_dir
47
+
48
+ default_config :require_puppet_collections, false
49
+ default_config :puppet_yum_collections_repo, 'http://yum.puppetlabs.com/puppetlabs-release-pc1-el-6.noarch.rpm'
50
+ default_config :puppet_apt_collections_repo, 'http://apt.puppetlabs.com/puppetlabs-release-pc1-wheezy.deb'
51
+ default_config :puppet_coll_remote_path, '/opt/puppetlabs'
52
+ default_config :puppet_version, nil
53
+ default_config :facter_version, nil
54
+ default_config :hiera_version, nil
55
+ default_config :install_hiera, false
56
+ default_config :hiera_package, 'hiera-puppet'
57
+ default_config :require_puppet_repo, true
58
+ default_config :require_chef_for_busser, true
59
+ default_config :resolve_with_librarian_puppet, true
60
+ default_config :puppet_environment, nil
61
+ default_config :puppet_apt_repo, 'http://apt.puppetlabs.com/puppetlabs-release-precise.deb'
62
+ default_config :puppet_yum_repo, 'https://yum.puppetlabs.com/puppetlabs-release-el-6.noarch.rpm'
63
+ default_config :chef_bootstrap_url, 'https://www.getchef.com/chef/install.sh'
64
+ default_config :puppet_logdest, nil
65
+ default_config :custom_install_command, nil
66
+ default_config :custom_pre_install_command, nil
67
+ default_config :custom_pre_apply_command, nil
68
+ default_config :puppet_whitelist_exit_code, nil
69
+ default_config :require_puppet_omnibus, false
70
+ default_config :puppet_omnibus_url, 'https://raw.githubusercontent.com/petems/puppet-install-shell/master/install_puppet.sh'
71
+ default_config :puppet_enc, nil
72
+ default_config :ignore_spec_fixtures, false
73
+
74
+ default_config :puppet_apply_command, nil
75
+
76
+ default_config :puppet_git_init, nil
77
+ default_config :puppet_git_pr, nil
78
+
79
+ default_config :http_proxy, nil
80
+ default_config :https_proxy, nil
81
+
82
+ default_config :ignored_paths_from_root, ['spec']
83
+ default_config :hiera_data_remote_path, '/var/lib/hiera'
84
+ default_config :manifest, 'site.pp'
85
+
86
+ default_config :manifests_path do |provisioner|
87
+ provisioner.calculate_path('manifests') ||
88
+ raise('No manifests_path detected. Please specify one in .kitchen.yml')
89
+ end
90
+
91
+ default_config :modules_path do |provisioner|
92
+ modules_path = provisioner.calculate_path('modules')
93
+ if modules_path.nil? && provisioner.calculate_path('Puppetfile', :file).nil?
94
+ raise('No modules_path detected. Please specify one in .kitchen.yml')
95
+ end
96
+ modules_path
97
+ end
98
+
99
+ default_config :files_path do |provisioner|
100
+ provisioner.calculate_path('files') || 'files'
101
+ end
102
+
103
+ default_config :hiera_data_path do |provisioner|
104
+ provisioner.calculate_path('hiera')
105
+ end
106
+
107
+ default_config :puppet_config_path do |provisioner|
108
+ provisioner.calculate_path('puppet.conf', :file)
109
+ end
110
+
111
+ default_config :hiera_config_path do |provisioner|
112
+ provisioner.calculate_path('hiera.yaml', :file)
113
+ end
114
+
115
+ default_config :fileserver_config_path do |provisioner|
116
+ provisioner.calculate_path('fileserver.conf', :file)
117
+ end
118
+ default_config :puppetfile_path do |provisioner|
119
+ provisioner.calculate_path('Puppetfile', :file)
120
+ end
121
+
122
+ default_config :modulefile_path do |provisioner|
123
+ provisioner.calculate_path('Modulefile', :file)
124
+ end
125
+
126
+ default_config :metadata_json_path do |provisioner|
127
+ provisioner.calculate_path('metadata.json', :file)
128
+ end
129
+
130
+ default_config :manifests_path do |provisioner|
131
+ provisioner.calculate_path('manifests', :directory)
132
+ end
133
+
134
+ default_config :spec_files_path do |provisioner|
135
+ provisioner.calculate_path('spec', :directory)
136
+ end
137
+
138
+ default_config :spec_files_remote_path, '/etc/puppet/spec'
139
+
140
+ default_config :puppet_debug, false
141
+ default_config :puppet_verbose, false
142
+ default_config :puppet_noop, false
143
+ default_config :platform, &:platform_name
144
+ default_config :update_package_repos, true
145
+ default_config :remove_puppet_repo, false
146
+ default_config :install_custom_facts, false
147
+ default_config :custom_facts, {}
148
+ default_config :facterlib, nil
149
+ default_config :puppet_detailed_exitcodes, nil
150
+ default_config :facter_file, nil
151
+ default_config :librarian_puppet_ssl_file, nil
152
+
153
+ default_config :hiera_eyaml, false
154
+ default_config :hiera_eyaml_key_remote_path, '/etc/puppet/secure/keys'
155
+
156
+ default_config :hiera_eyaml_key_path do |provisioner|
157
+ provisioner.calculate_path('hiera_keys')
158
+ end
159
+
160
+ default_config :hiera_deep_merge, false
161
+ default_config :puppet_no_sudo, false
162
+
163
+ def calculate_path(path, type = :directory)
164
+ base = config[:test_base_path]
165
+ candidates = []
166
+ candidates << File.join(base, instance.suite.name, 'puppet', path)
167
+ candidates << File.join(base, instance.suite.name, path)
168
+ candidates << File.join(base, path)
169
+ candidates << File.join(Dir.pwd, path)
170
+
171
+ candidates.find do |c|
172
+ type == :directory ? File.directory?(c) : File.file?(c)
173
+ end
174
+ end
175
+
176
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
177
+ def install_command
178
+ return unless config[:require_puppet_collections] || config[:require_puppet_repo] || config[:require_puppet_omnibus]
179
+ if config[:require_puppet_omnibus]
180
+ install_omnibus_command
181
+ elsif config[:require_puppet_collections]
182
+ install_command_collections
183
+ else
184
+ case puppet_platform
185
+ when 'debian', 'ubuntu'
186
+ info("Installing puppet on #{config[:platform]}")
187
+ # need to add a CR to avoid trouble with proxy settings concatenation
188
+ <<-INSTALL
189
+
190
+ #{custom_pre_install_command}
191
+ if [ ! $(which puppet) ]; then
192
+ #{sudo('apt-get')} -y install wget
193
+ #{sudo('wget')} #{wget_proxy_parm} #{puppet_apt_repo}
194
+ #{sudo('dpkg')} -i #{puppet_apt_repo_file}
195
+ #{update_packages_debian_cmd}
196
+ #{sudo_env('apt-get')} -y install facter#{facter_debian_version}
197
+ #{sudo_env('apt-get')} -y install puppet-common#{puppet_debian_version}
198
+ #{sudo_env('apt-get')} -y install puppet#{puppet_debian_version}
199
+ #{install_hiera}
200
+ fi
201
+ #{install_eyaml}
202
+ #{install_deep_merge}
203
+ #{install_busser}
204
+ #{custom_install_command}
205
+ INSTALL
206
+ when 'redhat', 'centos', 'fedora', 'oracle', 'amazon'
207
+ info("Installing puppet from yum on #{puppet_platform}")
208
+ # need to add a CR to avoid trouble with proxy settings concatenation
209
+ <<-INSTALL
210
+
211
+ #{custom_pre_install_command}
212
+ if [ ! $(which puppet) ]; then
213
+ #{install_puppet_yum_repo}
214
+ fi
215
+ #{install_eyaml}
216
+ #{install_deep_merge}
217
+ #{install_busser}
218
+ #{custom_install_command}
219
+ INSTALL
220
+ when /^windows.*/
221
+ info("Installing puppet on #{puppet_platform}")
222
+ <<-INSTALL
223
+ if(Get-Command puppet -ErrorAction 0) { return; }
224
+ if( [Environment]::Is64BitOperatingSystem ) {
225
+ $MsiUrl = "https://downloads.puppetlabs.com/windows/puppet-#{puppet_windows_version}-x64.msi"
226
+ } else {
227
+ $MsiUrl = "https://downloads.puppetlabs.com/windows/puppet-#{puppet_windows_version}.msi"
228
+ }
229
+ $process = Start-Process -FilePath msiexec.exe -Wait -PassThru -ArgumentList '/qn', '/norestart', '/i', $MsiUrl
230
+ if ($process.ExitCode -ne 0) {
231
+ Write-Host "Installer failed."
232
+ Exit 1
233
+ }
234
+
235
+ #{install_busser}
236
+ INSTALL
237
+ else
238
+ info('Installing puppet, will try to determine platform os')
239
+ # need to add a CR to avoid trouble with proxy settings concatenation
240
+ <<-INSTALL
241
+
242
+ #{custom_pre_install_command}
243
+ if [ ! $(which puppet) ]; then
244
+ if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ] || [ -f /etc/oracle-release ]; then
245
+ #{install_puppet_yum_repo}
246
+ else
247
+ if [ -f /etc/system-release ] || [ grep -q 'Amazon Linux' /etc/system-release ]; then
248
+ #{install_puppet_yum_repo}
249
+ else
250
+ #{sudo('apt-get')} -y install wget
251
+ #{sudo('wget')} #{wget_proxy_parm} #{puppet_apt_repo}
252
+ #{sudo('dpkg')} -i #{puppet_apt_repo_file}
253
+ #{update_packages_debian_cmd}
254
+ #{sudo_env('apt-get')} -y install facter#{facter_debian_version}
255
+ #{sudo_env('apt-get')} -y install puppet-common#{puppet_debian_version}
256
+ #{sudo_env('apt-get')} -y install puppet#{puppet_debian_version}
257
+ #{install_hiera}
258
+ fi
259
+ fi
260
+ fi
261
+ #{install_eyaml}
262
+ #{install_deep_merge}
263
+ #{install_busser}
264
+ #{custom_install_command}
265
+ INSTALL
266
+ end
267
+ end
268
+ end
269
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
270
+
271
+ def install_command_collections
272
+ case puppet_platform
273
+ when 'debian', 'ubuntu'
274
+ info("Installing Puppet Collections on #{puppet_platform}")
275
+ <<-INSTALL
276
+
277
+ #{Util.shell_helpers}
278
+ #{custom_pre_install_command}
279
+ if [ ! -d "#{config[:puppet_coll_remote_path]}" ]; then
280
+ if [ ! -f "#{config[:puppet_apt_collections_repo]}" ]; then
281
+ #{sudo('apt-get')} -y install wget
282
+ #{sudo('wget')} #{wget_proxy_parm} #{config[:puppet_apt_collections_repo]}
283
+ fi
284
+ #{sudo('dpkg')} -i #{puppet_apt_coll_repo_file}
285
+ #{sudo('apt-get')} update
286
+ #{sudo_env('apt-get')} -y install puppet-agent#{puppet_debian_version}
287
+ fi
288
+ #{install_eyaml("#{config[:puppet_coll_remote_path]}/puppet/bin/gem")}
289
+ #{install_deep_merge}
290
+ #{install_busser}
291
+ #{custom_install_command}
292
+ INSTALL
293
+ when 'redhat', 'centos', 'fedora', 'oracle', 'amazon'
294
+ info("Installing Puppet Collections on #{puppet_platform}")
295
+ <<-INSTALL
296
+
297
+ #{Util.shell_helpers}
298
+ if [ ! -d "#{config[:puppet_coll_remote_path]}" ]; then
299
+ echo "-----> #{sudo_env('yum')} -y localinstall #{config[:puppet_yum_collections_repo]}"
300
+ #{sudo_env('yum')} -y localinstall #{config[:puppet_yum_collections_repo]}
301
+ #{sudo_env('yum')} -y install puppet-agent#{puppet_redhat_version}
302
+ fi
303
+ #{install_eyaml("#{config[:puppet_coll_remote_path]}/puppet/bin/gem")}
304
+ #{install_deep_merge}
305
+ #{install_busser}
306
+ #{custom_install_command}
307
+ INSTALL
308
+ else
309
+ info('Installing Puppet Collections, will try to determine platform os')
310
+ <<-INSTALL
311
+
312
+ #{Util.shell_helpers}
313
+ #{custom_pre_install_command}
314
+ if [ ! -d "#{config[:puppet_coll_remote_path]}" ]; then
315
+ if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ] || [ -f /etc/oracle-release ] || \
316
+ [ -f /etc/system-release ] || [ grep -q 'Amazon Linux' /etc/system-release ]; then
317
+ echo "-----> #{sudo_env('yum')} -y localinstall #{config[:puppet_yum_collections_repo]}"
318
+ #{sudo_env('yum')} -y localinstall #{config[:puppet_yum_collections_repo]}
319
+ #{sudo_env('yum')} -y install puppet-agent#{puppet_redhat_version}
320
+ else
321
+ #{sudo('apt-get')} -y install wget
322
+ #{sudo('wget')} #{wget_proxy_parm} #{config[:puppet_apt_collections_repo]}
323
+ #{sudo('dpkg')} -i #{puppet_apt_coll_repo_file}
324
+ #{sudo('apt-get')} update
325
+ #{sudo_env('apt-get')} -y install puppet-agent#{puppet_debian_version}
326
+ fi
327
+ fi
328
+ #{install_eyaml("#{config[:puppet_coll_remote_path]}/puppet/bin/gem")}
329
+ #{install_deep_merge}
330
+ #{install_busser}
331
+ #{custom_install_command}
332
+ INSTALL
333
+ end
334
+ end
335
+
336
+ def install_deep_merge
337
+ return unless config[:hiera_deep_merge]
338
+ <<-INSTALL
339
+ # Support for hash merge lookups to recursively merge hash keys
340
+ if [[ $(#{sudo('gem')} list deep_merge -i) == 'false' ]]; then
341
+ echo '-----> Installing deep_merge to provide deep_merge of hiera hashes'
342
+ #{sudo('gem')} install #{gem_proxy_parm} --no-ri --no-rdoc deep_merge
343
+ fi
344
+ INSTALL
345
+ end
346
+
347
+ def install_eyaml(gem_cmd = 'gem')
348
+ return unless config[:hiera_eyaml]
349
+ <<-INSTALL
350
+ # A backend for Hiera that provides per-value asymmetric encryption of sensitive data
351
+ if [[ $(#{sudo(gem_cmd)} list hiera-eyaml -i) == 'false' ]]; then
352
+ echo '-----> Installing hiera-eyaml to provide encryption of hiera data'
353
+ #{sudo(gem_cmd)} install #{gem_proxy_parm} --no-ri --no-rdoc highline -v 1.6.21
354
+ #{sudo(gem_cmd)} install #{gem_proxy_parm} --no-ri --no-rdoc hiera-eyaml
355
+ fi
356
+ INSTALL
357
+ end
358
+
359
+ def install_busser
360
+ return unless config[:require_chef_for_busser]
361
+ info("Install busser on #{puppet_platform}")
362
+ case puppet_platform
363
+ when /^windows.*/
364
+ # https://raw.githubusercontent.com/opscode/knife-windows/master/lib/chef/knife/bootstrap/windows-chef-client-msi.erb
365
+ <<-INSTALL
366
+ $webclient = New-Object System.Net.WebClient; $webclient.DownloadFile('https://opscode-omnibus-packages.s3.amazonaws.com/windows/2008r2/x86_64/chef-windows-11.12.8-1.windows.msi','chef-windows-11.12.8-1.windows.msi')
367
+ msiexec /qn /i chef-windows-11.12.8-1.windows.msi
368
+
369
+ cmd.exe /C "SET PATH=%PATH%;`"C:\\opscode\\chef\\embedded\\bin`";`"C:\\tmp\\busser\\gems\\bin`""
370
+
371
+ INSTALL
372
+ else
373
+ <<-INSTALL
374
+ #{Util.shell_helpers}
375
+ # install chef omnibus so that busser works as this is needed to run tests :(
376
+ # TODO: work out how to install enough ruby
377
+ # and set busser: { :ruby_bindir => '/usr/bin/ruby' } so that we dont need the
378
+ # whole chef client
379
+ if [ ! -d "/opt/chef" ]
380
+ then
381
+ echo '-----> Installing Chef Omnibus to install busser to run tests'
382
+ #{export_http_proxy_parm}
383
+ #{export_https_proxy_parm}
384
+ do_download #{chef_url} /tmp/install.sh
385
+ #{sudo('sh')} /tmp/install.sh
386
+ fi
387
+ INSTALL
388
+ end
389
+ end
390
+
391
+ def install_omnibus_command
392
+ info('Installing puppet using puppet omnibus')
393
+
394
+ version = ''
395
+ version = "-v #{config[:puppet_version]}" unless config[:puppet_version].nil?
396
+
397
+ <<-INSTALL
398
+ #{Util.shell_helpers}
399
+ if [ ! $(which puppet) ]; then
400
+ echo "-----> Installing Puppet Omnibus"
401
+ #{export_http_proxy_parm}
402
+ #{export_https_proxy_parm}
403
+ do_download #{config[:puppet_omnibus_url]} /tmp/install_puppet.sh
404
+ #{sudo_env('sh')} /tmp/install_puppet.sh #{version}
405
+ fi
406
+ INSTALL
407
+ end
408
+
409
+ def install_hiera
410
+ return unless config[:install_hiera]
411
+ <<-INSTALL
412
+ #{sudo_env('apt-get')} -y install #{hiera_package}
413
+ INSTALL
414
+ end
415
+
416
+ def hiera_package
417
+ "#{config[:hiera_package]}#{puppet_hiera_debian_version}"
418
+ end
419
+
420
+ # /bin/wget -P /etc/pki/rpm-gpg/ http://yum.puppetlabs.com/RPM-GPG-KEY-puppetlabs
421
+ # changed to curl
422
+
423
+ def install_puppet_yum_repo
424
+ <<-INSTALL
425
+ rhelversion=$(cat /etc/redhat-release | grep 'release 7')
426
+ # For CentOS7/RHEL7 the rdo release contains puppetlabs repo, creating conflict. Create temp-repo
427
+ #{sudo_env('curl')} -o /etc/pki/rpm-gpg/RPM-GPG-KEY-puppetlabs http://yum.puppetlabs.com/RPM-GPG-KEY-puppetlabs
428
+ if [ -n "$rhelversion" ]; then
429
+ echo '[puppettemp-products]
430
+ name=Puppet Labs Products - \$basearch
431
+ baseurl=http://yum.puppetlabs.com/el/7/products/\$basearch
432
+ gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-puppetlabs
433
+ enabled=0
434
+ gpgcheck=1
435
+ [puppettemp-deps]
436
+ name=Puppet Labs Dependencies - \$basearch
437
+ baseurl=http://yum.puppetlabs.com/el/7/dependencies/\$basearch
438
+ gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-puppetlabs
439
+ enabled=0
440
+ gpgcheck=1' | sudo tee /etc/yum.repos.d/puppettemp.repo > /dev/null
441
+ sudo sed -i 's/^[ \t]*//' /etc/yum.repos.d/puppettemp.repo
442
+ #{update_packages_redhat_cmd}
443
+ #{sudo_env('yum')} -y --enablerepo=puppettemp-products --enablerepo=puppettemp-deps install puppet#{puppet_redhat_version}
444
+ # Clean up temporary puppet repo
445
+ sudo rm -rf /etc/pki/rpm-gpg/RPM-GPG-KEY-puppetlabs
446
+ sudo rm -rf /etc/yum.repos.d/puppettemp.repo
447
+ else
448
+ #{sudo('rpm')} -ivh #{proxy_parm} #{puppet_yum_repo}
449
+ #{update_packages_redhat_cmd}
450
+ #{sudo_env('yum')} -y install puppet#{puppet_redhat_version}
451
+ fi
452
+ INSTALL
453
+ end
454
+
455
+ def custom_pre_install_command
456
+ <<-INSTALL
457
+ #{config[:custom_pre_install_command]}
458
+ INSTALL
459
+ end
460
+
461
+ def custom_install_command
462
+ <<-INSTALL
463
+ #{config[:custom_install_command]}
464
+ INSTALL
465
+ end
466
+
467
+ def init_command
468
+ todelete = %w(modules manifests files hiera hiera.yaml facter spec enc)
469
+ .map { |dir| File.join(config[:root_path], dir) }
470
+ todelete += [hiera_data_remote_path,
471
+ '/etc/hiera.yaml',
472
+ "#{puppet_dir}/hiera.yaml",
473
+ spec_files_remote_path.to_s,
474
+ "#{puppet_dir}/fileserver.conf"]
475
+ todelete << File.join(puppet_dir, config[:puppet_environment]) if config[:puppet_environment]
476
+ cmd = "#{sudo(rm_command_paths(todelete))};"
477
+ cmd += " #{mkdir_command} #{config[:root_path]};"
478
+ cmd += " #{sudo(mkdir_command)} #{puppet_dir}"
479
+ debug(cmd)
480
+ cmd
481
+ end
482
+
483
+ def create_sandbox
484
+ super
485
+ debug("Creating local sandbox in #{sandbox_path}")
486
+ yield if block_given?
487
+ prepare_modules
488
+ prepare_manifests
489
+ prepare_files
490
+ prepare_facter_file
491
+ prepare_facts
492
+ prepare_puppet_config
493
+ prepare_hiera_config
494
+ prepare_fileserver_config
495
+ prepare_hiera_data
496
+ prepare_enc
497
+ prepare_spec_files
498
+ info('Finished Preparing files for transfer')
499
+ end
500
+
501
+ def cleanup_sandbox
502
+ return if sandbox_path.nil?
503
+ debug("Cleaning up local sandbox in #{sandbox_path}")
504
+ FileUtils.rmtree(sandbox_path)
505
+ return if remove_repo.nil?
506
+ debug("Cleaning up remote sandbox: #{remove_repo}")
507
+ instance.remote_exec remove_repo
508
+ end
509
+
510
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
511
+ def prepare_command
512
+ commands = []
513
+ if puppet_git_init
514
+ commands << [
515
+ sudo('rm -rf'), '/etc/puppet'
516
+ ].join(' ')
517
+
518
+ commands << [
519
+ sudo('git clone'), puppet_git_init, '/etc/puppet'
520
+ ].join(' ')
521
+ end
522
+
523
+ if puppet_git_pr
524
+ commands << [
525
+ sudo('git'),
526
+ '--git-dir=/etc/puppet/.git/',
527
+ 'fetch -f',
528
+ 'origin',
529
+ "pull/#{puppet_git_pr}/head:pr_#{puppet_git_pr}"
530
+ ].join(' ')
531
+
532
+ commands << [
533
+ sudo('git'),
534
+ '--git-dir=/etc/puppet/.git/',
535
+ '--work-tree=/etc/puppet/',
536
+ 'checkout',
537
+ "pr_#{puppet_git_pr}"
538
+ ].join(' ')
539
+ end
540
+
541
+ if puppet_config
542
+ commands << [
543
+ sudo(cp_command),
544
+ File.join(config[:root_path], 'puppet.conf'),
545
+ puppet_dir
546
+ ].join(' ')
547
+ end
548
+
549
+ if hiera_config
550
+ commands << [
551
+ sudo(cp_command), File.join(config[:root_path], 'hiera.yaml'), '/etc/'
552
+ ].join(' ')
553
+
554
+ commands << [
555
+ sudo(cp_command), File.join(config[:root_path], 'hiera.yaml'), hiera_config_dir
556
+ ].join(' ')
557
+ end
558
+
559
+ if fileserver_config
560
+ commands << [
561
+ sudo(cp_command),
562
+ File.join(config[:root_path], 'fileserver.conf'),
563
+ puppet_dir
564
+ ].join(' ')
565
+ end
566
+
567
+ if hiera_data && hiera_data_remote_path == '/var/lib/hiera'
568
+ commands << [
569
+ sudo("#{cp_command} -r"), File.join(config[:root_path], 'hiera'), '/var/lib/'
570
+ ].join(' ')
571
+ end
572
+
573
+ if hiera_data && hiera_data_remote_path != '/var/lib/hiera'
574
+ commands << [
575
+ sudo(mkdir_command), hiera_data_remote_path
576
+ ].join(' ')
577
+ commands << [
578
+ sudo("#{cp_command} -r"), File.join(config[:root_path], 'hiera/*'), hiera_data_remote_path
579
+ ].join(' ')
580
+ end
581
+
582
+ if hiera_eyaml
583
+ commands << [
584
+ sudo(mkdir_command), hiera_eyaml_key_remote_path
585
+ ].join(' ')
586
+ commands << [
587
+ sudo("#{cp_command} -r"), File.join(config[:root_path], 'hiera_keys/*'), hiera_eyaml_key_remote_path
588
+ ].join(' ')
589
+ end
590
+
591
+ if puppet_environment
592
+ commands << [
593
+ sudo('ln -s '), config[:root_path], File.join(puppet_dir, config[:puppet_environment])
594
+ ].join(' ')
595
+ end
596
+
597
+ if spec_files_path && spec_files_remote_path
598
+ commands << [
599
+ sudo(mkdir_command), spec_files_remote_path
600
+ ].join(' ')
601
+ commands << [
602
+ sudo("#{cp_command} -r"), File.join(config[:root_path], 'spec/*'), spec_files_remote_path
603
+ ].join(' ')
604
+ end
605
+
606
+ if config[:puppet_enc]
607
+ commands << [
608
+ sudo('chmod 755'), File.join("#{config[:root_path]}/enc", File.basename(config[:puppet_enc]))
609
+ ].join(' ')
610
+ end
611
+
612
+ command = powershell_shell? ? commands.join('; ') : commands.join(' && ')
613
+ debug(command)
614
+ command
615
+ end
616
+
617
+ def run_command
618
+ return config[:puppet_apply_command] unless config[:puppet_apply_command].nil?
619
+ result = [
620
+ facterlib,
621
+ custom_facts,
622
+ puppet_manifestdir,
623
+ puppet_cmd,
624
+ 'apply',
625
+ File.join(config[:root_path], 'manifests', manifest),
626
+ "--modulepath=#{File.join(config[:root_path], 'modules')}",
627
+ "--fileserverconfig=#{File.join(config[:root_path], 'fileserver.conf')}",
628
+ custom_options,
629
+ puppet_environment_flag,
630
+ puppet_noop_flag,
631
+ puppet_enc_flag,
632
+ puppet_detailed_exitcodes_flag,
633
+ puppet_verbose_flag,
634
+ puppet_debug_flag,
635
+ puppet_logdest_flag,
636
+ puppet_whitelist_exit_code
637
+ ].join(' ')
638
+ if config[:custom_post_apply_command]
639
+ custom_post_apply_trap = <<-TRAP
640
+ function custom_post_apply_command {
641
+ #{config[:custom_post_apply_command]}
642
+ }
643
+ trap custom_post_apply_command EXIT
644
+ TRAP
645
+ end
646
+ result = <<-RUN
647
+ #{config[:custom_pre_apply_command]}
648
+ #{custom_post_apply_trap}
649
+ #{result}
650
+ RUN
651
+ info("Going to invoke puppet apply with: #{result}")
652
+ result
653
+ end
654
+
655
+ protected
656
+
657
+ def load_needed_dependencies!
658
+ return unless File.exist?(puppetfile)
659
+ return unless config[:resolve_with_librarian_puppet]
660
+ debug("Puppetfile found at #{puppetfile}, loading Librarian-Puppet")
661
+ Puppet::Librarian.load!(logger)
662
+ end
663
+
664
+ def tmpmodules_dir
665
+ File.join(sandbox_path, 'modules')
666
+ end
667
+
668
+ def puppetfile
669
+ config[:puppetfile_path] || ''
670
+ end
671
+
672
+ def modulefile
673
+ config[:modulefile_path] || ''
674
+ end
675
+
676
+ def metadata_json
677
+ config[:metadata_json_path] || ''
678
+ end
679
+
680
+ def manifest
681
+ config[:manifest]
682
+ end
683
+
684
+ def manifests
685
+ config[:manifests_path]
686
+ end
687
+
688
+ def modules
689
+ config[:modules_path]
690
+ end
691
+
692
+ def files
693
+ config[:files_path] || 'files'
694
+ end
695
+
696
+ def puppet_config
697
+ config[:puppet_config_path]
698
+ end
699
+
700
+ def puppet_environment
701
+ config[:puppet_environment]
702
+ end
703
+
704
+ def puppet_git_init
705
+ config[:puppet_git_init]
706
+ end
707
+
708
+ def puppet_git_pr
709
+ config[:puppet_git_pr]
710
+ end
711
+
712
+ def hiera_config
713
+ config[:hiera_config_path]
714
+ end
715
+
716
+ def fileserver_config
717
+ config[:fileserver_config_path]
718
+ end
719
+
720
+ def hiera_data
721
+ config[:hiera_data_path]
722
+ end
723
+
724
+ def hiera_data_remote_path
725
+ config[:hiera_data_remote_path]
726
+ end
727
+
728
+ def hiera_eyaml
729
+ config[:hiera_eyaml]
730
+ end
731
+
732
+ def hiera_eyaml_key_path
733
+ config[:hiera_eyaml_key_path]
734
+ end
735
+
736
+ def hiera_eyaml_key_remote_path
737
+ config[:hiera_eyaml_key_remote_path]
738
+ end
739
+
740
+ def hiera_deep_merge
741
+ config[:hiera_deep_merge]
742
+ end
743
+
744
+ def librarian_puppet_ssl_file
745
+ config[:librarian_puppet_ssl_file]
746
+ end
747
+
748
+ def puppet_cmd
749
+ puppet_bin = powershell_shell? ? '& "C:\Program Files\Puppet Labs\Puppet\bin\puppet"' : 'puppet'
750
+ if config[:require_puppet_collections]
751
+ puppet_bin = "#{config[:puppet_coll_remote_path]}/bin/puppet"
752
+ end
753
+
754
+ if config[:puppet_no_sudo]
755
+ puppet_bin
756
+ else
757
+ sudo_env(puppet_bin)
758
+ end
759
+ end
760
+
761
+ def puppet_dir
762
+ return '/etc/puppetlabs/puppet' if config[:require_puppet_collections]
763
+ return '/etc/puppet' unless powershell_shell?
764
+ 'C:/ProgramData/PuppetLabs/puppet/etc'
765
+ end
766
+
767
+ def hiera_config_dir
768
+ return '/etc/puppetlabs/code' if config[:require_puppet_collections]
769
+ return '/etc/puppet' unless powershell_shell?
770
+ 'C:/ProgramData/PuppetLabs/puppet/etc'
771
+ end
772
+
773
+ def puppet_debian_version
774
+ config[:puppet_version] ? "=#{config[:puppet_version]}" : nil
775
+ end
776
+
777
+ def facter_debian_version
778
+ config[:facter_version] ? "=#{config[:facter_version]}" : nil
779
+ end
780
+
781
+ def puppet_hiera_debian_version
782
+ config[:hiera_version] ? "=#{config[:hiera_version]}" : nil
783
+ end
784
+
785
+ def puppet_redhat_version
786
+ if puppet_platform == 'amazon'
787
+ config[:puppet_version]
788
+ else
789
+ config[:puppet_version] ? "-#{config[:puppet_version]}" : nil
790
+ end
791
+ end
792
+
793
+ def puppet_windows_version
794
+ config[:puppet_version] ? config[:puppet_version].to_s : '3.8.6'
795
+ end
796
+
797
+ def puppet_environment_flag
798
+ if config[:puppet_version] =~ /^2/
799
+ config[:puppet_environment] ? "--environment=#{config[:puppet_environment]}" : nil
800
+ else
801
+ config[:puppet_environment] ? "--environment=#{config[:puppet_environment]} --environmentpath=#{puppet_dir}" : nil
802
+ end
803
+ end
804
+
805
+ def puppet_manifestdir
806
+ return nil if config[:require_puppet_collections]
807
+ return nil if config[:puppet_environment]
808
+ return nil if powershell_shell?
809
+ bash_vars = "export MANIFESTDIR='#{File.join(config[:root_path], 'manifests')}';"
810
+ debug(bash_vars)
811
+ bash_vars
812
+ end
813
+
814
+ def custom_options
815
+ config[:custom_options] || ''
816
+ end
817
+
818
+ def puppet_noop_flag
819
+ config[:puppet_noop] ? '--noop' : nil
820
+ end
821
+
822
+ def puppet_debug_flag
823
+ config[:puppet_debug] ? '-d' : nil
824
+ end
825
+
826
+ def puppet_verbose_flag
827
+ config[:puppet_verbose] ? '-v' : nil
828
+ end
829
+
830
+ def puppet_logdest_flag
831
+ return nil unless config[:puppet_logdest]
832
+ destinations = ''
833
+ config[:puppet_logdest].each do |dest|
834
+ destinations << "--logdest #{dest} "
835
+ end
836
+ destinations
837
+ end
838
+
839
+ def puppet_platform
840
+ config[:platform].gsub(/-.*/, '')
841
+ end
842
+
843
+ def update_packages_debian_cmd
844
+ config[:update_package_repos] ? "#{sudo_env('apt-get')} update" : nil
845
+ end
846
+
847
+ def update_packages_redhat_cmd
848
+ # #{sudo('yum')}
849
+ config[:update_package_repos] ? "#{sudo_env('yum')} makecache" : nil
850
+ end
851
+
852
+ def sudo_env(pm)
853
+ s = https_proxy ? "https_proxy=#{https_proxy}" : nil
854
+ p = http_proxy ? "http_proxy=#{http_proxy}" : nil
855
+ p || s ? "#{sudo('env')} #{p} #{s} #{pm}" : sudo(pm).to_s
856
+ end
857
+
858
+ def remove_puppet_repo
859
+ config[:remove_puppet_repo]
860
+ end
861
+
862
+ def spec_files_path
863
+ config[:spec_files_path]
864
+ end
865
+
866
+ def spec_files_remote_path
867
+ config[:spec_files_remote_path]
868
+ end
869
+
870
+ def facterlib
871
+ factpath = nil
872
+ factpath = File.join(config[:root_path], 'facter').to_s if config[:install_custom_facts] && !config[:custom_facts].none?
873
+ factpath = File.join(config[:root_path], 'facter').to_s if config[:facter_file]
874
+ factpath = "#{factpath}:" if config[:facterlib] && !factpath.nil?
875
+ factpath = "#{factpath}#{config[:facterlib]}" if config[:facterlib]
876
+ return nil if factpath.nil?
877
+ bash_vars = "export FACTERLIB='#{factpath}';"
878
+ debug(bash_vars)
879
+ bash_vars
880
+ end
881
+
882
+ def custom_facts
883
+ return nil if config[:custom_facts].none?
884
+ return nil if config[:install_custom_facts]
885
+ if powershell_shell?
886
+ environment_vars = config[:custom_facts].map { |k, v| "$env:FACTER_#{k}='#{v}'" }.join('; ')
887
+ environment_vars = "#{environment_vars};"
888
+ else
889
+ environment_vars = config[:custom_facts].map { |k, v| "FACTER_#{k}=#{v}" }.join(' ')
890
+ environment_vars = "export #{environment_vars};"
891
+ end
892
+ debug(environment_vars)
893
+ environment_vars
894
+ end
895
+
896
+ def puppet_enc_flag
897
+ config[:puppet_enc] ? "--node_terminus=exec --external_nodes=#{config[:root_path]}/enc/#{File.basename(config[:puppet_enc])}" : nil
898
+ end
899
+
900
+ def puppet_detailed_exitcodes_flag
901
+ config[:puppet_detailed_exitcodes] ? '--detailed-exitcodes' : nil
902
+ end
903
+
904
+ def remove_repo
905
+ remove_puppet_repo ? "#{sudo('rm')} -rf /tmp/kitchen #{hiera_data_remote_path} #{hiera_eyaml_key_remote_path} #{puppet_dir}/* " : nil
906
+ end
907
+
908
+ def puppet_whitelist_exit_code
909
+ if config[:puppet_whitelist_exit_code].nil?
910
+ powershell_shell? ? '; exit $LASTEXITCODE' : nil
911
+ elsif powershell_shell?
912
+ "; if(@(#{[config[:puppet_whitelist_exit_code]].join(', ')}) -contains $LASTEXITCODE) {exit 0} else {exit $LASTEXITCODE}"
913
+ else
914
+ "; [ $? -eq #{config[:puppet_whitelist_exit_code]} ] && exit 0"
915
+ end
916
+ end
917
+
918
+ def puppet_apt_repo
919
+ platform_version = config[:platform].partition('-')[2]
920
+ case puppet_platform
921
+ when 'ubuntu'
922
+ case platform_version
923
+ when '14.10'
924
+ # Utopic Repo
925
+ 'https://apt.puppetlabs.com/puppetlabs-release-utopic.deb'
926
+ when '14.04'
927
+ # Trusty Repo
928
+ 'https://apt.puppetlabs.com/puppetlabs-release-trusty.deb'
929
+ when '12.04'
930
+ # Precise Repo
931
+ 'https://apt.puppetlabs.com/puppetlabs-release-precise.deb'
932
+ else
933
+ # Configured Repo
934
+ config[:puppet_apt_repo]
935
+ end
936
+ when 'debian'
937
+ case platform_version.gsub(/\..*/, '')
938
+ when '8'
939
+ # Debian Jessie
940
+ 'https://apt.puppetlabs.com/puppetlabs-release-jessie.deb'
941
+ when '7'
942
+ # Debian Wheezy
943
+ 'https://apt.puppetlabs.com/puppetlabs-release-wheezy.deb'
944
+ when '6'
945
+ # Debian Squeeze
946
+ 'https://apt.puppetlabs.com/puppetlabs-release-squeeze.deb'
947
+ else
948
+ # Configured Repo
949
+ config[:puppet_apt_repo]
950
+ end
951
+ else
952
+ debug("Apt repo detection failed with platform - #{config[:platform]}")
953
+ false
954
+ end
955
+ end
956
+
957
+ def puppet_apt_repo_file
958
+ puppet_apt_repo.split('/').last if puppet_apt_repo
959
+ end
960
+
961
+ def puppet_apt_coll_repo_file
962
+ config[:puppet_apt_collections_repo].split('/').last
963
+ end
964
+
965
+ def puppet_yum_repo
966
+ config[:puppet_yum_repo]
967
+ end
968
+
969
+ def proxy_parm
970
+ http_proxy ? "--httpproxy #{URI.parse(http_proxy).host.downcase} --httpport #{URI.parse(http_proxy).port} " : nil
971
+ end
972
+
973
+ def gem_proxy_parm
974
+ http_proxy ? "--http-proxy #{http_proxy}" : nil
975
+ end
976
+
977
+ def wget_proxy_parm
978
+ p = http_proxy ? "-e http_proxy=#{http_proxy}" : nil
979
+ s = https_proxy ? "-e https_proxy=#{https_proxy}" : nil
980
+ p || s ? "-e use_proxy=yes #{p} #{s}" : nil
981
+ end
982
+
983
+ def export_http_proxy_parm
984
+ http_proxy ? "export http_proxy=#{http_proxy}" : nil
985
+ end
986
+
987
+ def export_https_proxy_parm
988
+ https_proxy ? "export https_proxy=#{https_proxy}" : nil
989
+ end
990
+
991
+ def http_proxy
992
+ config[:http_proxy]
993
+ end
994
+
995
+ def https_proxy
996
+ config[:https_proxy]
997
+ end
998
+
999
+ def chef_url
1000
+ config[:chef_bootstrap_url]
1001
+ end
1002
+
1003
+ def prepare_manifests
1004
+ info('Preparing manifests')
1005
+ debug("Using manifests from #{manifests}")
1006
+
1007
+ tmp_manifests_dir = File.join(sandbox_path, 'manifests')
1008
+ FileUtils.mkdir_p(tmp_manifests_dir)
1009
+ FileUtils.cp_r(Dir.glob("#{manifests}/*"), tmp_manifests_dir)
1010
+ end
1011
+
1012
+ def prepare_files
1013
+ info('Preparing files')
1014
+ unless File.directory?(files)
1015
+ info 'nothing to do for files'
1016
+ return
1017
+ end
1018
+
1019
+ debug("Using files from #{files}")
1020
+
1021
+ tmp_files_dir = File.join(sandbox_path, 'files')
1022
+ FileUtils.mkdir_p(tmp_files_dir)
1023
+ FileUtils.cp_r(Dir.glob("#{files}/*"), tmp_files_dir)
1024
+ end
1025
+
1026
+ def prepare_facter_file
1027
+ return unless config[:facter_file]
1028
+ info 'Copying facter file'
1029
+ facter_dir = File.join(sandbox_path, 'facter')
1030
+ FileUtils.mkdir_p(facter_dir)
1031
+ FileUtils.cp_r(config[:facter_file], facter_dir)
1032
+ end
1033
+
1034
+ def prepare_facts
1035
+ return unless config[:install_custom_facts]
1036
+ return unless config[:custom_facts]
1037
+ info 'Installing custom facts'
1038
+ facter_dir = File.join(sandbox_path, 'facter')
1039
+ FileUtils.mkdir_p(facter_dir)
1040
+ tmp_facter_file = File.join(facter_dir, 'kitchen.rb')
1041
+ facter_facts = Hash[config[:custom_facts].map { |k, v| [k.to_s, v.to_s] }]
1042
+ File.open(tmp_facter_file, 'a') do |out|
1043
+ facter_facts.each do |k, v|
1044
+ out.write "\nFacter.add(:#{k}) do\n"
1045
+ out.write " setcode do\n"
1046
+ out.write " \"#{v}\"\n"
1047
+ out.write " end\n"
1048
+ out.write "end\n"
1049
+ end
1050
+ end
1051
+ end
1052
+
1053
+ def prepare_modules
1054
+ info('Preparing modules')
1055
+
1056
+ FileUtils.mkdir_p(tmpmodules_dir)
1057
+ resolve_with_librarian if File.exist?(puppetfile) && config[:resolve_with_librarian_puppet]
1058
+
1059
+ if modules && modules.include?(':')
1060
+ debug('Found multiple directories in module path merging.....')
1061
+ modules_array = modules.split(':')
1062
+ modules_array.each do |m|
1063
+ copy_modules(m, tmpmodules_dir)
1064
+ end
1065
+ elsif modules
1066
+ copy_modules(modules, tmpmodules_dir)
1067
+ else
1068
+ info 'nothing to do for modules'
1069
+ end
1070
+
1071
+ copy_self_as_module
1072
+ end
1073
+
1074
+ def copy_modules(source, destination)
1075
+ return unless File.directory?(source)
1076
+
1077
+ debug("Copying modules from #{source} to #{destination}")
1078
+
1079
+ excluded_paths = %w(modules pkg) + config[:ignored_paths_from_root]
1080
+
1081
+ Dir.glob("#{source}/*").each do |f|
1082
+ module_name = File.basename(f)
1083
+ target = "#{destination}/#{module_name}"
1084
+ FileUtils.mkdir_p(target) unless File.exist? target
1085
+ FileUtils.cp_r(Dir.glob("#{source}/#{module_name}/*").reject { |entry| entry =~ /#{excluded_paths.join('$|')}$/ }, target, remove_destination: true)
1086
+ end
1087
+ end
1088
+
1089
+ def copy_self_as_module
1090
+ if File.exist?(modulefile)
1091
+ warn('Modulefile found but this is deprecated, ignoring it, see https://tickets.puppetlabs.com/browse/PUP-1188')
1092
+ end
1093
+
1094
+ return unless File.exist?(metadata_json)
1095
+ module_name = nil
1096
+ begin
1097
+ module_name = JSON.parse(IO.read(metadata_json))['name'].split('-').last
1098
+ rescue
1099
+ error("not able to load or parse #{metadata_json_path} for the name of the module")
1100
+ end
1101
+
1102
+ return unless module_name
1103
+ module_target_path = File.join(sandbox_path, 'modules', module_name)
1104
+ FileUtils.mkdir_p(module_target_path)
1105
+
1106
+ excluded_paths = %w(modules pkg) + config[:ignored_paths_from_root]
1107
+
1108
+ FileUtils.cp_r(
1109
+ Dir.glob(File.join(config[:kitchen_root], '*')).reject { |entry| entry =~ /#{excluded_paths.join('$|')}$/ },
1110
+ module_target_path,
1111
+ remove_destination: true
1112
+ )
1113
+ end
1114
+
1115
+ def prepare_puppet_config
1116
+ return unless puppet_config
1117
+
1118
+ info('Preparing puppet.conf')
1119
+ debug("Using puppet config from #{puppet_config}")
1120
+
1121
+ FileUtils.cp_r(puppet_config, File.join(sandbox_path, 'puppet.conf'))
1122
+ end
1123
+
1124
+ def prepare_enc
1125
+ return unless config[:puppet_enc]
1126
+ info 'Copying enc file'
1127
+ enc_dir = File.join(sandbox_path, 'enc')
1128
+ FileUtils.mkdir_p(enc_dir)
1129
+ FileUtils.cp_r(config[:puppet_enc], File.join(enc_dir, '/'))
1130
+ end
1131
+
1132
+ def prepare_hiera_config
1133
+ return unless hiera_config
1134
+
1135
+ info('Preparing hiera')
1136
+ debug("Using hiera from #{hiera_config}")
1137
+
1138
+ FileUtils.cp_r(hiera_config, File.join(sandbox_path, 'hiera.yaml'))
1139
+ end
1140
+
1141
+ def prepare_fileserver_config
1142
+ return unless fileserver_config
1143
+
1144
+ info('Preparing fileserver')
1145
+ debug("Using fileserver config from #{fileserver_config}")
1146
+
1147
+ FileUtils.cp_r(fileserver_config, File.join(sandbox_path, 'fileserver.conf'))
1148
+ end
1149
+
1150
+ def prepare_hiera_data
1151
+ return unless hiera_data
1152
+ info('Preparing hiera data')
1153
+ tmp_hiera_dir = File.join(sandbox_path, 'hiera')
1154
+ debug("Copying hiera data from #{hiera_data} to #{tmp_hiera_dir}")
1155
+ FileUtils.mkdir_p(tmp_hiera_dir)
1156
+ FileUtils.cp_r(Dir.glob("#{hiera_data}/*"), tmp_hiera_dir)
1157
+ return unless hiera_eyaml_key_path
1158
+ tmp_hiera_key_dir = File.join(sandbox_path, 'hiera_keys')
1159
+ debug("Copying hiera eyaml keys from #{hiera_eyaml_key_path} to #{tmp_hiera_key_dir}")
1160
+ FileUtils.mkdir_p(tmp_hiera_key_dir)
1161
+ FileUtils.cp_r(Dir.glob("#{hiera_eyaml_key_path}/*"), tmp_hiera_key_dir)
1162
+ end
1163
+
1164
+ def prepare_spec_files
1165
+ return unless spec_files_path
1166
+ info('Preparing spec files')
1167
+ tmp_spec_dir = File.join(sandbox_path, 'spec')
1168
+ debug("Copying specs from #{spec_files_path} to #{tmp_spec_dir}")
1169
+ FileUtils.mkdir_p(tmp_spec_dir)
1170
+ FileUtils.cp_r(Dir.glob(File.join(spec_files_path, '*')).reject { |entry| entry =~ /fixtures$/ }, tmp_spec_dir) if config[:ignore_spec_fixtures]
1171
+ FileUtils.cp_r(Dir.glob("#{spec_files_path}/*"), tmp_spec_dir) unless config[:ignore_spec_fixtures]
1172
+ end
1173
+
1174
+ def resolve_with_librarian
1175
+ Kitchen.mutex.synchronize do
1176
+ ENV['SSL_CERT_FILE'] = librarian_puppet_ssl_file if librarian_puppet_ssl_file
1177
+ Puppet::Librarian.new(puppetfile, tmpmodules_dir, logger).resolve
1178
+ ENV['SSL_CERT_FILE'] = '' if librarian_puppet_ssl_file
1179
+ end
1180
+ end
1181
+
1182
+ def cp_command
1183
+ return 'cp -force' if powershell_shell?
1184
+ 'cp'
1185
+ end
1186
+
1187
+ def rm_command
1188
+ return 'rm -force -recurse' if powershell_shell?
1189
+ 'rm -rf'
1190
+ end
1191
+
1192
+ def mkdir_command
1193
+ return 'mkdir -force -path' if powershell_shell?
1194
+ 'mkdir -p'
1195
+ end
1196
+
1197
+ def rm_command_paths(paths)
1198
+ return :nil if paths.length.zero?
1199
+ return "#{rm_command} \"#{paths.join('", "')}\"" if powershell_shell?
1200
+ "#{rm_command} #{paths.join(' ')}"
1201
+ end
1202
+ end
1203
+ end
1204
+ end