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.
@@ -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, :test_root => test_root)
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
 
@@ -18,7 +18,6 @@
18
18
 
19
19
  require 'benchmark'
20
20
  require 'fileutils'
21
- require 'thread'
22
21
  require 'vendor/hash_recursive_merge'
23
22
 
24
23
  module Kitchen
@@ -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
- "-s -- -v #{flag.downcase}"
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
- bash -c '
47
+ sh -c '
48
+ #{Util.shell_helpers}
49
+
44
50
  should_update_chef() {
45
51
  case "#{flag}" in
46
- true|$(chef-solo -v | cut -d " " -f 2)) return 1 ;;
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
- if command -v wget >/dev/null ; then
56
- wget #{url} -O - | #{sudo('bash')} #{version}
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
- filter_only_cookbook_files
174
+ remove_ignored_files
164
175
  end
165
176
 
166
- def filter_only_cookbook_files
167
- info("Removing non-cookbook files in sandbox")
168
-
169
- all_files = Dir.glob(File.join(tmpbooks_dir, "**/*")).
170
- select { |fn| File.file?(fn) }
171
- cookbook_files = Dir.glob(File.join(tmpbooks_dir, cookbook_files_glob)).
172
- select { |fn| File.file?(fn) }
173
-
174
- FileUtils.rm(all_files - cookbook_files)
175
- end
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
- glob = Dir.glob("#{kitchen_root}/{metadata.rb,README.*,definitions," +
241
- "attributes,files,libraries,providers,recipes,resources,templates}")
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 `berkself' gem is missing and must be installed." +
255
- " Run `gem install berkshelf` or add the following " +
256
- "to your Gemfile if you are using Bundler: `gem 'berkshelf'`.")
257
- raise UserError, "Could not load Berkshelf"
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
- " Run `gem install librarian-chef` or add the following " +
277
- "to your Gemfile if you are using Bundler: `gem 'librarian-chef'`.")
278
- raise UserError, "Could not load Librarian-Chef"
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
- ruby_bin = "/opt/chef/embedded/bin"
39
-
43
+ # use Bourne (/bin/sh) as Bash does not exist on all Unix flavors
40
44
  <<-PREPARE.gsub(/^ {10}/, '')
41
- bash -c '
42
- if [ ! -f "#{ruby_bin}/chef-zero" ] ; then
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("#{ruby_bin}/gem")} install \
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
- sudo('/opt/chef/embedded/bin/ruby'),
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})
@@ -32,7 +32,6 @@ module Kitchen
32
32
  # @yield [self] gives itself to the block
33
33
  def initialize
34
34
  @config = Kitchen::Config.new
35
- @config.supervised = false
36
35
  Kitchen.logger = Kitchen.default_file_logger
37
36
  yield self if block_given?
38
37
  define