kitchen-ansible 0.0.23 → 0.0.24

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,768 +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
- 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
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