kitchen-ansible 0.45.4 → 0.45.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,1073 +1,1090 @@
1
- # -*- encoding: utf-8 -*-
2
- #
3
- # Author:: Neill Turner (<neillwturner@gmail.com>)
4
- #
5
- # Copyright (C) 2013,2014 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-ansible/blob/master/provisioner_options.md
20
- # for documentation configuration parameters with ansible_playbook provisioner.
21
- #
22
-
23
- require 'json'
24
- require 'find'
25
- require 'kitchen/provisioner/base'
26
- require 'kitchen/provisioner/ansible/config'
27
- require 'kitchen/provisioner/ansible/os'
28
- require 'kitchen/provisioner/ansible/librarian'
29
-
30
- module Kitchen
31
- class Busser
32
- def non_suite_dirs
33
- %w(data)
34
- end
35
- end
36
-
37
- module Provisioner
38
- #
39
- # Ansible Playbook provisioner.
40
- #
41
- class AnsiblePlaybook < Base
42
- attr_accessor :tmp_dir
43
-
44
- def initialize(provisioner_config)
45
- config = Kitchen::Provisioner::Ansible::Config.new(provisioner_config)
46
- super(config)
47
-
48
- @os = Kitchen::Provisioner::Ansible::Os.make(ansible_platform, config)
49
- end
50
-
51
- def finalize_config!(instance)
52
- config.instance = instance
53
- super(instance)
54
- end
55
-
56
- def verbosity_level(level = 1)
57
- level = level.to_sym if level.is_a? String
58
- log_levels = { info: 1, warn: 2, debug: 3, trace: 4 }
59
- if level.is_a?(Symbol) && log_levels.include?(level)
60
- # puts "Log Level is: #{log_levels[level]}"
61
- log_levels[level]
62
- elsif level.is_a?(Integer) && level > 0
63
- # puts "Log Level is: #{level}"
64
- level
65
- else
66
- fail 'Invalid ansible_verbosity setting. Valid values are: 1, 2, 3, 4 OR :info, :warn, :debug, :trace'
67
- end
68
- end
69
-
70
- def install_command
71
- if config[:require_ansible_omnibus]
72
- cmd = install_omnibus_command
73
- elsif config[:require_ansible_source]
74
- info('Installing ansible from source')
75
- cmd = install_ansible_from_source_command
76
- elsif config[:require_pip]
77
- info('Installing ansible through pip')
78
- cmd = install_ansible_from_pip_command
79
- elsif config[:require_ansible_repo]
80
- if !@os.nil?
81
- info("Installing ansible on #{@os.name}")
82
- cmd = @os.install_command
83
- else
84
- info('Installing ansible, will try to determine platform os')
85
- cmd = <<-INSTALL
86
-
87
- if [ ! $(which ansible) ]; then
88
- if [ -f /etc/fedora-release ]; then
89
- #{Kitchen::Provisioner::Ansible::Os::Fedora.new('fedora', config).install_command}
90
- elif [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
91
- if [ -z `grep -q 'Amazon Linux' /etc/system-release` ]; then
92
- #{Kitchen::Provisioner::Ansible::Os::Redhat.new('redhat', config).install_command}
93
- else
94
- #{Kitchen::Provisioner::Ansible::Os::Amazon.new('amazon', config).install_command}
95
- fi
96
- elif [ -f /etc/SuSE-release ] || [ -f /etc/SUSE-brand ]; then
97
- #{Kitchen::Provisioner::Ansible::Os::Suse.new('suse', config).install_command}
98
- else
99
- #{Kitchen::Provisioner::Ansible::Os::Debian.new('debian', config).install_command}
100
- fi
101
- fi
102
- INSTALL
103
- end
104
- else
105
- return
106
- end
107
- result = cmd + install_windows_support + install_busser_prereqs
108
- debug("Going to install ansible with: #{result}")
109
- result
110
- end
111
-
112
- def install_windows_support
113
- install = ''
114
- if require_windows_support
115
- install << <<-INSTALL
116
- if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
117
- #{sudo_env('yum')} -y install python-devel krb5-devel krb5-libs krb5-workstation gcc
118
- else
119
- if [ -f /etc/SuSE-release ] || [ -f /etc/SUSE-brand ]; then
120
- #{sudo_env('zypper')} ar #{python_sles_repo}
121
- #{sudo_env('zypper')} --non-interactive install python python-devel krb5-client pam_krb5
122
- else
123
- #{sudo_env('apt-get')} -y install python-dev libkrb5-dev build-essential
124
- fi
125
- fi
126
- #{export_http_proxy}
127
- #{sudo_env('easy_install')} pip
128
- #{sudo_env('pip')} install pywinrm kerberos
129
- INSTALL
130
- end
131
- install
132
- end
133
-
134
- def install_busser_prereqs
135
- install = ''
136
- install << <<-INSTALL
137
- #{Util.shell_helpers}
138
- # Fix for https://github.com/test-kitchen/busser/issues/12
139
- if [ -h /usr/bin/ruby ]; then
140
- L=$(readlink -f /usr/bin/ruby)
141
- #{sudo_env('rm')} /usr/bin/ruby
142
- #{sudo_env('ln')} -s $L /usr/bin/ruby
143
- fi
144
- INSTALL
145
-
146
- if require_ruby_for_busser
147
- install << <<-INSTALL
148
- if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
149
- if [ -z `grep -q 'Amazon Linux' /etc/system-release` ]; then
150
- rhelversion6=$(cat /etc/redhat-release | grep 'release 6')
151
- rhelversion7=$(cat /etc/redhat-release | grep 'release 7')
152
- # For CentOS6/CentOS7/RHEL6/RHEL7 install ruby from SCL
153
- if [ -n "$rhelversion6" ] || [ -n "$rhelversion7" ]; then
154
- if [ ! -d "/opt/rh/ruby200" ]; then
155
- echo "-----> Installing ruby200 SCL in CentOS6/CentOS7/RHEL6/RHEL7 to install busser to run tests"
156
- #{sudo_env('yum')} install -y centos-release-scl
157
- #{sudo_env('yum')} install -y ruby200
158
- #{sudo_env('yum')} install -y ruby200-ruby-devel
159
- echo "-----> Enabling ruby200"
160
- source /opt/rh/ruby200/enable
161
- echo "/opt/rh/ruby200/root/usr/lib64" | sudo tee -a /etc/ld.so.conf
162
- #{sudo_env('ldconfig')}
163
- #{sudo_env('ln')} -sf /opt/rh/ruby200/root/usr/bin/ruby /usr/bin/ruby
164
- #{sudo_env('ln')} -sf /opt/rh/ruby200/root/usr/bin/gem /usr/bin/gem
165
- fi
166
- else
167
- if [ ! $(which ruby) ]; then
168
- #{update_packages_redhat_cmd}
169
- #{sudo_env('yum')} -y install ruby ruby-devel
170
- fi
171
- fi
172
- else
173
- #{update_packages_redhat_cmd}
174
- #{sudo_env('yum')} -y install ruby ruby-devel gcc
175
- fi
176
- elif [ -f /etc/SuSE-release ] || [ -f /etc/SUSE-brand ]; then
177
- #{update_packages_suse_cmd}
178
- #{sudo_env('zypper')} --non-interactive install ruby ruby-devel ca-certificates ca-certificates-cacert ca-certificates-mozilla
179
- #{sudo_env('gem')} sources --add https://rubygems.org/
180
- else
181
- if [ ! $(which ruby) ]; then
182
- #{update_packages_debian_cmd}
183
- # default package selection for Debian/Ubuntu machines
184
- PACKAGES="ruby1.9.1 ruby1.9.1-dev"
185
- if [ "$(lsb_release -si)" = "Debian" ]; then
186
- debvers=$(sed 's/\\..*//' /etc/debian_version)
187
- if [ $debvers -ge 8 ]; then
188
- # this is jessie or better, where ruby1.9.1 is
189
- # no longer in the repositories
190
- PACKAGES="ruby ruby-dev ruby2.1 ruby2.1-dev"
191
- fi
192
- fi
193
- if [ "$(lsb_release -si)" = "Ubuntu" ]; then
194
- ubuntuvers=$(lsb_release -sr | tr -d .)
195
- if [ $ubuntuvers -ge 1410 ]; then
196
- # Default ruby is 2.x in utopic and newer
197
- PACKAGES="ruby ruby-dev"
198
- fi
199
- fi
200
- #{sudo_env('apt-get')} -y install $PACKAGES
201
- if [ $debvers -eq 6 ]; then
202
- # in squeeze we need to update alternatives
203
- # for enable ruby1.9.1
204
- ALTERNATIVES_STRING="--install /usr/bin/ruby ruby /usr/bin/ruby1.9.1 10 --slave /usr/share/man/man1/ruby.1.gz ruby.1.gz /usr/share/man/man1/ruby1.9.1.1.gz --slave /usr/bin/erb erb /usr/bin/erb1.9.1 --slave /usr/bin/gem gem /usr/bin/gem1.9.1 --slave /usr/bin/irb irb /usr/bin/irb1.9.1 --slave /usr/bin/rake rake /usr/bin/rake1.9.1 --slave /usr/bin/rdoc rdoc /usr/bin/rdoc1.9.1 --slave /usr/bin/testrb testrb /usr/bin/testrb1.9.1 --slave /usr/share/man/man1/erb.1.gz erb.1.gz /usr/share/man/man1/erb1.9.1.1.gz --slave /usr/share/man/man1/gem.1.gz gem.1.gz /usr/share/man/man1/gem1.9.1.1.gz --slave /usr/share/man/man1/irb.1.gz irb.1.gz /usr/share/man/man1/irb1.9.1.1.gz --slave /usr/share/man/man1/rake.1.gz rake.1.gz /usr/share/man/man1/rake1.9.1.1.gz --slave /usr/share/man/man1/rdoc.1.gz rdoc.1.gz /usr/share/man/man1/rdoc1.9.1.1.gz --slave /usr/share/man/man1/testrb.1.gz testrb.1.gz /usr/share/man/man1/testrb1.9.1.1.gz"
205
- #{sudo_env('update-alternatives')} $ALTERNATIVES_STRING
206
- # need to update gem tool because gem 1.3.7 from ruby 1.9.1 is broken
207
- #{sudo_env('gem')} install rubygems-update
208
- #{sudo_env('/var/lib/gems/1.9.1/bin/update_rubygems')}
209
- # clear local gem cache
210
- #{sudo_env('rm')} -r /home/vagrant/.gem
211
- fi
212
- fi
213
- fi
214
- INSTALL
215
-
216
- elsif require_chef_for_busser && chef_url
217
- install << <<-INSTALL
218
- # install chef omnibus so that busser works as this is needed to run tests :(
219
- if [ ! -d "/opt/chef" ]
220
- then
221
- echo "-----> Installing Chef Omnibus to install busser to run tests"
222
- #{export_http_proxy}
223
- do_download #{chef_url} /tmp/install.sh
224
- #{sudo_env('sh')} /tmp/install.sh
225
- fi
226
- INSTALL
227
- end
228
-
229
- install
230
- end
231
-
232
- def init_command
233
- dirs = %w(modules roles group_vars host_vars)
234
- .map { |dir| File.join(config[:root_path], dir) }.join(' ')
235
- cmd = "#{sudo_env('rm')} -rf #{dirs};"
236
- cmd += " mkdir -p #{config[:root_path]}"
237
- debug(cmd)
238
- cmd
239
- end
240
-
241
- def create_sandbox
242
- super
243
- debug("Creating local sandbox in #{sandbox_path}")
244
-
245
- yield if block_given?
246
-
247
- prepare_playbook
248
- prepare_inventory
249
- prepare_modules
250
- prepare_roles
251
- prepare_ansible_cfg
252
- prepare_group_vars
253
- prepare_additional_copy_path
254
- prepare_host_vars
255
- prepare_hosts
256
- prepare_spec
257
- prepare_library_plugins
258
- prepare_callback_plugins
259
- prepare_filter_plugins
260
- prepare_lookup_plugins
261
- prepare_ansible_vault_password_file
262
- prepare_kerberos_conf_file
263
- info('Finished Preparing files for transfer')
264
- end
265
-
266
- def cleanup_sandbox
267
- return if sandbox_path.nil?
268
- debug("Cleaning up local sandbox in #{sandbox_path}")
269
- FileUtils.rmtree(sandbox_path)
270
- end
271
-
272
- def prepare_command
273
- commands = []
274
-
275
- # Prevent failure when ansible package installation doesn't contain /etc/ansible
276
- commands << [
277
- sudo_env("bash -c '[ -d /etc/ansible ] || mkdir /etc/ansible'")
278
- ]
279
-
280
- commands << [
281
- sudo_env('cp'), File.join(config[:root_path], 'ansible.cfg'), '/etc/ansible'
282
- ].join(' ')
283
-
284
- commands << [
285
- sudo_env('cp -r'), File.join(config[:root_path], 'group_vars'), '/etc/ansible/.'
286
- ].join(' ')
287
-
288
- commands << [
289
- sudo_env('cp -r'), File.join(config[:root_path], 'host_vars'), '/etc/ansible/.'
290
- ].join(' ')
291
-
292
- if config[:ssh_known_hosts]
293
- config[:ssh_known_hosts].each do |host|
294
- info("Add #{host} to ~/.ssh/known_hosts")
295
- commands << "ssh-keyscan #{host} > ~/.ssh/known_hosts 2> /dev/null"
296
- end
297
- end
298
-
299
- if ansible_inventory
300
- if File.directory?(ansible_inventory)
301
- Dir.foreach(ansible_inventory) do |f|
302
- next if f == "." or f == ".."
303
- contents = File.open("#{ansible_inventory}/#{f}", 'rb') { |g| g.read }
304
- if contents.start_with?('#!')
305
- commands << [
306
- sudo_env('chmod +x'), File.join("#{config[:root_path]}/#{File.basename(ansible_inventory)}", File.basename(f))
307
- ].join(' ')
308
- end
309
- end
310
- else
311
- contents = File.open(ansible_inventory, 'rb') { |f| f.read }
312
- if contents.start_with?('#!')
313
- commands << [
314
- sudo_env('chmod +x'), File.join(config[:root_path], File.basename(ansible_inventory))
315
- ].join(' ')
316
- end
317
- end
318
- end
319
-
320
- if galaxy_requirements
321
- if config[:require_ansible_source]
322
- commands << setup_ansible_env_from_source
323
- end
324
- commands << ansible_galaxy_command
325
- end
326
-
327
- if kerberos_conf_file
328
- commands << [
329
- sudo_env('cp -f'), File.join(config[:root_path], 'krb5.conf'), '/etc'
330
- ].join(' ')
331
- end
332
-
333
- command = commands.join(' && ')
334
- debug(command)
335
- command
336
- end
337
-
338
- def run_command
339
- if !config[:ansible_playbook_command].nil?
340
- return config[:ansible_playbook_command]
341
- else
342
-
343
- if config[:require_ansible_source] && !config[:ansible_binary_path]
344
- # this is an ugly hack to get around the fact that extra vars uses ' and "
345
- cmd = ansible_command("PATH=#{config[:root_path]}/ansible/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games PYTHONPATH=#{config[:root_path]}/ansible/lib MANPATH=#{config[:root_path]}/ansible/docs/man ansible-playbook")
346
- elsif config[:ansible_binary_path]
347
- cmd = ansible_command("#{config[:ansible_binary_path]}/ansible-playbook")
348
- else
349
- cmd = ansible_command('ansible-playbook')
350
- end
351
-
352
- cmd = "#{env_vars} #{cmd}" if !config[:env_vars].none?
353
- cmd = "HTTPS_PROXY=#{https_proxy} #{cmd}" if https_proxy
354
- cmd = "HTTP_PROXY=#{http_proxy} #{cmd}" if http_proxy
355
- cmd = "NO_PROXY=#{no_proxy} #{cmd}" if no_proxy
356
- cmd = "ANSIBLE_ROLES_PATH=#{ansible_roles_path} #{cmd}" if ansible_roles_path
357
- cmd = "ANSIBLE_HOST_KEY_CHECKING=false #{cmd}" if !ansible_host_key_checking
358
-
359
- cmd = "#{cd_ansible} #{cmd}" if !config[:ansible_sudo].nil? && !config[:ansible_sudo]
360
- cmd = "#{copy_private_key_cmd} #{cmd}" if config[:private_key]
361
-
362
- result = [
363
- cmd,
364
- ansible_inventory_flag,
365
- ansible_limit_flag,
366
- ansible_connection_flag,
367
- "-M #{File.join(config[:root_path], 'modules')}",
368
- ansible_verbose_flag,
369
- ansible_check_flag,
370
- ansible_diff_flag,
371
- ansible_vault_flag,
372
- private_key,
373
- extra_vars,
374
- tags,
375
- ansible_extra_flags,
376
- "#{File.join(config[:root_path], File.basename(config[:playbook]))}"
377
- ].join(' ')
378
- debug("Going to invoke ansible-playbook with: #{result}")
379
- if config[:idempotency_test]
380
- result = "#{result} && (echo 'Going to invoke ansible-playbook second time:'; #{result} | tee /tmp/idempotency_test.txt; grep -q 'changed=0.*failed=0' /tmp/idempotency_test.txt && (echo 'Idempotence test: PASS' && exit 0) || (echo 'Idempotence test: FAIL' && exit 1))"
381
- debug("Full cmd with idempotency test: #{result}")
382
- end
383
-
384
- result
385
- end
386
- end
387
-
388
- def ansible_command(script)
389
- if config[:ansible_sudo].nil? || config[:ansible_sudo] == true
390
- s = https_proxy ? "https_proxy=#{https_proxy}" : nil
391
- p = http_proxy ? "http_proxy=#{http_proxy}" : nil
392
- n = no_proxy ? "no_proxy=#{no_proxy}" : nil
393
- p || s || n ? " #{p} #{s} #{n} #{config[:sudo_command]} -s #{cd_ansible} #{script}" : "#{config[:sudo_command]} -s #{cd_ansible} #{script}"
394
- else
395
- return script
396
- end
397
- end
398
-
399
- def ansible_galaxy_command
400
- cmd = [
401
- 'ansible-galaxy', 'install', '--force',
402
- '-p', File.join(config[:root_path], 'roles'),
403
- '-r', File.join(config[:root_path], galaxy_requirements)
404
- ].join(' ')
405
- cmd = "https_proxy=#{https_proxy} #{cmd}" if https_proxy
406
- cmd = "http_proxy=#{http_proxy} #{cmd}" if http_proxy
407
- cmd = "no_proxy=#{no_proxy} #{cmd}" if no_proxy
408
- cmd
409
- end
410
-
411
- def cd_ansible
412
- # this is not working so just return nil for now
413
- # File.exist?('ansible.cfg') ? "cd #{config[:root_path]};" : nil
414
- nil
415
- end
416
-
417
- protected
418
-
419
- def load_needed_dependencies!
420
- return unless File.exist?(ansiblefile)
421
-
422
- debug("Ansiblefile found at #{ansiblefile}, loading Librarian-Ansible")
423
- Ansible::Librarian.load!(logger)
424
- end
425
-
426
- def install_ansible_from_source_command
427
- <<-INSTALL
428
- if [ ! -d #{config[:root_path]}/ansible ]; then
429
- if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
430
- #{Kitchen::Provisioner::Ansible::Os::Redhat.new('redhat', config).install_epel_repo}
431
- #{update_packages_redhat_cmd}
432
- #{sudo_env('yum')} -y install libselinux-python python2-devel git python-setuptools python-setuptools-dev libffi-devel libssl-devel
433
- else
434
- if [ -f /etc/SUSE-brand ] || [ -f /etc/SuSE-release ]; then
435
- #{sudo_env('zypper')} ar #{python_sles_repo}
436
- #{update_packages_suse_cmd}
437
- #{sudo_env('zypper')} --non-interactive install python python-devel git python-setuptools python-pip python-six libyaml-devel libffi-devel libopenssl-devel
438
- else
439
- #{update_packages_debian_cmd}
440
- #{sudo_env('apt-get')} -y install git python python-setuptools build-essential python-dev libffi-dev libssl-dev
441
- fi
442
- fi
443
-
444
- #{export_http_proxy}
445
- git clone git://github.com/ansible/ansible.git --recursive #{config[:root_path]}/ansible #{install_source_rev}
446
- #{sudo_env('easy_install')} pip
447
- #{sudo_env('pip')} install -U setuptools
448
- #{sudo_env('pip')} install six paramiko PyYAML Jinja2 httplib2
449
- fi
450
- INSTALL
451
- end
452
-
453
- def install_ansible_from_pip_command
454
- ansible_version = ''
455
- ansible_version = "==#{config[:ansible_version]}" unless config[:ansible_version] == 'latest'
456
-
457
- <<-INSTALL
458
- if [ ! -d #{config[:root_path]}/ansible ]; then
459
- if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
460
- #{Kitchen::Provisioner::Ansible::Os::Redhat.new('redhat', config).install_epel_repo}
461
- #{update_packages_redhat_cmd}
462
- #{sudo_env('yum')} -y install libselinux-python python2-devel git python-setuptools python-setuptools-dev libffi-devel openssl-devel gcc
463
- else
464
- if [ -f /etc/SUSE-brand ] || [ -f /etc/SuSE-release ]; then
465
- #{sudo_env('zypper')} ar #{python_sles_repo}
466
- #{update_packages_suse_cmd}
467
- #{sudo_env('zypper')} --non-interactive install python python-devel git python-setuptools python-pip python-six libyaml-devel libffi-devel libopenssl-devel
468
- else
469
- #{update_packages_debian_cmd}
470
- #{sudo_env('apt-get')} -y install git python python-setuptools build-essential python-dev libffi-dev libssl-dev
471
- fi
472
- fi
473
-
474
- #{export_http_proxy}
475
- #{sudo_env('easy_install')} pip
476
- #{sudo_env('pip')} install -U setuptools
477
- #{sudo_env('pip')} install ansible#{ansible_version}
478
- fi
479
- INSTALL
480
- end
481
-
482
- def install_omnibus_command
483
- info('Installing ansible using ansible omnibus')
484
-
485
- version = ''
486
- version = "-v #{config[:ansible_version]}" unless config[:ansible_version].nil?
487
-
488
- <<-INSTALL
489
- #{Util.shell_helpers}
490
-
491
- if [ ! -d "#{config[:ansible_omnibus_remote_path]}" ]; then
492
- echo "-----> Installing Ansible Omnibus"
493
- #{export_http_proxy}
494
- do_download #{config[:ansible_omnibus_url]} /tmp/ansible_install.sh
495
- #{sudo_env('sh')} /tmp/ansible_install.sh #{version}
496
- fi
497
- INSTALL
498
- end
499
-
500
- def setup_ansible_env_from_source
501
- "cd #{config[:root_path]}/ansible && source hacking/env-setup && cd ../"
502
- end
503
-
504
- def tmp_modules_dir
505
- File.join(sandbox_path, 'modules')
506
- end
507
-
508
- def tmp_playbook_path
509
- File.join(sandbox_path, File.basename(playbook))
510
- end
511
-
512
- def tmp_host_vars_dir
513
- File.join(sandbox_path, 'host_vars')
514
- end
515
-
516
- def tmp_roles_dir
517
- File.join(sandbox_path, 'roles')
518
- end
519
-
520
- def tmp_spec_dir
521
- File.join(sandbox_path, 'spec')
522
- end
523
-
524
- def tmp_library_plugins_dir
525
- File.join(sandbox_path, 'library')
526
- end
527
-
528
- def tmp_callback_plugins_dir
529
- File.join(sandbox_path, 'callback_plugins')
530
- end
531
-
532
- def tmp_filter_plugins_dir
533
- File.join(sandbox_path, 'filter_plugins')
534
- end
535
-
536
- def tmp_lookup_plugins_dir
537
- File.join(sandbox_path, 'lookup_plugins')
538
- end
539
-
540
- def tmp_ansible_vault_password_file_path
541
- File.join(sandbox_path, File.basename(ansible_vault_password_file).reverse.chomp('.').reverse)
542
- end
543
-
544
- def tmp_kerberos_conf_file_path
545
- File.join(sandbox_path, 'krb5.conf')
546
- end
547
-
548
- def tmp_inventory_path
549
- File.join(sandbox_path, File.basename(ansible_inventory))
550
- end
551
-
552
- def ansiblefile
553
- config[:ansiblefile_path] || ''
554
- end
555
-
556
- def galaxy_requirements
557
- config[:requirements_path] || nil
558
- end
559
-
560
- def env_vars
561
- return nil if config[:env_vars].none?
562
- config[:env_vars].map { |k, v| "#{k}=#{v}" }.join(' ')
563
- end
564
-
565
- def playbook
566
- config[:playbook]
567
- end
568
-
569
- def hosts
570
- config[:hosts]
571
- end
572
-
573
- def roles
574
- config[:roles_path]
575
- end
576
-
577
- def role_name
578
- if config[:role_name]
579
- config[:role_name]
580
- elsif File.basename(roles) == 'roles'
581
- ''
582
- else
583
- File.basename(roles)
584
- end
585
- end
586
-
587
- def modules
588
- config[:modules_path]
589
- end
590
-
591
- def spec
592
- 'spec'
593
- end
594
-
595
- def group_vars
596
- config[:group_vars_path].to_s
597
- end
598
-
599
- def additional_copy
600
- config[:additional_copy_path]
601
- end
602
-
603
- def recursive_additional_copy
604
- config[:recursive_additional_copy_path]
605
- end
606
-
607
- def host_vars
608
- config[:host_vars_path].to_s
609
- end
610
-
611
- def library_plugins
612
- config[:library_plugins_path].to_s
613
- end
614
-
615
- def callback_plugins
616
- config[:callback_plugins_path].to_s
617
- end
618
-
619
- def filter_plugins
620
- config[:filter_plugins_path].to_s
621
- end
622
-
623
- def lookup_plugins
624
- config[:lookup_plugins_path].to_s
625
- end
626
-
627
- def ansible_vault_password_file
628
- config[:ansible_vault_password_file]
629
- end
630
-
631
- def ansible_inventory
632
- return nil if config[:ansible_inventory] == 'none'
633
- config[:ansible_inventory] = config[:ansible_inventory_file] if config[:ansible_inventory].nil?
634
- info('ansible_inventory_file parameter deprecated use ansible_inventory') if config[:ansible_inventory_file]
635
- config[:ansible_inventory]
636
- end
637
-
638
- def ansible_debian_version
639
- if @config[:ansible_version] == 'latest' || @config[:ansible_version] == nil
640
- ''
641
- else
642
- "=#{@config[:ansible_version]}"
643
- end
644
- end
645
-
646
- def ansible_connection_flag
647
- "-c #{config[:ansible_connection]}" if config[:ansible_connection] != 'none'
648
- end
649
-
650
- def ansible_verbose_flag
651
- config[:ansible_verbose] ? '-' << ('v' * verbosity_level(config[:ansible_verbosity])) : nil
652
- end
653
-
654
- def ansible_check_flag
655
- config[:ansible_check] ? '--check' : nil
656
- end
657
-
658
- def ansible_diff_flag
659
- config[:ansible_diff] ? '--diff' : nil
660
- end
661
-
662
- def ansible_vault_flag
663
- debug(config[:ansible_vault_password_file])
664
- config[:ansible_vault_password_file] ? "--vault-password-file=#{File.join(config[:root_path], File.basename(config[:ansible_vault_password_file]).reverse.chomp('.').reverse)}" : nil
665
- end
666
-
667
- def ansible_inventory_flag
668
- return nil if config[:ansible_inventory] == 'none'
669
- ansible_inventory ? "-i #{File.join(config[:root_path], File.basename(ansible_inventory))}" : "-i #{File.join(config[:root_path], 'hosts')}"
670
- end
671
-
672
- def ansible_limit_flag
673
- config[:ansible_limit] ? "-l #{config[:ansible_limit]}" : ""
674
- end
675
-
676
- def ansible_extra_flags
677
- config[:ansible_extra_flags] || ''
678
- end
679
-
680
- def ansible_platform
681
- config[:ansible_platform].to_s.downcase
682
- end
683
-
684
- def ansible_host_key_checking
685
- config[:ansible_host_key_checking]
686
- end
687
-
688
- def private_key
689
- if config[:private_key]
690
- "--private-key #{private_key_file}"
691
- end
692
- end
693
-
694
- def copy_private_key_cmd
695
- if !config[:private_key].start_with?('/') && !config[:private_key].start_with?('~')
696
- ssh_private_key = File.join('~/.ssh', File.basename(config[:private_key]))
697
- tmp_private_key = File.join(config[:root_path], config[:private_key])
698
- "rm -rf #{ssh_private_key}; cp #{tmp_private_key} #{ssh_private_key}; chmod 400 #{ssh_private_key};"
699
- end
700
- end
701
-
702
- def private_key_file
703
- if config[:private_key].start_with?('/') || config[:private_key].start_with?('~')
704
- "#{config[:private_key]}"
705
- elsif config[:private_key]
706
- "#{File.join('~/.ssh', File.basename(config[:private_key]))}"
707
- end
708
- end
709
-
710
- def update_packages_debian_cmd
711
- Kitchen::Provisioner::Ansible::Os::Debian.new('debian', config).update_packages_command
712
- end
713
-
714
- def update_packages_suse_cmd
715
- Kitchen::Provisioner::Ansible::Os::Suse.new('suse', config).update_packages_command
716
- end
717
-
718
- def update_packages_redhat_cmd
719
- Kitchen::Provisioner::Ansible::Os::Redhat.new('redhat', config).update_packages_command
720
- end
721
-
722
- def python_sles_repo
723
- config[:python_sles_repo]
724
- end
725
-
726
- def extra_vars
727
- bash_vars = config[:extra_vars]
728
- if config.key?(:attributes) && config[:attributes].key?(:extra_vars) && config[:attributes][:extra_vars].is_a?(Hash)
729
- bash_vars = config[:attributes][:extra_vars]
730
- end
731
-
732
- return nil if bash_vars.none?
733
- bash_vars = JSON.dump(bash_vars)
734
- bash_vars = "-e '#{bash_vars}'"
735
- debug(bash_vars)
736
- bash_vars
737
- end
738
-
739
- def tags
740
- bash_tags = config.key?(:attributes) && config[:attributes].key?(:tags) && config[:attributes][:tags].is_a?(Array) ? config[:attributes][:tags] : config[:tags]
741
- return nil if bash_tags.empty?
742
-
743
- bash_tags = bash_tags.join(',')
744
- bash_tags = "-t '#{bash_tags}'"
745
- debug(bash_tags)
746
- bash_tags
747
- end
748
-
749
- def chef_url
750
- config[:chef_bootstrap_url]
751
- end
752
-
753
- def require_ruby_for_busser
754
- config[:require_ruby_for_busser]
755
- end
756
-
757
- def require_chef_for_busser
758
- config[:require_chef_for_busser]
759
- end
760
-
761
- def require_windows_support
762
- config[:require_windows_support]
763
- end
764
-
765
- def kerberos_conf_file
766
- config[:kerberos_conf_file]
767
- end
768
-
769
- def install_source_rev
770
- config[:ansible_source_rev] ? "--branch #{config[:ansible_source_rev]}" : nil
771
- end
772
-
773
- def http_proxy
774
- config[:http_proxy]
775
- end
776
-
777
- def https_proxy
778
- config[:https_proxy]
779
- end
780
-
781
- def no_proxy
782
- config[:no_proxy]
783
- end
784
-
785
- def sudo_env(pm,home=false)
786
- s = https_proxy ? "https_proxy=#{https_proxy}" : nil
787
- p = http_proxy ? "http_proxy=#{http_proxy}" : nil
788
- n = no_proxy ? "no_proxy=#{no_proxy}" : nil
789
- if home
790
- p || s || n ? "#{sudo_home('env')} #{p} #{s} #{n} #{pm}" : "#{sudo_home(pm)}"
791
- else
792
- p || s || n ? "#{sudo('env')} #{p} #{s} #{n} #{pm}" : "#{sudo(pm)}"
793
- end
794
- end
795
-
796
- def export_http_proxy
797
- cmd = ''
798
- cmd = " HTTP_PROXY=#{http_proxy}" if http_proxy
799
- cmd = "#{cmd} HTTPS_PROXY=#{https_proxy}" if https_proxy
800
- cmd = "#{cmd} NO_PROXY=#{no_proxy}" if no_proxy
801
- cmd = "export #{cmd}" if cmd != ''
802
- cmd
803
- end
804
-
805
- def ansible_roles_path
806
- roles_paths = []
807
- roles_paths << File.join(config[:root_path], 'roles') unless config[:roles_path].nil?
808
- if config[:additional_copy_role_path]
809
- additional_files.each do |additional_file|
810
- roles_paths << File.join(config[:root_path], File.basename(additional_file))
811
- end
812
- end
813
- if roles_paths.empty?
814
- info('No roles have been set.')
815
- nil
816
- else
817
- debug("Setting roles_path inside VM to #{ roles_paths.join(':') }")
818
- roles_paths.join(':')
819
- end
820
- end
821
-
822
- def prepare_roles
823
- info('Preparing roles')
824
- debug("Using roles from #{roles}")
825
-
826
- resolve_with_librarian if File.exist?(ansiblefile)
827
-
828
- if galaxy_requirements
829
- dest = File.join(sandbox_path, galaxy_requirements)
830
- FileUtils.mkdir_p(File.dirname(dest))
831
- FileUtils.cp(galaxy_requirements, dest)
832
- end
833
-
834
- FileUtils.mkdir_p(File.join(tmp_roles_dir, role_name))
835
- Find.find(roles) do |source|
836
- # Detect whether we are running tests on a role
837
- # If so, make sure to copy into VM so dir structure is like: /tmp/kitchen/roles/role_name
838
- role_path = source.sub(/#{roles}|\/roles/, '')
839
- unless roles =~ /\/roles$/
840
- role_path = "#{role_name}/#{role_path}"
841
- end
842
-
843
- target = File.join(tmp_roles_dir, role_path)
844
-
845
- Find.prune if config[:ignore_paths_from_root].include? File.basename(source)
846
- if File.directory?(source)
847
- FileUtils.mkdir_p(target)
848
- else
849
- FileUtils.cp(source, target)
850
- end
851
- end
852
- end
853
-
854
- # copy ansible.cfg if found in root of repo
855
- def prepare_ansible_cfg
856
- info('Preparing ansible.cfg file')
857
- ansible_config_file = "#{File.join(sandbox_path, 'ansible.cfg')}"
858
- if File.exist?('ansible.cfg')
859
- info('Found existing ansible.cfg')
860
- FileUtils.cp_r('ansible.cfg', ansible_config_file)
861
- else
862
- info('Empty ansible.cfg generated')
863
- File.open(ansible_config_file, 'wb') do |file|
864
- file.write("#no config parameters\n")
865
- end
866
- end
867
- end
868
-
869
- def prepare_inventory
870
- info('Preparing inventory')
871
- return unless ansible_inventory
872
- if File.directory?(ansible_inventory)
873
- debug("Copying inventory directory from #{ansible_inventory} to #{tmp_inventory_path}")
874
- FileUtils.cp_r(ansible_inventory, sandbox_path)
875
- else
876
- debug("Copying inventory file from #{ansible_inventory} to #{tmp_inventory_path}")
877
- FileUtils.cp_r(ansible_inventory, tmp_inventory_path)
878
- end
879
- end
880
-
881
- # localhost ansible_connection=local
882
- # [example_servers]
883
- # localhost
884
- def prepare_hosts
885
- return if ansible_inventory
886
- info('Preparing hosts file')
887
-
888
- if config[:hosts].nil?
889
- fail 'No hosts have been set. Please specify one in .kitchen.yml'
890
- else
891
- debug("Using host from #{hosts}")
892
- File.open(File.join(sandbox_path, 'hosts'), 'wb') do |file|
893
- file.write("localhost ansible_connection=local\n[#{hosts}]\nlocalhost\n")
894
- end
895
- end
896
- end
897
-
898
- def prepare_playbook
899
- info('Preparing playbook')
900
- debug("Copying playbook from #{playbook} to #{tmp_playbook_path}")
901
- FileUtils.cp_r(playbook, tmp_playbook_path)
902
- end
903
-
904
- def prepare_group_vars
905
- info('Preparing group_vars')
906
- tmp_group_vars_dir = File.join(sandbox_path, 'group_vars')
907
- FileUtils.mkdir_p(tmp_group_vars_dir)
908
-
909
- unless File.directory?(group_vars)
910
- info('nothing to do for group_vars')
911
- return
912
- end
913
-
914
- debug("Using group_vars from #{group_vars}")
915
- FileUtils.cp_r(Dir.glob("#{group_vars}/*"), tmp_group_vars_dir)
916
- end
917
-
918
- def prepare_additional_copy_path
919
- info('Preparing additional_copy_path')
920
- additional_files.each do |file|
921
- destination = File.join(sandbox_path, File.basename(file))
922
- if File.directory?(file)
923
- info("Copy dir: #{file} #{destination}")
924
- Find.prune if config[:ignore_paths_from_root].include? File.basename(file)
925
- FileUtils.mkdir_p(destination)
926
- else
927
- info("Copy file: #{file} #{destination}")
928
- FileUtils.cp(file, destination)
929
- end
930
- end
931
- recursive_additional_files.each do |file|
932
- info("Copy recursive additional path: #{file}")
933
- Find.find(file) do |files|
934
- destination = File.join(sandbox_path, files)
935
- Find.prune if config[:ignore_paths_from_root].include? File.basename(files)
936
- if File.directory?(files)
937
- FileUtils.mkdir_p(destination)
938
- else
939
- FileUtils.cp(files, destination)
940
- end
941
- end
942
- end
943
- end
944
-
945
- def additional_files
946
- additional_files = []
947
- if additional_copy
948
- additional_files = additional_copy.is_a?(Array) ? additional_copy : [additional_copy]
949
- end
950
- additional_files.map(&:to_s)
951
- end
952
-
953
- def recursive_additional_files
954
- recursive_additional_files = []
955
- if recursive_additional_copy
956
- recursive_additional_files = recursive_additional_copy.is_a?(Array) ? recursive_additional_copy : [recursive_additional_copy]
957
- end
958
- recursive_additional_files.map(&:to_s)
959
- end
960
-
961
- def prepare_host_vars
962
- info('Preparing host_vars')
963
- FileUtils.mkdir_p(tmp_host_vars_dir)
964
-
965
- unless File.directory?(host_vars)
966
- info 'nothing to do for host_vars'
967
- return
968
- end
969
-
970
- debug("Using host_vars from #{host_vars}")
971
- FileUtils.cp_r(Dir.glob("#{host_vars}/*"), tmp_host_vars_dir)
972
- end
973
-
974
- def prepare_modules
975
- info('Preparing modules')
976
-
977
- FileUtils.mkdir_p(tmp_modules_dir)
978
-
979
- if modules && File.directory?(modules)
980
- debug("Using modules from #{modules}")
981
- FileUtils.cp_r(Dir.glob("#{modules}/*"), tmp_modules_dir, remove_destination: true)
982
- else
983
- info 'nothing to do for modules'
984
- end
985
- end
986
-
987
- def prepare_spec
988
- info('Preparing spec')
989
-
990
- FileUtils.mkdir_p(tmp_spec_dir)
991
-
992
- if spec && File.directory?(spec)
993
- debug("Using spec from #{spec}")
994
- FileUtils.cp_r(Dir.glob("#{spec}/*"), tmp_spec_dir, remove_destination: true)
995
- else
996
- info 'nothing to do for spec'
997
- end
998
- end
999
-
1000
- def prepare_library_plugins
1001
- info('Preparing library plugins')
1002
- FileUtils.mkdir_p(tmp_library_plugins_dir)
1003
-
1004
- if library_plugins && File.directory?(library_plugins)
1005
- debug("Using library plugins from #{library_plugins}")
1006
- FileUtils.cp_r(Dir.glob("#{library_plugins}/{*,!*.pyc}"), tmp_library_plugins_dir, remove_destination: true)
1007
- else
1008
- info 'nothing to do for library plugins'
1009
- end
1010
- end
1011
-
1012
- def prepare_callback_plugins
1013
- info('Preparing callback plugins')
1014
- FileUtils.mkdir_p(tmp_callback_plugins_dir)
1015
-
1016
- if callback_plugins && File.directory?(callback_plugins)
1017
- debug("Using callback plugins from #{callback_plugins}")
1018
- FileUtils.cp_r(Dir.glob("#{callback_plugins}/{*,!*.pyc}"), tmp_callback_plugins_dir, remove_destination: true)
1019
- else
1020
- info 'nothing to do for callback plugins'
1021
- end
1022
- end
1023
-
1024
- def prepare_filter_plugins
1025
- info('Preparing filter_plugins')
1026
- FileUtils.mkdir_p(tmp_filter_plugins_dir)
1027
-
1028
- if filter_plugins && File.directory?(filter_plugins)
1029
- debug("Using filter_plugins from #{filter_plugins}")
1030
- FileUtils.cp_r(Dir.glob("#{filter_plugins}/*.py"), tmp_filter_plugins_dir, remove_destination: true)
1031
- else
1032
- info 'nothing to do for filter_plugins'
1033
- end
1034
- end
1035
-
1036
- def prepare_lookup_plugins
1037
- info('Preparing lookup_plugins')
1038
- FileUtils.mkdir_p(tmp_lookup_plugins_dir)
1039
-
1040
- if lookup_plugins && File.directory?(lookup_plugins)
1041
- debug("Using lookup_plugins from #{lookup_plugins}")
1042
- FileUtils.cp_r(Dir.glob("#{lookup_plugins}/*.py"), tmp_lookup_plugins_dir, remove_destination: true)
1043
- else
1044
- info 'nothing to do for lookup_plugins'
1045
- end
1046
- end
1047
-
1048
- def prepare_ansible_vault_password_file
1049
- return unless ansible_vault_password_file
1050
-
1051
- info('Preparing ansible vault password')
1052
- debug("Copying ansible vault password file from #{ansible_vault_password_file} to #{tmp_ansible_vault_password_file_path}")
1053
-
1054
- FileUtils.cp(ansible_vault_password_file, tmp_ansible_vault_password_file_path)
1055
- end
1056
-
1057
- def prepare_kerberos_conf_file
1058
- return unless kerberos_conf_file
1059
-
1060
- info('Preparing kerberos configuration file')
1061
- debug("Copying kerberos configuration file from #{kerberos_conf_file} to #{tmp_kerberos_conf_file_path}")
1062
-
1063
- FileUtils.cp(kerberos_conf_file, tmp_kerberos_conf_file_path)
1064
- end
1065
-
1066
- def resolve_with_librarian
1067
- Kitchen.mutex.synchronize do
1068
- Ansible::Librarian.new(ansiblefile, tmp_roles_dir, logger).resolve
1069
- end
1070
- end
1071
- end
1072
- end
1073
- end
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Neill Turner (<neillwturner@gmail.com>)
4
+ #
5
+ # Copyright (C) 2013,2014 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-ansible/blob/master/provisioner_options.md
20
+ # for documentation configuration parameters with ansible_playbook provisioner.
21
+ #
22
+
23
+ require 'json'
24
+ require 'find'
25
+ require 'kitchen/provisioner/base'
26
+ require 'kitchen/provisioner/ansible/config'
27
+ require 'kitchen/provisioner/ansible/os'
28
+ require 'kitchen/provisioner/ansible/librarian'
29
+
30
+ module Kitchen
31
+ class Busser
32
+ def non_suite_dirs
33
+ %w(data)
34
+ end
35
+ end
36
+
37
+ module Provisioner
38
+ #
39
+ # Ansible Playbook provisioner.
40
+ #
41
+ class AnsiblePlaybook < Base
42
+ attr_accessor :tmp_dir
43
+
44
+ def initialize(provisioner_config)
45
+ config = Kitchen::Provisioner::Ansible::Config.new(provisioner_config)
46
+ super(config)
47
+
48
+ @os = Kitchen::Provisioner::Ansible::Os.make(ansible_platform, config)
49
+ end
50
+
51
+ def finalize_config!(instance)
52
+ config.instance = instance
53
+ super(instance)
54
+ end
55
+
56
+ def verbosity_level(level = 1)
57
+ level = level.to_sym if level.is_a? String
58
+ log_levels = { info: 1, warn: 2, debug: 3, trace: 4 }
59
+ if level.is_a?(Symbol) && log_levels.include?(level)
60
+ # puts "Log Level is: #{log_levels[level]}"
61
+ log_levels[level]
62
+ elsif level.is_a?(Integer) && level > 0
63
+ # puts "Log Level is: #{level}"
64
+ level
65
+ else
66
+ fail 'Invalid ansible_verbosity setting. Valid values are: 1, 2, 3, 4 OR :info, :warn, :debug, :trace'
67
+ end
68
+ end
69
+
70
+ def install_command
71
+ if config[:require_ansible_omnibus]
72
+ cmd = install_omnibus_command
73
+ elsif config[:require_ansible_source]
74
+ info('Installing ansible from source')
75
+ cmd = install_ansible_from_source_command
76
+ elsif config[:require_pip]
77
+ info('Installing ansible through pip')
78
+ cmd = install_ansible_from_pip_command
79
+ elsif config[:require_ansible_repo]
80
+ if !@os.nil?
81
+ info("Installing ansible on #{@os.name}")
82
+ cmd = @os.install_command
83
+ else
84
+ info('Installing ansible, will try to determine platform os')
85
+ cmd = <<-INSTALL
86
+
87
+ if [ ! $(which ansible) ]; then
88
+ if [ -f /etc/fedora-release ]; then
89
+ #{Kitchen::Provisioner::Ansible::Os::Fedora.new('fedora', config).install_command}
90
+ elif [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
91
+ if [ -z `grep -q 'Amazon Linux' /etc/system-release` ]; then
92
+ #{Kitchen::Provisioner::Ansible::Os::Redhat.new('redhat', config).install_command}
93
+ else
94
+ #{Kitchen::Provisioner::Ansible::Os::Amazon.new('amazon', config).install_command}
95
+ fi
96
+ elif [ -f /etc/SuSE-release ] || [ -f /etc/SUSE-brand ]; then
97
+ #{Kitchen::Provisioner::Ansible::Os::Suse.new('suse', config).install_command}
98
+ elif [[ "$OSTYPE" == "darwin"* ]]; then
99
+ #{Kitchen::Provisioner::Ansible::Os::Darwin.new('darwin', config).install_command}
100
+ elif [ -f /etc/alpine-release ] || [ -d /etc/apk ]; then
101
+ #{Kitchen::Provisioner::Ansible::Os::Alpine.new('alpine', config).install_command}
102
+ else
103
+ #{Kitchen::Provisioner::Ansible::Os::Debian.new('debian', config).install_command}
104
+ fi
105
+ fi
106
+ INSTALL
107
+ end
108
+ else
109
+ return
110
+ end
111
+ result = cmd + install_windows_support + install_busser_prereqs
112
+ debug("Going to install ansible with: #{result}")
113
+ result
114
+ end
115
+
116
+ def install_windows_support
117
+ install = ''
118
+ if require_windows_support
119
+ install << <<-INSTALL
120
+ if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
121
+ #{sudo_env('yum')} -y install python-devel krb5-devel krb5-libs krb5-workstation gcc
122
+ else
123
+ if [ -f /etc/SuSE-release ] || [ -f /etc/SUSE-brand ]; then
124
+ #{sudo_env('zypper')} ar #{python_sles_repo}
125
+ #{sudo_env('zypper')} --non-interactive install python python-devel krb5-client pam_krb5
126
+ else
127
+ #{sudo_env('apt-get')} -y install python-dev libkrb5-dev build-essential
128
+ fi
129
+ fi
130
+ #{export_http_proxy}
131
+ #{sudo_env('easy_install')} pip
132
+ #{sudo_env('pip')} install pywinrm kerberos
133
+ INSTALL
134
+ end
135
+ install
136
+ end
137
+
138
+ def install_busser_prereqs
139
+ install = ''
140
+ install << <<-INSTALL
141
+ #{Util.shell_helpers}
142
+ # Fix for https://github.com/test-kitchen/busser/issues/12
143
+ if [ -h /usr/bin/ruby ]; then
144
+ L=$(readlink -f /usr/bin/ruby)
145
+ #{sudo_env('rm')} /usr/bin/ruby
146
+ #{sudo_env('ln')} -s $L /usr/bin/ruby
147
+ fi
148
+ INSTALL
149
+
150
+ if require_ruby_for_busser
151
+ install << <<-INSTALL
152
+ if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
153
+ if [ -z `grep -q 'Amazon Linux' /etc/system-release` ]; then
154
+ rhelversion6=$(cat /etc/redhat-release | grep 'release 6')
155
+ rhelversion7=$(cat /etc/redhat-release | grep 'release 7')
156
+ # For CentOS6/CentOS7/RHEL6/RHEL7 install ruby from SCL
157
+ if [ -n "$rhelversion6" ] || [ -n "$rhelversion7" ]; then
158
+ if [ ! -d "/opt/rh/ruby200" ]; then
159
+ echo "-----> Installing ruby200 SCL in CentOS6/CentOS7/RHEL6/RHEL7 to install busser to run tests"
160
+ #{sudo_env('yum')} install -y centos-release-scl
161
+ #{sudo_env('yum')} install -y ruby200
162
+ #{sudo_env('yum')} install -y ruby200-ruby-devel
163
+ echo "-----> Enabling ruby200"
164
+ source /opt/rh/ruby200/enable
165
+ echo "/opt/rh/ruby200/root/usr/lib64" | sudo tee -a /etc/ld.so.conf
166
+ #{sudo_env('ldconfig')}
167
+ #{sudo_env('ln')} -sf /opt/rh/ruby200/root/usr/bin/ruby /usr/bin/ruby
168
+ #{sudo_env('ln')} -sf /opt/rh/ruby200/root/usr/bin/gem /usr/bin/gem
169
+ fi
170
+ else
171
+ if [ ! $(which ruby) ]; then
172
+ #{update_packages_redhat_cmd}
173
+ #{sudo_env('yum')} -y install ruby ruby-devel
174
+ fi
175
+ fi
176
+ else
177
+ #{update_packages_redhat_cmd}
178
+ #{sudo_env('yum')} -y install ruby ruby-devel gcc
179
+ fi
180
+ elif [ -f /etc/SuSE-release ] || [ -f /etc/SUSE-brand ]; then
181
+ #{update_packages_suse_cmd}
182
+ #{sudo_env('zypper')} --non-interactive install ruby ruby-devel ca-certificates ca-certificates-cacert ca-certificates-mozilla
183
+ #{sudo_env('gem')} sources --add https://rubygems.org/
184
+ elif [ -f /etc/alpine-release ] || [ -d /etc/apk ]; then
185
+ #{update_packages_alpine_cmd}
186
+ #{sudo_env('apk')} add ruby ruby-dev ruby-io-console ca-certificates
187
+ else
188
+ if [ ! $(which ruby) ]; then
189
+ #{update_packages_debian_cmd}
190
+ # default package selection for Debian/Ubuntu machines
191
+ PACKAGES="ruby1.9.1 ruby1.9.1-dev"
192
+ if [ "$(lsb_release -si)" = "Debian" ]; then
193
+ debvers=$(sed 's/\\..*//' /etc/debian_version)
194
+ if [ $debvers -ge 8 ]; then
195
+ # this is jessie or better, where ruby1.9.1 is
196
+ # no longer in the repositories
197
+ PACKAGES="ruby ruby-dev ruby2.1 ruby2.1-dev"
198
+ fi
199
+ fi
200
+ if [ "$(lsb_release -si)" = "Ubuntu" ]; then
201
+ ubuntuvers=$(lsb_release -sr | tr -d .)
202
+ if [ $ubuntuvers -ge 1410 ]; then
203
+ # Default ruby is 2.x in utopic and newer
204
+ PACKAGES="ruby ruby-dev"
205
+ fi
206
+ fi
207
+ #{sudo_env('apt-get')} -y install $PACKAGES
208
+ if [ $debvers -eq 6 ]; then
209
+ # in squeeze we need to update alternatives
210
+ # for enable ruby1.9.1
211
+ ALTERNATIVES_STRING="--install /usr/bin/ruby ruby /usr/bin/ruby1.9.1 10 --slave /usr/share/man/man1/ruby.1.gz ruby.1.gz /usr/share/man/man1/ruby1.9.1.1.gz --slave /usr/bin/erb erb /usr/bin/erb1.9.1 --slave /usr/bin/gem gem /usr/bin/gem1.9.1 --slave /usr/bin/irb irb /usr/bin/irb1.9.1 --slave /usr/bin/rake rake /usr/bin/rake1.9.1 --slave /usr/bin/rdoc rdoc /usr/bin/rdoc1.9.1 --slave /usr/bin/testrb testrb /usr/bin/testrb1.9.1 --slave /usr/share/man/man1/erb.1.gz erb.1.gz /usr/share/man/man1/erb1.9.1.1.gz --slave /usr/share/man/man1/gem.1.gz gem.1.gz /usr/share/man/man1/gem1.9.1.1.gz --slave /usr/share/man/man1/irb.1.gz irb.1.gz /usr/share/man/man1/irb1.9.1.1.gz --slave /usr/share/man/man1/rake.1.gz rake.1.gz /usr/share/man/man1/rake1.9.1.1.gz --slave /usr/share/man/man1/rdoc.1.gz rdoc.1.gz /usr/share/man/man1/rdoc1.9.1.1.gz --slave /usr/share/man/man1/testrb.1.gz testrb.1.gz /usr/share/man/man1/testrb1.9.1.1.gz"
212
+ #{sudo_env('update-alternatives')} $ALTERNATIVES_STRING
213
+ # need to update gem tool because gem 1.3.7 from ruby 1.9.1 is broken
214
+ #{sudo_env('gem')} install rubygems-update
215
+ #{sudo_env('/var/lib/gems/1.9.1/bin/update_rubygems')}
216
+ # clear local gem cache
217
+ #{sudo_env('rm')} -r /home/vagrant/.gem
218
+ fi
219
+ fi
220
+ fi
221
+ INSTALL
222
+
223
+ elsif require_chef_for_busser && chef_url
224
+ install << <<-INSTALL
225
+ # install chef omnibus so that busser works as this is needed to run tests :(
226
+ if [ ! -d "/opt/chef" ]
227
+ then
228
+ echo "-----> Installing Chef Omnibus to install busser to run tests"
229
+ #{export_http_proxy}
230
+ do_download #{chef_url} /tmp/install.sh
231
+ #{sudo_env('sh')} /tmp/install.sh
232
+ fi
233
+ INSTALL
234
+ end
235
+
236
+ install
237
+ end
238
+
239
+ def init_command
240
+ dirs = %w(modules roles group_vars host_vars)
241
+ .map { |dir| File.join(config[:root_path], dir) }.join(' ')
242
+ cmd = "#{sudo_env('rm')} -rf #{dirs};"
243
+ cmd += " mkdir -p #{config[:root_path]}"
244
+ debug(cmd)
245
+ cmd
246
+ end
247
+
248
+ def create_sandbox
249
+ super
250
+ debug("Creating local sandbox in #{sandbox_path}")
251
+
252
+ yield if block_given?
253
+
254
+ prepare_playbook
255
+ prepare_inventory
256
+ prepare_modules
257
+ prepare_roles
258
+ prepare_ansible_cfg
259
+ prepare_group_vars
260
+ prepare_additional_copy_path
261
+ prepare_host_vars
262
+ prepare_hosts
263
+ prepare_spec
264
+ prepare_library_plugins
265
+ prepare_callback_plugins
266
+ prepare_filter_plugins
267
+ prepare_lookup_plugins
268
+ prepare_ansible_vault_password_file
269
+ prepare_kerberos_conf_file
270
+ info('Finished Preparing files for transfer')
271
+ end
272
+
273
+ def cleanup_sandbox
274
+ return if sandbox_path.nil?
275
+ debug("Cleaning up local sandbox in #{sandbox_path}")
276
+ FileUtils.rmtree(sandbox_path)
277
+ end
278
+
279
+ def prepare_command
280
+ commands = []
281
+
282
+ # Prevent failure when ansible package installation doesn't contain /etc/ansible
283
+ commands << [
284
+ sudo_env("#{config[:shell_command]} -c '[ -d /etc/ansible ] || mkdir /etc/ansible'")
285
+ ]
286
+
287
+ commands << [
288
+ sudo_env('cp'), File.join(config[:root_path], 'ansible.cfg'), '/etc/ansible'
289
+ ].join(' ')
290
+
291
+ commands << [
292
+ sudo_env('cp -r'), File.join(config[:root_path], 'group_vars'), '/etc/ansible/.'
293
+ ].join(' ')
294
+
295
+ commands << [
296
+ sudo_env('cp -r'), File.join(config[:root_path], 'host_vars'), '/etc/ansible/.'
297
+ ].join(' ')
298
+
299
+ if config[:ssh_known_hosts]
300
+ config[:ssh_known_hosts].each do |host|
301
+ info("Add #{host} to ~/.ssh/known_hosts")
302
+ commands << "ssh-keyscan #{host} > ~/.ssh/known_hosts 2> /dev/null"
303
+ end
304
+ end
305
+
306
+ if ansible_inventory
307
+ if File.directory?(ansible_inventory)
308
+ Dir.foreach(ansible_inventory) do |f|
309
+ next if f == "." or f == ".."
310
+ contents = File.open("#{ansible_inventory}/#{f}", 'rb') { |g| g.read }
311
+ if contents.start_with?('#!')
312
+ commands << [
313
+ sudo_env('chmod +x'), File.join("#{config[:root_path]}/#{File.basename(ansible_inventory)}", File.basename(f))
314
+ ].join(' ')
315
+ end
316
+ end
317
+ else
318
+ contents = File.open(ansible_inventory, 'rb') { |f| f.read }
319
+ if contents.start_with?('#!')
320
+ commands << [
321
+ sudo_env('chmod +x'), File.join(config[:root_path], File.basename(ansible_inventory))
322
+ ].join(' ')
323
+ end
324
+ end
325
+ end
326
+
327
+ if galaxy_requirements
328
+ if config[:require_ansible_source]
329
+ commands << setup_ansible_env_from_source
330
+ end
331
+ commands << ansible_galaxy_command
332
+ end
333
+
334
+ if kerberos_conf_file
335
+ commands << [
336
+ sudo_env('cp -f'), File.join(config[:root_path], 'krb5.conf'), '/etc'
337
+ ].join(' ')
338
+ end
339
+
340
+ command = commands.join(' && ')
341
+ debug(command)
342
+ command
343
+ end
344
+
345
+ def run_command
346
+ if !config[:ansible_playbook_command].nil?
347
+ return config[:ansible_playbook_command]
348
+ else
349
+
350
+ if config[:require_ansible_source] && !config[:ansible_binary_path]
351
+ # this is an ugly hack to get around the fact that extra vars uses ' and "
352
+ cmd = ansible_command("PATH=#{config[:root_path]}/ansible/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games PYTHONPATH=#{config[:root_path]}/ansible/lib MANPATH=#{config[:root_path]}/ansible/docs/man ansible-playbook")
353
+ elsif config[:ansible_binary_path]
354
+ cmd = ansible_command("#{config[:ansible_binary_path]}/ansible-playbook")
355
+ else
356
+ cmd = ansible_command('ansible-playbook')
357
+ end
358
+
359
+ cmd = "#{env_vars} #{cmd}" if !config[:env_vars].none?
360
+ cmd = "HTTPS_PROXY=#{https_proxy} #{cmd}" if https_proxy
361
+ cmd = "HTTP_PROXY=#{http_proxy} #{cmd}" if http_proxy
362
+ cmd = "NO_PROXY=#{no_proxy} #{cmd}" if no_proxy
363
+ cmd = "ANSIBLE_ROLES_PATH=#{ansible_roles_path} #{cmd}" if ansible_roles_path
364
+ cmd = "ANSIBLE_HOST_KEY_CHECKING=false #{cmd}" if !ansible_host_key_checking
365
+
366
+ cmd = "#{cd_ansible} #{cmd}" if !config[:ansible_sudo].nil? && !config[:ansible_sudo]
367
+ cmd = "#{copy_private_key_cmd} #{cmd}" if config[:private_key]
368
+
369
+ result = [
370
+ cmd,
371
+ ansible_inventory_flag,
372
+ ansible_limit_flag,
373
+ ansible_connection_flag,
374
+ "-M #{File.join(config[:root_path], 'modules')}",
375
+ ansible_verbose_flag,
376
+ ansible_check_flag,
377
+ ansible_diff_flag,
378
+ ansible_vault_flag,
379
+ private_key,
380
+ extra_vars,
381
+ tags,
382
+ ansible_extra_flags,
383
+ "#{File.join(config[:root_path], File.basename(config[:playbook]))}"
384
+ ].join(' ')
385
+ debug("Going to invoke ansible-playbook with: #{result}")
386
+ if config[:idempotency_test]
387
+ result = "#{result} && (echo 'Going to invoke ansible-playbook second time:'; #{result} | tee /tmp/idempotency_test.txt; grep -q 'changed=0.*failed=0' /tmp/idempotency_test.txt && (echo 'Idempotence test: PASS' && exit 0) || (echo 'Idempotence test: FAIL' && exit 1))"
388
+ debug("Full cmd with idempotency test: #{result}")
389
+ end
390
+
391
+ result
392
+ end
393
+ end
394
+
395
+ def ansible_command(script)
396
+ if config[:ansible_sudo].nil? || config[:ansible_sudo] == true
397
+ s = https_proxy ? "https_proxy=#{https_proxy}" : nil
398
+ p = http_proxy ? "http_proxy=#{http_proxy}" : nil
399
+ n = no_proxy ? "no_proxy=#{no_proxy}" : nil
400
+ p || s || n ? " #{p} #{s} #{n} #{config[:sudo_command]} -s #{cd_ansible} #{script}" : "#{config[:sudo_command]} -s #{cd_ansible} #{script}"
401
+ else
402
+ return script
403
+ end
404
+ end
405
+
406
+ def ansible_galaxy_command
407
+ cmd = [
408
+ 'ansible-galaxy', 'install', '--force',
409
+ '-p', File.join(config[:root_path], 'roles'),
410
+ '-r', File.join(config[:root_path], galaxy_requirements)
411
+ ].join(' ')
412
+ cmd = "https_proxy=#{https_proxy} #{cmd}" if https_proxy
413
+ cmd = "http_proxy=#{http_proxy} #{cmd}" if http_proxy
414
+ cmd = "no_proxy=#{no_proxy} #{cmd}" if no_proxy
415
+ cmd
416
+ end
417
+
418
+ def cd_ansible
419
+ # this is not working so just return nil for now
420
+ # File.exist?('ansible.cfg') ? "cd #{config[:root_path]};" : nil
421
+ nil
422
+ end
423
+
424
+ protected
425
+
426
+ def load_needed_dependencies!
427
+ return unless File.exist?(ansiblefile)
428
+
429
+ debug("Ansiblefile found at #{ansiblefile}, loading Librarian-Ansible")
430
+ Ansible::Librarian.load!(logger)
431
+ end
432
+
433
+ def install_ansible_from_source_command
434
+ <<-INSTALL
435
+ if [ ! -d #{config[:root_path]}/ansible ]; then
436
+ if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
437
+ #{Kitchen::Provisioner::Ansible::Os::Redhat.new('redhat', config).install_epel_repo}
438
+ #{update_packages_redhat_cmd}
439
+ #{sudo_env('yum')} -y install libselinux-python python2-devel git python-setuptools python-setuptools-dev libffi-devel libssl-devel
440
+ else
441
+ if [ -f /etc/SUSE-brand ] || [ -f /etc/SuSE-release ]; then
442
+ #{sudo_env('zypper')} ar #{python_sles_repo}
443
+ #{update_packages_suse_cmd}
444
+ #{sudo_env('zypper')} --non-interactive install python python-devel git python-setuptools python-pip python-six libyaml-devel libffi-devel libopenssl-devel
445
+ else
446
+ #{update_packages_debian_cmd}
447
+ #{sudo_env('apt-get')} -y install git python python-setuptools build-essential python-dev libffi-dev libssl-dev
448
+ fi
449
+ fi
450
+
451
+ #{export_http_proxy}
452
+ git clone git://github.com/ansible/ansible.git --recursive #{config[:root_path]}/ansible #{install_source_rev}
453
+ #{sudo_env('easy_install')} pip
454
+ #{sudo_env('pip')} install -U setuptools
455
+ #{sudo_env('pip')} install six paramiko PyYAML Jinja2 httplib2
456
+ fi
457
+ INSTALL
458
+ end
459
+
460
+ def install_ansible_from_pip_command
461
+ ansible_version = ''
462
+ ansible_version = "==#{config[:ansible_version]}" unless config[:ansible_version] == 'latest'
463
+
464
+ <<-INSTALL
465
+ if [ ! -d #{config[:root_path]}/ansible ]; then
466
+ if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
467
+ #{Kitchen::Provisioner::Ansible::Os::Redhat.new('redhat', config).install_epel_repo}
468
+ #{update_packages_redhat_cmd}
469
+ #{sudo_env('yum')} -y install libselinux-python python2-devel git python-setuptools python-setuptools-dev libffi-devel openssl-devel gcc
470
+ else
471
+ if [ -f /etc/SUSE-brand ] || [ -f /etc/SuSE-release ]; then
472
+ #{sudo_env('zypper')} ar #{python_sles_repo}
473
+ #{update_packages_suse_cmd}
474
+ #{sudo_env('zypper')} --non-interactive install python python-devel git python-setuptools python-pip python-six libyaml-devel libffi-devel libopenssl-devel
475
+ else
476
+ #{update_packages_debian_cmd}
477
+ #{sudo_env('apt-get')} -y install git python python-setuptools build-essential python-dev libffi-dev libssl-dev
478
+ fi
479
+ fi
480
+
481
+ #{export_http_proxy}
482
+ #{sudo_env('easy_install')} pip
483
+ #{sudo_env('pip')} install -U setuptools
484
+ #{sudo_env('pip')} install ansible#{ansible_version}
485
+ fi
486
+ INSTALL
487
+ end
488
+
489
+ def install_omnibus_command
490
+ info('Installing ansible using ansible omnibus')
491
+
492
+ version = ''
493
+ version = "-v #{config[:ansible_version]}" unless config[:ansible_version].nil?
494
+
495
+ <<-INSTALL
496
+ #{Util.shell_helpers}
497
+
498
+ if [ ! -d "#{config[:ansible_omnibus_remote_path]}" ]; then
499
+ echo "-----> Installing Ansible Omnibus"
500
+ #{export_http_proxy}
501
+ do_download #{config[:ansible_omnibus_url]} /tmp/ansible_install.sh
502
+ #{sudo_env(config[:shell_command])} /tmp/ansible_install.sh #{version}
503
+ fi
504
+ INSTALL
505
+ end
506
+
507
+ def setup_ansible_env_from_source
508
+ "cd #{config[:root_path]}/ansible && source hacking/env-setup && cd ../"
509
+ end
510
+
511
+ def tmp_modules_dir
512
+ File.join(sandbox_path, 'modules')
513
+ end
514
+
515
+ def tmp_playbook_path
516
+ File.join(sandbox_path, File.basename(playbook))
517
+ end
518
+
519
+ def tmp_host_vars_dir
520
+ File.join(sandbox_path, 'host_vars')
521
+ end
522
+
523
+ def tmp_roles_dir
524
+ File.join(sandbox_path, 'roles')
525
+ end
526
+
527
+ def tmp_spec_dir
528
+ File.join(sandbox_path, 'spec')
529
+ end
530
+
531
+ def tmp_library_plugins_dir
532
+ File.join(sandbox_path, 'library')
533
+ end
534
+
535
+ def tmp_callback_plugins_dir
536
+ File.join(sandbox_path, 'callback_plugins')
537
+ end
538
+
539
+ def tmp_filter_plugins_dir
540
+ File.join(sandbox_path, 'filter_plugins')
541
+ end
542
+
543
+ def tmp_lookup_plugins_dir
544
+ File.join(sandbox_path, 'lookup_plugins')
545
+ end
546
+
547
+ def tmp_ansible_vault_password_file_path
548
+ File.join(sandbox_path, File.basename(ansible_vault_password_file).reverse.chomp('.').reverse)
549
+ end
550
+
551
+ def tmp_kerberos_conf_file_path
552
+ File.join(sandbox_path, 'krb5.conf')
553
+ end
554
+
555
+ def tmp_inventory_path
556
+ File.join(sandbox_path, File.basename(ansible_inventory))
557
+ end
558
+
559
+ def ansiblefile
560
+ config[:ansiblefile_path] || ''
561
+ end
562
+
563
+ def galaxy_requirements
564
+ config[:requirements_path] || nil
565
+ end
566
+
567
+ def env_vars
568
+ return nil if config[:env_vars].none?
569
+ config[:env_vars].map { |k, v| "#{k}=#{v}" }.join(' ')
570
+ end
571
+
572
+ def playbook
573
+ config[:playbook]
574
+ end
575
+
576
+ def hosts
577
+ config[:hosts]
578
+ end
579
+
580
+ def roles
581
+ config[:roles_path]
582
+ end
583
+
584
+ def role_name
585
+ if config[:role_name]
586
+ config[:role_name]
587
+ elsif File.basename(roles) == 'roles'
588
+ ''
589
+ else
590
+ File.basename(roles)
591
+ end
592
+ end
593
+
594
+ def modules
595
+ config[:modules_path]
596
+ end
597
+
598
+ def spec
599
+ 'spec'
600
+ end
601
+
602
+ def group_vars
603
+ config[:group_vars_path].to_s
604
+ end
605
+
606
+ def additional_copy
607
+ config[:additional_copy_path]
608
+ end
609
+
610
+ def ansible_cfg_path
611
+ config[:ansible_cfg_path]
612
+ end
613
+
614
+ def recursive_additional_copy
615
+ config[:recursive_additional_copy_path]
616
+ end
617
+
618
+ def host_vars
619
+ config[:host_vars_path].to_s
620
+ end
621
+
622
+ def library_plugins
623
+ config[:library_plugins_path].to_s
624
+ end
625
+
626
+ def callback_plugins
627
+ config[:callback_plugins_path].to_s
628
+ end
629
+
630
+ def filter_plugins
631
+ config[:filter_plugins_path].to_s
632
+ end
633
+
634
+ def lookup_plugins
635
+ config[:lookup_plugins_path].to_s
636
+ end
637
+
638
+ def ansible_vault_password_file
639
+ config[:ansible_vault_password_file]
640
+ end
641
+
642
+ def ansible_inventory
643
+ return nil if config[:ansible_inventory] == 'none'
644
+ config[:ansible_inventory] = config[:ansible_inventory_file] if config[:ansible_inventory].nil?
645
+ info('ansible_inventory_file parameter deprecated use ansible_inventory') if config[:ansible_inventory_file]
646
+ config[:ansible_inventory]
647
+ end
648
+
649
+ def ansible_debian_version
650
+ if @config[:ansible_version] == 'latest' || @config[:ansible_version] == nil
651
+ ''
652
+ else
653
+ "=#{@config[:ansible_version]}"
654
+ end
655
+ end
656
+
657
+ def ansible_connection_flag
658
+ "-c #{config[:ansible_connection]}" if config[:ansible_connection] != 'none'
659
+ end
660
+
661
+ def ansible_verbose_flag
662
+ config[:ansible_verbose] ? '-' << ('v' * verbosity_level(config[:ansible_verbosity])) : nil
663
+ end
664
+
665
+ def ansible_check_flag
666
+ config[:ansible_check] ? '--check' : nil
667
+ end
668
+
669
+ def ansible_diff_flag
670
+ config[:ansible_diff] ? '--diff' : nil
671
+ end
672
+
673
+ def ansible_vault_flag
674
+ debug(config[:ansible_vault_password_file])
675
+ config[:ansible_vault_password_file] ? "--vault-password-file=#{File.join(config[:root_path], File.basename(config[:ansible_vault_password_file]).reverse.chomp('.').reverse)}" : nil
676
+ end
677
+
678
+ def ansible_inventory_flag
679
+ return nil if config[:ansible_inventory] == 'none'
680
+ ansible_inventory ? "-i #{File.join(config[:root_path], File.basename(ansible_inventory))}" : "-i #{File.join(config[:root_path], 'hosts')}"
681
+ end
682
+
683
+ def ansible_limit_flag
684
+ config[:ansible_limit] ? "-l #{config[:ansible_limit]}" : ""
685
+ end
686
+
687
+ def ansible_extra_flags
688
+ config[:ansible_extra_flags] || ''
689
+ end
690
+
691
+ def ansible_platform
692
+ config[:ansible_platform].to_s.downcase
693
+ end
694
+
695
+ def ansible_host_key_checking
696
+ config[:ansible_host_key_checking]
697
+ end
698
+
699
+ def private_key
700
+ if config[:private_key]
701
+ "--private-key #{private_key_file}"
702
+ end
703
+ end
704
+
705
+ def copy_private_key_cmd
706
+ if !config[:private_key].start_with?('/') && !config[:private_key].start_with?('~')
707
+ ssh_private_key = File.join('~/.ssh', File.basename(config[:private_key]))
708
+ tmp_private_key = File.join(config[:root_path], config[:private_key])
709
+ "rm -rf #{ssh_private_key}; cp #{tmp_private_key} #{ssh_private_key}; chmod 400 #{ssh_private_key};"
710
+ end
711
+ end
712
+
713
+ def private_key_file
714
+ if config[:private_key].start_with?('/') || config[:private_key].start_with?('~')
715
+ "#{config[:private_key]}"
716
+ elsif config[:private_key]
717
+ "#{File.join('~/.ssh', File.basename(config[:private_key]))}"
718
+ end
719
+ end
720
+
721
+ def update_packages_debian_cmd
722
+ Kitchen::Provisioner::Ansible::Os::Debian.new('debian', config).update_packages_command
723
+ end
724
+
725
+ def update_packages_suse_cmd
726
+ Kitchen::Provisioner::Ansible::Os::Suse.new('suse', config).update_packages_command
727
+ end
728
+
729
+ def update_packages_redhat_cmd
730
+ Kitchen::Provisioner::Ansible::Os::Redhat.new('redhat', config).update_packages_command
731
+ end
732
+
733
+ def update_packages_alpine_cmd
734
+ Kitchen::Provisioner::Ansible::Os::Alpine.new('alpine', config).update_packages_command
735
+ end
736
+
737
+ def python_sles_repo
738
+ config[:python_sles_repo]
739
+ end
740
+
741
+ def extra_vars
742
+ bash_vars = config[:extra_vars]
743
+ if config.key?(:attributes) && config[:attributes].key?(:extra_vars) && config[:attributes][:extra_vars].is_a?(Hash)
744
+ bash_vars = config[:attributes][:extra_vars]
745
+ end
746
+
747
+ return nil if bash_vars.none?
748
+ bash_vars = JSON.dump(bash_vars)
749
+ bash_vars = "-e '#{bash_vars}'"
750
+ debug(bash_vars)
751
+ bash_vars
752
+ end
753
+
754
+ def tags
755
+ bash_tags = config.key?(:attributes) && config[:attributes].key?(:tags) && config[:attributes][:tags].is_a?(Array) ? config[:attributes][:tags] : config[:tags]
756
+ return nil if bash_tags.empty?
757
+
758
+ bash_tags = bash_tags.join(',')
759
+ bash_tags = "-t '#{bash_tags}'"
760
+ debug(bash_tags)
761
+ bash_tags
762
+ end
763
+
764
+ def chef_url
765
+ config[:chef_bootstrap_url]
766
+ end
767
+
768
+ def require_ruby_for_busser
769
+ config[:require_ruby_for_busser]
770
+ end
771
+
772
+ def require_chef_for_busser
773
+ config[:require_chef_for_busser]
774
+ end
775
+
776
+ def require_windows_support
777
+ config[:require_windows_support]
778
+ end
779
+
780
+ def kerberos_conf_file
781
+ config[:kerberos_conf_file]
782
+ end
783
+
784
+ def install_source_rev
785
+ config[:ansible_source_rev] ? "--branch #{config[:ansible_source_rev]}" : nil
786
+ end
787
+
788
+ def http_proxy
789
+ config[:http_proxy]
790
+ end
791
+
792
+ def https_proxy
793
+ config[:https_proxy]
794
+ end
795
+
796
+ def no_proxy
797
+ config[:no_proxy]
798
+ end
799
+
800
+ def sudo_env(pm,home=false)
801
+ s = https_proxy ? "https_proxy=#{https_proxy}" : nil
802
+ p = http_proxy ? "http_proxy=#{http_proxy}" : nil
803
+ n = no_proxy ? "no_proxy=#{no_proxy}" : nil
804
+ if home
805
+ p || s || n ? "#{sudo_home('env')} #{p} #{s} #{n} #{pm}" : "#{sudo_home(pm)}"
806
+ else
807
+ p || s || n ? "#{sudo('env')} #{p} #{s} #{n} #{pm}" : "#{sudo(pm)}"
808
+ end
809
+ end
810
+
811
+ def export_http_proxy
812
+ cmd = ''
813
+ cmd = " HTTP_PROXY=#{http_proxy}" if http_proxy
814
+ cmd = "#{cmd} HTTPS_PROXY=#{https_proxy}" if https_proxy
815
+ cmd = "#{cmd} NO_PROXY=#{no_proxy}" if no_proxy
816
+ cmd = "export #{cmd}" if cmd != ''
817
+ cmd
818
+ end
819
+
820
+ def ansible_roles_path
821
+ roles_paths = []
822
+ roles_paths << File.join(config[:root_path], 'roles') unless config[:roles_path].nil?
823
+ if config[:additional_copy_role_path]
824
+ config[:additional_copy_role_path].each do |additional_role_path|
825
+ roles_paths << File.join(config[:root_path], File.basename(additional_role_path))
826
+ end
827
+ end
828
+ if roles_paths.empty?
829
+ info('No roles have been set.')
830
+ nil
831
+ else
832
+ debug("Setting roles_path inside VM to #{ roles_paths.join(':') }")
833
+ roles_paths.join(':')
834
+ end
835
+ end
836
+
837
+ def prepare_roles
838
+ info('Preparing roles')
839
+ debug("Using roles from #{roles}")
840
+
841
+ resolve_with_librarian if File.exist?(ansiblefile)
842
+
843
+ if galaxy_requirements
844
+ dest = File.join(sandbox_path, galaxy_requirements)
845
+ FileUtils.mkdir_p(File.dirname(dest))
846
+ FileUtils.cp(galaxy_requirements, dest)
847
+ end
848
+
849
+ FileUtils.mkdir_p(File.join(tmp_roles_dir, role_name))
850
+ Find.find(roles) do |source|
851
+ # Detect whether we are running tests on a role
852
+ # If so, make sure to copy into VM so dir structure is like: /tmp/kitchen/roles/role_name
853
+ role_path = source.sub(/#{roles}|\/roles/, '')
854
+ unless roles =~ /\/roles$/
855
+ role_path = "#{role_name}/#{role_path}"
856
+ end
857
+
858
+ target = File.join(tmp_roles_dir, role_path)
859
+
860
+ Find.prune if config[:ignore_paths_from_root].include? File.basename(source)
861
+ Find.prune if config[:ignore_extensions_from_root].include? File.extname(source)
862
+ if File.directory?(source)
863
+ FileUtils.mkdir_p(target)
864
+ else
865
+ FileUtils.cp(source, target)
866
+ end
867
+ end
868
+ end
869
+
870
+ # copy ansible.cfg if found
871
+ def prepare_ansible_cfg
872
+ info('Preparing ansible.cfg file')
873
+ ansible_config_file = "#{File.join(sandbox_path, 'ansible.cfg')}"
874
+ if !ansible_cfg_path.nil? && File.exist?(ansible_cfg_path)
875
+ info('Found existing ansible.cfg')
876
+ FileUtils.cp_r(ansible_cfg_path, ansible_config_file)
877
+ else
878
+ info('Empty ansible.cfg generated')
879
+ File.open(ansible_config_file, 'wb') do |file|
880
+ file.write("#no config parameters\n")
881
+ end
882
+ end
883
+ end
884
+
885
+ def prepare_inventory
886
+ info('Preparing inventory')
887
+ return unless ansible_inventory
888
+ if File.directory?(ansible_inventory)
889
+ debug("Copying inventory directory from #{ansible_inventory} to #{tmp_inventory_path}")
890
+ FileUtils.cp_r(ansible_inventory, sandbox_path)
891
+ else
892
+ debug("Copying inventory file from #{ansible_inventory} to #{tmp_inventory_path}")
893
+ FileUtils.cp_r(ansible_inventory, tmp_inventory_path)
894
+ end
895
+ end
896
+
897
+ # localhost ansible_connection=local
898
+ # [example_servers]
899
+ # localhost
900
+ def prepare_hosts
901
+ return if ansible_inventory
902
+ info('Preparing hosts file')
903
+
904
+ if config[:hosts].nil?
905
+ fail 'No hosts have been set. Please specify one in .kitchen.yml'
906
+ else
907
+ debug("Using host from #{hosts}")
908
+ File.open(File.join(sandbox_path, 'hosts'), 'wb') do |file|
909
+ file.write("localhost ansible_connection=local\n[#{hosts}]\nlocalhost\n")
910
+ end
911
+ end
912
+ end
913
+
914
+ def prepare_playbook
915
+ info('Preparing playbook')
916
+ debug("Copying playbook from #{playbook} to #{tmp_playbook_path}")
917
+ FileUtils.cp_r(playbook, tmp_playbook_path)
918
+ end
919
+
920
+ def prepare_group_vars
921
+ info('Preparing group_vars')
922
+ tmp_group_vars_dir = File.join(sandbox_path, 'group_vars')
923
+ FileUtils.mkdir_p(tmp_group_vars_dir)
924
+
925
+ unless File.directory?(group_vars)
926
+ info('nothing to do for group_vars')
927
+ return
928
+ end
929
+
930
+ debug("Using group_vars from #{group_vars}")
931
+ FileUtils.cp_r(Dir.glob("#{group_vars}/*"), tmp_group_vars_dir)
932
+ end
933
+
934
+ def prepare_additional_copy_path
935
+ info('Preparing additional_copy_path')
936
+ additional_files.each do |file|
937
+ info("Copy additional path: #{file}")
938
+ destination = File.join(sandbox_path, File.basename(file))
939
+ if File.directory?(file)
940
+ debug("Copy dir: #{file} #{destination}")
941
+ FileUtils.cp_r(file, destination)
942
+ else
943
+ debug("Copy file: #{file} #{destination}")
944
+ FileUtils.cp(file, destination)
945
+ end
946
+ end
947
+ recursive_additional_files.each do |file|
948
+ info("Copy recursive additional path: #{file}")
949
+ Find.find(file) do |files|
950
+ destination = File.join(sandbox_path, files)
951
+ Find.prune if config[:ignore_paths_from_root].include? File.basename(files)
952
+ Find.prune if config[:ignore_extensions_from_root].include? File.extname(files)
953
+ if File.directory?(files)
954
+ FileUtils.mkdir_p(destination)
955
+ else
956
+ FileUtils.cp(files, destination)
957
+ end
958
+ end
959
+ end
960
+ end
961
+
962
+ def additional_files
963
+ additional_files = []
964
+ if additional_copy
965
+ additional_files = additional_copy.is_a?(Array) ? additional_copy : [additional_copy]
966
+ end
967
+ additional_files.map(&:to_s)
968
+ end
969
+
970
+ def recursive_additional_files
971
+ recursive_additional_files = []
972
+ if recursive_additional_copy
973
+ recursive_additional_files = recursive_additional_copy.is_a?(Array) ? recursive_additional_copy : [recursive_additional_copy]
974
+ end
975
+ recursive_additional_files.map(&:to_s)
976
+ end
977
+
978
+ def prepare_host_vars
979
+ info('Preparing host_vars')
980
+ FileUtils.mkdir_p(tmp_host_vars_dir)
981
+
982
+ unless File.directory?(host_vars)
983
+ info 'nothing to do for host_vars'
984
+ return
985
+ end
986
+
987
+ debug("Using host_vars from #{host_vars}")
988
+ FileUtils.cp_r(Dir.glob("#{host_vars}/*"), tmp_host_vars_dir)
989
+ end
990
+
991
+ def prepare_modules
992
+ info('Preparing modules')
993
+
994
+ FileUtils.mkdir_p(tmp_modules_dir)
995
+
996
+ if modules && File.directory?(modules)
997
+ debug("Using modules from #{modules}")
998
+ FileUtils.cp_r(Dir.glob("#{modules}/*"), tmp_modules_dir, remove_destination: true)
999
+ else
1000
+ info 'nothing to do for modules'
1001
+ end
1002
+ end
1003
+
1004
+ def prepare_spec
1005
+ info('Preparing spec')
1006
+
1007
+ FileUtils.mkdir_p(tmp_spec_dir)
1008
+
1009
+ if spec && File.directory?(spec)
1010
+ debug("Using spec from #{spec}")
1011
+ FileUtils.cp_r(Dir.glob("#{spec}/*"), tmp_spec_dir, remove_destination: true)
1012
+ else
1013
+ info 'nothing to do for spec'
1014
+ end
1015
+ end
1016
+
1017
+ def prepare_library_plugins
1018
+ info('Preparing library plugins')
1019
+ FileUtils.mkdir_p(tmp_library_plugins_dir)
1020
+
1021
+ if library_plugins && File.directory?(library_plugins)
1022
+ debug("Using library plugins from #{library_plugins}")
1023
+ FileUtils.cp_r(Dir.glob("#{library_plugins}/{*,!*.pyc}"), tmp_library_plugins_dir, remove_destination: true)
1024
+ else
1025
+ info 'nothing to do for library plugins'
1026
+ end
1027
+ end
1028
+
1029
+ def prepare_callback_plugins
1030
+ info('Preparing callback plugins')
1031
+ FileUtils.mkdir_p(tmp_callback_plugins_dir)
1032
+
1033
+ if callback_plugins && File.directory?(callback_plugins)
1034
+ debug("Using callback plugins from #{callback_plugins}")
1035
+ FileUtils.cp_r(Dir.glob("#{callback_plugins}/{*,!*.pyc}"), tmp_callback_plugins_dir, remove_destination: true)
1036
+ else
1037
+ info 'nothing to do for callback plugins'
1038
+ end
1039
+ end
1040
+
1041
+ def prepare_filter_plugins
1042
+ info('Preparing filter_plugins')
1043
+ FileUtils.mkdir_p(tmp_filter_plugins_dir)
1044
+
1045
+ if filter_plugins && File.directory?(filter_plugins)
1046
+ debug("Using filter_plugins from #{filter_plugins}")
1047
+ FileUtils.cp_r(Dir.glob("#{filter_plugins}/*.py"), tmp_filter_plugins_dir, remove_destination: true)
1048
+ else
1049
+ info 'nothing to do for filter_plugins'
1050
+ end
1051
+ end
1052
+
1053
+ def prepare_lookup_plugins
1054
+ info('Preparing lookup_plugins')
1055
+ FileUtils.mkdir_p(tmp_lookup_plugins_dir)
1056
+
1057
+ if lookup_plugins && File.directory?(lookup_plugins)
1058
+ debug("Using lookup_plugins from #{lookup_plugins}")
1059
+ FileUtils.cp_r(Dir.glob("#{lookup_plugins}/*.py"), tmp_lookup_plugins_dir, remove_destination: true)
1060
+ else
1061
+ info 'nothing to do for lookup_plugins'
1062
+ end
1063
+ end
1064
+
1065
+ def prepare_ansible_vault_password_file
1066
+ return unless ansible_vault_password_file
1067
+
1068
+ info('Preparing ansible vault password')
1069
+ debug("Copying ansible vault password file from #{ansible_vault_password_file} to #{tmp_ansible_vault_password_file_path}")
1070
+
1071
+ FileUtils.cp(ansible_vault_password_file, tmp_ansible_vault_password_file_path)
1072
+ end
1073
+
1074
+ def prepare_kerberos_conf_file
1075
+ return unless kerberos_conf_file
1076
+
1077
+ info('Preparing kerberos configuration file')
1078
+ debug("Copying kerberos configuration file from #{kerberos_conf_file} to #{tmp_kerberos_conf_file_path}")
1079
+
1080
+ FileUtils.cp(kerberos_conf_file, tmp_kerberos_conf_file_path)
1081
+ end
1082
+
1083
+ def resolve_with_librarian
1084
+ Kitchen.mutex.synchronize do
1085
+ Ansible::Librarian.new(ansiblefile, tmp_roles_dir, logger).resolve
1086
+ end
1087
+ end
1088
+ end
1089
+ end
1090
+ end