kitchen-ansible 0.0.17 → 0.0.19

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,139 +1,144 @@
1
- # -*- encoding: utf-8 -*-
2
- #
3
- # Author:: Michael Heap (<m@michaelheap.com>)
4
- #
5
- # Copyright (C) 2015 Michael Heap
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
-
20
- require 'json'
21
-
22
- module Kitchen
23
-
24
- module Provisioner
25
-
26
- module Ansible
27
- #
28
- # Ansible Playbook provisioner.
29
- #
30
- class Config
31
- include Kitchen::Configurable
32
-
33
- attr_reader :instance
34
-
35
- default_config :ansible_verbose, false
36
- default_config :require_ansible_omnibus, false
37
- default_config :ansible_omnibus_url, nil
38
- default_config :ansible_omnibus_remote_path, '/opt/ansible'
39
- default_config :ansible_version, nil
40
- default_config :require_ansible_repo, true
41
- default_config :extra_vars, {}
42
- default_config :tags, []
43
- default_config :ansible_apt_repo, "ppa:ansible/ansible"
44
- default_config :ansible_yum_repo, "https://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm"
45
- default_config :chef_bootstrap_url, "https://www.getchef.com/chef/install.sh"
46
- default_config :require_chef_for_busser, false
47
- default_config :require_ruby_for_busser, true
48
- default_config :requirements_path, false
49
- default_config :ansible_verbose, false
50
- default_config :ansible_verbosity, 1
51
- default_config :ansible_check, false
52
- default_config :ansible_diff, false
53
- default_config :ansible_platform, ''
54
- default_config :update_package_repos, true
55
-
56
- default_config :playbook do |provisioner|
57
- provisioner.calculate_path('default.yml', :file) or
58
- raise "No playbook found or specified! Please either set a playbook in your .kitchen.yml config, or create a default wrapper playbook for your role in test/integration/playbooks/default.yml or test/integration/default.yml"
59
- end
60
-
61
- default_config :roles_path do |provisioner|
62
- provisioner.calculate_path('roles') or
63
- raise 'No roles_path detected. Please specify one in .kitchen.yml'
64
- end
65
-
66
- default_config :group_vars_path do |provisioner|
67
- provisioner.calculate_path('group_vars', :directory)
68
- end
69
-
70
- default_config :additional_copy_path do |provisioner|
71
- provisioner.calculate_path('additional_copy', :directory)
72
- end
73
-
74
- default_config :host_vars_path do |provisioner|
75
- provisioner.calculate_path('host_vars', :directory)
76
- end
77
-
78
- default_config :modules_path do |provisioner|
79
- provisioner.calculate_path('modules', :directory)
80
- end
81
-
82
- default_config :ansiblefile_path do |provisioner|
83
- provisioner.calculate_path('Ansiblefile', :file)
84
- end
85
-
86
- default_config :filter_plugins_path do |provisioner|
87
- provisioner.calculate_path('filter_plugins', :directory)
88
- end
89
-
90
- default_config :ansible_vault_password_file do |provisioner|
91
- provisioner.calculate_path('ansible-vault-password', :file)
92
- end
93
-
94
- def initialize(config = {})
95
- init_config(config)
96
- end
97
-
98
- def set_instance(instance)
99
- @instance = instance
100
- end
101
-
102
- def []=(attr, val)
103
- config[attr] = val
104
- end
105
-
106
- def [](attr)
107
- config[attr]
108
- end
109
-
110
- def key?(k)
111
- return config.key?(k)
112
- end
113
-
114
- def calculate_path(path, type = :directory)
115
-
116
- if not instance
117
- raise "Please ensure that an instance is provided before calling calculate_path"
118
- end
119
-
120
- base = config[:test_base_path]
121
- candidates = []
122
- candidates << File.join(base, instance.suite.name, 'ansible', path)
123
- candidates << File.join(base, instance.suite.name, path)
124
- candidates << File.join(base, path)
125
- candidates << File.join(Dir.pwd, path)
126
- candidates << File.join(Dir.pwd) if path == 'roles'
127
-
128
- candidates.find do |c|
129
- type == :directory ? File.directory?(c) : File.file?(c)
130
- end
131
- end
132
-
133
-
134
- end
135
-
136
- end
137
- end
138
-
139
- end
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Michael Heap (<m@michaelheap.com>)
4
+ #
5
+ # Copyright (C) 2015 Michael Heap
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
+
20
+ require 'json'
21
+
22
+ module Kitchen
23
+
24
+ module Provisioner
25
+
26
+ module Ansible
27
+ #
28
+ # Ansible Playbook provisioner.
29
+ #
30
+ class Config
31
+ include Kitchen::Configurable
32
+
33
+ attr_reader :instance
34
+
35
+ default_config :ansible_verbose, false
36
+ default_config :require_ansible_omnibus, false
37
+ default_config :ansible_omnibus_url, nil
38
+ default_config :ansible_omnibus_remote_path, '/opt/ansible'
39
+ default_config :ansible_version, nil
40
+ default_config :require_ansible_repo, true
41
+ default_config :extra_vars, {}
42
+ default_config :tags, []
43
+ default_config :ansible_apt_repo, "ppa:ansible/ansible"
44
+ default_config :ansible_yum_repo, "https://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm"
45
+ default_config :chef_bootstrap_url, "https://www.getchef.com/chef/install.sh"
46
+ default_config :require_chef_for_busser, false
47
+ default_config :require_ruby_for_busser, true
48
+ default_config :requirements_path, false
49
+ default_config :ansible_verbose, false
50
+ default_config :ansible_verbosity, 1
51
+ default_config :ansible_check, false
52
+ default_config :ansible_diff, false
53
+ default_config :ansible_platform, ''
54
+ default_config :update_package_repos, true
55
+ default_config :require_ansible_source, false
56
+
57
+ default_config :playbook do |provisioner|
58
+ provisioner.calculate_path('default.yml', :file) or
59
+ raise "No playbook found or specified! Please either set a playbook in your .kitchen.yml config, or create a default wrapper playbook for your role in test/integration/playbooks/default.yml or test/integration/default.yml"
60
+ end
61
+
62
+ default_config :roles_path do |provisioner|
63
+ provisioner.calculate_path('roles') or
64
+ raise 'No roles_path detected. Please specify one in .kitchen.yml'
65
+ end
66
+
67
+ default_config :group_vars_path do |provisioner|
68
+ provisioner.calculate_path('group_vars', :directory)
69
+ end
70
+
71
+ default_config :additional_copy_path do |provisioner|
72
+ provisioner.calculate_path('additional_copy', :directory)
73
+ end
74
+
75
+ default_config :host_vars_path do |provisioner|
76
+ provisioner.calculate_path('host_vars', :directory)
77
+ end
78
+
79
+ default_config :modules_path do |provisioner|
80
+ provisioner.calculate_path('modules', :directory)
81
+ end
82
+
83
+ default_config :ansiblefile_path do |provisioner|
84
+ provisioner.calculate_path('Ansiblefile', :file)
85
+ end
86
+
87
+ default_config :filter_plugins_path do |provisioner|
88
+ provisioner.calculate_path('filter_plugins', :directory)
89
+ end
90
+
91
+ default_config :ansible_vault_password_file do |provisioner|
92
+ provisioner.calculate_path('ansible-vault-password', :file)
93
+ end
94
+
95
+ def initialize(config = {})
96
+ init_config(config)
97
+ end
98
+
99
+ def set_instance(instance)
100
+ @instance = instance
101
+ end
102
+
103
+ def []=(attr, val)
104
+ config[attr] = val
105
+ end
106
+
107
+ def [](attr)
108
+ config[attr]
109
+ end
110
+
111
+ def key?(k)
112
+ return config.key?(k)
113
+ end
114
+
115
+ def keys
116
+ config.keys
117
+ end
118
+
119
+ def calculate_path(path, type = :directory)
120
+
121
+ if not instance
122
+ raise "Please ensure that an instance is provided before calling calculate_path"
123
+ end
124
+
125
+ base = config[:test_base_path]
126
+ candidates = []
127
+ candidates << File.join(base, instance.suite.name, 'ansible', path)
128
+ candidates << File.join(base, instance.suite.name, path)
129
+ candidates << File.join(base, path)
130
+ candidates << File.join(Dir.pwd, path)
131
+ candidates << File.join(Dir.pwd) if path == 'roles'
132
+
133
+ candidates.find do |c|
134
+ type == :directory ? File.directory?(c) : File.file?(c)
135
+ end
136
+ end
137
+
138
+
139
+ end
140
+
141
+ end
142
+ end
143
+
144
+ end
@@ -1,83 +1,83 @@
1
- # -*- encoding: utf-8 -*-
2
- #
3
- # Author:: Fletcher Nichol (<fnichol@nichol.ca>) Neill Turner (<neillwturner@gmail.com>)
4
- #
5
- # Copyright (C) 2013, Fletcher Nichol, 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
- require 'kitchen/errors'
20
- require 'kitchen/logging'
21
-
22
- module Kitchen
23
-
24
- module Provisioner
25
-
26
- module Ansible
27
-
28
- # Ansible module resolver that uses Librarian-Ansible and a Ansiblefile to
29
- # calculate # dependencies.
30
- #
31
- class Librarian
32
-
33
- include Logging
34
-
35
-
36
- def initialize(ansiblefile, path, logger = Kitchen.logger)
37
- @ansiblefile = ansiblefile
38
- @path = path
39
- @logger = logger
40
- end
41
-
42
- def self.load!(logger = Kitchen.logger)
43
- load_librarian!(logger)
44
- end
45
-
46
- def resolve
47
- version = ::Librarian::Ansible::VERSION
48
- info("Resolving role dependencies with Librarian-Ansible #{version}...")
49
- debug("Using Ansiblefile from #{ansiblefile}")
50
-
51
- env = ::Librarian::Ansible::Environment.new(
52
- :project_path => File.dirname(ansiblefile))
53
- env.config_db.local["path"] = path
54
- ::Librarian::Action::Resolve.new(env).run
55
- ::Librarian::Action::Install.new(env).run
56
- end
57
-
58
- attr_reader :ansiblefile, :path, :logger
59
-
60
- def self.load_librarian!(logger)
61
- first_load = require 'librarian/ansible'
62
- require 'librarian/ansible/environment'
63
- require 'librarian/action/resolve'
64
- require 'librarian/action/install'
65
-
66
- version = ::Librarian::Ansible::VERSION
67
- if first_load
68
- logger.debug("Librarian-Ansible #{version} library loaded")
69
- else
70
- logger.debug("Librarian-Ansible #{version} previously loaded")
71
- end
72
- rescue LoadError => e
73
- logger.fatal("The `librarian-ansible' gem is missing and must be installed" +
74
- " or cannot be properly activated. Run" +
75
- " `gem install librarian-ansible` or add the following to your" +
76
- " Gemfile if you are using Bundler: `gem 'librarian-ansible'`.")
77
- raise UserError,
78
- "Could not load or activate Librarian-Ansible (#{e.message})"
79
- end
80
- end
81
- end
82
- end
83
- end
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>) Neill Turner (<neillwturner@gmail.com>)
4
+ #
5
+ # Copyright (C) 2013, Fletcher Nichol, 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
+ require 'kitchen/errors'
20
+ require 'kitchen/logging'
21
+
22
+ module Kitchen
23
+
24
+ module Provisioner
25
+
26
+ module Ansible
27
+
28
+ # Ansible module resolver that uses Librarian-Ansible and a Ansiblefile to
29
+ # calculate # dependencies.
30
+ #
31
+ class Librarian
32
+
33
+ include Logging
34
+
35
+
36
+ def initialize(ansiblefile, path, logger = Kitchen.logger)
37
+ @ansiblefile = ansiblefile
38
+ @path = path
39
+ @logger = logger
40
+ end
41
+
42
+ def self.load!(logger = Kitchen.logger)
43
+ load_librarian!(logger)
44
+ end
45
+
46
+ def resolve
47
+ version = ::Librarian::Ansible::VERSION
48
+ info("Resolving role dependencies with Librarian-Ansible #{version}...")
49
+ debug("Using Ansiblefile from #{ansiblefile}")
50
+
51
+ env = ::Librarian::Ansible::Environment.new(
52
+ :project_path => File.dirname(ansiblefile))
53
+ env.config_db.local["path"] = path
54
+ ::Librarian::Action::Resolve.new(env).run
55
+ ::Librarian::Action::Install.new(env).run
56
+ end
57
+
58
+ attr_reader :ansiblefile, :path, :logger
59
+
60
+ def self.load_librarian!(logger)
61
+ first_load = require 'librarian/ansible'
62
+ require 'librarian/ansible/environment'
63
+ require 'librarian/action/resolve'
64
+ require 'librarian/action/install'
65
+
66
+ version = ::Librarian::Ansible::VERSION
67
+ if first_load
68
+ logger.debug("Librarian-Ansible #{version} library loaded")
69
+ else
70
+ logger.debug("Librarian-Ansible #{version} previously loaded")
71
+ end
72
+ rescue LoadError => e
73
+ logger.fatal("The `librarian-ansible' gem is missing and must be installed" +
74
+ " or cannot be properly activated. Run" +
75
+ " `gem install librarian-ansible` or add the following to your" +
76
+ " Gemfile if you are using Bundler: `gem 'librarian-ansible'`.")
77
+ raise UserError,
78
+ "Could not load or activate Librarian-Ansible (#{e.message})"
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -1,632 +1,673 @@
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
- return unless config[:require_ansible_omnibus] or config[:require_ansible_repo]
70
- if config[:require_ansible_omnibus]
71
- info("Installing ansible using ansible omnibus")
72
- version = if !config[:ansible_version].nil?
73
- "-v #{config[:ansible_version]}"
74
- else
75
- ""
76
- end
77
- <<-INSTALL
78
- #{Util.shell_helpers}
79
-
80
- if [ ! -d "#{config[:ansible_omnibus_remote_path]}" ]; then
81
- echo "-----> Installing Ansible Omnibus"
82
- do_download #{config[:ansible_omnibus_url]} /tmp/ansible_install.sh
83
- #{sudo('sh')} /tmp/ansible_install.sh #{version}
84
- fi
85
- #{install_busser_prereqs}
86
- INSTALL
87
- else
88
- case ansible_platform
89
- when "debian", "ubuntu"
90
- info("Installing ansible on #{ansible_platform}")
91
- <<-INSTALL
92
- if [ ! $(which ansible) ]; then
93
- #{update_packages_debian_cmd}
94
- ## Install apt-utils to silence debconf warning: http://serverfault.com/q/358943/77156
95
- #{sudo('apt-get')} -y install apt-utils git
96
- ## Fix debconf tty warning messages
97
- export DEBIAN_FRONTEND=noninteractive
98
- ## 13.10, 14.04 include add-apt-repository in software-properties-common
99
- #{sudo('apt-get')} -y install software-properties-common
100
- ## 10.04, 12.04 include add-apt-repository in
101
- #{sudo('apt-get')} -y install python-software-properties
102
- # #{sudo('wget')} #{ansible_apt_repo}
103
- # #{sudo('dpkg')} -i #{ansible_apt_repo_file}
104
- # #{sudo('apt-get')} -y autoremove ## These autoremove/autoclean are sometimes useful but
105
- # #{sudo('apt-get')} -y autoclean ## don't seem necessary for the Ubuntu OpsCode bento boxes that are not EOL by Canonical
106
- # #{sudo('apt-get')} -y --force-yes install ansible#{ansible_debian_version} python-selinux
107
- ## 10.04 version of add-apt-repository doesn't accept --yes
108
- ## later versions require interaction from user, so we must specify --yes
109
- ## First try with -y flag, else if it fails, try without.
110
- ## "add-apt-repository: error: no such option: -y" is returned but is ok to ignore, we just retry
111
- #{sudo('add-apt-repository')} -y #{ansible_apt_repo} || #{sudo('add-apt-repository')} #{ansible_apt_repo}
112
- #{sudo('apt-get')} update
113
- #{sudo('apt-get')} -y install ansible
114
- ## This test works on ubuntu to test if ansible repo has been installed via rquillo ppa repo
115
- ## if [ $(apt-cache madison ansible | grep -c rquillo ) -gt 0 ]; then echo 'success'; else echo 'fail'; fi
116
- fi
117
- #{install_busser_prereqs}
118
- INSTALL
119
- when "redhat", "centos", "fedora"
120
- info("Installing ansible on #{ansible_platform}")
121
- <<-INSTALL
122
- if [ ! $(which ansible) ]; then
123
- #{sudo('rpm')} -ivh #{ansible_yum_repo}
124
- #{update_packages_redhat_cmd}
125
- #{sudo('yum')} -y install ansible#{ansible_redhat_version} libselinux-python git
126
- fi
127
- #{install_busser_prereqs}
128
- INSTALL
129
- else
130
- info("Installing ansible, will try to determine platform os")
131
- <<-INSTALL
132
- if [ ! $(which ansible) ]; then
133
- if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
134
- #{sudo('rpm')} -ivh #{ansible_yum_repo}
135
- #{update_packages_redhat_cmd}
136
- #{sudo('yum')} -y install ansible#{ansible_redhat_version} libselinux-python git
137
- else
138
- #{update_packages_debian_cmd}
139
- ## Install apt-utils to silence debconf warning: http://serverfault.com/q/358943/77156
140
- #{sudo('apt-get')} -y install apt-utils git
141
- ## Fix debconf tty warning messages
142
- export DEBIAN_FRONTEND=noninteractive
143
- ## 13.10, 14.04 include add-apt-repository in software-properties-common
144
- #{sudo('apt-get')} -y install software-properties-common
145
- ## 10.04, 12.04 include add-apt-repository in
146
- #{sudo('apt-get')} -y install python-software-properties
147
- # #{sudo('wget')} #{ansible_apt_repo}
148
- # #{sudo('dpkg')} -i #{ansible_apt_repo_file}
149
- # #{sudo('apt-get')} -y autoremove ## These autoremove/autoclean are sometimes useful but
150
- # #{sudo('apt-get')} -y autoclean ## don't seem necessary for the Ubuntu OpsCode bento boxes that are not EOL by Canonical
151
- # #{sudo('apt-get')} -y --force-yes install ansible#{ansible_debian_version} python-selinux
152
- ## 10.04 version of add-apt-repository doesn't accept --yes
153
- ## later versions require interaction from user, so we must specify --yes
154
- ## First try with -y flag, else if it fails, try without.
155
- ## "add-apt-repository: error: no such option: -y" is returned but is ok to ignore, we just retry
156
- #{sudo('add-apt-repository')} -y #{ansible_apt_repo} || #{sudo('add-apt-repository')} #{ansible_apt_repo}
157
- #{sudo('apt-get')} update
158
- #{sudo('apt-get')} -y install ansible
159
- ## This test works on ubuntu to test if ansible repo has been installed via rquillo ppa repo
160
- ## if [ $(apt-cache madison ansible | grep -c rquillo ) -gt 0 ]; then echo 'success'; else echo 'fail'; fi
161
- fi
162
- fi
163
- #{install_busser_prereqs}
164
- INSTALL
165
- end
166
- end
167
- end
168
-
169
- def install_busser_prereqs
170
- install = ''
171
- install << <<-INSTALL
172
- #{Util.shell_helpers}
173
- # Fix for https://github.com/test-kitchen/busser/issues/12
174
- if [ -h /usr/bin/ruby ]; then
175
- L=$(readlink -f /usr/bin/ruby)
176
- #{sudo('rm')} /usr/bin/ruby
177
- #{sudo('ln')} -s $L /usr/bin/ruby
178
- fi
179
- INSTALL
180
-
181
- if require_ruby_for_busser
182
- install << <<-INSTALL
183
- if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
184
- rhelversion=$(cat /etc/redhat-release | grep 'release 6')
185
- # For CentOS6/RHEL6 install ruby from SCL
186
- if [ -n "$rhelversion" ]; then
187
- if [ ! -d "/opt/rh/ruby193" ]; then
188
- echo "-----> Installing ruby SCL in CentOS6/RHEL6 to install busser to run tests"
189
- #{sudo('yum')} install -y centos-release-SCL
190
- #{sudo('yum')} install -y ruby193
191
- #{sudo('yum')} install -y ruby193-ruby-devel
192
- echo "-----> Enabling ruby193"
193
- source /opt/rh/ruby193/enable
194
- echo "/opt/rh/ruby193/root/usr/lib64" | sudo tee -a /etc/ld.so.conf
195
- sudo ldconfig
196
- sudo ln -s /opt/rh/ruby193/root/usr/bin/ruby /usr/bin/ruby
197
- sudo ln -s /opt/rh/ruby193/root/usr/bin/gem /usr/bin/gem
198
- fi
199
- else
200
- if [ ! $(which ruby) ]; then
201
- #{update_packages_redhat_cmd}
202
- #{sudo('yum')} -y install ruby ruby-devel
203
- fi
204
- fi
205
- else
206
- if [ ! $(which ruby) ]; then
207
- #{update_packages_debian_cmd}
208
- #{sudo('apt-get')} -y install ruby1.9.1 ruby1.9.1-dev
209
- fi
210
- fi
211
- INSTALL
212
-
213
- elsif require_chef_for_busser && chef_url then
214
- install << <<-INSTALL
215
- # install chef omnibus so that busser works as this is needed to run tests :(
216
- if [ ! -d "/opt/chef" ]
217
- then
218
- echo "-----> Installing Chef Omnibus to install busser to run tests"
219
- do_download #{chef_url} /tmp/install.sh
220
- #{sudo('sh')} /tmp/install.sh
221
- fi
222
- INSTALL
223
- end
224
-
225
- install
226
- end
227
-
228
- def init_command
229
- dirs = %w{modules roles group_vars host_vars}.
230
- map { |dir| File.join(config[:root_path], dir) }.join(" ")
231
- cmd = "#{sudo('rm')} -rf #{dirs};"
232
- cmd = cmd+" mkdir -p #{config[:root_path]}"
233
- debug(cmd)
234
- cmd
235
- end
236
-
237
- def create_sandbox
238
- super
239
- debug("Creating local sandbox in #{sandbox_path}")
240
-
241
- yield if block_given?
242
-
243
- prepare_playbook
244
- prepare_modules
245
- prepare_roles
246
- prepare_ansible_cfg
247
- prepare_group_vars
248
- prepare_additional_copy_path
249
- prepare_host_vars
250
- prepare_hosts
251
- prepare_filter_plugins
252
- prepare_ansible_vault_password_file
253
- info('Finished Preparing files for transfer')
254
-
255
- end
256
-
257
- def cleanup_sandbox
258
- return if sandbox_path.nil?
259
- debug("Cleaning up local sandbox in #{sandbox_path}")
260
- FileUtils.rmtree(sandbox_path)
261
- end
262
-
263
- def prepare_command
264
- commands = []
265
-
266
- # Prevent failure when ansible package installation doesn't contain /etc/ansible
267
- commands << [
268
- sudo("bash -c '[ -d /etc/ansible ] || mkdir /etc/ansible'")
269
- ]
270
-
271
- commands << [
272
- sudo('cp'),File.join(config[:root_path], 'ansible.cfg'),'/etc/ansible',
273
- ].join(' ')
274
-
275
- commands << [
276
- sudo('cp -r'), File.join(config[:root_path],'group_vars'), '/etc/ansible/.',
277
- ].join(' ')
278
-
279
- commands << [
280
- sudo('cp -r'), File.join(config[:root_path],'host_vars'), '/etc/ansible/.',
281
- ].join(' ')
282
-
283
- if galaxy_requirements
284
- commands << [
285
- 'ansible-galaxy', 'install', '--force',
286
- '-p', File.join(config[:root_path], 'roles'),
287
- '-r', File.join(config[:root_path], galaxy_requirements),
288
- ].join(' ')
289
- end
290
-
291
- command = commands.join(' && ')
292
- debug(command)
293
- command
294
- end
295
-
296
- def run_command
297
- [
298
- sudo("ansible-playbook"),
299
- "-i #{File.join(config[:root_path], 'hosts')}",
300
- "-M #{File.join(config[:root_path], 'modules')}",
301
- ansible_verbose_flag,
302
- ansible_check_flag,
303
- ansible_diff_flag,
304
- ansible_vault_flag,
305
- extra_vars,
306
- tags,
307
- "#{File.join(config[:root_path], File.basename(config[:playbook]))}",
308
- ].join(" ")
309
- end
310
-
311
- protected
312
-
313
- def load_needed_dependencies!
314
- if File.exists?(ansiblefile)
315
- debug("Ansiblefile found at #{ansiblefile}, loading Librarian-Ansible")
316
- Ansible::Librarian.load!(logger)
317
- end
318
- end
319
-
320
- def tmp_modules_dir
321
- File.join(sandbox_path, 'modules')
322
- end
323
-
324
- def tmp_playbook_path
325
- File.join(sandbox_path, File.basename(playbook))
326
- end
327
-
328
- def tmp_host_vars_dir
329
- File.join(sandbox_path, 'host_vars')
330
- end
331
-
332
- def tmp_roles_dir
333
- File.join(sandbox_path, 'roles')
334
- end
335
-
336
- def tmp_filter_plugins_dir
337
- File.join(sandbox_path, 'filter_plugins')
338
- end
339
-
340
- def tmp_ansible_vault_password_file_path
341
- File.join(sandbox_path, File.basename(ansible_vault_password_file))
342
- end
343
-
344
- def ansiblefile
345
- config[:ansiblefile_path] || ''
346
- end
347
-
348
- def galaxy_requirements
349
- config[:requirements_path] || nil
350
- end
351
-
352
- def playbook
353
- config[:playbook]
354
- end
355
-
356
- def hosts
357
- config[:hosts]
358
- end
359
-
360
- def roles
361
- config[:roles_path]
362
- end
363
-
364
- def role_name
365
- File.basename(roles) == 'roles' ? '' : File.basename(roles)
366
- end
367
-
368
- def modules
369
- config[:modules_path]
370
- end
371
-
372
- def group_vars
373
- config[:group_vars_path].to_s
374
- end
375
-
376
- def additional_copy
377
- config[:additional_copy_path]
378
- end
379
-
380
- def host_vars
381
- config[:host_vars_path].to_s
382
- end
383
-
384
- def filter_plugins
385
- config[:filter_plugins_path].to_s
386
- end
387
-
388
- def ansible_vault_password_file
389
- config[:ansible_vault_password_file]
390
- end
391
-
392
- def ansible_debian_version
393
- config[:ansible_version] ? "=#{config[:ansible_version]}" : nil
394
- end
395
-
396
- def ansible_redhat_version
397
- config[:ansible_version] ? "-#{config[:ansible_version]}" : nil
398
- end
399
-
400
- def ansible_verbose_flag
401
- config[:ansible_verbose] ? '-' << ('v' * verbosity_level(config[:ansible_verbosity])) : nil
402
- end
403
-
404
- def ansible_check_flag
405
- config[:ansible_check] ? '--check' : nil
406
- end
407
-
408
- def ansible_diff_flag
409
- config[:ansible_diff] ? '--diff' : nil
410
- end
411
-
412
- def ansible_vault_flag
413
- debug(config[:ansible_vault_password_file])
414
- config[:ansible_vault_password_file] ? "--vault-password-file=#{File.join(config[:root_path], File.basename(config[:ansible_vault_password_file]))}" : nil
415
- end
416
-
417
- def ansible_platform
418
- config[:ansible_platform].to_s.downcase
419
- end
420
-
421
- def update_packages_debian_cmd
422
- config[:update_package_repos] ? "#{sudo('apt-get')} update" : nil
423
- end
424
-
425
- def update_packages_redhat_cmd
426
- config[:update_package_repos] ? "#{sudo('yum')} makecache" : nil
427
- end
428
-
429
- def extra_vars
430
- bash_vars = config[:extra_vars]
431
- if config.key?(:attributes) && config[:attributes].key?(:extra_vars) && config[:attributes][:extra_vars].is_a?(Hash)
432
- bash_vars = config[:attributes][:extra_vars]
433
- end
434
-
435
- return nil if bash_vars.none?
436
- bash_vars = JSON.dump(bash_vars)
437
- bash_vars = "-e '#{bash_vars}'"
438
- debug(bash_vars)
439
- bash_vars
440
- end
441
-
442
- def tags
443
- bash_tags = config.key?(:attributes) && config[:attributes].key?(:tags) && config[:attributes][:tags].is_a?(Array) ? config[:attributes][:tags] : config[:tags]
444
- return nil if bash_tags.empty?
445
-
446
- bash_tags = bash_tags.join(",")
447
- bash_tags = "-t '#{bash_tags}'"
448
- debug(bash_tags)
449
- bash_tags
450
- end
451
-
452
- def ansible_apt_repo
453
- config[:ansible_apt_repo]
454
- end
455
-
456
- def ansible_apt_repo_file
457
- config[:ansible_apt_repo].split('/').last
458
- end
459
-
460
- def ansible_yum_repo
461
- config[:ansible_yum_repo]
462
- end
463
-
464
- def chef_url
465
- config[:chef_bootstrap_url]
466
- end
467
-
468
- def require_ruby_for_busser
469
- config[:require_ruby_for_busser]
470
- end
471
-
472
- def require_chef_for_busser
473
- config[:require_chef_for_busser]
474
- end
475
-
476
- def prepare_roles
477
- info('Preparing roles')
478
- debug("Using roles from #{roles}")
479
-
480
- resolve_with_librarian if File.exists?(ansiblefile)
481
-
482
- if galaxy_requirements
483
- FileUtils.cp(galaxy_requirements, File.join(sandbox_path, galaxy_requirements))
484
- end
485
-
486
- # Detect whether we are running tests on a role
487
- # If so, make sure to copy into VM so dir structure is like: /tmp/kitchen/roles/role_name
488
-
489
- FileUtils.mkdir_p(File.join(tmp_roles_dir, role_name))
490
- FileUtils.cp_r(Dir.glob("#{roles}/*"), File.join(tmp_roles_dir, role_name))
491
- end
492
-
493
- # /etc/ansible/ansible.cfg should contain
494
- # roles_path = /tmp/kitchen/roles
495
- def prepare_ansible_cfg
496
- info('Preparing ansible.cfg file')
497
- ansible_config_file = "#{File.join(sandbox_path, 'ansible.cfg')}"
498
-
499
- roles_paths = []
500
- roles_paths << File.join(config[:root_path], 'roles') unless config[:roles_path].nil?
501
- additional_files.each do |additional_file|
502
- roles_paths << File.join(config[:root_path], File.basename(additional_file))
503
- end
504
-
505
- if roles_paths.empty?
506
- info('No roles have been set. empty ansible.cfg generated')
507
- File.open(ansible_config_file, "wb") do |file|
508
- file.write("#no roles path specified\n")
509
- end
510
- else
511
- debug("Setting roles_path inside VM to #{ roles_paths.join(':') }")
512
- File.open( ansible_config_file, "wb") do |file|
513
- file.write("[defaults]\nroles_path = #{ roles_paths.join(':') }\n")
514
- end
515
- end
516
- end
517
-
518
-
519
- # localhost ansible_connection=local
520
- # [example_servers]
521
- # localhost
522
- def prepare_hosts
523
- info('Preparing hosts file')
524
-
525
- if config[:hosts].nil?
526
- raise 'No hosts have been set. Please specify one in .kitchen.yml'
527
- else
528
- debug("Using host from #{hosts}")
529
- File.open(File.join(sandbox_path, "hosts"), "wb") do |file|
530
- file.write("localhost ansible_connection=local\n[#{hosts}]\nlocalhost\n")
531
- end
532
- end
533
- end
534
-
535
- def prepare_playbook
536
- info('Preparing playbook')
537
- debug("Copying playbook from #{playbook} to #{tmp_playbook_path}")
538
- FileUtils.cp_r(playbook, tmp_playbook_path)
539
- end
540
-
541
-
542
- def prepare_group_vars
543
- info('Preparing group_vars')
544
- tmp_group_vars_dir = File.join(sandbox_path, 'group_vars')
545
- FileUtils.mkdir_p(tmp_group_vars_dir)
546
-
547
- unless File.directory?(group_vars)
548
- info 'nothing to do for group_vars'
549
- return
550
- end
551
-
552
- debug("Using group_vars from #{group_vars}")
553
- FileUtils.cp_r(Dir.glob("#{group_vars}/*"), tmp_group_vars_dir)
554
- end
555
-
556
- def prepare_additional_copy_path
557
- info('Preparing additional_copy_path')
558
- additional_files.each do |file|
559
- destination = File.join(sandbox_path, File.basename(file))
560
- if File.directory?(file)
561
- info("Copy dir: #{file} #{destination}")
562
- FileUtils.cp_r(file, destination)
563
- else
564
- info("Copy file: #{file} #{destination}")
565
- FileUtils.cp file, destination
566
- end
567
- end
568
- end
569
-
570
- def additional_files
571
- additional_files = []
572
- if ( additional_copy )
573
- additional_files = additional_copy.kind_of?(Array) ? additional_copy : [additional_copy]
574
- end
575
- additional_files.map { |additional_dir | additional_dir.to_s }
576
- end
577
-
578
- def prepare_host_vars
579
- info('Preparing host_vars')
580
- FileUtils.mkdir_p(tmp_host_vars_dir)
581
-
582
- unless File.directory?(host_vars)
583
- info 'nothing to do for host_vars'
584
- return
585
- end
586
-
587
- debug("Using host_vars from #{host_vars}")
588
- FileUtils.cp_r(Dir.glob("#{host_vars}/*"), tmp_host_vars_dir)
589
- end
590
-
591
- def prepare_modules
592
- info('Preparing modules')
593
-
594
- FileUtils.mkdir_p(tmp_modules_dir)
595
-
596
- if modules && File.directory?(modules)
597
- debug("Using modules from #{modules}")
598
- FileUtils.cp_r(Dir.glob("#{modules}/*"), tmp_modules_dir, remove_destination: true)
599
- else
600
- info 'nothing to do for modules'
601
- end
602
- end
603
-
604
- def prepare_filter_plugins
605
- info('Preparing filter_plugins')
606
- FileUtils.mkdir_p(tmp_filter_plugins_dir)
607
-
608
- if filter_plugins && File.directory?(filter_plugins)
609
- debug("Using filter_plugins from #{filter_plugins}")
610
- FileUtils.cp_r(Dir.glob("#{filter_plugins}/*.py"), tmp_filter_plugins_dir, remove_destination: true)
611
- else
612
- info 'nothing to do for filter_plugins'
613
- end
614
- end
615
-
616
- def prepare_ansible_vault_password_file
617
- if ansible_vault_password_file
618
- info('Preparing ansible vault password')
619
- debug("Copying ansible vault password file from #{ansible_vault_password_file} to #{tmp_ansible_vault_password_file_path}")
620
-
621
- FileUtils.cp(ansible_vault_password_file, tmp_ansible_vault_password_file_path)
622
- end
623
- end
624
-
625
- def resolve_with_librarian
626
- Kitchen.mutex.synchronize do
627
- Ansible::Librarian.new(ansiblefile, tmp_roles_dir, logger).resolve
628
- end
629
- end
630
- end
631
- end
632
- 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_repo]
72
+ case ansible_platform
73
+ when "debian", "ubuntu"
74
+ info("Installing ansible on #{ansible_platform}")
75
+ cmd = install_debian_command
76
+ when "redhat", "centos", "fedora"
77
+ info("Installing ansible on #{ansible_platform}")
78
+ cmd = install_redhat_command
79
+ when "amazon"
80
+ info("Installing ansible on #{ansible_platform}")
81
+ cmd = install_amazon_linux_command
82
+ else
83
+ info("Installing ansible, will try to determine platform os")
84
+ cmd = <<-INSTALL
85
+ if [ ! $(which ansible) ]; then
86
+ if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
87
+ if ! [ grep -q 'Amazon Linux' /etc/system-release ]; then
88
+ #{install_redhat_command}
89
+ else
90
+ #{install_amazon_linux_command}
91
+ fi
92
+ else
93
+ #{install_debian_command}
94
+ fi
95
+ fi
96
+ INSTALL
97
+ end
98
+ elsif config[:require_ansible_source]
99
+ info("Installing ansible from source")
100
+ cmd = install_ansible_from_source_command
101
+ else
102
+ return
103
+ end
104
+ cmd + install_busser_prereqs
105
+ end
106
+
107
+ def install_busser_prereqs
108
+ install = ''
109
+ install << <<-INSTALL
110
+ #{Util.shell_helpers}
111
+ # Fix for https://github.com/test-kitchen/busser/issues/12
112
+ if [ -h /usr/bin/ruby ]; then
113
+ L=$(readlink -f /usr/bin/ruby)
114
+ #{sudo('rm')} /usr/bin/ruby
115
+ #{sudo('ln')} -s $L /usr/bin/ruby
116
+ fi
117
+ INSTALL
118
+
119
+ if require_ruby_for_busser
120
+ install << <<-INSTALL
121
+ if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
122
+ if ! [ grep -q 'Amazon Linux' /etc/system-release ]; then
123
+ rhelversion=$(cat /etc/redhat-release | grep 'release 6')
124
+ # For CentOS6/RHEL6 install ruby from SCL
125
+ if [ -n "$rhelversion" ]; then
126
+ if [ ! -d "/opt/rh/ruby193" ]; then
127
+ echo "-----> Installing ruby SCL in CentOS6/RHEL6 to install busser to run tests"
128
+ #{sudo('yum')} install -y centos-release-SCL
129
+ #{sudo('yum')} install -y ruby193
130
+ #{sudo('yum')} install -y ruby193-ruby-devel
131
+ echo "-----> Enabling ruby193"
132
+ source /opt/rh/ruby193/enable
133
+ echo "/opt/rh/ruby193/root/usr/lib64" | sudo tee -a /etc/ld.so.conf
134
+ sudo ldconfig
135
+ sudo ln -s /opt/rh/ruby193/root/usr/bin/ruby /usr/bin/ruby
136
+ sudo ln -s /opt/rh/ruby193/root/usr/bin/gem /usr/bin/gem
137
+ fi
138
+ else
139
+ if [ ! $(which ruby) ]; then
140
+ #{update_packages_redhat_cmd}
141
+ #{sudo('yum')} -y install ruby ruby-devel
142
+ fi
143
+ fi
144
+ else
145
+ #{update_packages_redhat_cmd}
146
+ #{sudo('yum')} -y install ruby ruby-devel gcc
147
+ fi
148
+ else
149
+ if [ ! $(which ruby) ]; then
150
+ #{update_packages_debian_cmd}
151
+ #{sudo('apt-get')} -y install ruby1.9.1 ruby1.9.1-dev
152
+ fi
153
+ fi
154
+ INSTALL
155
+
156
+ elsif require_chef_for_busser && chef_url then
157
+ install << <<-INSTALL
158
+ # install chef omnibus so that busser works as this is needed to run tests :(
159
+ if [ ! -d "/opt/chef" ]
160
+ then
161
+ echo "-----> Installing Chef Omnibus to install busser to run tests"
162
+ do_download #{chef_url} /tmp/install.sh
163
+ #{sudo('sh')} /tmp/install.sh
164
+ fi
165
+ INSTALL
166
+ end
167
+
168
+ install
169
+ end
170
+
171
+ def init_command
172
+ dirs = %w{modules roles group_vars host_vars}.
173
+ map { |dir| File.join(config[:root_path], dir) }.join(" ")
174
+ cmd = "#{sudo('rm')} -rf #{dirs};"
175
+ cmd = cmd+" mkdir -p #{config[:root_path]}"
176
+ debug(cmd)
177
+ cmd
178
+ end
179
+
180
+ def create_sandbox
181
+ super
182
+ debug("Creating local sandbox in #{sandbox_path}")
183
+
184
+ yield if block_given?
185
+
186
+ prepare_playbook
187
+ prepare_modules
188
+ prepare_roles
189
+ prepare_ansible_cfg
190
+ prepare_group_vars
191
+ prepare_additional_copy_path
192
+ prepare_host_vars
193
+ prepare_hosts
194
+ prepare_filter_plugins
195
+ prepare_ansible_vault_password_file
196
+ info('Finished Preparing files for transfer')
197
+
198
+ end
199
+
200
+ def cleanup_sandbox
201
+ return if sandbox_path.nil?
202
+ debug("Cleaning up local sandbox in #{sandbox_path}")
203
+ FileUtils.rmtree(sandbox_path)
204
+ end
205
+
206
+ def prepare_command
207
+ commands = []
208
+
209
+ # Prevent failure when ansible package installation doesn't contain /etc/ansible
210
+ commands << [
211
+ sudo("bash -c '[ -d /etc/ansible ] || mkdir /etc/ansible'")
212
+ ]
213
+
214
+ commands << [
215
+ sudo('cp'),File.join(config[:root_path], 'ansible.cfg'),'/etc/ansible',
216
+ ].join(' ')
217
+
218
+ commands << [
219
+ sudo('cp -r'), File.join(config[:root_path],'group_vars'), '/etc/ansible/.',
220
+ ].join(' ')
221
+
222
+ commands << [
223
+ sudo('cp -r'), File.join(config[:root_path],'host_vars'), '/etc/ansible/.',
224
+ ].join(' ')
225
+
226
+ if galaxy_requirements
227
+ if config[:require_ansible_source]
228
+ commands << setup_ansible_env_from_source
229
+ end
230
+ commands << [
231
+ 'ansible-galaxy', 'install', '--force',
232
+ '-p', File.join(config[:root_path], 'roles'),
233
+ '-r', File.join(config[:root_path], galaxy_requirements),
234
+ ].join(' ')
235
+ end
236
+
237
+ command = commands.join(' && ')
238
+ debug(command)
239
+ command
240
+ end
241
+
242
+ def run_command
243
+ if config[:require_ansible_source]
244
+ cmd = "#{setup_ansible_env_from_source} && ansible-playbook"
245
+ else
246
+ cmd = sudo("ansible-playbook")
247
+ end
248
+ [
249
+ cmd,
250
+ "-i #{File.join(config[:root_path], 'hosts')}",
251
+ "-M #{File.join(config[:root_path], 'modules')}",
252
+ ansible_verbose_flag,
253
+ ansible_check_flag,
254
+ ansible_diff_flag,
255
+ ansible_vault_flag,
256
+ extra_vars,
257
+ tags,
258
+ "#{File.join(config[:root_path], File.basename(config[:playbook]))}",
259
+ ].join(" ")
260
+ end
261
+
262
+ protected
263
+
264
+ def load_needed_dependencies!
265
+ if File.exists?(ansiblefile)
266
+ debug("Ansiblefile found at #{ansiblefile}, loading Librarian-Ansible")
267
+ Ansible::Librarian.load!(logger)
268
+ end
269
+ end
270
+
271
+ def install_ansible_from_source_command
272
+ <<-INSTALL
273
+ if [ ! -d #{config[:root_path]}/ansible ]; then
274
+ if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ]; then
275
+ #{update_packages_redhat_cmd}
276
+ #{sudo('yum')} -y install libselinux-python python2-devel git python-setuptools python-setuptools-dev
277
+ else
278
+ #{update_packages_debian_cmd}
279
+ #{sudo('apt-get')} -y install git python python-setuptools
280
+ fi
281
+
282
+ git clone git://github.com/ansible/ansible.git --recursive #{config[:root_path]}/ansible
283
+ #{sudo('easy_install')} pip
284
+ sudo -EH 'pip' install paramiko PyYAML Jinja2 httplib2
285
+ fi
286
+ INSTALL
287
+ end
288
+
289
+ def install_omnibus_command
290
+ info("Installing ansible using ansible omnibus")
291
+ version = if !config[:ansible_version].nil?
292
+ "-v #{config[:ansible_version]}"
293
+ else
294
+ ""
295
+ end
296
+ <<-INSTALL
297
+ #{Util.shell_helpers}
298
+
299
+ if [ ! -d "#{config[:ansible_omnibus_remote_path]}" ]; then
300
+ echo "-----> Installing Ansible Omnibus"
301
+ do_download #{config[:ansible_omnibus_url]} /tmp/ansible_install.sh
302
+ #{sudo('sh')} /tmp/ansible_install.sh #{version}
303
+ fi
304
+ INSTALL
305
+ end
306
+
307
+ def install_debian_command
308
+ <<-INSTALL
309
+ if [ ! $(which ansible) ]; then
310
+ #{update_packages_debian_cmd}
311
+
312
+ ## Install apt-utils to silence debconf warning: http://serverfault.com/q/358943/77156
313
+ #{sudo('apt-get')} -y install apt-utils git
314
+
315
+ ## Fix debconf tty warning messages
316
+ export DEBIAN_FRONTEND=noninteractive
317
+
318
+ ## 13.10, 14.04 include add-apt-repository in software-properties-common
319
+ #{sudo('apt-get')} -y install software-properties-common
320
+
321
+ ## 10.04, 12.04 include add-apt-repository in
322
+ #{sudo('apt-get')} -y install python-software-properties
323
+
324
+ ## 10.04 version of add-apt-repository doesn't accept --yes
325
+ ## later versions require interaction from user, so we must specify --yes
326
+ ## First try with -y flag, else if it fails, try without.
327
+ ## "add-apt-repository: error: no such option: -y" is returned but is ok to ignore, we just retry
328
+ #{sudo('add-apt-repository')} -y #{ansible_apt_repo} || #{sudo('add-apt-repository')} #{ansible_apt_repo}
329
+ #{sudo('apt-get')} update
330
+ #{sudo('apt-get')} -y install ansible
331
+ fi
332
+ INSTALL
333
+ end
334
+
335
+ def install_redhat_command
336
+ <<-INSTALL
337
+ if [ ! $(which ansible) ]; then
338
+ #{sudo('rpm')} -ivh #{ansible_yum_repo}
339
+ #{update_packages_redhat_cmd}
340
+ #{sudo('yum')} -y install ansible#{ansible_redhat_version} libselinux-python git
341
+ fi
342
+ INSTALL
343
+ end
344
+
345
+ def install_amazon_linux_command
346
+ <<-INSTALL
347
+ if [ ! $(which ansible) ]; then
348
+ #{sudo('yum-config-manager')} --enable epel/x86_64
349
+ #{sudo('yum')} -y install ansible#{ansible_redhat_version} git
350
+ #{sudo('alternatives')} --set python /usr/bin/python2.6
351
+ #{sudo('yum')} clean all
352
+ #{sudo('yum')} install yum-python26 -y
353
+ fi
354
+ INSTALL
355
+ end
356
+
357
+ def setup_ansible_env_from_source
358
+ "cd #{config[:root_path]}/ansible && source hacking/env-setup && cd ../"
359
+ end
360
+
361
+ def tmp_modules_dir
362
+ File.join(sandbox_path, 'modules')
363
+ end
364
+
365
+ def tmp_playbook_path
366
+ File.join(sandbox_path, File.basename(playbook))
367
+ end
368
+
369
+ def tmp_host_vars_dir
370
+ File.join(sandbox_path, 'host_vars')
371
+ end
372
+
373
+ def tmp_roles_dir
374
+ File.join(sandbox_path, 'roles')
375
+ end
376
+
377
+ def tmp_filter_plugins_dir
378
+ File.join(sandbox_path, 'filter_plugins')
379
+ end
380
+
381
+ def tmp_ansible_vault_password_file_path
382
+ File.join(sandbox_path, File.basename(ansible_vault_password_file))
383
+ end
384
+
385
+ def ansiblefile
386
+ config[:ansiblefile_path] || ''
387
+ end
388
+
389
+ def galaxy_requirements
390
+ config[:requirements_path] || nil
391
+ end
392
+
393
+ def playbook
394
+ config[:playbook]
395
+ end
396
+
397
+ def hosts
398
+ config[:hosts]
399
+ end
400
+
401
+ def roles
402
+ config[:roles_path]
403
+ end
404
+
405
+ def role_name
406
+ File.basename(roles) == 'roles' ? '' : File.basename(roles)
407
+ end
408
+
409
+ def modules
410
+ config[:modules_path]
411
+ end
412
+
413
+ def group_vars
414
+ config[:group_vars_path].to_s
415
+ end
416
+
417
+ def additional_copy
418
+ config[:additional_copy_path]
419
+ end
420
+
421
+ def host_vars
422
+ config[:host_vars_path].to_s
423
+ end
424
+
425
+ def filter_plugins
426
+ config[:filter_plugins_path].to_s
427
+ end
428
+
429
+ def ansible_vault_password_file
430
+ config[:ansible_vault_password_file]
431
+ end
432
+
433
+ def ansible_debian_version
434
+ config[:ansible_version] ? "=#{config[:ansible_version]}" : nil
435
+ end
436
+
437
+ def ansible_redhat_version
438
+ config[:ansible_version] ? "-#{config[:ansible_version]}" : nil
439
+ end
440
+
441
+ def ansible_verbose_flag
442
+ config[:ansible_verbose] ? '-' << ('v' * verbosity_level(config[:ansible_verbosity])) : nil
443
+ end
444
+
445
+ def ansible_check_flag
446
+ config[:ansible_check] ? '--check' : nil
447
+ end
448
+
449
+ def ansible_diff_flag
450
+ config[:ansible_diff] ? '--diff' : nil
451
+ end
452
+
453
+ def ansible_vault_flag
454
+ debug(config[:ansible_vault_password_file])
455
+ config[:ansible_vault_password_file] ? "--vault-password-file=#{File.join(config[:root_path], File.basename(config[:ansible_vault_password_file]))}" : nil
456
+ end
457
+
458
+ def ansible_platform
459
+ config[:ansible_platform].to_s.downcase
460
+ end
461
+
462
+ def update_packages_debian_cmd
463
+ config[:update_package_repos] ? "#{sudo('apt-get')} update" : nil
464
+ end
465
+
466
+ def update_packages_redhat_cmd
467
+ config[:update_package_repos] ? "#{sudo('yum')} makecache" : nil
468
+ end
469
+
470
+ def extra_vars
471
+ bash_vars = config[:extra_vars]
472
+ if config.key?(:attributes) && config[:attributes].key?(:extra_vars) && config[:attributes][:extra_vars].is_a?(Hash)
473
+ bash_vars = config[:attributes][:extra_vars]
474
+ end
475
+
476
+ return nil if bash_vars.none?
477
+ bash_vars = JSON.dump(bash_vars)
478
+ bash_vars = "-e '#{bash_vars}'"
479
+ debug(bash_vars)
480
+ bash_vars
481
+ end
482
+
483
+ def tags
484
+ bash_tags = config.key?(:attributes) && config[:attributes].key?(:tags) && config[:attributes][:tags].is_a?(Array) ? config[:attributes][:tags] : config[:tags]
485
+ return nil if bash_tags.empty?
486
+
487
+ bash_tags = bash_tags.join(",")
488
+ bash_tags = "-t '#{bash_tags}'"
489
+ debug(bash_tags)
490
+ bash_tags
491
+ end
492
+
493
+ def ansible_apt_repo
494
+ config[:ansible_apt_repo]
495
+ end
496
+
497
+ def ansible_apt_repo_file
498
+ config[:ansible_apt_repo].split('/').last
499
+ end
500
+
501
+ def ansible_yum_repo
502
+ config[:ansible_yum_repo]
503
+ end
504
+
505
+ def chef_url
506
+ config[:chef_bootstrap_url]
507
+ end
508
+
509
+ def require_ruby_for_busser
510
+ config[:require_ruby_for_busser]
511
+ end
512
+
513
+ def require_chef_for_busser
514
+ config[:require_chef_for_busser]
515
+ end
516
+
517
+ def prepare_roles
518
+ info('Preparing roles')
519
+ debug("Using roles from #{roles}")
520
+
521
+ resolve_with_librarian if File.exists?(ansiblefile)
522
+
523
+ if galaxy_requirements
524
+ FileUtils.cp(galaxy_requirements, File.join(sandbox_path, galaxy_requirements))
525
+ end
526
+
527
+ # Detect whether we are running tests on a role
528
+ # If so, make sure to copy into VM so dir structure is like: /tmp/kitchen/roles/role_name
529
+
530
+ FileUtils.mkdir_p(File.join(tmp_roles_dir, role_name))
531
+ FileUtils.cp_r(Dir.glob("#{roles}/*"), File.join(tmp_roles_dir, role_name))
532
+ end
533
+
534
+ # /etc/ansible/ansible.cfg should contain
535
+ # roles_path = /tmp/kitchen/roles
536
+ def prepare_ansible_cfg
537
+ info('Preparing ansible.cfg file')
538
+ ansible_config_file = "#{File.join(sandbox_path, 'ansible.cfg')}"
539
+
540
+ roles_paths = []
541
+ roles_paths << File.join(config[:root_path], 'roles') unless config[:roles_path].nil?
542
+ additional_files.each do |additional_file|
543
+ roles_paths << File.join(config[:root_path], File.basename(additional_file))
544
+ end
545
+
546
+ if roles_paths.empty?
547
+ info('No roles have been set. empty ansible.cfg generated')
548
+ File.open(ansible_config_file, "wb") do |file|
549
+ file.write("#no roles path specified\n")
550
+ end
551
+ else
552
+ debug("Setting roles_path inside VM to #{ roles_paths.join(':') }")
553
+ File.open( ansible_config_file, "wb") do |file|
554
+ file.write("[defaults]\nroles_path = #{ roles_paths.join(':') }\n")
555
+ end
556
+ end
557
+ end
558
+
559
+
560
+ # localhost ansible_connection=local
561
+ # [example_servers]
562
+ # localhost
563
+ def prepare_hosts
564
+ info('Preparing hosts file')
565
+
566
+ if config[:hosts].nil?
567
+ raise 'No hosts have been set. Please specify one in .kitchen.yml'
568
+ else
569
+ debug("Using host from #{hosts}")
570
+ File.open(File.join(sandbox_path, "hosts"), "wb") do |file|
571
+ file.write("localhost ansible_connection=local\n[#{hosts}]\nlocalhost\n")
572
+ end
573
+ end
574
+ end
575
+
576
+ def prepare_playbook
577
+ info('Preparing playbook')
578
+ debug("Copying playbook from #{playbook} to #{tmp_playbook_path}")
579
+ FileUtils.cp_r(playbook, tmp_playbook_path)
580
+ end
581
+
582
+
583
+ def prepare_group_vars
584
+ info('Preparing group_vars')
585
+ tmp_group_vars_dir = File.join(sandbox_path, 'group_vars')
586
+ FileUtils.mkdir_p(tmp_group_vars_dir)
587
+
588
+ unless File.directory?(group_vars)
589
+ info 'nothing to do for group_vars'
590
+ return
591
+ end
592
+
593
+ debug("Using group_vars from #{group_vars}")
594
+ FileUtils.cp_r(Dir.glob("#{group_vars}/*"), tmp_group_vars_dir)
595
+ end
596
+
597
+ def prepare_additional_copy_path
598
+ info('Preparing additional_copy_path')
599
+ additional_files.each do |file|
600
+ destination = File.join(sandbox_path, File.basename(file))
601
+ if File.directory?(file)
602
+ info("Copy dir: #{file} #{destination}")
603
+ FileUtils.cp_r(file, destination)
604
+ else
605
+ info("Copy file: #{file} #{destination}")
606
+ FileUtils.cp file, destination
607
+ end
608
+ end
609
+ end
610
+
611
+ def additional_files
612
+ additional_files = []
613
+ if ( additional_copy )
614
+ additional_files = additional_copy.kind_of?(Array) ? additional_copy : [additional_copy]
615
+ end
616
+ additional_files.map { |additional_dir | additional_dir.to_s }
617
+ end
618
+
619
+ def prepare_host_vars
620
+ info('Preparing host_vars')
621
+ FileUtils.mkdir_p(tmp_host_vars_dir)
622
+
623
+ unless File.directory?(host_vars)
624
+ info 'nothing to do for host_vars'
625
+ return
626
+ end
627
+
628
+ debug("Using host_vars from #{host_vars}")
629
+ FileUtils.cp_r(Dir.glob("#{host_vars}/*"), tmp_host_vars_dir)
630
+ end
631
+
632
+ def prepare_modules
633
+ info('Preparing modules')
634
+
635
+ FileUtils.mkdir_p(tmp_modules_dir)
636
+
637
+ if modules && File.directory?(modules)
638
+ debug("Using modules from #{modules}")
639
+ FileUtils.cp_r(Dir.glob("#{modules}/*"), tmp_modules_dir, remove_destination: true)
640
+ else
641
+ info 'nothing to do for modules'
642
+ end
643
+ end
644
+
645
+ def prepare_filter_plugins
646
+ info('Preparing filter_plugins')
647
+ FileUtils.mkdir_p(tmp_filter_plugins_dir)
648
+
649
+ if filter_plugins && File.directory?(filter_plugins)
650
+ debug("Using filter_plugins from #{filter_plugins}")
651
+ FileUtils.cp_r(Dir.glob("#{filter_plugins}/*.py"), tmp_filter_plugins_dir, remove_destination: true)
652
+ else
653
+ info 'nothing to do for filter_plugins'
654
+ end
655
+ end
656
+
657
+ def prepare_ansible_vault_password_file
658
+ if ansible_vault_password_file
659
+ info('Preparing ansible vault password')
660
+ debug("Copying ansible vault password file from #{ansible_vault_password_file} to #{tmp_ansible_vault_password_file_path}")
661
+
662
+ FileUtils.cp(ansible_vault_password_file, tmp_ansible_vault_password_file_path)
663
+ end
664
+ end
665
+
666
+ def resolve_with_librarian
667
+ Kitchen.mutex.synchronize do
668
+ Ansible::Librarian.new(ansiblefile, tmp_roles_dir, logger).resolve
669
+ end
670
+ end
671
+ end
672
+ end
673
+ end