kitchen-ansible 0.0.25 → 0.0.26

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,808 +1,821 @@
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_env('rm')} /usr/bin/ruby
120
- #{sudo_env('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_env('yum')} install -y centos-release-SCL
134
- #{sudo_env('yum')} install -y ruby193
135
- #{sudo_env('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_env('ldconfig')}
140
- #{sudo_env('ln')} -s /opt/rh/ruby193/root/usr/bin/ruby /usr/bin/ruby
141
- #{sudo_env('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_env('yum')} -y install ruby ruby-devel
147
- fi
148
- fi
149
- else
150
- #{update_packages_redhat_cmd}
151
- #{sudo_env('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_env('zypper')} --non-interactive install ruby ruby-devel ca-certificates ca-certificates-cacert ca-certificates-mozilla
156
- #{sudo_env('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_env('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
- #{export_http_proxy}
182
- do_download #{chef_url} /tmp/install.sh
183
- #{sudo_env('sh')} /tmp/install.sh
184
- fi
185
- INSTALL
186
- end
187
-
188
- install
189
- end
190
-
191
- def init_command
192
- dirs = %w{modules roles group_vars host_vars}.
193
- map { |dir| File.join(config[:root_path], dir) }.join(" ")
194
- cmd = "#{sudo_env('rm')} -rf #{dirs};"
195
- cmd = cmd+" mkdir -p #{config[:root_path]}"
196
- debug(cmd)
197
- cmd
198
- end
199
-
200
- def create_sandbox
201
- super
202
- debug("Creating local sandbox in #{sandbox_path}")
203
-
204
- yield if block_given?
205
-
206
- prepare_playbook
207
- prepare_inventory_file
208
- prepare_modules
209
- prepare_roles
210
- prepare_ansible_cfg
211
- prepare_group_vars
212
- prepare_additional_copy_path
213
- prepare_host_vars
214
- prepare_hosts
215
- prepare_filter_plugins
216
- prepare_lookup_plugins
217
- prepare_ansible_vault_password_file
218
- info('Finished Preparing files for transfer')
219
-
220
- end
221
-
222
- def cleanup_sandbox
223
- return if sandbox_path.nil?
224
- debug("Cleaning up local sandbox in #{sandbox_path}")
225
- FileUtils.rmtree(sandbox_path)
226
- end
227
-
228
- def prepare_command
229
- commands = []
230
-
231
- # Prevent failure when ansible package installation doesn't contain /etc/ansible
232
- commands << [
233
- sudo_env("bash -c '[ -d /etc/ansible ] || mkdir /etc/ansible'")
234
- ]
235
-
236
- commands << [
237
- sudo_env('cp'),File.join(config[:root_path], 'ansible.cfg'),'/etc/ansible',
238
- ].join(' ')
239
-
240
- commands << [
241
- sudo_env('cp -r'), File.join(config[:root_path],'group_vars'), '/etc/ansible/.',
242
- ].join(' ')
243
-
244
- commands << [
245
- sudo_env('cp -r'), File.join(config[:root_path],'host_vars'), '/etc/ansible/.',
246
- ].join(' ')
247
-
248
- if galaxy_requirements
249
- if config[:require_ansible_source]
250
- commands << setup_ansible_env_from_source
251
- end
252
- commands << [
253
- 'ansible-galaxy', 'install', '--force',
254
- '-p', File.join(config[:root_path], 'roles'),
255
- '-r', File.join(config[:root_path], galaxy_requirements),
256
- ].join(' ')
257
- end
258
-
259
- command = commands.join(' && ')
260
- debug(command)
261
- command
262
- end
263
-
264
- def run_command
265
- if config[:require_ansible_source]
266
- # this is an ugly hack to get around the fact that extra vars uses ' and "
267
- 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")
268
- else
269
- cmd = ansible_command("ansible-playbook")
270
- end
271
- if https_proxy
272
- cmd = "HTTPS_PROXY=#{https_proxy} #{cmd}"
273
- end
274
- if http_proxy
275
- cmd = "HTTP_PROXY=#{http_proxy} #{cmd}"
276
- end
277
- [
278
- cmd,
279
- ansible_inventory_flag,
280
- "-c #{config[:ansible_connection]}",
281
- "-M #{File.join(config[:root_path], 'modules')}",
282
- ansible_verbose_flag,
283
- ansible_check_flag,
284
- ansible_diff_flag,
285
- ansible_vault_flag,
286
- extra_vars,
287
- tags,
288
- "#{File.join(config[:root_path], File.basename(config[:playbook]))}",
289
- ].join(" ")
290
- end
291
-
292
- def ansible_command(script)
293
- config[:ansible_sudo].nil? || config[:ansible_sudo] == true ? sudo_env(script) : script
294
- end
295
-
296
- protected
297
-
298
- def load_needed_dependencies!
299
- if File.exists?(ansiblefile)
300
- debug("Ansiblefile found at #{ansiblefile}, loading Librarian-Ansible")
301
- Ansible::Librarian.load!(logger)
302
- end
303
- end
304
-
305
- def install_ansible_from_source_command
306
- <<-INSTALL
307
- if [ ! -d #{config[:root_path]}/ansible ]; then
308
- if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
309
- #{install_epel_repo}
310
- #{update_packages_redhat_cmd}
311
- #{sudo_env('yum')} -y install libselinux-python python2-devel git python-setuptools python-setuptools-dev
312
- else
313
- if [ -f /etc/SUSE-brand ] || [ -f /etc/SuSE-release ]; then
314
- #{sudo_env('zypper')} ar #{python_sles_repo}
315
- #{update_packages_suse_cmd}
316
- #{sudo_env('zypper')} --non-interactive install python python-devel git python-setuptools python-pip python-six libyaml-devel
317
- else
318
- #{update_packages_debian_cmd}
319
- #{sudo_env('apt-get')} -y install git python python-setuptools build-essential python-dev
320
- fi
321
- fi
322
-
323
- #{export_http_proxy}
324
- git clone git://github.com/ansible/ansible.git --recursive #{config[:root_path]}/ansible
325
- #{sudo_env('easy_install')} pip
326
- #{sudo_env('pip')} install paramiko PyYAML Jinja2 httplib2
327
- fi
328
- INSTALL
329
- end
330
-
331
- def install_omnibus_command
332
- info("Installing ansible using ansible omnibus")
333
- version = if !config[:ansible_version].nil?
334
- "-v #{config[:ansible_version]}"
335
- else
336
- ""
337
- end
338
-
339
- <<-INSTALL
340
- #{Util.shell_helpers}
341
-
342
- if [ ! -d "#{config[:ansible_omnibus_remote_path]}" ]; then
343
- echo "-----> Installing Ansible Omnibus"
344
- #{export_http_proxy}
345
- #{install_epel_repo}
346
- do_download #{config[:ansible_omnibus_url]} /tmp/ansible_install.sh
347
- #{sudo_env('sh')} /tmp/ansible_install.sh #{version}
348
- fi
349
- INSTALL
350
- end
351
-
352
- def install_debian_command
353
- <<-INSTALL
354
- if [ ! $(which ansible) ]; then
355
- #{update_packages_debian_cmd}
356
-
357
- ## Install apt-utils to silence debconf warning: http://serverfault.com/q/358943/77156
358
- #{sudo_env('apt-get')} -y install apt-utils git
359
-
360
- ## Fix debconf tty warning messages
361
- export DEBIAN_FRONTEND=noninteractive
362
-
363
- ## 13.10, 14.04 include add-apt-repository in software-properties-common
364
- #{sudo_env('apt-get')} -y install software-properties-common
365
-
366
- ## 10.04, 12.04 include add-apt-repository in
367
- #{sudo_env('apt-get')} -y install python-software-properties
368
-
369
- ## 10.04 version of add-apt-repository doesn't accept --yes
370
- ## later versions require interaction from user, so we must specify --yes
371
- ## First try with -y flag, else if it fails, try without.
372
- ## "add-apt-repository: error: no such option: -y" is returned but is ok to ignore, we just retry
373
- #{sudo_env('add-apt-repository')} -y #{ansible_apt_repo} || #{sudo_env('add-apt-repository')} #{ansible_apt_repo}
374
- #{sudo_env('apt-get')} update
375
- #{sudo_env('apt-get')} -y install ansible
376
- fi
377
- INSTALL
378
- end
379
-
380
- def install_suse_command
381
- <<-INSTALL
382
- if [ ! $(which ansible) ]; then
383
- #{sudo_env('zypper')} ar #{python_sles_repo}
384
- #{sudo_env('zypper')} ar #{ansible_sles_repo}
385
- #{update_packages_suse_cmd}
386
- #{sudo_env('zypper')} --non-interactive install ansible
387
- fi
388
- INSTALL
389
- end
390
-
391
- def install_redhat_command
392
- <<-INSTALL
393
- if [ ! $(which ansible) ]; then
394
- #{install_epel_repo}
395
- #{sudo_env('rpm')} -ivh #{ansible_yum_repo}
396
- #{update_packages_redhat_cmd}
397
- #{sudo_env('yum')} -y install ansible#{ansible_redhat_version} libselinux-python git
398
- fi
399
- INSTALL
400
- end
401
-
402
- def install_amazon_linux_command
403
- <<-INSTALL
404
- if [ ! $(which ansible) ]; then
405
- #{install_epel_repo}
406
- #{sudo_env('yum-config-manager')} --enable epel/x86_64
407
- #{sudo_env('yum')} -y install ansible#{ansible_redhat_version} git
408
- #{sudo_env('alternatives')} --set python /usr/bin/python2.6
409
- #{sudo_env('yum')} clean all
410
- #{sudo_env('yum')} install yum-python26 -y
411
- fi
412
- INSTALL
413
- end
414
-
415
- def setup_ansible_env_from_source
416
- "cd #{config[:root_path]}/ansible && source hacking/env-setup && cd ../"
417
- end
418
-
419
- def tmp_modules_dir
420
- File.join(sandbox_path, 'modules')
421
- end
422
-
423
- def tmp_playbook_path
424
- File.join(sandbox_path, File.basename(playbook))
425
- end
426
-
427
- def tmp_host_vars_dir
428
- File.join(sandbox_path, 'host_vars')
429
- end
430
-
431
- def tmp_roles_dir
432
- File.join(sandbox_path, 'roles')
433
- end
434
-
435
- def tmp_filter_plugins_dir
436
- File.join(sandbox_path, 'filter_plugins')
437
- end
438
-
439
- def tmp_lookup_plugins_dir
440
- File.join(sandbox_path, 'lookup_plugins')
441
- end
442
-
443
- def tmp_ansible_vault_password_file_path
444
- File.join(sandbox_path, File.basename(ansible_vault_password_file))
445
- end
446
-
447
- def tmp_inventory_file_path
448
- File.join(sandbox_path, File.basename(ansible_inventory_file))
449
- end
450
-
451
- def ansiblefile
452
- config[:ansiblefile_path] || ''
453
- end
454
-
455
- def galaxy_requirements
456
- config[:requirements_path] || nil
457
- end
458
-
459
- def playbook
460
- config[:playbook]
461
- end
462
-
463
- def hosts
464
- config[:hosts]
465
- end
466
-
467
- def roles
468
- config[:roles_path]
469
- end
470
-
471
- def role_name
472
- File.basename(roles) == 'roles' ? '' : File.basename(roles)
473
- end
474
-
475
- def modules
476
- config[:modules_path]
477
- end
478
-
479
- def group_vars
480
- config[:group_vars_path].to_s
481
- end
482
-
483
- def additional_copy
484
- config[:additional_copy_path]
485
- end
486
-
487
- def host_vars
488
- config[:host_vars_path].to_s
489
- end
490
-
491
- def filter_plugins
492
- config[:filter_plugins_path].to_s
493
- end
494
-
495
- def lookup_plugins
496
- config[:lookup_plugins_path].to_s
497
- end
498
-
499
- def ansible_vault_password_file
500
- config[:ansible_vault_password_file]
501
- end
502
-
503
- def ansible_inventory_file
504
- config[:ansible_inventory_file]
505
- end
506
-
507
- def ansible_debian_version
508
- config[:ansible_version] ? "=#{config[:ansible_version]}" : nil
509
- end
510
-
511
- def ansible_redhat_version
512
- config[:ansible_version] ? "-#{config[:ansible_version]}" : nil
513
- end
514
-
515
- def ansible_verbose_flag
516
- config[:ansible_verbose] ? '-' << ('v' * verbosity_level(config[:ansible_verbosity])) : nil
517
- end
518
-
519
- def ansible_check_flag
520
- config[:ansible_check] ? '--check' : nil
521
- end
522
-
523
- def ansible_diff_flag
524
- config[:ansible_diff] ? '--diff' : nil
525
- end
526
-
527
- def ansible_vault_flag
528
- debug(config[:ansible_vault_password_file])
529
- config[:ansible_vault_password_file] ? "--vault-password-file=#{File.join(config[:root_path], File.basename(config[:ansible_vault_password_file]))}" : nil
530
- end
531
-
532
- def ansible_inventory_flag
533
- 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')}"
534
- end
535
-
536
- def ansible_platform
537
- config[:ansible_platform].to_s.downcase
538
- end
539
-
540
- def update_packages_debian_cmd
541
- config[:update_package_repos] ? "#{sudo_env('apt-get')} update" : nil
542
- end
543
-
544
- def update_packages_suse_cmd
545
- config[:update_package_repos] ? "#{sudo_env('zypper')} --gpg-auto-import-keys ref" : nil
546
- end
547
-
548
- def update_packages_redhat_cmd
549
- config[:update_package_repos] ? "#{sudo_env('yum')} makecache" : nil
550
- end
551
-
552
- def extra_vars
553
- bash_vars = config[:extra_vars]
554
- if config.key?(:attributes) && config[:attributes].key?(:extra_vars) && config[:attributes][:extra_vars].is_a?(Hash)
555
- bash_vars = config[:attributes][:extra_vars]
556
- end
557
-
558
- return nil if bash_vars.none?
559
- bash_vars = JSON.dump(bash_vars)
560
- bash_vars = "-e '#{bash_vars}'"
561
- debug(bash_vars)
562
- bash_vars
563
- end
564
-
565
- def tags
566
- bash_tags = config.key?(:attributes) && config[:attributes].key?(:tags) && config[:attributes][:tags].is_a?(Array) ? config[:attributes][:tags] : config[:tags]
567
- return nil if bash_tags.empty?
568
-
569
- bash_tags = bash_tags.join(",")
570
- bash_tags = "-t '#{bash_tags}'"
571
- debug(bash_tags)
572
- bash_tags
573
- end
574
-
575
- def ansible_apt_repo
576
- config[:ansible_apt_repo]
577
- end
578
-
579
- def ansible_apt_repo_file
580
- config[:ansible_apt_repo].split('/').last
581
- end
582
-
583
- def ansible_yum_repo
584
- config[:ansible_yum_repo]
585
- end
586
-
587
- def ansible_sles_repo
588
- config[:ansible_sles_repo]
589
- end
590
-
591
- def python_sles_repo
592
- config[:python_sles_repo]
593
- end
594
-
595
- def chef_url
596
- config[:chef_bootstrap_url]
597
- end
598
-
599
- def require_ruby_for_busser
600
- config[:require_ruby_for_busser]
601
- end
602
-
603
- def require_chef_for_busser
604
- config[:require_chef_for_busser]
605
- end
606
-
607
- def install_epel_repo
608
- config[:enable_yum_epel] ? sudo_env('yum install epel-release -y') : nil
609
- end
610
-
611
- def http_proxy
612
- config[:http_proxy]
613
- end
614
-
615
- def https_proxy
616
- config[:https_proxy]
617
- end
618
-
619
- def sudo_env(pm)
620
- s = https_proxy ? "https_proxy=#{https_proxy}" : nil
621
- p = http_proxy ? "http_proxy=#{http_proxy}" : nil
622
- p || s ? "#{sudo('env')} #{p} #{s} #{pm}" : "#{sudo(pm)}"
623
- end
624
-
625
- def export_http_proxy
626
- cmd = ""
627
- cmd = " HTTP_PROXY=#{http_proxy}" if http_proxy
628
- cmd = "#{cmd} HTTPS_PROXY=#{https_proxy}" if https_proxy
629
- cmd = "export #{cmd}" if cmd != ""
630
- cmd
631
- end
632
-
633
- def prepare_roles
634
- info('Preparing roles')
635
- debug("Using roles from #{roles}")
636
-
637
- resolve_with_librarian if File.exists?(ansiblefile)
638
-
639
- if galaxy_requirements
640
- FileUtils.cp(galaxy_requirements, File.join(sandbox_path, galaxy_requirements))
641
- end
642
-
643
- # Detect whether we are running tests on a role
644
- # If so, make sure to copy into VM so dir structure is like: /tmp/kitchen/roles/role_name
645
-
646
- FileUtils.mkdir_p(File.join(tmp_roles_dir, role_name))
647
- FileUtils.cp_r(Dir.glob("#{roles}/*"), File.join(tmp_roles_dir, role_name))
648
- end
649
-
650
- # /etc/ansible/ansible.cfg should contain
651
- # roles_path = /tmp/kitchen/roles
652
- def prepare_ansible_cfg
653
- info('Preparing ansible.cfg file')
654
- ansible_config_file = "#{File.join(sandbox_path, 'ansible.cfg')}"
655
-
656
- roles_paths = []
657
- roles_paths << File.join(config[:root_path], 'roles') unless config[:roles_path].nil?
658
- additional_files.each do |additional_file|
659
- roles_paths << File.join(config[:root_path], File.basename(additional_file))
660
- end
661
-
662
- if roles_paths.empty?
663
- info('No roles have been set. empty ansible.cfg generated')
664
- File.open(ansible_config_file, "wb") do |file|
665
- file.write("#no roles path specified\n")
666
- end
667
- else
668
- debug("Setting roles_path inside VM to #{ roles_paths.join(':') }")
669
- File.open( ansible_config_file, "wb") do |file|
670
- file.write("[defaults]\nroles_path = #{ roles_paths.join(':') }\n")
671
- end
672
- end
673
- end
674
-
675
- def prepare_inventory_file
676
- info('Preparing inventory file')
677
-
678
- if ansible_inventory_file
679
- debug("Copying inventory file from #{ansible_inventory_file} to #{tmp_inventory_file_path}")
680
- FileUtils.cp_r(ansible_inventory_file, tmp_inventory_file_path)
681
- end
682
- end
683
-
684
- # localhost ansible_connection=local
685
- # [example_servers]
686
- # localhost
687
- def prepare_hosts
688
- info('Preparing hosts file')
689
-
690
- if config[:hosts].nil?
691
- raise 'No hosts have been set. Please specify one in .kitchen.yml'
692
- else
693
- debug("Using host from #{hosts}")
694
- File.open(File.join(sandbox_path, "hosts"), "wb") do |file|
695
- file.write("localhost ansible_connection=local\n[#{hosts}]\nlocalhost\n")
696
- end
697
- end
698
- end
699
-
700
- def prepare_playbook
701
- info('Preparing playbook')
702
- debug("Copying playbook from #{playbook} to #{tmp_playbook_path}")
703
- FileUtils.cp_r(playbook, tmp_playbook_path)
704
- end
705
-
706
- def prepare_group_vars
707
- info('Preparing group_vars')
708
- tmp_group_vars_dir = File.join(sandbox_path, 'group_vars')
709
- FileUtils.mkdir_p(tmp_group_vars_dir)
710
-
711
- unless File.directory?(group_vars)
712
- info('nothing to do for group_vars')
713
- return
714
- end
715
-
716
- debug("Using group_vars from #{group_vars}")
717
- FileUtils.cp_r(Dir.glob("#{group_vars}/*"), tmp_group_vars_dir)
718
- end
719
-
720
- def prepare_additional_copy_path
721
- info('Preparing additional_copy_path')
722
- additional_files.each do |file|
723
- destination = File.join(sandbox_path, File.basename(file))
724
- if File.directory?(file)
725
- info("Copy dir: #{file} #{destination}")
726
- FileUtils.cp_r(file, destination)
727
- else
728
- info("Copy file: #{file} #{destination}")
729
- FileUtils.cp file, destination
730
- end
731
- end
732
- end
733
-
734
- def additional_files
735
- additional_files = []
736
- if ( additional_copy )
737
- additional_files = additional_copy.kind_of?(Array) ? additional_copy : [additional_copy]
738
- end
739
- additional_files.map { |additional_dir | additional_dir.to_s }
740
- end
741
-
742
- def prepare_host_vars
743
- info('Preparing host_vars')
744
- FileUtils.mkdir_p(tmp_host_vars_dir)
745
-
746
- unless File.directory?(host_vars)
747
- info 'nothing to do for host_vars'
748
- return
749
- end
750
-
751
- debug("Using host_vars from #{host_vars}")
752
- FileUtils.cp_r(Dir.glob("#{host_vars}/*"), tmp_host_vars_dir)
753
- end
754
-
755
- def prepare_modules
756
- info('Preparing modules')
757
-
758
- FileUtils.mkdir_p(tmp_modules_dir)
759
-
760
- if modules && File.directory?(modules)
761
- debug("Using modules from #{modules}")
762
- FileUtils.cp_r(Dir.glob("#{modules}/*"), tmp_modules_dir, remove_destination: true)
763
- else
764
- info 'nothing to do for modules'
765
- end
766
- end
767
-
768
- def prepare_filter_plugins
769
- info('Preparing filter_plugins')
770
- FileUtils.mkdir_p(tmp_filter_plugins_dir)
771
-
772
- if filter_plugins && File.directory?(filter_plugins)
773
- debug("Using filter_plugins from #{filter_plugins}")
774
- FileUtils.cp_r(Dir.glob("#{filter_plugins}/*.py"), tmp_filter_plugins_dir, remove_destination: true)
775
- else
776
- info 'nothing to do for filter_plugins'
777
- end
778
- end
779
-
780
- def prepare_lookup_plugins
781
- info('Preparing lookup_plugins')
782
- FileUtils.mkdir_p(tmp_lookup_plugins_dir)
783
-
784
- if lookup_plugins && File.directory?(lookup_plugins)
785
- debug("Using lookup_plugins from #{lookup_plugins}")
786
- FileUtils.cp_r(Dir.glob("#{lookup_plugins}/*.py"), tmp_lookup_plugins_dir, remove_destination: true)
787
- else
788
- info 'nothing to do for lookup_plugins'
789
- end
790
- end
791
-
792
- def prepare_ansible_vault_password_file
793
- if ansible_vault_password_file
794
- info('Preparing ansible vault password')
795
- debug("Copying ansible vault password file from #{ansible_vault_password_file} to #{tmp_ansible_vault_password_file_path}")
796
-
797
- FileUtils.cp(ansible_vault_password_file, tmp_ansible_vault_password_file_path)
798
- end
799
- end
800
-
801
- def resolve_with_librarian
802
- Kitchen.mutex.synchronize do
803
- Ansible::Librarian.new(ansiblefile, tmp_roles_dir, logger).resolve
804
- end
805
- end
806
- end
807
- end
808
- 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_env('rm')} /usr/bin/ruby
120
+ #{sudo_env('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_env('yum')} install -y centos-release-SCL
134
+ #{sudo_env('yum')} install -y ruby193
135
+ #{sudo_env('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_env('ldconfig')}
140
+ #{sudo_env('ln')} -s /opt/rh/ruby193/root/usr/bin/ruby /usr/bin/ruby
141
+ #{sudo_env('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_env('yum')} -y install ruby ruby-devel
147
+ fi
148
+ fi
149
+ else
150
+ #{update_packages_redhat_cmd}
151
+ #{sudo_env('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_env('zypper')} --non-interactive install ruby ruby-devel ca-certificates ca-certificates-cacert ca-certificates-mozilla
156
+ #{sudo_env('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_env('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
+ #{export_http_proxy}
182
+ do_download #{chef_url} /tmp/install.sh
183
+ #{sudo_env('sh')} /tmp/install.sh
184
+ fi
185
+ INSTALL
186
+ end
187
+
188
+ install
189
+ end
190
+
191
+ def init_command
192
+ dirs = %w{modules roles group_vars host_vars}.
193
+ map { |dir| File.join(config[:root_path], dir) }.join(" ")
194
+ cmd = "#{sudo_env('rm')} -rf #{dirs};"
195
+ cmd = cmd+" mkdir -p #{config[:root_path]}"
196
+ debug(cmd)
197
+ cmd
198
+ end
199
+
200
+ def create_sandbox
201
+ super
202
+ debug("Creating local sandbox in #{sandbox_path}")
203
+
204
+ yield if block_given?
205
+
206
+ prepare_playbook
207
+ prepare_inventory_file
208
+ prepare_modules
209
+ prepare_roles
210
+ prepare_ansible_cfg
211
+ prepare_group_vars
212
+ prepare_additional_copy_path
213
+ prepare_host_vars
214
+ prepare_hosts
215
+ prepare_filter_plugins
216
+ prepare_lookup_plugins
217
+ prepare_ansible_vault_password_file
218
+ info('Finished Preparing files for transfer')
219
+
220
+ end
221
+
222
+ def cleanup_sandbox
223
+ return if sandbox_path.nil?
224
+ debug("Cleaning up local sandbox in #{sandbox_path}")
225
+ FileUtils.rmtree(sandbox_path)
226
+ end
227
+
228
+ def prepare_command
229
+ commands = []
230
+
231
+ # Prevent failure when ansible package installation doesn't contain /etc/ansible
232
+ commands << [
233
+ sudo_env("bash -c '[ -d /etc/ansible ] || mkdir /etc/ansible'")
234
+ ]
235
+
236
+ commands << [
237
+ sudo_env('cp'),File.join(config[:root_path], 'ansible.cfg'),'/etc/ansible',
238
+ ].join(' ')
239
+
240
+ commands << [
241
+ sudo_env('cp -r'), File.join(config[:root_path],'group_vars'), '/etc/ansible/.',
242
+ ].join(' ')
243
+
244
+ commands << [
245
+ sudo_env('cp -r'), File.join(config[:root_path],'host_vars'), '/etc/ansible/.',
246
+ ].join(' ')
247
+
248
+ if galaxy_requirements
249
+ if config[:require_ansible_source]
250
+ commands << setup_ansible_env_from_source
251
+ end
252
+ commands << [
253
+ 'ansible-galaxy', 'install', '--force',
254
+ '-p', File.join(config[:root_path], 'roles'),
255
+ '-r', File.join(config[:root_path], galaxy_requirements),
256
+ ].join(' ')
257
+ end
258
+
259
+ command = commands.join(' && ')
260
+ debug(command)
261
+ command
262
+ end
263
+
264
+ def run_command
265
+ if config[:require_ansible_source]
266
+ # this is an ugly hack to get around the fact that extra vars uses ' and "
267
+ 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")
268
+ else
269
+ cmd = ansible_command("ansible-playbook")
270
+ end
271
+ if https_proxy
272
+ cmd = "HTTPS_PROXY=#{https_proxy} #{cmd}"
273
+ end
274
+ if http_proxy
275
+ cmd = "HTTP_PROXY=#{http_proxy} #{cmd}"
276
+ end
277
+ result = [
278
+ cmd,
279
+ ansible_inventory_flag,
280
+ "-c #{config[:ansible_connection]}",
281
+ "-M #{File.join(config[:root_path], 'modules')}",
282
+ ansible_verbose_flag,
283
+ ansible_check_flag,
284
+ ansible_diff_flag,
285
+ ansible_vault_flag,
286
+ extra_vars,
287
+ tags,
288
+ ansible_extra_flags,
289
+ "#{File.join(config[:root_path], File.basename(config[:playbook]))}",
290
+ ].join(" ")
291
+ info("Going to invoke ansible-playbook with: #{result}")
292
+ result
293
+ end
294
+
295
+ def ansible_command(script)
296
+ config[:ansible_sudo].nil? || config[:ansible_sudo] == true ? sudo_env(script) : script
297
+ end
298
+
299
+ protected
300
+
301
+ def load_needed_dependencies!
302
+ if File.exists?(ansiblefile)
303
+ debug("Ansiblefile found at #{ansiblefile}, loading Librarian-Ansible")
304
+ Ansible::Librarian.load!(logger)
305
+ end
306
+ end
307
+
308
+ def install_ansible_from_source_command
309
+ <<-INSTALL
310
+ if [ ! -d #{config[:root_path]}/ansible ]; then
311
+ if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
312
+ #{install_epel_repo}
313
+ #{update_packages_redhat_cmd}
314
+ #{sudo_env('yum')} -y install libselinux-python python2-devel git python-setuptools python-setuptools-dev
315
+ else
316
+ if [ -f /etc/SUSE-brand ] || [ -f /etc/SuSE-release ]; then
317
+ #{sudo_env('zypper')} ar #{python_sles_repo}
318
+ #{update_packages_suse_cmd}
319
+ #{sudo_env('zypper')} --non-interactive install python python-devel git python-setuptools python-pip python-six libyaml-devel
320
+ else
321
+ #{update_packages_debian_cmd}
322
+ #{sudo_env('apt-get')} -y install git python python-setuptools build-essential python-dev
323
+ fi
324
+ fi
325
+
326
+ #{export_http_proxy}
327
+ git clone git://github.com/ansible/ansible.git --recursive #{config[:root_path]}/ansible
328
+ #{sudo_env('easy_install')} pip
329
+ #{sudo_env('pip')} install paramiko PyYAML Jinja2 httplib2
330
+ fi
331
+ INSTALL
332
+ end
333
+
334
+ def install_omnibus_command
335
+ info("Installing ansible using ansible omnibus")
336
+ version = if !config[:ansible_version].nil?
337
+ "-v #{config[:ansible_version]}"
338
+ else
339
+ ""
340
+ end
341
+
342
+ <<-INSTALL
343
+ #{Util.shell_helpers}
344
+
345
+ if [ ! -d "#{config[:ansible_omnibus_remote_path]}" ]; then
346
+ echo "-----> Installing Ansible Omnibus"
347
+ #{export_http_proxy}
348
+ #{install_epel_repo}
349
+ do_download #{config[:ansible_omnibus_url]} /tmp/ansible_install.sh
350
+ #{sudo_env('sh')} /tmp/ansible_install.sh #{version}
351
+ fi
352
+ INSTALL
353
+ end
354
+
355
+ def install_debian_command
356
+ <<-INSTALL
357
+ if [ ! $(which ansible) ]; then
358
+ #{update_packages_debian_cmd}
359
+
360
+ ## Install apt-utils to silence debconf warning: http://serverfault.com/q/358943/77156
361
+ #{sudo_env('apt-get')} -y install apt-utils git
362
+
363
+ ## Fix debconf tty warning messages
364
+ export DEBIAN_FRONTEND=noninteractive
365
+
366
+ ## 13.10, 14.04 include add-apt-repository in software-properties-common
367
+ #{sudo_env('apt-get')} -y install software-properties-common
368
+
369
+ ## 10.04, 12.04 include add-apt-repository in
370
+ #{sudo_env('apt-get')} -y install python-software-properties
371
+
372
+ ## 10.04 version of add-apt-repository doesn't accept --yes
373
+ ## later versions require interaction from user, so we must specify --yes
374
+ ## First try with -y flag, else if it fails, try without.
375
+ ## "add-apt-repository: error: no such option: -y" is returned but is ok to ignore, we just retry
376
+ #{sudo_env('add-apt-repository')} -y #{ansible_apt_repo} || #{sudo_env('add-apt-repository')} #{ansible_apt_repo}
377
+ #{sudo_env('apt-get')} update
378
+ #{sudo_env('apt-get')} -y install ansible
379
+ fi
380
+ INSTALL
381
+ end
382
+
383
+ def install_suse_command
384
+ <<-INSTALL
385
+ if [ ! $(which ansible) ]; then
386
+ #{sudo_env('zypper')} ar #{python_sles_repo}
387
+ #{sudo_env('zypper')} ar #{ansible_sles_repo}
388
+ #{update_packages_suse_cmd}
389
+ #{sudo_env('zypper')} --non-interactive install ansible
390
+ fi
391
+ INSTALL
392
+ end
393
+
394
+ def install_redhat_command
395
+ <<-INSTALL
396
+ if [ ! $(which ansible) ]; then
397
+ #{install_epel_repo}
398
+ #{sudo_env('rpm')} -ivh #{ansible_yum_repo}
399
+ #{update_packages_redhat_cmd}
400
+ #{sudo_env('yum')} -y install ansible#{ansible_redhat_version} libselinux-python git
401
+ fi
402
+ INSTALL
403
+ end
404
+
405
+ def install_amazon_linux_command
406
+ <<-INSTALL
407
+ if [ ! $(which ansible) ]; then
408
+ #{install_epel_repo}
409
+ #{sudo_env('yum-config-manager')} --enable epel/x86_64
410
+ #{sudo_env('yum')} -y install ansible#{ansible_redhat_version} git
411
+ #{sudo_env('alternatives')} --set python /usr/bin/python2.6
412
+ #{sudo_env('yum')} clean all
413
+ #{sudo_env('yum')} install yum-python26 -y
414
+ fi
415
+ INSTALL
416
+ end
417
+
418
+ def setup_ansible_env_from_source
419
+ "cd #{config[:root_path]}/ansible && source hacking/env-setup && cd ../"
420
+ end
421
+
422
+ def tmp_modules_dir
423
+ File.join(sandbox_path, 'modules')
424
+ end
425
+
426
+ def tmp_playbook_path
427
+ File.join(sandbox_path, File.basename(playbook))
428
+ end
429
+
430
+ def tmp_host_vars_dir
431
+ File.join(sandbox_path, 'host_vars')
432
+ end
433
+
434
+ def tmp_roles_dir
435
+ File.join(sandbox_path, 'roles')
436
+ end
437
+
438
+ def tmp_filter_plugins_dir
439
+ File.join(sandbox_path, 'filter_plugins')
440
+ end
441
+
442
+ def tmp_lookup_plugins_dir
443
+ File.join(sandbox_path, 'lookup_plugins')
444
+ end
445
+
446
+ def tmp_ansible_vault_password_file_path
447
+ File.join(sandbox_path, File.basename(ansible_vault_password_file))
448
+ end
449
+
450
+ def tmp_inventory_file_path
451
+ File.join(sandbox_path, File.basename(ansible_inventory_file))
452
+ end
453
+
454
+ def ansiblefile
455
+ config[:ansiblefile_path] || ''
456
+ end
457
+
458
+ def galaxy_requirements
459
+ config[:requirements_path] || nil
460
+ end
461
+
462
+ def playbook
463
+ config[:playbook]
464
+ end
465
+
466
+ def hosts
467
+ config[:hosts]
468
+ end
469
+
470
+ def roles
471
+ config[:roles_path]
472
+ end
473
+
474
+ def role_name
475
+ File.basename(roles) == 'roles' ? '' : File.basename(roles)
476
+ end
477
+
478
+ def modules
479
+ config[:modules_path]
480
+ end
481
+
482
+ def group_vars
483
+ config[:group_vars_path].to_s
484
+ end
485
+
486
+ def additional_copy
487
+ config[:additional_copy_path]
488
+ end
489
+
490
+ def host_vars
491
+ config[:host_vars_path].to_s
492
+ end
493
+
494
+ def filter_plugins
495
+ config[:filter_plugins_path].to_s
496
+ end
497
+
498
+ def lookup_plugins
499
+ config[:lookup_plugins_path].to_s
500
+ end
501
+
502
+ def ansible_vault_password_file
503
+ config[:ansible_vault_password_file]
504
+ end
505
+
506
+ def ansible_inventory_file
507
+ config[:ansible_inventory_file]
508
+ end
509
+
510
+ def ansible_debian_version
511
+ config[:ansible_version] ? "=#{config[:ansible_version]}" : nil
512
+ end
513
+
514
+ def ansible_redhat_version
515
+ config[:ansible_version] ? "-#{config[:ansible_version]}" : nil
516
+ end
517
+
518
+ def ansible_verbose_flag
519
+ config[:ansible_verbose] ? '-' << ('v' * verbosity_level(config[:ansible_verbosity])) : nil
520
+ end
521
+
522
+ def ansible_check_flag
523
+ config[:ansible_check] ? '--check' : nil
524
+ end
525
+
526
+ def ansible_diff_flag
527
+ config[:ansible_diff] ? '--diff' : nil
528
+ end
529
+
530
+ def ansible_vault_flag
531
+ debug(config[:ansible_vault_password_file])
532
+ config[:ansible_vault_password_file] ? "--vault-password-file=#{File.join(config[:root_path], File.basename(config[:ansible_vault_password_file]))}" : nil
533
+ end
534
+
535
+ def ansible_inventory_flag
536
+ 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')}"
537
+ end
538
+
539
+ def ansible_extra_flags
540
+ config[:ansible_extra_flags] || ''
541
+ end
542
+
543
+ def ansible_platform
544
+ config[:ansible_platform].to_s.downcase
545
+ end
546
+
547
+ def update_packages_debian_cmd
548
+ config[:update_package_repos] ? "#{sudo_env('apt-get')} update" : nil
549
+ end
550
+
551
+ def update_packages_suse_cmd
552
+ config[:update_package_repos] ? "#{sudo_env('zypper')} --gpg-auto-import-keys ref" : nil
553
+ end
554
+
555
+ def update_packages_redhat_cmd
556
+ config[:update_package_repos] ? "#{sudo_env('yum')} makecache" : nil
557
+ end
558
+
559
+ def extra_vars
560
+ bash_vars = config[:extra_vars]
561
+ if config.key?(:attributes) && config[:attributes].key?(:extra_vars) && config[:attributes][:extra_vars].is_a?(Hash)
562
+ bash_vars = config[:attributes][:extra_vars]
563
+ end
564
+
565
+ return nil if bash_vars.none?
566
+ bash_vars = JSON.dump(bash_vars)
567
+ bash_vars = "-e '#{bash_vars}'"
568
+ debug(bash_vars)
569
+ bash_vars
570
+ end
571
+
572
+ def tags
573
+ bash_tags = config.key?(:attributes) && config[:attributes].key?(:tags) && config[:attributes][:tags].is_a?(Array) ? config[:attributes][:tags] : config[:tags]
574
+ return nil if bash_tags.empty?
575
+
576
+ bash_tags = bash_tags.join(",")
577
+ bash_tags = "-t '#{bash_tags}'"
578
+ debug(bash_tags)
579
+ bash_tags
580
+ end
581
+
582
+ def ansible_apt_repo
583
+ config[:ansible_apt_repo]
584
+ end
585
+
586
+ def ansible_apt_repo_file
587
+ config[:ansible_apt_repo].split('/').last
588
+ end
589
+
590
+ def ansible_yum_repo
591
+ config[:ansible_yum_repo]
592
+ end
593
+
594
+ def ansible_sles_repo
595
+ config[:ansible_sles_repo]
596
+ end
597
+
598
+ def python_sles_repo
599
+ config[:python_sles_repo]
600
+ end
601
+
602
+ def chef_url
603
+ config[:chef_bootstrap_url]
604
+ end
605
+
606
+ def require_ruby_for_busser
607
+ config[:require_ruby_for_busser]
608
+ end
609
+
610
+ def require_chef_for_busser
611
+ config[:require_chef_for_busser]
612
+ end
613
+
614
+ def install_epel_repo
615
+ config[:enable_yum_epel] ? sudo_env('yum install epel-release -y') : nil
616
+ end
617
+
618
+ def http_proxy
619
+ config[:http_proxy]
620
+ end
621
+
622
+ def https_proxy
623
+ config[:https_proxy]
624
+ end
625
+
626
+ def no_proxy
627
+ config[:no_proxy]
628
+ end
629
+
630
+ def sudo_env(pm)
631
+ s = https_proxy ? "https_proxy=#{https_proxy}" : nil
632
+ p = http_proxy ? "http_proxy=#{http_proxy}" : nil
633
+ n = no_proxy ? "no_proxy=#{no_proxy}" : nil
634
+ p || s ? "#{sudo('env')} #{p} #{s} #{n} #{pm}" : "#{sudo(pm)}"
635
+ end
636
+
637
+ def export_http_proxy
638
+ cmd = ""
639
+ cmd = " HTTP_PROXY=#{http_proxy}" if http_proxy
640
+ cmd = "#{cmd} HTTPS_PROXY=#{https_proxy}" if https_proxy
641
+ cmd = "#{cmd} NO_PROXY=#{no_proxy}" if no_proxy
642
+ cmd = "export #{cmd}" if cmd != ""
643
+ cmd
644
+ end
645
+
646
+ def prepare_roles
647
+ info('Preparing roles')
648
+ debug("Using roles from #{roles}")
649
+
650
+ resolve_with_librarian if File.exists?(ansiblefile)
651
+
652
+ if galaxy_requirements
653
+ FileUtils.cp(galaxy_requirements, File.join(sandbox_path, galaxy_requirements))
654
+ end
655
+
656
+ # Detect whether we are running tests on a role
657
+ # If so, make sure to copy into VM so dir structure is like: /tmp/kitchen/roles/role_name
658
+
659
+ FileUtils.mkdir_p(File.join(tmp_roles_dir, role_name))
660
+ FileUtils.cp_r(Dir.glob("#{roles}/*"), File.join(tmp_roles_dir, role_name))
661
+ end
662
+
663
+ # /etc/ansible/ansible.cfg should contain
664
+ # roles_path = /tmp/kitchen/roles
665
+ def prepare_ansible_cfg
666
+ info('Preparing ansible.cfg file')
667
+ ansible_config_file = "#{File.join(sandbox_path, 'ansible.cfg')}"
668
+
669
+ roles_paths = []
670
+ roles_paths << File.join(config[:root_path], 'roles') unless config[:roles_path].nil?
671
+ additional_files.each do |additional_file|
672
+ roles_paths << File.join(config[:root_path], File.basename(additional_file))
673
+ end
674
+
675
+ if roles_paths.empty?
676
+ info('No roles have been set. empty ansible.cfg generated')
677
+ File.open(ansible_config_file, "wb") do |file|
678
+ file.write("#no roles path specified\n")
679
+ end
680
+ else
681
+ debug("Setting roles_path inside VM to #{ roles_paths.join(':') }")
682
+ File.open( ansible_config_file, "wb") do |file|
683
+ file.write("[defaults]\nroles_path = #{ roles_paths.join(':') }\n")
684
+ end
685
+ end
686
+ end
687
+
688
+ def prepare_inventory_file
689
+ info('Preparing inventory file')
690
+
691
+ if ansible_inventory_file
692
+ debug("Copying inventory file from #{ansible_inventory_file} to #{tmp_inventory_file_path}")
693
+ FileUtils.cp_r(ansible_inventory_file, tmp_inventory_file_path)
694
+ end
695
+ end
696
+
697
+ # localhost ansible_connection=local
698
+ # [example_servers]
699
+ # localhost
700
+ def prepare_hosts
701
+ info('Preparing hosts file')
702
+
703
+ if config[:hosts].nil?
704
+ raise 'No hosts have been set. Please specify one in .kitchen.yml'
705
+ else
706
+ debug("Using host from #{hosts}")
707
+ File.open(File.join(sandbox_path, "hosts"), "wb") do |file|
708
+ file.write("localhost ansible_connection=local\n[#{hosts}]\nlocalhost\n")
709
+ end
710
+ end
711
+ end
712
+
713
+ def prepare_playbook
714
+ info('Preparing playbook')
715
+ debug("Copying playbook from #{playbook} to #{tmp_playbook_path}")
716
+ FileUtils.cp_r(playbook, tmp_playbook_path)
717
+ end
718
+
719
+ def prepare_group_vars
720
+ info('Preparing group_vars')
721
+ tmp_group_vars_dir = File.join(sandbox_path, 'group_vars')
722
+ FileUtils.mkdir_p(tmp_group_vars_dir)
723
+
724
+ unless File.directory?(group_vars)
725
+ info('nothing to do for group_vars')
726
+ return
727
+ end
728
+
729
+ debug("Using group_vars from #{group_vars}")
730
+ FileUtils.cp_r(Dir.glob("#{group_vars}/*"), tmp_group_vars_dir)
731
+ end
732
+
733
+ def prepare_additional_copy_path
734
+ info('Preparing additional_copy_path')
735
+ additional_files.each do |file|
736
+ destination = File.join(sandbox_path, File.basename(file))
737
+ if File.directory?(file)
738
+ info("Copy dir: #{file} #{destination}")
739
+ FileUtils.cp_r(file, destination)
740
+ else
741
+ info("Copy file: #{file} #{destination}")
742
+ FileUtils.cp file, destination
743
+ end
744
+ end
745
+ end
746
+
747
+ def additional_files
748
+ additional_files = []
749
+ if ( additional_copy )
750
+ additional_files = additional_copy.kind_of?(Array) ? additional_copy : [additional_copy]
751
+ end
752
+ additional_files.map { |additional_dir | additional_dir.to_s }
753
+ end
754
+
755
+ def prepare_host_vars
756
+ info('Preparing host_vars')
757
+ FileUtils.mkdir_p(tmp_host_vars_dir)
758
+
759
+ unless File.directory?(host_vars)
760
+ info 'nothing to do for host_vars'
761
+ return
762
+ end
763
+
764
+ debug("Using host_vars from #{host_vars}")
765
+ FileUtils.cp_r(Dir.glob("#{host_vars}/*"), tmp_host_vars_dir)
766
+ end
767
+
768
+ def prepare_modules
769
+ info('Preparing modules')
770
+
771
+ FileUtils.mkdir_p(tmp_modules_dir)
772
+
773
+ if modules && File.directory?(modules)
774
+ debug("Using modules from #{modules}")
775
+ FileUtils.cp_r(Dir.glob("#{modules}/*"), tmp_modules_dir, remove_destination: true)
776
+ else
777
+ info 'nothing to do for modules'
778
+ end
779
+ end
780
+
781
+ def prepare_filter_plugins
782
+ info('Preparing filter_plugins')
783
+ FileUtils.mkdir_p(tmp_filter_plugins_dir)
784
+
785
+ if filter_plugins && File.directory?(filter_plugins)
786
+ debug("Using filter_plugins from #{filter_plugins}")
787
+ FileUtils.cp_r(Dir.glob("#{filter_plugins}/*.py"), tmp_filter_plugins_dir, remove_destination: true)
788
+ else
789
+ info 'nothing to do for filter_plugins'
790
+ end
791
+ end
792
+
793
+ def prepare_lookup_plugins
794
+ info('Preparing lookup_plugins')
795
+ FileUtils.mkdir_p(tmp_lookup_plugins_dir)
796
+
797
+ if lookup_plugins && File.directory?(lookup_plugins)
798
+ debug("Using lookup_plugins from #{lookup_plugins}")
799
+ FileUtils.cp_r(Dir.glob("#{lookup_plugins}/*.py"), tmp_lookup_plugins_dir, remove_destination: true)
800
+ else
801
+ info 'nothing to do for lookup_plugins'
802
+ end
803
+ end
804
+
805
+ def prepare_ansible_vault_password_file
806
+ if ansible_vault_password_file
807
+ info('Preparing ansible vault password')
808
+ debug("Copying ansible vault password file from #{ansible_vault_password_file} to #{tmp_ansible_vault_password_file_path}")
809
+
810
+ FileUtils.cp(ansible_vault_password_file, tmp_ansible_vault_password_file_path)
811
+ end
812
+ end
813
+
814
+ def resolve_with_librarian
815
+ Kitchen.mutex.synchronize do
816
+ Ansible::Librarian.new(ansiblefile, tmp_roles_dir, logger).resolve
817
+ end
818
+ end
819
+ end
820
+ end
821
+ end