test-kitchen 1.0.0.beta.3 → 1.0.0.beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +2 -0
- data/CHANGELOG.md +41 -0
- data/Gemfile +3 -2
- data/Rakefile +1 -0
- data/lib/kitchen.rb +2 -16
- data/lib/kitchen/busser.rb +38 -14
- data/lib/kitchen/cli.rb +11 -16
- data/lib/kitchen/config.rb +2 -47
- data/lib/kitchen/driver/base.rb +1 -2
- data/lib/kitchen/driver/proxy.rb +58 -0
- data/lib/kitchen/driver/ssh_base.rb +6 -0
- data/lib/kitchen/instance.rb +0 -1
- data/lib/kitchen/provisioner/chef_base.rb +78 -44
- data/lib/kitchen/provisioner/chef_solo.rb +18 -1
- data/lib/kitchen/provisioner/chef_zero.rb +39 -6
- data/lib/kitchen/rake_tasks.rb +0 -1
- data/lib/kitchen/ssh.rb +1 -0
- data/lib/kitchen/suite.rb +17 -0
- data/lib/kitchen/thor_tasks.rb +0 -1
- data/lib/kitchen/util.rb +120 -0
- data/lib/kitchen/version.rb +1 -1
- data/spec/kitchen/instance_spec.rb +0 -4
- data/test-kitchen.gemspec +22 -25
- metadata +73 -116
- data/lib/kitchen/instance_actor.rb +0 -42
- data/lib/kitchen/manager.rb +0 -45
data/lib/kitchen/driver/base.rb
CHANGED
@@ -160,11 +160,10 @@ module Kitchen
|
|
160
160
|
end
|
161
161
|
|
162
162
|
def busser
|
163
|
-
test_root = File.join(config[:kitchen_root], 'test/integration')
|
164
163
|
@busser ||= begin
|
165
164
|
raise ClientError, "Instance must be set for Driver" if instance.nil?
|
166
165
|
|
167
|
-
Busser.new(instance.suite.name,
|
166
|
+
Busser.new(instance.suite.name, config)
|
168
167
|
end
|
169
168
|
end
|
170
169
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Seth Chisamore <schisamo@opscode.com>
|
3
|
+
#
|
4
|
+
# Copyright:: Copyright (c) 2013 Opscode, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
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 'kitchen/driver/ssh_base'
|
21
|
+
|
22
|
+
module Kitchen
|
23
|
+
|
24
|
+
module Driver
|
25
|
+
|
26
|
+
# Proxy driver for Test Kitchen.
|
27
|
+
#
|
28
|
+
# @author Seth Chisamore <schisamo@opscode.com>
|
29
|
+
class Proxy < Kitchen::Driver::SSHBase
|
30
|
+
|
31
|
+
required_config :host
|
32
|
+
required_config :reset_command
|
33
|
+
|
34
|
+
no_parallel_for :create, :destroy
|
35
|
+
|
36
|
+
def create(state)
|
37
|
+
state[:hostname] = config[:host]
|
38
|
+
reset_instance(state)
|
39
|
+
end
|
40
|
+
|
41
|
+
def destroy(state)
|
42
|
+
return if state[:hostname].nil?
|
43
|
+
reset_instance(state)
|
44
|
+
state.delete(:hostname)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def reset_instance(state)
|
50
|
+
if cmd = config[:reset_command]
|
51
|
+
info("Resetting instance state with command: #{cmd}")
|
52
|
+
ssh(build_ssh_args(state), cmd)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -91,6 +91,7 @@ module Kitchen
|
|
91
91
|
opts[:user_known_hosts_file] = "/dev/null"
|
92
92
|
opts[:paranoid] = false
|
93
93
|
opts[:password] = combined[:password] if combined[:password]
|
94
|
+
opts[:forward_agent] = combined[:forward_agent] if combined.key? :forward_agent
|
94
95
|
opts[:port] = combined[:port] if combined[:port]
|
95
96
|
opts[:keys] = Array(combined[:ssh_key]) if combined[:ssh_key]
|
96
97
|
opts[:logger] = logger
|
@@ -103,6 +104,11 @@ module Kitchen
|
|
103
104
|
env << " http_proxy=#{config[:http_proxy]}" if config[:http_proxy]
|
104
105
|
env << " https_proxy=#{config[:https_proxy]}" if config[:https_proxy]
|
105
106
|
|
107
|
+
additional_paths = []
|
108
|
+
additional_paths << config[:ruby_binpath] if config[:ruby_binpath]
|
109
|
+
additional_paths << config[:path] if config[:path]
|
110
|
+
env << " PATH=$PATH:#{additional_paths.join(':')}" if additional_paths.any?
|
111
|
+
|
106
112
|
env == "env" ? cmd : "#{env} #{cmd}"
|
107
113
|
end
|
108
114
|
|
data/lib/kitchen/instance.rb
CHANGED
@@ -16,8 +16,11 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
|
19
|
+
require 'buff/ignore'
|
19
20
|
require 'fileutils'
|
21
|
+
require 'pathname'
|
20
22
|
require 'json'
|
23
|
+
require 'kitchen/util'
|
21
24
|
|
22
25
|
module Kitchen
|
23
26
|
|
@@ -34,32 +37,27 @@ module Kitchen
|
|
34
37
|
url = config[:chef_omnibus_url] || "https://www.opscode.com/chef/install.sh"
|
35
38
|
flag = config[:require_chef_omnibus]
|
36
39
|
version = if flag.is_a?(String) && flag != "latest"
|
37
|
-
"-
|
40
|
+
"-v #{flag.downcase}"
|
38
41
|
else
|
39
42
|
""
|
40
43
|
end
|
41
44
|
|
45
|
+
# use Bourne (/bin/sh) as Bash does not exist on all Unix flavors
|
42
46
|
<<-INSTALL.gsub(/^ {10}/, '')
|
43
|
-
|
47
|
+
sh -c '
|
48
|
+
#{Util.shell_helpers}
|
49
|
+
|
44
50
|
should_update_chef() {
|
45
51
|
case "#{flag}" in
|
46
|
-
true
|
52
|
+
true|`chef-solo -v | cut -d " " -f 2`) return 1 ;;
|
47
53
|
latest|*) return 0 ;;
|
48
54
|
esac
|
49
55
|
}
|
50
56
|
|
51
57
|
if [ ! -d "/opt/chef" ] || should_update_chef ; then
|
52
|
-
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
53
|
-
export PATH
|
54
58
|
echo "-----> Installing Chef Omnibus (#{flag})"
|
55
|
-
|
56
|
-
|
57
|
-
elif command -v curl >/dev/null ; then
|
58
|
-
curl -sSL #{url} | #{sudo('bash')} #{version}
|
59
|
-
else
|
60
|
-
echo ">>>>>> Neither wget nor curl found on this instance."
|
61
|
-
exit 16
|
62
|
-
fi
|
59
|
+
do_download #{url} /tmp/install.sh
|
60
|
+
#{sudo('sh')} /tmp/install.sh #{version}
|
63
61
|
fi'
|
64
62
|
INSTALL
|
65
63
|
end
|
@@ -79,6 +77,7 @@ module Kitchen
|
|
79
77
|
|
80
78
|
def create_chef_sandbox
|
81
79
|
@tmpdir = Dir.mktmpdir("#{instance.name}-sandbox-")
|
80
|
+
File.chmod(0755, @tmpdir)
|
82
81
|
debug("Creating local sandbox in #{tmpdir}")
|
83
82
|
|
84
83
|
yield if block_given?
|
@@ -86,6 +85,7 @@ module Kitchen
|
|
86
85
|
prepare_data_bags
|
87
86
|
prepare_roles
|
88
87
|
prepare_nodes
|
88
|
+
prepare_environments
|
89
89
|
prepare_secret
|
90
90
|
prepare_cache
|
91
91
|
prepare_cookbooks
|
@@ -131,6 +131,17 @@ module Kitchen
|
|
131
131
|
FileUtils.cp_r(Dir.glob("#{nodes}/*"), tmpnodes_dir)
|
132
132
|
end
|
133
133
|
|
134
|
+
def prepare_environments
|
135
|
+
return unless environments
|
136
|
+
|
137
|
+
info("Preparing environments")
|
138
|
+
debug("Using environments from #{environments}")
|
139
|
+
|
140
|
+
tmpenvs_dir = File.join(tmpdir, "environments")
|
141
|
+
FileUtils.mkdir_p(tmpenvs_dir)
|
142
|
+
FileUtils.cp_r(Dir.glob("#{environments}/*"), tmpenvs_dir)
|
143
|
+
end
|
144
|
+
|
134
145
|
def prepare_secret
|
135
146
|
return unless secret
|
136
147
|
|
@@ -160,27 +171,19 @@ module Kitchen
|
|
160
171
|
raise UserError, "Cookbooks could not be found"
|
161
172
|
end
|
162
173
|
|
163
|
-
|
174
|
+
remove_ignored_files
|
164
175
|
end
|
165
176
|
|
166
|
-
def
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
def cookbook_files_glob
|
178
|
-
files = %w{README.* metadata.{json,rb}
|
179
|
-
attributes/**/* definitions/**/* files/**/* libraries/**/*
|
180
|
-
providers/**/* recipes/**/* resources/**/* templates/**/*
|
181
|
-
}
|
182
|
-
|
183
|
-
"*/{#{files.join(',')}}"
|
177
|
+
def remove_ignored_files
|
178
|
+
cookbooks_in_tmpdir do |cookbook_path|
|
179
|
+
chefignore = File.join(cookbook_path, "chefignore")
|
180
|
+
if File.exist? chefignore
|
181
|
+
ignores = Buff::Ignore::IgnoreFile.new(chefignore)
|
182
|
+
cookbook_files = Dir.glob(File.join(cookbook_path, "**/*"), File::FNM_DOTMATCH).
|
183
|
+
select { |fn| File.file?(fn) && fn != '.' && fn != '..' }
|
184
|
+
cookbook_files.each { |file| FileUtils.rm(file) if ignores.ignored?(file) }
|
185
|
+
end
|
186
|
+
end
|
184
187
|
end
|
185
188
|
|
186
189
|
def berksfile
|
@@ -199,6 +202,10 @@ module Kitchen
|
|
199
202
|
File.join(kitchen_root, "cookbooks")
|
200
203
|
end
|
201
204
|
|
205
|
+
def site_cookbooks_dir
|
206
|
+
File.join(kitchen_root, "site-cookbooks")
|
207
|
+
end
|
208
|
+
|
202
209
|
def data_bags
|
203
210
|
instance.suite.data_bags_path
|
204
211
|
end
|
@@ -211,6 +218,10 @@ module Kitchen
|
|
211
218
|
instance.suite.nodes_path
|
212
219
|
end
|
213
220
|
|
221
|
+
def environments
|
222
|
+
instance.suite.environments_path
|
223
|
+
end
|
224
|
+
|
214
225
|
def secret
|
215
226
|
instance.suite.encrypted_data_bag_secret_key_path
|
216
227
|
end
|
@@ -219,12 +230,23 @@ module Kitchen
|
|
219
230
|
File.join(tmpdir, "cookbooks")
|
220
231
|
end
|
221
232
|
|
233
|
+
def tmpsitebooks_dir
|
234
|
+
File.join(tmpdir, "cookbooks")
|
235
|
+
end
|
236
|
+
|
222
237
|
def cp_cookbooks
|
223
238
|
info("Preparing cookbooks from project directory")
|
224
239
|
debug("Using cookbooks from #{cookbooks_dir}")
|
225
240
|
|
226
241
|
FileUtils.mkdir_p(tmpbooks_dir)
|
227
242
|
FileUtils.cp_r(File.join(cookbooks_dir, "."), tmpbooks_dir)
|
243
|
+
|
244
|
+
info("Preparing site-cookbooks from project directory")
|
245
|
+
debug("Using cookbooks from #{site_cookbooks_dir}")
|
246
|
+
|
247
|
+
FileUtils.mkdir_p(tmpsitebooks_dir)
|
248
|
+
FileUtils.cp_r(File.join(site_cookbooks_dir, "."), tmpsitebooks_dir)
|
249
|
+
|
228
250
|
cp_this_cookbook if File.exists?(metadata_rb)
|
229
251
|
end
|
230
252
|
|
@@ -237,8 +259,8 @@ module Kitchen
|
|
237
259
|
" Please add: `name '<cookbook_name>'` to metadata.rb and retry")
|
238
260
|
|
239
261
|
cb_path = File.join(tmpbooks_dir, cb_name)
|
240
|
-
|
241
|
-
|
262
|
+
|
263
|
+
glob = Dir.glob("#{kitchen_root}/**")
|
242
264
|
|
243
265
|
FileUtils.mkdir_p(cb_path)
|
244
266
|
FileUtils.cp_r(glob, cb_path)
|
@@ -250,11 +272,13 @@ module Kitchen
|
|
250
272
|
|
251
273
|
begin
|
252
274
|
require 'berkshelf'
|
253
|
-
rescue LoadError
|
254
|
-
fatal("The `
|
255
|
-
"
|
256
|
-
"
|
257
|
-
|
275
|
+
rescue LoadError => e
|
276
|
+
fatal("The `berkshelf' gem is missing and must be installed" +
|
277
|
+
" or cannot be properly activated. Run" +
|
278
|
+
" `gem install berkshelf` or add the following to your" +
|
279
|
+
" Gemfile if you are using Bundler: `gem 'berkshelf'`.")
|
280
|
+
raise UserError,
|
281
|
+
"Could not load or activate Berkshelf (#{e.message})"
|
258
282
|
end
|
259
283
|
|
260
284
|
Kitchen.mutex.synchronize do
|
@@ -271,11 +295,13 @@ module Kitchen
|
|
271
295
|
require 'librarian/chef/environment'
|
272
296
|
require 'librarian/action/resolve'
|
273
297
|
require 'librarian/action/install'
|
274
|
-
rescue LoadError
|
275
|
-
fatal("The `librarian-chef' gem is missing and must be installed
|
276
|
-
"
|
277
|
-
"
|
278
|
-
|
298
|
+
rescue LoadError => e
|
299
|
+
fatal("The `librarian-chef' gem is missing and must be installed" +
|
300
|
+
" or cannot be properly activated. Run" +
|
301
|
+
" `gem install librarian-chef` or add the following to your" +
|
302
|
+
" Gemfile if you are using Bundler: `gem 'librarian-chef'`.")
|
303
|
+
raise UserError,
|
304
|
+
"Could not load or activate Librarian-Chef (#{e.message})"
|
279
305
|
end
|
280
306
|
|
281
307
|
Kitchen.mutex.synchronize do
|
@@ -285,6 +311,14 @@ module Kitchen
|
|
285
311
|
Librarian::Action::Install.new(env).run
|
286
312
|
end
|
287
313
|
end
|
314
|
+
|
315
|
+
private
|
316
|
+
|
317
|
+
def cookbooks_in_tmpdir
|
318
|
+
Dir.glob(File.join(tmpbooks_dir, "*/")).each do |cookbook_path|
|
319
|
+
yield cookbook_path if block_given?
|
320
|
+
end
|
321
|
+
end
|
288
322
|
end
|
289
323
|
end
|
290
324
|
end
|
@@ -51,11 +51,28 @@ module Kitchen
|
|
51
51
|
solo = []
|
52
52
|
solo << %{node_name "#{instance.name}"}
|
53
53
|
solo << %{file_cache_path "#{home_path}/cache"}
|
54
|
-
solo << %{cookbook_path "#{home_path}/cookbooks"}
|
54
|
+
solo << %{cookbook_path ["#{home_path}/cookbooks","#{home_path}/site-cookbooks"]}
|
55
55
|
solo << %{role_path "#{home_path}/roles"}
|
56
|
+
if config[:chef]
|
57
|
+
if config[:chef][:http_proxy]
|
58
|
+
solo << %{http_proxy "#{config[:chef][:http_proxy]}"}
|
59
|
+
end
|
60
|
+
if config[:chef][:https_proxy]
|
61
|
+
solo << %{https_proxy "#{config[:chef][:https_proxy]}"}
|
62
|
+
end
|
63
|
+
if config[:chef][:no_proxy]
|
64
|
+
solo << %{no_proxy "#{config[:chef][:no_proxy]}"}
|
65
|
+
end
|
66
|
+
end
|
56
67
|
if instance.suite.data_bags_path
|
57
68
|
solo << %{data_bag_path "#{home_path}/data_bags"}
|
58
69
|
end
|
70
|
+
if instance.suite.environments_path
|
71
|
+
solo << %{environment_path "#{home_path}/environments"}
|
72
|
+
end
|
73
|
+
if instance.suite.environment
|
74
|
+
solo << %{environment "#{instance.suite.environment}"}
|
75
|
+
end
|
59
76
|
if instance.suite.encrypted_data_bag_secret_key_path
|
60
77
|
secret = "#{home_path}/encrypted_data_bag_secret"
|
61
78
|
solo << %{encrypted_data_bag_secret "#{secret}"}
|
@@ -27,6 +27,11 @@ module Kitchen
|
|
27
27
|
# @author Fletcher Nichol <fnichol@nichol.ca>
|
28
28
|
class ChefZero < ChefBase
|
29
29
|
|
30
|
+
def initialize(instance, config)
|
31
|
+
super
|
32
|
+
@ruby_binpath = config.fetch(:ruby_binpath, DEFAULT_RUBY_BINPATH)
|
33
|
+
end
|
34
|
+
|
30
35
|
def create_sandbox
|
31
36
|
create_chef_sandbox do
|
32
37
|
prepare_chef_client_zero_rb
|
@@ -35,13 +40,13 @@ module Kitchen
|
|
35
40
|
end
|
36
41
|
|
37
42
|
def prepare_command
|
38
|
-
|
39
|
-
|
43
|
+
# use Bourne (/bin/sh) as Bash does not exist on all Unix flavors
|
40
44
|
<<-PREPARE.gsub(/^ {10}/, '')
|
41
|
-
|
42
|
-
|
45
|
+
sh -c '
|
46
|
+
#{sandbox_env(true)}
|
47
|
+
if ! #{sudo(gem_bin)} list chef-zero -i >/dev/null; then
|
43
48
|
echo "-----> Installing chef-zero and knife-essentials gems"
|
44
|
-
#{sudo(
|
49
|
+
#{sudo(gem_bin)} install \
|
45
50
|
chef-zero knife-essentials --no-ri --no-rdoc
|
46
51
|
fi'
|
47
52
|
PREPARE
|
@@ -49,7 +54,8 @@ module Kitchen
|
|
49
54
|
|
50
55
|
def run_command
|
51
56
|
[
|
52
|
-
|
57
|
+
sandbox_env,
|
58
|
+
sudo(ruby_bin),
|
53
59
|
"#{home_path}/chef-client-zero.rb",
|
54
60
|
"--config #{home_path}/client.rb",
|
55
61
|
"--json-attributes #{home_path}/dna.json",
|
@@ -61,8 +67,35 @@ module Kitchen
|
|
61
67
|
"/tmp/kitchen-chef-zero".freeze
|
62
68
|
end
|
63
69
|
|
70
|
+
def gem_bin
|
71
|
+
@gem_bin ||= File.join(ruby_binpath, 'gem')
|
72
|
+
end
|
73
|
+
|
74
|
+
def ruby_bin
|
75
|
+
@ruby_bin ||= File.join(ruby_binpath, 'ruby')
|
76
|
+
end
|
77
|
+
|
64
78
|
private
|
65
79
|
|
80
|
+
DEFAULT_RUBY_BINPATH = "/opt/chef/embedded/bin".freeze
|
81
|
+
|
82
|
+
attr_reader :ruby_binpath
|
83
|
+
|
84
|
+
def sandbox_env(export=false)
|
85
|
+
env = [
|
86
|
+
"GEM_HOME=#{home_path}/gems",
|
87
|
+
"GEM_PATH=$GEM_HOME",
|
88
|
+
"GEM_CACHE=$GEM_HOME/cache",
|
89
|
+
"PATH=$PATH:$GEM_HOME/bin"
|
90
|
+
]
|
91
|
+
|
92
|
+
if export
|
93
|
+
env << "; export GEM_HOME GEM_PATH GEM_CACHE PATH;"
|
94
|
+
end
|
95
|
+
|
96
|
+
env.join(" ")
|
97
|
+
end
|
98
|
+
|
66
99
|
def prepare_chef_client_zero_rb
|
67
100
|
source = File.join(File.dirname(__FILE__),
|
68
101
|
%w{.. .. .. support chef-client-zero.rb})
|
data/lib/kitchen/rake_tasks.rb
CHANGED