kitchen-ansible 0.0.22 → 0.0.23

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,709 +1,768 @@
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 'kitchen/provisioner/base'
25
- require 'kitchen/provisioner/ansible/config'
26
- require 'kitchen/provisioner/ansible/librarian'
27
-
28
- module Kitchen
29
-
30
- class Busser
31
-
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
- end
48
-
49
- def finalize_config!(instance)
50
- config.set_instance(instance)
51
- super(instance)
52
- end
53
-
54
- def verbosity_level(level = 1)
55
- level = level.to_sym if level.is_a? String
56
- log_levels = { :info => 1, :warn => 2, :debug => 3, :trace => 4 }
57
- if level.is_a? Symbol and log_levels.include? level
58
- # puts "Log Level is: #{log_levels[level]}"
59
- log_levels[level]
60
- elsif level.is_a? Integer and level > 0
61
- # puts "Log Level is: #{level}"
62
- level
63
- else
64
- raise 'Invalid ansible_verbosity setting. Valid values are: 1, 2, 3, 4 OR :info, :warn, :debug, :trace'
65
- end
66
- end
67
-
68
- def install_command
69
- if config[:require_ansible_omnibus]
70
- cmd = install_omnibus_command
71
- elsif config[:require_ansible_source]
72
- info("Installing ansible from source")
73
- cmd = install_ansible_from_source_command
74
- elsif config[:require_ansible_repo]
75
- case ansible_platform
76
- when "debian", "ubuntu"
77
- info("Installing ansible on #{ansible_platform}")
78
- cmd = install_debian_command
79
- when "redhat", "centos", "fedora"
80
- info("Installing ansible on #{ansible_platform}")
81
- cmd = install_redhat_command
82
- when "amazon"
83
- info("Installing ansible on #{ansible_platform}")
84
- cmd = install_amazon_linux_command
85
- else
86
- info("Installing ansible, will try to determine platform os")
87
- cmd = <<-INSTALL
88
- if [ ! $(which ansible) ]; then
89
- if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
90
- if ! [ grep -q 'Amazon Linux' /etc/system-release ]; then
91
- #{install_redhat_command}
92
- else
93
- #{install_amazon_linux_command}
94
- fi
95
- else
96
- #{install_debian_command}
97
- fi
98
- fi
99
- INSTALL
100
- end
101
- else
102
- return
103
- end
104
- cmd + install_busser_prereqs
105
- end
106
-
107
- def install_busser_prereqs
108
- install = ''
109
- install << <<-INSTALL
110
- #{Util.shell_helpers}
111
- # Fix for https://github.com/test-kitchen/busser/issues/12
112
- if [ -h /usr/bin/ruby ]; then
113
- L=$(readlink -f /usr/bin/ruby)
114
- #{sudo('rm')} /usr/bin/ruby
115
- #{sudo('ln')} -s $L /usr/bin/ruby
116
- fi
117
- INSTALL
118
-
119
- if require_ruby_for_busser
120
- install << <<-INSTALL
121
- if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
122
- if ! [ grep -q 'Amazon Linux' /etc/system-release ]; then
123
- rhelversion=$(cat /etc/redhat-release | grep 'release 6')
124
- # For CentOS6/RHEL6 install ruby from SCL
125
- if [ -n "$rhelversion" ]; then
126
- if [ ! -d "/opt/rh/ruby193" ]; then
127
- echo "-----> Installing ruby SCL in CentOS6/RHEL6 to install busser to run tests"
128
- #{sudo('yum')} install -y centos-release-SCL
129
- #{sudo('yum')} install -y ruby193
130
- #{sudo('yum')} install -y ruby193-ruby-devel
131
- echo "-----> Enabling ruby193"
132
- source /opt/rh/ruby193/enable
133
- echo "/opt/rh/ruby193/root/usr/lib64" | sudo tee -a /etc/ld.so.conf
134
- #{sudo('ldconfig')}
135
- #{sudo('ln')} -s /opt/rh/ruby193/root/usr/bin/ruby /usr/bin/ruby
136
- #{sudo('ln')} -s /opt/rh/ruby193/root/usr/bin/gem /usr/bin/gem
137
- fi
138
- else
139
- if [ ! $(which ruby) ]; then
140
- #{update_packages_redhat_cmd}
141
- #{sudo('yum')} -y install ruby ruby-devel
142
- fi
143
- fi
144
- else
145
- #{update_packages_redhat_cmd}
146
- #{sudo('yum')} -y install ruby ruby-devel gcc
147
- fi
148
- else
149
- if [ ! $(which ruby) ]; then
150
- #{update_packages_debian_cmd}
151
- # default package selection for Debian/Ubuntu machines
152
- PACKAGES="ruby1.9.1 ruby1.9.1-dev"
153
- if [ "$(lsb_release -si)" = "Debian" ]; then
154
- debvers=$(sed 's/\\..*//' /etc/debian_version)
155
- if [ $debvers -ge 8 ]; then
156
- # this is jessie or better, where ruby1.9.1 is
157
- # no longer in the repositories
158
- PACKAGES="ruby ruby-dev ruby2.1 ruby2.1-dev"
159
- fi
160
- fi
161
- #{sudo('apt-get')} -y install $PACKAGES
162
- fi
163
- fi
164
- INSTALL
165
-
166
- elsif require_chef_for_busser && chef_url then
167
- install << <<-INSTALL
168
- # install chef omnibus so that busser works as this is needed to run tests :(
169
- if [ ! -d "/opt/chef" ]
170
- then
171
- echo "-----> Installing Chef Omnibus to install busser to run tests"
172
- do_download #{chef_url} /tmp/install.sh
173
- #{sudo('sh')} /tmp/install.sh
174
- fi
175
- INSTALL
176
- end
177
-
178
- install
179
- end
180
-
181
- def init_command
182
- dirs = %w{modules roles group_vars host_vars}.
183
- map { |dir| File.join(config[:root_path], dir) }.join(" ")
184
- cmd = "#{sudo('rm')} -rf #{dirs};"
185
- cmd = cmd+" mkdir -p #{config[:root_path]}"
186
- debug(cmd)
187
- cmd
188
- end
189
-
190
- def create_sandbox
191
- super
192
- debug("Creating local sandbox in #{sandbox_path}")
193
-
194
- yield if block_given?
195
-
196
- prepare_playbook
197
- prepare_inventory_file
198
- prepare_modules
199
- prepare_roles
200
- prepare_ansible_cfg
201
- prepare_group_vars
202
- prepare_additional_copy_path
203
- prepare_host_vars
204
- prepare_hosts
205
- prepare_filter_plugins
206
- prepare_ansible_vault_password_file
207
- info('Finished Preparing files for transfer')
208
-
209
- end
210
-
211
- def cleanup_sandbox
212
- return if sandbox_path.nil?
213
- debug("Cleaning up local sandbox in #{sandbox_path}")
214
- FileUtils.rmtree(sandbox_path)
215
- end
216
-
217
- def prepare_command
218
- commands = []
219
-
220
- # Prevent failure when ansible package installation doesn't contain /etc/ansible
221
- commands << [
222
- sudo("bash -c '[ -d /etc/ansible ] || mkdir /etc/ansible'")
223
- ]
224
-
225
- commands << [
226
- sudo('cp'),File.join(config[:root_path], 'ansible.cfg'),'/etc/ansible',
227
- ].join(' ')
228
-
229
- commands << [
230
- sudo('cp -r'), File.join(config[:root_path],'group_vars'), '/etc/ansible/.',
231
- ].join(' ')
232
-
233
- commands << [
234
- sudo('cp -r'), File.join(config[:root_path],'host_vars'), '/etc/ansible/.',
235
- ].join(' ')
236
-
237
- if galaxy_requirements
238
- if config[:require_ansible_source]
239
- commands << setup_ansible_env_from_source
240
- end
241
- commands << [
242
- 'ansible-galaxy', 'install', '--force',
243
- '-p', File.join(config[:root_path], 'roles'),
244
- '-r', File.join(config[:root_path], galaxy_requirements),
245
- ].join(' ')
246
- end
247
-
248
- command = commands.join(' && ')
249
- debug(command)
250
- command
251
- end
252
-
253
- def run_command
254
- if config[:require_ansible_source]
255
- # this is an ugly hack to get around the fact that extra vars uses ' and "
256
- 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 #{config[:root_path]}/ansible/bin/ansible-playbook")
257
- else
258
- cmd = ansible_command("ansible-playbook")
259
- end
260
- [
261
- cmd,
262
- ansible_inventory_flag,
263
- "-c #{config[:ansible_connection]}",
264
- "-M #{File.join(config[:root_path], 'modules')}",
265
- ansible_verbose_flag,
266
- ansible_check_flag,
267
- ansible_diff_flag,
268
- ansible_vault_flag,
269
- extra_vars,
270
- tags,
271
- "#{File.join(config[:root_path], File.basename(config[:playbook]))}",
272
- ].join(" ")
273
- end
274
-
275
- def ansible_command(script)
276
- config[:ansible_sudo].nil? || config[:ansible_sudo] == true ? sudo(script) : script
277
- end
278
-
279
- protected
280
-
281
- def load_needed_dependencies!
282
- if File.exists?(ansiblefile)
283
- debug("Ansiblefile found at #{ansiblefile}, loading Librarian-Ansible")
284
- Ansible::Librarian.load!(logger)
285
- end
286
- end
287
-
288
- def install_ansible_from_source_command
289
- <<-INSTALL
290
- if [ ! -d #{config[:root_path]}/ansible ]; then
291
- if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
292
- #{update_packages_redhat_cmd}
293
- #{sudo('yum')} -y install libselinux-python python2-devel git python-setuptools python-setuptools-dev
294
- else
295
- #{update_packages_debian_cmd}
296
- #{sudo('apt-get')} -y install git python python-setuptools build-essential python-dev
297
- fi
298
-
299
- git clone git://github.com/ansible/ansible.git --recursive #{config[:root_path]}/ansible
300
- #{sudo('easy_install')} pip
301
- #{sudo('pip')} install paramiko PyYAML Jinja2 httplib2
302
- fi
303
- INSTALL
304
- end
305
-
306
- def install_omnibus_command
307
- info("Installing ansible using ansible omnibus")
308
- version = if !config[:ansible_version].nil?
309
- "-v #{config[:ansible_version]}"
310
- else
311
- ""
312
- end
313
- <<-INSTALL
314
- #{Util.shell_helpers}
315
-
316
- if [ ! -d "#{config[:ansible_omnibus_remote_path]}" ]; then
317
- echo "-----> Installing Ansible Omnibus"
318
- do_download #{config[:ansible_omnibus_url]} /tmp/ansible_install.sh
319
- #{sudo('sh')} /tmp/ansible_install.sh #{version}
320
- fi
321
- INSTALL
322
- end
323
-
324
- def install_debian_command
325
- <<-INSTALL
326
- if [ ! $(which ansible) ]; then
327
- #{update_packages_debian_cmd}
328
-
329
- ## Install apt-utils to silence debconf warning: http://serverfault.com/q/358943/77156
330
- #{sudo('apt-get')} -y install apt-utils git
331
-
332
- ## Fix debconf tty warning messages
333
- export DEBIAN_FRONTEND=noninteractive
334
-
335
- ## 13.10, 14.04 include add-apt-repository in software-properties-common
336
- #{sudo('apt-get')} -y install software-properties-common
337
-
338
- ## 10.04, 12.04 include add-apt-repository in
339
- #{sudo('apt-get')} -y install python-software-properties
340
-
341
- ## 10.04 version of add-apt-repository doesn't accept --yes
342
- ## later versions require interaction from user, so we must specify --yes
343
- ## First try with -y flag, else if it fails, try without.
344
- ## "add-apt-repository: error: no such option: -y" is returned but is ok to ignore, we just retry
345
- #{sudo('add-apt-repository')} -y #{ansible_apt_repo} || #{sudo('add-apt-repository')} #{ansible_apt_repo}
346
- #{sudo('apt-get')} update
347
- #{sudo('apt-get')} -y install ansible
348
- fi
349
- INSTALL
350
- end
351
-
352
- def install_redhat_command
353
- <<-INSTALL
354
- if [ ! $(which ansible) ]; then
355
- #{sudo('rpm')} -ivh #{ansible_yum_repo}
356
- #{update_packages_redhat_cmd}
357
- #{sudo('yum')} -y install ansible#{ansible_redhat_version} libselinux-python git
358
- fi
359
- INSTALL
360
- end
361
-
362
- def install_amazon_linux_command
363
- <<-INSTALL
364
- if [ ! $(which ansible) ]; then
365
- #{sudo('yum-config-manager')} --enable epel/x86_64
366
- #{sudo('yum')} -y install ansible#{ansible_redhat_version} git
367
- #{sudo('alternatives')} --set python /usr/bin/python2.6
368
- #{sudo('yum')} clean all
369
- #{sudo('yum')} install yum-python26 -y
370
- fi
371
- INSTALL
372
- end
373
-
374
- def setup_ansible_env_from_source
375
- "cd #{config[:root_path]}/ansible && source hacking/env-setup && cd ../"
376
- end
377
-
378
- def tmp_modules_dir
379
- File.join(sandbox_path, 'modules')
380
- end
381
-
382
- def tmp_playbook_path
383
- File.join(sandbox_path, File.basename(playbook))
384
- end
385
-
386
- def tmp_host_vars_dir
387
- File.join(sandbox_path, 'host_vars')
388
- end
389
-
390
- def tmp_roles_dir
391
- File.join(sandbox_path, 'roles')
392
- end
393
-
394
- def tmp_filter_plugins_dir
395
- File.join(sandbox_path, 'filter_plugins')
396
- end
397
-
398
- def tmp_ansible_vault_password_file_path
399
- File.join(sandbox_path, File.basename(ansible_vault_password_file))
400
- end
401
-
402
- def tmp_inventory_file_path
403
- File.join(sandbox_path, File.basename(ansible_inventory_file))
404
- end
405
-
406
- def ansiblefile
407
- config[:ansiblefile_path] || ''
408
- end
409
-
410
- def galaxy_requirements
411
- config[:requirements_path] || nil
412
- end
413
-
414
- def playbook
415
- config[:playbook]
416
- end
417
-
418
- def hosts
419
- config[:hosts]
420
- end
421
-
422
- def roles
423
- config[:roles_path]
424
- end
425
-
426
- def role_name
427
- File.basename(roles) == 'roles' ? '' : File.basename(roles)
428
- end
429
-
430
- def modules
431
- config[:modules_path]
432
- end
433
-
434
- def group_vars
435
- config[:group_vars_path].to_s
436
- end
437
-
438
- def additional_copy
439
- config[:additional_copy_path]
440
- end
441
-
442
- def host_vars
443
- config[:host_vars_path].to_s
444
- end
445
-
446
- def filter_plugins
447
- config[:filter_plugins_path].to_s
448
- end
449
-
450
- def ansible_vault_password_file
451
- config[:ansible_vault_password_file]
452
- end
453
-
454
- def ansible_inventory_file
455
- config[:ansible_inventory_file]
456
- end
457
-
458
- def ansible_debian_version
459
- config[:ansible_version] ? "=#{config[:ansible_version]}" : nil
460
- end
461
-
462
- def ansible_redhat_version
463
- config[:ansible_version] ? "-#{config[:ansible_version]}" : nil
464
- end
465
-
466
- def ansible_verbose_flag
467
- config[:ansible_verbose] ? '-' << ('v' * verbosity_level(config[:ansible_verbosity])) : nil
468
- end
469
-
470
- def ansible_check_flag
471
- config[:ansible_check] ? '--check' : nil
472
- end
473
-
474
- def ansible_diff_flag
475
- config[:ansible_diff] ? '--diff' : nil
476
- end
477
-
478
- def ansible_vault_flag
479
- debug(config[:ansible_vault_password_file])
480
- config[:ansible_vault_password_file] ? "--vault-password-file=#{File.join(config[:root_path], File.basename(config[:ansible_vault_password_file]))}" : nil
481
- end
482
-
483
- def ansible_inventory_flag
484
- config[:ansible_inventory_file] ? "--inventory-file=#{File.join(config[:root_path], File.basename(config[:ansible_inventory_file]))}" : "--inventory-file=#{File.join(config[:root_path], 'hosts')}"
485
- end
486
-
487
- def ansible_platform
488
- config[:ansible_platform].to_s.downcase
489
- end
490
-
491
- def update_packages_debian_cmd
492
- config[:update_package_repos] ? "#{sudo('apt-get')} update" : nil
493
- end
494
-
495
- def update_packages_redhat_cmd
496
- config[:update_package_repos] ? "#{sudo('yum')} makecache" : nil
497
- end
498
-
499
- def extra_vars
500
- bash_vars = config[:extra_vars]
501
- if config.key?(:attributes) && config[:attributes].key?(:extra_vars) && config[:attributes][:extra_vars].is_a?(Hash)
502
- bash_vars = config[:attributes][:extra_vars]
503
- end
504
-
505
- return nil if bash_vars.none?
506
- bash_vars = JSON.dump(bash_vars)
507
- bash_vars = "-e '#{bash_vars}'"
508
- debug(bash_vars)
509
- bash_vars
510
- end
511
-
512
- def tags
513
- bash_tags = config.key?(:attributes) && config[:attributes].key?(:tags) && config[:attributes][:tags].is_a?(Array) ? config[:attributes][:tags] : config[:tags]
514
- return nil if bash_tags.empty?
515
-
516
- bash_tags = bash_tags.join(",")
517
- bash_tags = "-t '#{bash_tags}'"
518
- debug(bash_tags)
519
- bash_tags
520
- end
521
-
522
- def ansible_apt_repo
523
- config[:ansible_apt_repo]
524
- end
525
-
526
- def ansible_apt_repo_file
527
- config[:ansible_apt_repo].split('/').last
528
- end
529
-
530
- def ansible_yum_repo
531
- config[:ansible_yum_repo]
532
- end
533
-
534
- def chef_url
535
- config[:chef_bootstrap_url]
536
- end
537
-
538
- def require_ruby_for_busser
539
- config[:require_ruby_for_busser]
540
- end
541
-
542
- def require_chef_for_busser
543
- config[:require_chef_for_busser]
544
- end
545
-
546
- def prepare_roles
547
- info('Preparing roles')
548
- debug("Using roles from #{roles}")
549
-
550
- resolve_with_librarian if File.exists?(ansiblefile)
551
-
552
- if galaxy_requirements
553
- FileUtils.cp(galaxy_requirements, File.join(sandbox_path, galaxy_requirements))
554
- end
555
-
556
- # Detect whether we are running tests on a role
557
- # If so, make sure to copy into VM so dir structure is like: /tmp/kitchen/roles/role_name
558
-
559
- FileUtils.mkdir_p(File.join(tmp_roles_dir, role_name))
560
- FileUtils.cp_r(Dir.glob("#{roles}/*"), File.join(tmp_roles_dir, role_name))
561
- end
562
-
563
- # /etc/ansible/ansible.cfg should contain
564
- # roles_path = /tmp/kitchen/roles
565
- def prepare_ansible_cfg
566
- info('Preparing ansible.cfg file')
567
- ansible_config_file = "#{File.join(sandbox_path, 'ansible.cfg')}"
568
-
569
- roles_paths = []
570
- roles_paths << File.join(config[:root_path], 'roles') unless config[:roles_path].nil?
571
- additional_files.each do |additional_file|
572
- roles_paths << File.join(config[:root_path], File.basename(additional_file))
573
- end
574
-
575
- if roles_paths.empty?
576
- info('No roles have been set. empty ansible.cfg generated')
577
- File.open(ansible_config_file, "wb") do |file|
578
- file.write("#no roles path specified\n")
579
- end
580
- else
581
- debug("Setting roles_path inside VM to #{ roles_paths.join(':') }")
582
- File.open( ansible_config_file, "wb") do |file|
583
- file.write("[defaults]\nroles_path = #{ roles_paths.join(':') }\n")
584
- end
585
- end
586
- end
587
-
588
- def prepare_inventory_file
589
- info('Preparing inventory file')
590
-
591
- if ansible_inventory_file
592
- debug("Copying inventory file from #{ansible_inventory_file} to #{tmp_inventory_file_path}")
593
- FileUtils.cp_r(ansible_inventory_file, tmp_inventory_file_path)
594
- end
595
- end
596
-
597
- # localhost ansible_connection=local
598
- # [example_servers]
599
- # localhost
600
- def prepare_hosts
601
- info('Preparing hosts file')
602
-
603
- if config[:hosts].nil?
604
- raise 'No hosts have been set. Please specify one in .kitchen.yml'
605
- else
606
- debug("Using host from #{hosts}")
607
- File.open(File.join(sandbox_path, "hosts"), "wb") do |file|
608
- file.write("localhost ansible_connection=local\n[#{hosts}]\nlocalhost\n")
609
- end
610
- end
611
- end
612
-
613
- def prepare_playbook
614
- info('Preparing playbook')
615
- debug("Copying playbook from #{playbook} to #{tmp_playbook_path}")
616
- FileUtils.cp_r(playbook, tmp_playbook_path)
617
- end
618
-
619
- def prepare_group_vars
620
- info('Preparing group_vars')
621
- tmp_group_vars_dir = File.join(sandbox_path, 'group_vars')
622
- FileUtils.mkdir_p(tmp_group_vars_dir)
623
-
624
- unless File.directory?(group_vars)
625
- info 'nothing to do for group_vars'
626
- return
627
- end
628
-
629
- debug("Using group_vars from #{group_vars}")
630
- FileUtils.cp_r(Dir.glob("#{group_vars}/*"), tmp_group_vars_dir)
631
- end
632
-
633
- def prepare_additional_copy_path
634
- info('Preparing additional_copy_path')
635
- additional_files.each do |file|
636
- destination = File.join(sandbox_path, File.basename(file))
637
- if File.directory?(file)
638
- info("Copy dir: #{file} #{destination}")
639
- FileUtils.cp_r(file, destination)
640
- else
641
- info("Copy file: #{file} #{destination}")
642
- FileUtils.cp file, destination
643
- end
644
- end
645
- end
646
-
647
- def additional_files
648
- additional_files = []
649
- if ( additional_copy )
650
- additional_files = additional_copy.kind_of?(Array) ? additional_copy : [additional_copy]
651
- end
652
- additional_files.map { |additional_dir | additional_dir.to_s }
653
- end
654
-
655
- def prepare_host_vars
656
- info('Preparing host_vars')
657
- FileUtils.mkdir_p(tmp_host_vars_dir)
658
-
659
- unless File.directory?(host_vars)
660
- info 'nothing to do for host_vars'
661
- return
662
- end
663
-
664
- debug("Using host_vars from #{host_vars}")
665
- FileUtils.cp_r(Dir.glob("#{host_vars}/*"), tmp_host_vars_dir)
666
- end
667
-
668
- def prepare_modules
669
- info('Preparing modules')
670
-
671
- FileUtils.mkdir_p(tmp_modules_dir)
672
-
673
- if modules && File.directory?(modules)
674
- debug("Using modules from #{modules}")
675
- FileUtils.cp_r(Dir.glob("#{modules}/*"), tmp_modules_dir, remove_destination: true)
676
- else
677
- info 'nothing to do for modules'
678
- end
679
- end
680
-
681
- def prepare_filter_plugins
682
- info('Preparing filter_plugins')
683
- FileUtils.mkdir_p(tmp_filter_plugins_dir)
684
-
685
- if filter_plugins && File.directory?(filter_plugins)
686
- debug("Using filter_plugins from #{filter_plugins}")
687
- FileUtils.cp_r(Dir.glob("#{filter_plugins}/*.py"), tmp_filter_plugins_dir, remove_destination: true)
688
- else
689
- info 'nothing to do for filter_plugins'
690
- end
691
- end
692
-
693
- def prepare_ansible_vault_password_file
694
- if ansible_vault_password_file
695
- info('Preparing ansible vault password')
696
- debug("Copying ansible vault password file from #{ansible_vault_password_file} to #{tmp_ansible_vault_password_file_path}")
697
-
698
- FileUtils.cp(ansible_vault_password_file, tmp_ansible_vault_password_file_path)
699
- end
700
- end
701
-
702
- def resolve_with_librarian
703
- Kitchen.mutex.synchronize do
704
- Ansible::Librarian.new(ansiblefile, tmp_roles_dir, logger).resolve
705
- end
706
- end
707
- end
708
- end
709
- 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 'kitchen/provisioner/base'
25
+ require 'kitchen/provisioner/ansible/config'
26
+ require 'kitchen/provisioner/ansible/librarian'
27
+
28
+ module Kitchen
29
+
30
+ class Busser
31
+
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
+ end
48
+
49
+ def finalize_config!(instance)
50
+ config.set_instance(instance)
51
+ super(instance)
52
+ end
53
+
54
+ def verbosity_level(level = 1)
55
+ level = level.to_sym if level.is_a? String
56
+ log_levels = { :info => 1, :warn => 2, :debug => 3, :trace => 4 }
57
+ if level.is_a? Symbol and log_levels.include? level
58
+ # puts "Log Level is: #{log_levels[level]}"
59
+ log_levels[level]
60
+ elsif level.is_a? Integer and level > 0
61
+ # puts "Log Level is: #{level}"
62
+ level
63
+ else
64
+ raise 'Invalid ansible_verbosity setting. Valid values are: 1, 2, 3, 4 OR :info, :warn, :debug, :trace'
65
+ end
66
+ end
67
+
68
+ def install_command
69
+ if config[:require_ansible_omnibus]
70
+ cmd = install_omnibus_command
71
+ elsif config[:require_ansible_source]
72
+ info("Installing ansible from source")
73
+ cmd = install_ansible_from_source_command
74
+ elsif config[:require_ansible_repo]
75
+ case ansible_platform
76
+ when "debian", "ubuntu"
77
+ info("Installing ansible on #{ansible_platform}")
78
+ cmd = install_debian_command
79
+ when "redhat", "centos", "fedora"
80
+ info("Installing ansible on #{ansible_platform}")
81
+ cmd = install_redhat_command
82
+ when "amazon"
83
+ info("Installing ansible on #{ansible_platform}")
84
+ cmd = install_amazon_linux_command
85
+ when "suse", "opensuse", "sles"
86
+ info("Installing ansible on #{ansible_platform}")
87
+ cmd = install_suse_command
88
+ else
89
+ info("Installing ansible, will try to determine platform os")
90
+ cmd = <<-INSTALL
91
+ if [ ! $(which ansible) ]; then
92
+ if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
93
+ if ! [ grep -q 'Amazon Linux' /etc/system-release ]; then
94
+ #{install_redhat_command}
95
+ else
96
+ #{install_amazon_linux_command}
97
+ fi
98
+ elif [ -f /etc/SuSE-release ] || [ -f /etc/SUSE-brand ]; then
99
+ #{install_suse_command}
100
+ else
101
+ #{install_debian_command}
102
+ fi
103
+ fi
104
+ INSTALL
105
+ end
106
+ else
107
+ return
108
+ end
109
+ cmd + install_busser_prereqs
110
+ end
111
+
112
+ def install_busser_prereqs
113
+ install = ''
114
+ install << <<-INSTALL
115
+ #{Util.shell_helpers}
116
+ # Fix for https://github.com/test-kitchen/busser/issues/12
117
+ if [ -h /usr/bin/ruby ]; then
118
+ L=$(readlink -f /usr/bin/ruby)
119
+ #{sudo('rm')} /usr/bin/ruby
120
+ #{sudo('ln')} -s $L /usr/bin/ruby
121
+ fi
122
+ INSTALL
123
+
124
+ if require_ruby_for_busser
125
+ install << <<-INSTALL
126
+ if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
127
+ if ! [ grep -q 'Amazon Linux' /etc/system-release ]; then
128
+ rhelversion=$(cat /etc/redhat-release | grep 'release 6')
129
+ # For CentOS6/RHEL6 install ruby from SCL
130
+ if [ -n "$rhelversion" ]; then
131
+ if [ ! -d "/opt/rh/ruby193" ]; then
132
+ echo "-----> Installing ruby SCL in CentOS6/RHEL6 to install busser to run tests"
133
+ #{sudo('yum')} install -y centos-release-SCL
134
+ #{sudo('yum')} install -y ruby193
135
+ #{sudo('yum')} install -y ruby193-ruby-devel
136
+ echo "-----> Enabling ruby193"
137
+ source /opt/rh/ruby193/enable
138
+ echo "/opt/rh/ruby193/root/usr/lib64" | sudo tee -a /etc/ld.so.conf
139
+ #{sudo('ldconfig')}
140
+ #{sudo('ln')} -s /opt/rh/ruby193/root/usr/bin/ruby /usr/bin/ruby
141
+ #{sudo('ln')} -s /opt/rh/ruby193/root/usr/bin/gem /usr/bin/gem
142
+ fi
143
+ else
144
+ if [ ! $(which ruby) ]; then
145
+ #{update_packages_redhat_cmd}
146
+ #{sudo('yum')} -y install ruby ruby-devel
147
+ fi
148
+ fi
149
+ else
150
+ #{update_packages_redhat_cmd}
151
+ #{sudo('yum')} -y install ruby ruby-devel gcc
152
+ fi
153
+ elif [ -f /etc/SuSE-release ] || [ -f /etc/SUSE-brand ]; then
154
+ #{update_packages_suse_cmd}
155
+ #{sudo('zypper')} --non-interactive install ruby ruby-devel ca-certificates ca-certificates-cacert ca-certificates-mozilla
156
+ #{sudo('gem')} sources --add https://rubygems.org/
157
+ else
158
+ if [ ! $(which ruby) ]; then
159
+ #{update_packages_debian_cmd}
160
+ # default package selection for Debian/Ubuntu machines
161
+ PACKAGES="ruby1.9.1 ruby1.9.1-dev"
162
+ if [ "$(lsb_release -si)" = "Debian" ]; then
163
+ debvers=$(sed 's/\\..*//' /etc/debian_version)
164
+ if [ $debvers -ge 8 ]; then
165
+ # this is jessie or better, where ruby1.9.1 is
166
+ # no longer in the repositories
167
+ PACKAGES="ruby ruby-dev ruby2.1 ruby2.1-dev"
168
+ fi
169
+ fi
170
+ #{sudo('apt-get')} -y install $PACKAGES
171
+ fi
172
+ fi
173
+ INSTALL
174
+
175
+ elsif require_chef_for_busser && chef_url then
176
+ install << <<-INSTALL
177
+ # install chef omnibus so that busser works as this is needed to run tests :(
178
+ if [ ! -d "/opt/chef" ]
179
+ then
180
+ echo "-----> Installing Chef Omnibus to install busser to run tests"
181
+ do_download #{chef_url} /tmp/install.sh
182
+ #{sudo('sh')} /tmp/install.sh
183
+ fi
184
+ INSTALL
185
+ end
186
+
187
+ install
188
+ end
189
+
190
+ def init_command
191
+ dirs = %w{modules roles group_vars host_vars}.
192
+ map { |dir| File.join(config[:root_path], dir) }.join(" ")
193
+ cmd = "#{sudo('rm')} -rf #{dirs};"
194
+ cmd = cmd+" mkdir -p #{config[:root_path]}"
195
+ debug(cmd)
196
+ cmd
197
+ end
198
+
199
+ def create_sandbox
200
+ super
201
+ debug("Creating local sandbox in #{sandbox_path}")
202
+
203
+ yield if block_given?
204
+
205
+ prepare_playbook
206
+ prepare_inventory_file
207
+ prepare_modules
208
+ prepare_roles
209
+ prepare_ansible_cfg
210
+ prepare_group_vars
211
+ prepare_additional_copy_path
212
+ prepare_host_vars
213
+ prepare_hosts
214
+ prepare_filter_plugins
215
+ prepare_lookup_plugins
216
+ prepare_ansible_vault_password_file
217
+ info('Finished Preparing files for transfer')
218
+
219
+ end
220
+
221
+ def cleanup_sandbox
222
+ return if sandbox_path.nil?
223
+ debug("Cleaning up local sandbox in #{sandbox_path}")
224
+ FileUtils.rmtree(sandbox_path)
225
+ end
226
+
227
+ def prepare_command
228
+ commands = []
229
+
230
+ # Prevent failure when ansible package installation doesn't contain /etc/ansible
231
+ commands << [
232
+ sudo("bash -c '[ -d /etc/ansible ] || mkdir /etc/ansible'")
233
+ ]
234
+
235
+ commands << [
236
+ sudo('cp'),File.join(config[:root_path], 'ansible.cfg'),'/etc/ansible',
237
+ ].join(' ')
238
+
239
+ commands << [
240
+ sudo('cp -r'), File.join(config[:root_path],'group_vars'), '/etc/ansible/.',
241
+ ].join(' ')
242
+
243
+ commands << [
244
+ sudo('cp -r'), File.join(config[:root_path],'host_vars'), '/etc/ansible/.',
245
+ ].join(' ')
246
+
247
+ if galaxy_requirements
248
+ if config[:require_ansible_source]
249
+ commands << setup_ansible_env_from_source
250
+ end
251
+ commands << [
252
+ 'ansible-galaxy', 'install', '--force',
253
+ '-p', File.join(config[:root_path], 'roles'),
254
+ '-r', File.join(config[:root_path], galaxy_requirements),
255
+ ].join(' ')
256
+ end
257
+
258
+ command = commands.join(' && ')
259
+ debug(command)
260
+ command
261
+ end
262
+
263
+ def run_command
264
+ if config[:require_ansible_source]
265
+ # this is an ugly hack to get around the fact that extra vars uses ' and "
266
+ 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 #{config[:root_path]}/ansible/bin/ansible-playbook")
267
+ else
268
+ cmd = ansible_command("ansible-playbook")
269
+ end
270
+ [
271
+ cmd,
272
+ ansible_inventory_flag,
273
+ "-c #{config[:ansible_connection]}",
274
+ "-M #{File.join(config[:root_path], 'modules')}",
275
+ ansible_verbose_flag,
276
+ ansible_check_flag,
277
+ ansible_diff_flag,
278
+ ansible_vault_flag,
279
+ extra_vars,
280
+ tags,
281
+ "#{File.join(config[:root_path], File.basename(config[:playbook]))}",
282
+ ].join(" ")
283
+ end
284
+
285
+ def ansible_command(script)
286
+ config[:ansible_sudo].nil? || config[:ansible_sudo] == true ? sudo(script) : script
287
+ end
288
+
289
+ protected
290
+
291
+ def load_needed_dependencies!
292
+ if File.exists?(ansiblefile)
293
+ debug("Ansiblefile found at #{ansiblefile}, loading Librarian-Ansible")
294
+ Ansible::Librarian.load!(logger)
295
+ end
296
+ end
297
+
298
+ def install_ansible_from_source_command
299
+ <<-INSTALL
300
+ if [ ! -d #{config[:root_path]}/ansible ]; then
301
+ if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
302
+ #{update_packages_redhat_cmd}
303
+ #{sudo('yum')} -y install libselinux-python python2-devel git python-setuptools python-setuptools-dev
304
+ else
305
+ if [ -f /etc/SUSE-brand ] || [ -f /etc/SuSE-release ]; then
306
+ #{sudo('zypper')} ar #{python_sles_repo}
307
+ #{update_packages_suse_cmd}
308
+ #{sudo('zypper')} --non-interactive install python python-devel git python-setuptools python-pip python-six libyaml-devel
309
+ else
310
+ #{update_packages_debian_cmd}
311
+ #{sudo('apt-get')} -y install git python python-setuptools build-essential python-dev
312
+ fi
313
+ fi
314
+
315
+ git clone git://github.com/ansible/ansible.git --recursive #{config[:root_path]}/ansible
316
+ #{sudo('easy_install')} pip
317
+ #{sudo('pip')} install paramiko PyYAML Jinja2 httplib2
318
+ fi
319
+ INSTALL
320
+ end
321
+
322
+ def install_omnibus_command
323
+ info("Installing ansible using ansible omnibus")
324
+ version = if !config[:ansible_version].nil?
325
+ "-v #{config[:ansible_version]}"
326
+ else
327
+ ""
328
+ end
329
+ <<-INSTALL
330
+ #{Util.shell_helpers}
331
+
332
+ if [ ! -d "#{config[:ansible_omnibus_remote_path]}" ]; then
333
+ echo "-----> Installing Ansible Omnibus"
334
+ do_download #{config[:ansible_omnibus_url]} /tmp/ansible_install.sh
335
+ #{sudo('sh')} /tmp/ansible_install.sh #{version}
336
+ fi
337
+ INSTALL
338
+ end
339
+
340
+ def install_debian_command
341
+ <<-INSTALL
342
+ if [ ! $(which ansible) ]; then
343
+ #{update_packages_debian_cmd}
344
+
345
+ ## Install apt-utils to silence debconf warning: http://serverfault.com/q/358943/77156
346
+ #{sudo('apt-get')} -y install apt-utils git
347
+
348
+ ## Fix debconf tty warning messages
349
+ export DEBIAN_FRONTEND=noninteractive
350
+
351
+ ## 13.10, 14.04 include add-apt-repository in software-properties-common
352
+ #{sudo('apt-get')} -y install software-properties-common
353
+
354
+ ## 10.04, 12.04 include add-apt-repository in
355
+ #{sudo('apt-get')} -y install python-software-properties
356
+
357
+ ## 10.04 version of add-apt-repository doesn't accept --yes
358
+ ## later versions require interaction from user, so we must specify --yes
359
+ ## First try with -y flag, else if it fails, try without.
360
+ ## "add-apt-repository: error: no such option: -y" is returned but is ok to ignore, we just retry
361
+ #{sudo('add-apt-repository')} -y #{ansible_apt_repo} || #{sudo('add-apt-repository')} #{ansible_apt_repo}
362
+ #{sudo('apt-get')} update
363
+ #{sudo('apt-get')} -y install ansible
364
+ fi
365
+ INSTALL
366
+ end
367
+
368
+ def install_suse_command
369
+ <<-INSTALL
370
+ if [ ! $(which ansible) ]; then
371
+ #{sudo('zypper')} ar #{python_sles_repo}
372
+ #{sudo('zypper')} ar #{ansible_sles_repo}
373
+ #{update_packages_suse_cmd}
374
+ #{sudo('zypper')} --non-interactive install ansible
375
+ fi
376
+ INSTALL
377
+ end
378
+
379
+ def install_redhat_command
380
+ <<-INSTALL
381
+ if [ ! $(which ansible) ]; then
382
+ #{sudo('rpm')} -ivh #{ansible_yum_repo}
383
+ #{update_packages_redhat_cmd}
384
+ #{sudo('yum')} -y install ansible#{ansible_redhat_version} libselinux-python git
385
+ fi
386
+ INSTALL
387
+ end
388
+
389
+ def install_amazon_linux_command
390
+ <<-INSTALL
391
+ if [ ! $(which ansible) ]; then
392
+ #{sudo('yum-config-manager')} --enable epel/x86_64
393
+ #{sudo('yum')} -y install ansible#{ansible_redhat_version} git
394
+ #{sudo('alternatives')} --set python /usr/bin/python2.6
395
+ #{sudo('yum')} clean all
396
+ #{sudo('yum')} install yum-python26 -y
397
+ fi
398
+ INSTALL
399
+ end
400
+
401
+ def setup_ansible_env_from_source
402
+ "cd #{config[:root_path]}/ansible && source hacking/env-setup && cd ../"
403
+ end
404
+
405
+ def tmp_modules_dir
406
+ File.join(sandbox_path, 'modules')
407
+ end
408
+
409
+ def tmp_playbook_path
410
+ File.join(sandbox_path, File.basename(playbook))
411
+ end
412
+
413
+ def tmp_host_vars_dir
414
+ File.join(sandbox_path, 'host_vars')
415
+ end
416
+
417
+ def tmp_roles_dir
418
+ File.join(sandbox_path, 'roles')
419
+ end
420
+
421
+ def tmp_filter_plugins_dir
422
+ File.join(sandbox_path, 'filter_plugins')
423
+ end
424
+
425
+ def tmp_lookup_plugins_dir
426
+ File.join(sandbox_path, 'lookup_plugins')
427
+ end
428
+
429
+ def tmp_ansible_vault_password_file_path
430
+ File.join(sandbox_path, File.basename(ansible_vault_password_file))
431
+ end
432
+
433
+ def tmp_inventory_file_path
434
+ File.join(sandbox_path, File.basename(ansible_inventory_file))
435
+ end
436
+
437
+ def ansiblefile
438
+ config[:ansiblefile_path] || ''
439
+ end
440
+
441
+ def galaxy_requirements
442
+ config[:requirements_path] || nil
443
+ end
444
+
445
+ def playbook
446
+ config[:playbook]
447
+ end
448
+
449
+ def hosts
450
+ config[:hosts]
451
+ end
452
+
453
+ def roles
454
+ config[:roles_path]
455
+ end
456
+
457
+ def role_name
458
+ File.basename(roles) == 'roles' ? '' : File.basename(roles)
459
+ end
460
+
461
+ def modules
462
+ config[:modules_path]
463
+ end
464
+
465
+ def group_vars
466
+ config[:group_vars_path].to_s
467
+ end
468
+
469
+ def additional_copy
470
+ config[:additional_copy_path]
471
+ end
472
+
473
+ def host_vars
474
+ config[:host_vars_path].to_s
475
+ end
476
+
477
+ def filter_plugins
478
+ config[:filter_plugins_path].to_s
479
+ end
480
+
481
+ def lookup_plugins
482
+ config[:lookup_plugins_path].to_s
483
+ end
484
+
485
+ def ansible_vault_password_file
486
+ config[:ansible_vault_password_file]
487
+ end
488
+
489
+ def ansible_inventory_file
490
+ config[:ansible_inventory_file]
491
+ end
492
+
493
+ def ansible_debian_version
494
+ config[:ansible_version] ? "=#{config[:ansible_version]}" : nil
495
+ end
496
+
497
+ def ansible_redhat_version
498
+ config[:ansible_version] ? "-#{config[:ansible_version]}" : nil
499
+ end
500
+
501
+ def ansible_verbose_flag
502
+ config[:ansible_verbose] ? '-' << ('v' * verbosity_level(config[:ansible_verbosity])) : nil
503
+ end
504
+
505
+ def ansible_check_flag
506
+ config[:ansible_check] ? '--check' : nil
507
+ end
508
+
509
+ def ansible_diff_flag
510
+ config[:ansible_diff] ? '--diff' : nil
511
+ end
512
+
513
+ def ansible_vault_flag
514
+ debug(config[:ansible_vault_password_file])
515
+ config[:ansible_vault_password_file] ? "--vault-password-file=#{File.join(config[:root_path], File.basename(config[:ansible_vault_password_file]))}" : nil
516
+ end
517
+
518
+ def ansible_inventory_flag
519
+ config[:ansible_inventory_file] ? "--inventory-file=#{File.join(config[:root_path], File.basename(config[:ansible_inventory_file]))}" : "--inventory-file=#{File.join(config[:root_path], 'hosts')}"
520
+ end
521
+
522
+ def ansible_platform
523
+ config[:ansible_platform].to_s.downcase
524
+ end
525
+
526
+ def update_packages_debian_cmd
527
+ config[:update_package_repos] ? "#{sudo('apt-get')} update" : nil
528
+ end
529
+
530
+ def update_packages_suse_cmd
531
+ config[:update_package_repos] ? "#{sudo('zypper')} --gpg-auto-import-keys ref" : nil
532
+ end
533
+
534
+ def update_packages_redhat_cmd
535
+ config[:update_package_repos] ? "#{sudo('yum')} makecache" : nil
536
+ end
537
+
538
+ def extra_vars
539
+ bash_vars = config[:extra_vars]
540
+ if config.key?(:attributes) && config[:attributes].key?(:extra_vars) && config[:attributes][:extra_vars].is_a?(Hash)
541
+ bash_vars = config[:attributes][:extra_vars]
542
+ end
543
+
544
+ return nil if bash_vars.none?
545
+ bash_vars = JSON.dump(bash_vars)
546
+ bash_vars = "-e '#{bash_vars}'"
547
+ debug(bash_vars)
548
+ bash_vars
549
+ end
550
+
551
+ def tags
552
+ bash_tags = config.key?(:attributes) && config[:attributes].key?(:tags) && config[:attributes][:tags].is_a?(Array) ? config[:attributes][:tags] : config[:tags]
553
+ return nil if bash_tags.empty?
554
+
555
+ bash_tags = bash_tags.join(",")
556
+ bash_tags = "-t '#{bash_tags}'"
557
+ debug(bash_tags)
558
+ bash_tags
559
+ end
560
+
561
+ def ansible_apt_repo
562
+ config[:ansible_apt_repo]
563
+ end
564
+
565
+ def ansible_apt_repo_file
566
+ config[:ansible_apt_repo].split('/').last
567
+ end
568
+
569
+ def ansible_yum_repo
570
+ config[:ansible_yum_repo]
571
+ end
572
+
573
+ def ansible_sles_repo
574
+ config[:ansible_sles_repo]
575
+ end
576
+
577
+ def python_sles_repo
578
+ config[:python_sles_repo]
579
+ end
580
+
581
+ def chef_url
582
+ config[:chef_bootstrap_url]
583
+ end
584
+
585
+ def require_ruby_for_busser
586
+ config[:require_ruby_for_busser]
587
+ end
588
+
589
+ def require_chef_for_busser
590
+ config[:require_chef_for_busser]
591
+ end
592
+
593
+ def prepare_roles
594
+ info('Preparing roles')
595
+ debug("Using roles from #{roles}")
596
+
597
+ resolve_with_librarian if File.exists?(ansiblefile)
598
+
599
+ if galaxy_requirements
600
+ FileUtils.cp(galaxy_requirements, File.join(sandbox_path, galaxy_requirements))
601
+ end
602
+
603
+ # Detect whether we are running tests on a role
604
+ # If so, make sure to copy into VM so dir structure is like: /tmp/kitchen/roles/role_name
605
+
606
+ FileUtils.mkdir_p(File.join(tmp_roles_dir, role_name))
607
+ FileUtils.cp_r(Dir.glob("#{roles}/*"), File.join(tmp_roles_dir, role_name))
608
+ end
609
+
610
+ # /etc/ansible/ansible.cfg should contain
611
+ # roles_path = /tmp/kitchen/roles
612
+ def prepare_ansible_cfg
613
+ info('Preparing ansible.cfg file')
614
+ ansible_config_file = "#{File.join(sandbox_path, 'ansible.cfg')}"
615
+
616
+ roles_paths = []
617
+ roles_paths << File.join(config[:root_path], 'roles') unless config[:roles_path].nil?
618
+ additional_files.each do |additional_file|
619
+ roles_paths << File.join(config[:root_path], File.basename(additional_file))
620
+ end
621
+
622
+ if roles_paths.empty?
623
+ info('No roles have been set. empty ansible.cfg generated')
624
+ File.open(ansible_config_file, "wb") do |file|
625
+ file.write("#no roles path specified\n")
626
+ end
627
+ else
628
+ debug("Setting roles_path inside VM to #{ roles_paths.join(':') }")
629
+ File.open( ansible_config_file, "wb") do |file|
630
+ file.write("[defaults]\nroles_path = #{ roles_paths.join(':') }\n")
631
+ end
632
+ end
633
+ end
634
+
635
+ def prepare_inventory_file
636
+ info('Preparing inventory file')
637
+
638
+ if ansible_inventory_file
639
+ debug("Copying inventory file from #{ansible_inventory_file} to #{tmp_inventory_file_path}")
640
+ FileUtils.cp_r(ansible_inventory_file, tmp_inventory_file_path)
641
+ end
642
+ end
643
+
644
+ # localhost ansible_connection=local
645
+ # [example_servers]
646
+ # localhost
647
+ def prepare_hosts
648
+ info('Preparing hosts file')
649
+
650
+ if config[:hosts].nil?
651
+ raise 'No hosts have been set. Please specify one in .kitchen.yml'
652
+ else
653
+ debug("Using host from #{hosts}")
654
+ File.open(File.join(sandbox_path, "hosts"), "wb") do |file|
655
+ file.write("localhost ansible_connection=local\n[#{hosts}]\nlocalhost\n")
656
+ end
657
+ end
658
+ end
659
+
660
+ def prepare_playbook
661
+ info('Preparing playbook')
662
+ debug("Copying playbook from #{playbook} to #{tmp_playbook_path}")
663
+ FileUtils.cp_r(playbook, tmp_playbook_path)
664
+ end
665
+
666
+ def prepare_group_vars
667
+ info('Preparing group_vars')
668
+ tmp_group_vars_dir = File.join(sandbox_path, 'group_vars')
669
+ FileUtils.mkdir_p(tmp_group_vars_dir)
670
+
671
+ unless File.directory?(group_vars)
672
+ info('nothing to do for group_vars')
673
+ return
674
+ end
675
+
676
+ debug("Using group_vars from #{group_vars}")
677
+ FileUtils.cp_r(Dir.glob("#{group_vars}/*"), tmp_group_vars_dir)
678
+ end
679
+
680
+ def prepare_additional_copy_path
681
+ info('Preparing additional_copy_path')
682
+ additional_files.each do |file|
683
+ destination = File.join(sandbox_path, File.basename(file))
684
+ if File.directory?(file)
685
+ info("Copy dir: #{file} #{destination}")
686
+ FileUtils.cp_r(file, destination)
687
+ else
688
+ info("Copy file: #{file} #{destination}")
689
+ FileUtils.cp file, destination
690
+ end
691
+ end
692
+ end
693
+
694
+ def additional_files
695
+ additional_files = []
696
+ if ( additional_copy )
697
+ additional_files = additional_copy.kind_of?(Array) ? additional_copy : [additional_copy]
698
+ end
699
+ additional_files.map { |additional_dir | additional_dir.to_s }
700
+ end
701
+
702
+ def prepare_host_vars
703
+ info('Preparing host_vars')
704
+ FileUtils.mkdir_p(tmp_host_vars_dir)
705
+
706
+ unless File.directory?(host_vars)
707
+ info 'nothing to do for host_vars'
708
+ return
709
+ end
710
+
711
+ debug("Using host_vars from #{host_vars}")
712
+ FileUtils.cp_r(Dir.glob("#{host_vars}/*"), tmp_host_vars_dir)
713
+ end
714
+
715
+ def prepare_modules
716
+ info('Preparing modules')
717
+
718
+ FileUtils.mkdir_p(tmp_modules_dir)
719
+
720
+ if modules && File.directory?(modules)
721
+ debug("Using modules from #{modules}")
722
+ FileUtils.cp_r(Dir.glob("#{modules}/*"), tmp_modules_dir, remove_destination: true)
723
+ else
724
+ info 'nothing to do for modules'
725
+ end
726
+ end
727
+
728
+ def prepare_filter_plugins
729
+ info('Preparing filter_plugins')
730
+ FileUtils.mkdir_p(tmp_filter_plugins_dir)
731
+
732
+ if filter_plugins && File.directory?(filter_plugins)
733
+ debug("Using filter_plugins from #{filter_plugins}")
734
+ FileUtils.cp_r(Dir.glob("#{filter_plugins}/*.py"), tmp_filter_plugins_dir, remove_destination: true)
735
+ else
736
+ info 'nothing to do for filter_plugins'
737
+ end
738
+ end
739
+
740
+ def prepare_lookup_plugins
741
+ info('Preparing lookup_plugins')
742
+ FileUtils.mkdir_p(tmp_lookup_plugins_dir)
743
+
744
+ if lookup_plugins && File.directory?(lookup_plugins)
745
+ debug("Using lookup_plugins from #{lookup_plugins}")
746
+ FileUtils.cp_r(Dir.glob("#{lookup_plugins}/*.py"), tmp_lookup_plugins_dir, remove_destination: true)
747
+ else
748
+ info 'nothing to do for lookup_plugins'
749
+ end
750
+ end
751
+
752
+ def prepare_ansible_vault_password_file
753
+ if ansible_vault_password_file
754
+ info('Preparing ansible vault password')
755
+ debug("Copying ansible vault password file from #{ansible_vault_password_file} to #{tmp_ansible_vault_password_file_path}")
756
+
757
+ FileUtils.cp(ansible_vault_password_file, tmp_ansible_vault_password_file_path)
758
+ end
759
+ end
760
+
761
+ def resolve_with_librarian
762
+ Kitchen.mutex.synchronize do
763
+ Ansible::Librarian.new(ansiblefile, tmp_roles_dir, logger).resolve
764
+ end
765
+ end
766
+ end
767
+ end
768
+ end