test-kitchen 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.cane +5 -0
  3. data/.travis.yml +8 -3
  4. data/CHANGELOG.md +66 -0
  5. data/Guardfile +3 -1
  6. data/README.md +3 -1
  7. data/Rakefile +1 -16
  8. data/features/kitchen_command.feature +1 -0
  9. data/features/kitchen_driver_create_command.feature +1 -0
  10. data/features/kitchen_driver_discover_command.feature +1 -0
  11. data/features/kitchen_help_command.feature +16 -0
  12. data/features/kitchen_init_command.feature +2 -0
  13. data/features/kitchen_list_command.feature +42 -0
  14. data/features/support/env.rb +25 -0
  15. data/lib/kitchen.rb +0 -1
  16. data/lib/kitchen/busser.rb +2 -2
  17. data/lib/kitchen/cli.rb +80 -233
  18. data/lib/kitchen/command.rb +117 -0
  19. data/lib/kitchen/command/action.rb +44 -0
  20. data/lib/kitchen/command/console.rb +51 -0
  21. data/lib/kitchen/command/diagnose.rb +51 -0
  22. data/lib/kitchen/command/driver_discover.rb +72 -0
  23. data/lib/kitchen/command/list.rb +86 -0
  24. data/lib/kitchen/command/login.rb +42 -0
  25. data/lib/kitchen/command/sink.rb +53 -0
  26. data/lib/kitchen/command/test.rb +50 -0
  27. data/lib/kitchen/driver/ssh_base.rb +2 -1
  28. data/lib/kitchen/loader/yaml.rb +67 -29
  29. data/lib/kitchen/provisioner/base.rb +67 -4
  30. data/lib/kitchen/provisioner/chef_base.rb +50 -65
  31. data/lib/kitchen/provisioner/chef_solo.rb +3 -2
  32. data/lib/kitchen/provisioner/chef_zero.rb +11 -9
  33. data/lib/kitchen/provisioner/shell.rb +88 -0
  34. data/lib/kitchen/state_file.rb +7 -2
  35. data/lib/kitchen/util.rb +1 -1
  36. data/lib/kitchen/version.rb +1 -1
  37. data/spec/kitchen/loader/yaml_spec.rb +327 -13
  38. data/spec/spec_helper.rb +2 -7
  39. data/support/chef-client-zero.rb +1 -0
  40. data/templates/driver/README.md.erb +1 -1
  41. data/test-kitchen.gemspec +2 -2
  42. metadata +59 -46
@@ -0,0 +1,53 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
+ #
5
+ # Copyright (C) 2013, Fletcher Nichol
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/command'
20
+
21
+ module Kitchen
22
+
23
+ module Command
24
+
25
+ # Command to... include the sink.
26
+ #
27
+ # @author Seth Vargo <sethvargo@gmail.com>
28
+ class Sink < Kitchen::Command::Base
29
+
30
+ def call
31
+ puts [
32
+ "",
33
+ " ___ ",
34
+ " ' _ '. ",
35
+ " / /` `\\ \\ ",
36
+ " | | [__] ",
37
+ " | | {{ ",
38
+ " | | }} ",
39
+ " _ | | _ {{ ",
40
+ " ___________<_>_| |_<_>}}________ ",
41
+ " .=======^=(___)=^={{====. ",
42
+ " / .----------------}}---. \\ ",
43
+ " / / {{ \\ \\ ",
44
+ " / / }} \\ \\ ",
45
+ " ( '=========================' ) ",
46
+ " '-----------------------------' ",
47
+ " ", # necessary newline
48
+ ""
49
+ ].map(&:rstrip).join("\n")
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,50 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
+ #
5
+ # Copyright (C) 2013, Fletcher Nichol
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/command'
20
+
21
+ require 'benchmark'
22
+
23
+ module Kitchen
24
+
25
+ module Command
26
+
27
+ # Command to test one or more instances.
28
+ #
29
+ # @author Fletcher Nichol <fnichol@nichol.ca>
30
+ class Test < Kitchen::Command::Base
31
+
32
+ include RunAction
33
+
34
+ def call
35
+ if ! %w{passing always never}.include?(options[:destroy])
36
+ raise ArgumentError, "Destroy mode must be passing, always, or never."
37
+ end
38
+
39
+ banner "Starting Kitchen (v#{Kitchen::VERSION})"
40
+ elapsed = Benchmark.measure do
41
+ destroy_mode = options[:destroy].to_sym
42
+ results = parse_subcommand(args.join('|'))
43
+
44
+ run_action(:test, results, destroy_mode)
45
+ end
46
+ banner "Kitchen is finished. #{Util.duration(elapsed.real)}"
47
+ end
48
+ end
49
+ end
50
+ end
@@ -37,7 +37,8 @@ module Kitchen
37
37
 
38
38
  def converge(state)
39
39
  provisioner = instance.provisioner
40
- sandbox_dirs = Dir.glob("#{provisioner.create_sandbox}/*")
40
+ provisioner.create_sandbox
41
+ sandbox_dirs = Dir.glob("#{provisioner.sandbox_path}/*")
41
42
 
42
43
  Kitchen::SSH.new(*build_ssh_args(state)) do |conn|
43
44
  run_remote(provisioner.install_command, conn)
@@ -18,7 +18,13 @@
18
18
 
19
19
  require 'erb'
20
20
  require 'vendor/hash_recursive_merge'
21
- require 'safe_yaml'
21
+
22
+ if RUBY_VERSION <= "1.9.3"
23
+ # ensure that Psych and not Syck is used for Ruby 1.9.2
24
+ require 'yaml'
25
+ YAML::ENGINE.yamler = 'psych'
26
+ end
27
+ require 'safe_yaml/load'
22
28
 
23
29
  module Kitchen
24
30
 
@@ -33,18 +39,27 @@ module Kitchen
33
39
  # @author Fletcher Nichol <fnichol@nichol.ca>
34
40
  class YAML
35
41
 
36
- attr_reader :config_file
37
-
38
42
  # Creates a new loader that can parse and load YAML files.
39
43
  #
40
- # @param config_file [String] path to Kitchen config YAML file
41
44
  # @param options [Hash] configuration for a new loader
45
+ # @option options [String] :project_config path to the Kitchen
46
+ # config YAML file (default: `./.kitchen.yml`)
47
+ # @option options [String] :local_config path to the Kitchen local
48
+ # config YAML file (default: `./.kitchen.local.yml`)
49
+ # @option options [String] :local_config path to the Kitchen global
50
+ # config YAML file (default: `$HOME/.kitchen/config.yml`)
42
51
  # @option options [String] :process_erb whether or not to process YAML
43
52
  # through an ERB processor (default: `true`)
44
53
  # @option options [String] :process_local whether or not to process a
45
54
  # local kitchen YAML file, if it exists (default: `true`)
46
- def initialize(config_file = nil, options = {})
47
- @config_file = File.expand_path(config_file || default_config_file)
55
+ def initialize(options = {})
56
+ @config_file =
57
+ File.expand_path(options[:project_config] || default_config_file)
58
+ @local_config_file =
59
+ File.expand_path(options[:local_config] || default_local_config_file)
60
+ @global_config_file =
61
+ File.expand_path(options[:global_config] || default_global_config_file)
62
+
48
63
  @process_erb = options.fetch(:process_erb, true)
49
64
  @process_local = options.fetch(:process_local, true)
50
65
  @process_global = options.fetch(:process_global, true)
@@ -67,26 +82,20 @@ module Kitchen
67
82
  # @return [Hash] a diagnostic hash
68
83
  def diagnose
69
84
  result = Hash.new
70
- result[:proces_erb] = @process_erb
85
+ result[:process_erb] = @process_erb
71
86
  result[:process_local] = @process_local
72
87
  result[:process_global] = @process_global
73
- if File.exists?(global_config_file)
74
- result[:global_config] =
75
- { :filename => global_config_file, :raw_data => global_yaml }
76
- end
77
- result[:project_config] =
78
- { :filename => config_file, :raw_data => yaml }
79
- if File.exists?(local_config_file)
80
- result[:local_config] =
81
- { :filename => local_config_file, :raw_data => local_yaml }
82
- end
83
- combined = begin ; combined_hash ; rescue => e ; failure_hash(e) ; end
84
- result[:combined_config] = { :raw_data => combined }
88
+ result[:global_config] = diagnose_component(:global_yaml, global_config_file)
89
+ result[:project_config] = diagnose_component(:yaml, config_file)
90
+ result[:local_config] = diagnose_component(:local_yaml, local_config_file)
91
+ result[:combined_config] = diagnose_component(:combined_hash)
85
92
  result
86
93
  end
87
94
 
88
95
  protected
89
96
 
97
+ attr_reader :config_file, :local_config_file, :global_config_file
98
+
90
99
  def default_config_file
91
100
  File.join(Dir.pwd, '.kitchen.yml')
92
101
  end
@@ -98,9 +107,6 @@ module Kitchen
98
107
  normalize(yaml)
99
108
  end
100
109
  @process_global ? y.rmerge(normalize(global_yaml)) : y
101
- rescue NoMethodError
102
- raise UserError, "Error merging #{File.basename(config_file)} and" +
103
- "#{File.basename(local_config_file)}"
104
110
  end
105
111
 
106
112
  def yaml
@@ -118,29 +124,52 @@ module Kitchen
118
124
  def yaml_string(file)
119
125
  string = read_file(file)
120
126
 
121
- @process_erb ? ERB.new(string).result : string
127
+ @process_erb ? process_erb(string, file) : string
128
+ end
129
+
130
+ def process_erb(string, file)
131
+ ERB.new(string).result
132
+ rescue => e
133
+ raise UserError, "Error parsing ERB content in #{file} " +
134
+ "(#{e.class}: #{e.message}).\n" +
135
+ "Please run `kitchen diagnose --no-instances --loader' to help " +
136
+ "debug your issue."
122
137
  end
123
138
 
124
139
  def read_file(file)
125
140
  File.exists?(file.to_s) ? IO.read(file) : ""
126
141
  end
127
142
 
128
- def local_config_file
143
+ def default_local_config_file
129
144
  config_file.sub(/(#{File.extname(config_file)})$/, '.local\1')
130
145
  end
131
146
 
132
- def global_config_file
147
+ def default_global_config_file
133
148
  File.join(File.expand_path(ENV["HOME"]), ".kitchen", "config.yml")
134
149
  end
135
150
 
136
- def failure_hash(e)
137
- {
151
+ def diagnose_component(component, file = nil)
152
+ return if file && !File.exists?(file)
153
+
154
+ hash = begin
155
+ send(component)
156
+ rescue => e
157
+ failure_hash(e, file)
158
+ end
159
+
160
+ { :filename => file, :raw_data => hash }
161
+ end
162
+
163
+ def failure_hash(e, file = nil)
164
+ result = {
138
165
  :error => {
139
166
  :exception => e.inspect,
140
167
  :message => e.message,
141
168
  :backtrace => e.backtrace
142
169
  }
143
170
  }
171
+ result[:error][:raw_file] = IO.read(file) unless file.nil?
172
+ result
144
173
  end
145
174
 
146
175
  def normalize(obj)
@@ -170,9 +199,18 @@ module Kitchen
170
199
  def parse_yaml_string(string, file_name)
171
200
  return Hash.new if string.nil? || string.empty?
172
201
 
173
- ::YAML.safe_load(string) || Hash.new
202
+ result = SafeYAML.load(string) || Hash.new
203
+ unless result.is_a?(Hash)
204
+ raise UserError, "Error parsing #{file_name} as YAML " +
205
+ "(Result of parse was not a Hash, but was a #{result.class}).\n" +
206
+ "Please run `kitchen diagnose --no-instances --loader' to help " +
207
+ "debug your issue."
208
+ end
209
+ result
174
210
  rescue SyntaxError, Psych::SyntaxError
175
- raise UserError, "Error parsing #{file_name}"
211
+ raise UserError, "Error parsing #{file_name} as YAML.\n" +
212
+ "Please run `kitchen diagnose --no-instances --loader' to help " +
213
+ "debug your issue."
176
214
  end
177
215
  end
178
216
  end
@@ -38,6 +38,11 @@ module Kitchen
38
38
  end
39
39
  end
40
40
 
41
+ def instance=(instance)
42
+ @instance = instance
43
+ expand_paths!
44
+ end
45
+
41
46
  # Returns the name of this driver, suitable for display in a CLI.
42
47
  #
43
48
  # @return [String] name of this driver
@@ -60,17 +65,33 @@ module Kitchen
60
65
  config.keys
61
66
  end
62
67
 
63
- def install_command ; end
64
-
65
68
  def init_command ; end
66
69
 
67
- def create_sandbox ; end
70
+ def install_command ; end
68
71
 
69
72
  def prepare_command ; end
70
73
 
71
74
  def run_command ; end
72
75
 
73
- def cleanup_sandbox ; end
76
+ def create_sandbox
77
+ @sandbox_path = Dir.mktmpdir("#{instance.name}-sandbox-")
78
+ File.chmod(0755, sandbox_path)
79
+ info("Preparing files for transfer")
80
+ debug("Creating local sandbox in #{sandbox_path}")
81
+ end
82
+
83
+ def sandbox_path
84
+ @sandbox_path || (raise ClientError, "Sandbox directory has not yet " +
85
+ "been created. Please run #{self.class}#create_sandox before " +
86
+ "trying to access the path.")
87
+ end
88
+
89
+ def cleanup_sandbox
90
+ return if sandbox_path.nil?
91
+
92
+ debug("Cleaning up local sandbox in #{sandbox_path}")
93
+ FileUtils.rmtree(sandbox_path)
94
+ end
74
95
 
75
96
  # Returns a Hash of configuration and other useful diagnostic information.
76
97
  #
@@ -81,10 +102,32 @@ module Kitchen
81
102
  result
82
103
  end
83
104
 
105
+ def calculate_path(path, type = :directory)
106
+ base = config[:test_base_path]
107
+ candidates = []
108
+ candidates << File.join(base, instance.suite.name, path)
109
+ candidates << File.join(base, path)
110
+ candidates << File.join(Dir.pwd, path)
111
+
112
+ candidates.find do |c|
113
+ type == :directory ? File.directory?(c) : File.file?(c)
114
+ end
115
+ end
116
+
84
117
  protected
85
118
 
86
119
  attr_reader :config
87
120
 
121
+ def expand_paths!
122
+ expanded_paths = LazyHash.new(self.class.expanded_paths, self).to_hash
123
+
124
+ expanded_paths.each do |key, should_expand|
125
+ if should_expand && !config[key].nil?
126
+ config[key] = File.expand_path(config[key], config[:kitchen_root])
127
+ end
128
+ end
129
+ end
130
+
88
131
  def logger
89
132
  instance ? instance.logger : Kitchen.logger
90
133
  end
@@ -111,8 +154,28 @@ module Kitchen
111
154
  defaults[attr] = block_given? ? block : value
112
155
  end
113
156
 
157
+ def self.expanded_paths
158
+ @expanded_paths ||= Hash.new.merge(super_expanded_paths)
159
+ end
160
+
161
+ def self.super_expanded_paths
162
+ klass = self.superclass
163
+
164
+ if klass.respond_to?(:expanded_paths)
165
+ klass.expanded_paths
166
+ else
167
+ Hash.new
168
+ end
169
+ end
170
+
171
+ def self.expand_path_for(attr, value = true, &block)
172
+ expanded_paths[attr] = block_given? ? block : value
173
+ end
174
+
114
175
  default_config :root_path, "/tmp/kitchen"
115
176
  default_config :sudo, true
177
+
178
+ expand_path_for :test_base_path
116
179
  end
117
180
  end
118
181
  end
@@ -34,7 +34,7 @@ module Kitchen
34
34
  class ChefBase < Base
35
35
 
36
36
  default_config :require_chef_omnibus, true
37
- default_config :chef_omnibus_url, "https://www.opscode.com/chef/install.sh"
37
+ default_config :chef_omnibus_url, "https://www.getchef.com/chef/install.sh"
38
38
  default_config :run_list, []
39
39
  default_config :attributes, {}
40
40
  default_config :cookbook_files_glob, %w[README.* metadata.{json,rb}
@@ -44,31 +44,37 @@ module Kitchen
44
44
  default_config :data_path do |provisioner|
45
45
  provisioner.calculate_path("data")
46
46
  end
47
+ expand_path_for :data_path
47
48
 
48
49
  default_config :data_bags_path do |provisioner|
49
50
  provisioner.calculate_path("data_bags")
50
51
  end
52
+ expand_path_for :data_bags_path
51
53
 
52
54
  default_config :environments_path do |provisioner|
53
55
  provisioner.calculate_path("environments")
54
56
  end
57
+ expand_path_for :environments_path
55
58
 
56
59
  default_config :nodes_path do |provisioner|
57
60
  provisioner.calculate_path("nodes")
58
61
  end
62
+ expand_path_for :nodes_path
59
63
 
60
64
  default_config :roles_path do |provisioner|
61
65
  provisioner.calculate_path("roles")
62
66
  end
67
+ expand_path_for :roles_path
63
68
 
64
- default_config :encrypted_data_bag_secret_key_path do |provisioner|
65
- provisioner.calculate_path("encrypted_data_bag_secret_key", :file)
69
+ default_config :clients_path do |provisioner|
70
+ provisioner.calculate_path("clients")
66
71
  end
72
+ expand_path_for :clients_path
67
73
 
68
- def instance=(instance)
69
- @instance = instance
70
- expand_paths!
74
+ default_config :encrypted_data_bag_secret_key_path do |provisioner|
75
+ provisioner.calculate_path("encrypted_data_bag_secret_key", :file)
71
76
  end
77
+ expand_path_for :encrypted_data_bag_secret_key_path
72
78
 
73
79
  def install_command
74
80
  return unless config[:require_chef_omnibus]
@@ -102,44 +108,27 @@ module Kitchen
102
108
  end
103
109
 
104
110
  def init_command
105
- dirs = %w{cookbooks data data_bags environments roles}.
111
+ dirs = %w{cookbooks data data_bags environments roles clients}.
106
112
  map { |dir| File.join(config[:root_path], dir) }.join(" ")
107
113
  "#{sudo('rm')} -rf #{dirs} ; mkdir -p #{config[:root_path]}"
108
114
  end
109
115
 
110
- def cleanup_sandbox
111
- return if tmpdir.nil?
112
-
113
- debug("Cleaning up local sandbox in #{tmpdir}")
114
- FileUtils.rmtree(tmpdir)
115
- end
116
-
117
- def calculate_path(path, type = :directory)
118
- base = config[:test_base_path]
119
- candidates = []
120
- candidates << File.join(base, instance.suite.name, path)
121
- candidates << File.join(base, path)
122
- candidates << File.join(Dir.pwd, path)
123
-
124
- candidates.find do |c|
125
- type == :directory ? File.directory?(c) : File.file?(c)
126
- end
116
+ def create_sandbox
117
+ super
118
+ prepare_json
119
+ prepare_cache
120
+ prepare_cookbooks
121
+ prepare_data
122
+ prepare_data_bags
123
+ prepare_environments
124
+ prepare_nodes
125
+ prepare_roles
126
+ prepare_clients
127
+ prepare_secret
127
128
  end
128
129
 
129
130
  protected
130
131
 
131
- attr_reader :tmpdir
132
-
133
- def expand_paths!
134
- paths = %w{test_base data data_bags encrypted_data_bag_secret_key
135
- environments nodes roles}
136
- paths.map{ |p| "#{p}_path".to_sym }.each do |key|
137
- unless config[key].nil?
138
- config[key] = File.expand_path(config[key], config[:kitchen_root])
139
- end
140
- end
141
- end
142
-
143
132
  def format_config_file(data)
144
133
  data.each.map { |attr, value|
145
134
  [attr, (value.is_a?(Array) ? value.to_s : %{"#{value}"})].join(" ")
@@ -168,29 +157,10 @@ module Kitchen
168
157
  }
169
158
  end
170
159
 
171
- def create_chef_sandbox
172
- @tmpdir = Dir.mktmpdir("#{instance.name}-sandbox-")
173
- File.chmod(0755, @tmpdir)
174
- info("Preparing files for transfer")
175
- debug("Creating local sandbox in #{tmpdir}")
176
-
177
- yield if block_given?
178
- prepare_json
179
- prepare_cache
180
- prepare_cookbooks
181
- prepare_data
182
- prepare_data_bags
183
- prepare_environments
184
- prepare_nodes
185
- prepare_roles
186
- prepare_secret
187
- tmpdir
188
- end
189
-
190
160
  def prepare_json
191
161
  dna = config[:attributes].merge({ :run_list => config[:run_list] })
192
162
 
193
- File.open(File.join(tmpdir, "dna.json"), "wb") do |file|
163
+ File.open(File.join(sandbox_path, "dna.json"), "wb") do |file|
194
164
  file.write(dna.to_json)
195
165
  end
196
166
  end
@@ -201,7 +171,7 @@ module Kitchen
201
171
  info("Preparing data")
202
172
  debug("Using data from #{data}")
203
173
 
204
- tmpdata_dir = File.join(tmpdir, "data")
174
+ tmpdata_dir = File.join(sandbox_path, "data")
205
175
  FileUtils.mkdir_p(tmpdata_dir)
206
176
  FileUtils.cp_r(Dir.glob("#{data}/*"), tmpdata_dir)
207
177
  end
@@ -212,7 +182,7 @@ module Kitchen
212
182
  info("Preparing data bags")
213
183
  debug("Using data bags from #{data_bags}")
214
184
 
215
- tmpbags_dir = File.join(tmpdir, "data_bags")
185
+ tmpbags_dir = File.join(sandbox_path, "data_bags")
216
186
  FileUtils.mkdir_p(tmpbags_dir)
217
187
  FileUtils.cp_r(Dir.glob("#{data_bags}/*"), tmpbags_dir)
218
188
  end
@@ -223,18 +193,29 @@ module Kitchen
223
193
  info("Preparing roles")
224
194
  debug("Using roles from #{roles}")
225
195
 
226
- tmproles_dir = File.join(tmpdir, "roles")
196
+ tmproles_dir = File.join(sandbox_path, "roles")
227
197
  FileUtils.mkdir_p(tmproles_dir)
228
198
  FileUtils.cp_r(Dir.glob("#{roles}/*"), tmproles_dir)
229
199
  end
230
200
 
201
+ def prepare_clients
202
+ return unless clients
203
+
204
+ info("Preparing clients")
205
+ debug("Using roles from #{clients}")
206
+
207
+ tmpclients_dir = File.join(sandbox_path, "clients")
208
+ FileUtils.mkdir_p(tmpclients_dir)
209
+ FileUtils.cp_r(Dir.glob("#{clients}/*"), tmpclients_dir)
210
+ end
211
+
231
212
  def prepare_nodes
232
213
  return unless nodes
233
214
 
234
215
  info("Preparing nodes")
235
216
  debug("Using nodes from #{nodes}")
236
217
 
237
- tmpnodes_dir = File.join(tmpdir, "nodes")
218
+ tmpnodes_dir = File.join(sandbox_path, "nodes")
238
219
  FileUtils.mkdir_p(tmpnodes_dir)
239
220
  FileUtils.cp_r(Dir.glob("#{nodes}/*"), tmpnodes_dir)
240
221
  end
@@ -245,7 +226,7 @@ module Kitchen
245
226
  info("Preparing environments")
246
227
  debug("Using environments from #{environments}")
247
228
 
248
- tmpenvs_dir = File.join(tmpdir, "environments")
229
+ tmpenvs_dir = File.join(sandbox_path, "environments")
249
230
  FileUtils.mkdir_p(tmpenvs_dir)
250
231
  FileUtils.cp_r(Dir.glob("#{environments}/*"), tmpenvs_dir)
251
232
  end
@@ -256,11 +237,11 @@ module Kitchen
256
237
  info("Preparing encrypted data bag secret")
257
238
  debug("Using secret from #{secret}")
258
239
 
259
- FileUtils.cp_r(secret, File.join(tmpdir, "encrypted_data_bag_secret"))
240
+ FileUtils.cp_r(secret, File.join(sandbox_path, "encrypted_data_bag_secret"))
260
241
  end
261
242
 
262
243
  def prepare_cache
263
- FileUtils.mkdir_p(File.join(tmpdir, "cache"))
244
+ FileUtils.mkdir_p(File.join(sandbox_path, "cache"))
264
245
  end
265
246
 
266
247
  def prepare_cookbooks
@@ -324,6 +305,10 @@ module Kitchen
324
305
  config[:roles_path]
325
306
  end
326
307
 
308
+ def clients
309
+ config[:clients_path]
310
+ end
311
+
327
312
  def nodes
328
313
  config[:nodes_path]
329
314
  end
@@ -341,11 +326,11 @@ module Kitchen
341
326
  end
342
327
 
343
328
  def tmpbooks_dir
344
- File.join(tmpdir, "cookbooks")
329
+ File.join(sandbox_path, "cookbooks")
345
330
  end
346
331
 
347
332
  def tmpsitebooks_dir
348
- File.join(tmpdir, "cookbooks")
333
+ File.join(sandbox_path, "cookbooks")
349
334
  end
350
335
 
351
336
  def cp_cookbooks