kitchen-puppet 1.44.2 → 1.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,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