kitchen-ansible 0.0.22 → 0.0.23

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