test-kitchen 1.2.1 → 1.3.0

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.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/.cane +1 -1
  3. data/.rubocop.yml +3 -0
  4. data/.travis.yml +20 -9
  5. data/CHANGELOG.md +219 -108
  6. data/Gemfile +10 -6
  7. data/Guardfile +38 -9
  8. data/README.md +11 -1
  9. data/Rakefile +21 -37
  10. data/bin/kitchen +4 -4
  11. data/features/kitchen_action_commands.feature +161 -0
  12. data/features/kitchen_console_command.feature +34 -0
  13. data/features/kitchen_diagnose_command.feature +64 -0
  14. data/features/kitchen_init_command.feature +29 -17
  15. data/features/kitchen_list_command.feature +2 -2
  16. data/features/kitchen_login_command.feature +56 -0
  17. data/features/{sink_command.feature → kitchen_sink_command.feature} +0 -0
  18. data/features/kitchen_test_command.feature +88 -0
  19. data/features/step_definitions/gem_steps.rb +8 -6
  20. data/features/step_definitions/git_steps.rb +4 -2
  21. data/features/step_definitions/output_steps.rb +5 -0
  22. data/features/support/env.rb +12 -9
  23. data/lib/kitchen.rb +60 -38
  24. data/lib/kitchen/base64_stream.rb +55 -0
  25. data/lib/kitchen/busser.rb +124 -58
  26. data/lib/kitchen/cli.rb +121 -38
  27. data/lib/kitchen/collection.rb +3 -3
  28. data/lib/kitchen/color.rb +4 -4
  29. data/lib/kitchen/command.rb +78 -11
  30. data/lib/kitchen/command/action.rb +3 -2
  31. data/lib/kitchen/command/console.rb +12 -5
  32. data/lib/kitchen/command/diagnose.rb +17 -3
  33. data/lib/kitchen/command/driver_discover.rb +26 -7
  34. data/lib/kitchen/command/exec.rb +41 -0
  35. data/lib/kitchen/command/list.rb +44 -14
  36. data/lib/kitchen/command/login.rb +2 -1
  37. data/lib/kitchen/command/sink.rb +2 -1
  38. data/lib/kitchen/command/test.rb +5 -4
  39. data/lib/kitchen/config.rb +146 -14
  40. data/lib/kitchen/configurable.rb +314 -0
  41. data/lib/kitchen/data_munger.rb +522 -18
  42. data/lib/kitchen/diagnostic.rb +43 -4
  43. data/lib/kitchen/driver.rb +4 -4
  44. data/lib/kitchen/driver/base.rb +80 -115
  45. data/lib/kitchen/driver/dummy.rb +34 -6
  46. data/lib/kitchen/driver/proxy.rb +14 -3
  47. data/lib/kitchen/driver/ssh_base.rb +61 -7
  48. data/lib/kitchen/errors.rb +109 -9
  49. data/lib/kitchen/generator/driver_create.rb +39 -5
  50. data/lib/kitchen/generator/init.rb +130 -45
  51. data/lib/kitchen/instance.rb +162 -28
  52. data/lib/kitchen/lazy_hash.rb +79 -7
  53. data/lib/kitchen/loader/yaml.rb +159 -27
  54. data/lib/kitchen/logger.rb +267 -21
  55. data/lib/kitchen/logging.rb +30 -3
  56. data/lib/kitchen/login_command.rb +11 -2
  57. data/lib/kitchen/metadata_chopper.rb +2 -2
  58. data/lib/kitchen/provisioner.rb +4 -4
  59. data/lib/kitchen/provisioner/base.rb +107 -103
  60. data/lib/kitchen/provisioner/chef/berkshelf.rb +36 -8
  61. data/lib/kitchen/provisioner/chef/librarian.rb +40 -11
  62. data/lib/kitchen/provisioner/chef_base.rb +206 -167
  63. data/lib/kitchen/provisioner/chef_solo.rb +25 -7
  64. data/lib/kitchen/provisioner/chef_zero.rb +105 -29
  65. data/lib/kitchen/provisioner/dummy.rb +1 -1
  66. data/lib/kitchen/provisioner/shell.rb +21 -6
  67. data/lib/kitchen/rake_tasks.rb +8 -3
  68. data/lib/kitchen/shell_out.rb +15 -18
  69. data/lib/kitchen/ssh.rb +122 -27
  70. data/lib/kitchen/state_file.rb +24 -7
  71. data/lib/kitchen/thor_tasks.rb +9 -4
  72. data/lib/kitchen/util.rb +43 -118
  73. data/lib/kitchen/version.rb +1 -1
  74. data/lib/vendor/hash_recursive_merge.rb +10 -2
  75. data/spec/kitchen/base64_stream_spec.rb +77 -0
  76. data/spec/kitchen/busser_spec.rb +490 -0
  77. data/spec/kitchen/collection_spec.rb +10 -10
  78. data/spec/kitchen/color_spec.rb +2 -2
  79. data/spec/kitchen/config_spec.rb +234 -62
  80. data/spec/kitchen/configurable_spec.rb +490 -0
  81. data/spec/kitchen/data_munger_spec.rb +1070 -862
  82. data/spec/kitchen/diagnostic_spec.rb +79 -0
  83. data/spec/kitchen/driver/base_spec.rb +80 -85
  84. data/spec/kitchen/driver/dummy_spec.rb +43 -14
  85. data/spec/kitchen/driver/proxy_spec.rb +134 -0
  86. data/spec/kitchen/driver/ssh_base_spec.rb +644 -0
  87. data/spec/kitchen/driver_spec.rb +15 -15
  88. data/spec/kitchen/errors_spec.rb +309 -0
  89. data/spec/kitchen/instance_spec.rb +143 -46
  90. data/spec/kitchen/lazy_hash_spec.rb +36 -9
  91. data/spec/kitchen/loader/yaml_spec.rb +237 -226
  92. data/spec/kitchen/logger_spec.rb +419 -0
  93. data/spec/kitchen/logging_spec.rb +59 -0
  94. data/spec/kitchen/login_command_spec.rb +49 -0
  95. data/spec/kitchen/metadata_chopper_spec.rb +82 -0
  96. data/spec/kitchen/platform_spec.rb +4 -4
  97. data/spec/kitchen/provisioner/base_spec.rb +65 -125
  98. data/spec/kitchen/provisioner/chef_base_spec.rb +798 -0
  99. data/spec/kitchen/provisioner/chef_solo_spec.rb +316 -0
  100. data/spec/kitchen/provisioner/chef_zero_spec.rb +624 -0
  101. data/spec/kitchen/provisioner/shell_spec.rb +269 -0
  102. data/spec/kitchen/provisioner_spec.rb +6 -6
  103. data/spec/kitchen/shell_out_spec.rb +143 -0
  104. data/spec/kitchen/ssh_spec.rb +683 -0
  105. data/spec/kitchen/state_file_spec.rb +28 -21
  106. data/spec/kitchen/suite_spec.rb +7 -7
  107. data/spec/kitchen/util_spec.rb +68 -10
  108. data/spec/kitchen_spec.rb +107 -0
  109. data/spec/spec_helper.rb +18 -13
  110. data/support/chef-client-zero.rb +10 -9
  111. data/support/chef_helpers.sh +16 -0
  112. data/support/download_helpers.sh +109 -0
  113. data/test-kitchen.gemspec +42 -33
  114. metadata +107 -33
@@ -16,8 +16,8 @@
16
16
  # See the License for the specific language governing permissions and
17
17
  # limitations under the License.
18
18
 
19
- require 'kitchen/errors'
20
- require 'kitchen/logging'
19
+ require "kitchen/errors"
20
+ require "kitchen/logging"
21
21
 
22
22
  module Kitchen
23
23
 
@@ -26,24 +26,36 @@ module Kitchen
26
26
  module Chef
27
27
 
28
28
  # Chef cookbook resolver that uses Librarian-Chef and a Cheffile to
29
- # calculate # dependencies.
29
+ # calculate dependencies.
30
30
  #
31
31
  # @author Fletcher Nichol <fnichol@nichol.ca>
32
32
  class Librarian
33
33
 
34
34
  include Logging
35
35
 
36
-
36
+ # Creates a new cookbook resolver.
37
+ #
38
+ # @param cheffile [String] path to a Cheffile
39
+ # @param path [String] path in which to vendor the resulting
40
+ # cookbooks
41
+ # @param logger [Kitchen::Logger] a logger to use for output, defaults
42
+ # to `Kitchen.logger`
37
43
  def initialize(cheffile, path, logger = Kitchen.logger)
38
44
  @cheffile = cheffile
39
45
  @path = path
40
46
  @logger = logger
41
47
  end
42
48
 
49
+ # Loads the library code required to use the resolver.
50
+ #
51
+ # @param logger [Kitchen::Logger] a logger to use for output, defaults
52
+ # to `Kitchen.logger`
43
53
  def self.load!(logger = Kitchen.logger)
44
54
  load_librarian!(logger)
45
55
  end
46
56
 
57
+ # Performs the cookbook resolution and vendors the resulting cookbooks
58
+ # in the desired path.
47
59
  def resolve
48
60
  version = ::Librarian::Chef::VERSION
49
61
  info("Resolving cookbook dependencies with Librarian-Chef #{version}...")
@@ -56,12 +68,29 @@ module Kitchen
56
68
  ::Librarian::Action::Install.new(env).run
57
69
  end
58
70
 
59
- attr_reader :cheffile, :path, :logger
71
+ private
72
+
73
+ # @return [String] path to a Cheffile
74
+ # @api private
75
+ attr_reader :cheffile
76
+
77
+ # @return [String] path in which to vendor the resulting cookbooks
78
+ # @api private
79
+ attr_reader :path
80
+
81
+ # @return [Kitchen::Logger] a logger to use for output
82
+ # @api private
83
+ attr_reader :logger
60
84
 
85
+ # Load the Librarian-specific libary code.
86
+ #
87
+ # @param logger [Kitchen::Logger] the logger to use
88
+ # @raise [UserError] if the library couldn't be loaded
89
+ # @api private
61
90
  def self.load_librarian!(logger)
62
- first_load = require 'librarian/chef/environment'
63
- require 'librarian/action/resolve'
64
- require 'librarian/action/install'
91
+ first_load = require "librarian/chef/environment"
92
+ require "librarian/action/resolve"
93
+ require "librarian/action/install"
65
94
 
66
95
  version = ::Librarian::Chef::VERSION
67
96
  if first_load
@@ -70,9 +99,9 @@ module Kitchen
70
99
  logger.debug("Librarian-Chef #{version} previously loaded")
71
100
  end
72
101
  rescue LoadError => e
73
- logger.fatal("The `librarian-chef' gem is missing and must be installed" +
74
- " or cannot be properly activated. Run" +
75
- " `gem install librarian-chef` or add the following to your" +
102
+ logger.fatal("The `librarian-chef' gem is missing and must be installed" \
103
+ " or cannot be properly activated. Run" \
104
+ " `gem install librarian-chef` or add the following to your" \
76
105
  " Gemfile if you are using Bundler: `gem 'librarian-chef'`.")
77
106
  raise UserError,
78
107
  "Could not load or activate Librarian-Chef (#{e.message})"
@@ -16,13 +16,13 @@
16
16
  # See the License for the specific language governing permissions and
17
17
  # limitations under the License.
18
18
 
19
- require 'fileutils'
20
- require 'pathname'
21
- require 'json'
19
+ require "fileutils"
20
+ require "pathname"
21
+ require "json"
22
22
 
23
- require 'kitchen/provisioner/chef/berkshelf'
24
- require 'kitchen/provisioner/chef/librarian'
25
- require 'kitchen/util'
23
+ require "kitchen/provisioner/chef/berkshelf"
24
+ require "kitchen/provisioner/chef/librarian"
25
+ require "kitchen/util"
26
26
 
27
27
  module Kitchen
28
28
 
@@ -34,12 +34,17 @@ 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.getchef.com/chef/install.sh"
37
+ default_config :chef_omnibus_url, "https://www.chef.io/chef/install.sh"
38
+ default_config :chef_omnibus_root, "/opt/chef"
39
+ default_config :chef_omnibus_install_options, nil
38
40
  default_config :run_list, []
39
41
  default_config :attributes, {}
40
- default_config :cookbook_files_glob, %w[README.* metadata.{json,rb}
42
+ default_config :log_file, nil
43
+ default_config :cookbook_files_glob, %w[
44
+ README.* metadata.{json,rb}
41
45
  attributes/**/* definitions/**/* files/**/* libraries/**/*
42
- providers/**/* recipes/**/* resources/**/* templates/**/*].join(",")
46
+ providers/**/* recipes/**/* resources/**/* templates/**/*
47
+ ].join(",")
43
48
 
44
49
  default_config :data_path do |provisioner|
45
50
  provisioner.calculate_path("data")
@@ -72,79 +77,117 @@ module Kitchen
72
77
  expand_path_for :clients_path
73
78
 
74
79
  default_config :encrypted_data_bag_secret_key_path do |provisioner|
75
- provisioner.calculate_path("encrypted_data_bag_secret_key", :file)
80
+ provisioner.calculate_path("encrypted_data_bag_secret_key", :type => :file)
76
81
  end
77
82
  expand_path_for :encrypted_data_bag_secret_key_path
78
83
 
84
+ # (see Base#install_command)
79
85
  def install_command
80
86
  return unless config[:require_chef_omnibus]
81
87
 
82
- url = config[:chef_omnibus_url]
83
- flag = config[:require_chef_omnibus]
84
- version = if flag.is_a?(String) && flag != "latest"
85
- "-v #{flag.downcase}"
86
- else
87
- ""
88
- end
89
-
90
- # use Bourne (/bin/sh) as Bash does not exist on all Unix flavors
91
- <<-INSTALL.gsub(/^ {10}/, '')
92
- sh -c '
93
- #{Util.shell_helpers}
94
-
95
- should_update_chef() {
96
- case "#{flag}" in
97
- true|`chef-solo -v | cut -d " " -f 2`) return 1 ;;
98
- latest|*) return 0 ;;
99
- esac
100
- }
101
-
102
- if [ ! -d "/opt/chef" ] || should_update_chef ; then
103
- echo "-----> Installing Chef Omnibus (#{flag})"
104
- do_download #{url} /tmp/install.sh
105
- #{sudo('sh')} /tmp/install.sh #{version}
106
- fi'
107
- INSTALL
88
+ lines = [Util.shell_helpers, chef_shell_helpers, chef_install_function]
89
+ Util.wrap_command(lines.join("\n"))
108
90
  end
109
91
 
92
+ # (see Base#init_command)
110
93
  def init_command
111
- dirs = %w{cookbooks data data_bags environments roles clients}.
94
+ dirs = %w[cookbooks data data_bags environments roles clients].
112
95
  map { |dir| File.join(config[:root_path], dir) }.join(" ")
113
- "#{sudo('rm')} -rf #{dirs} ; mkdir -p #{config[:root_path]}"
96
+ lines = ["#{sudo("rm")} -rf #{dirs}", "mkdir -p #{config[:root_path]}"]
97
+
98
+ Util.wrap_command(lines.join("\n"))
114
99
  end
115
100
 
101
+ # (see Base#create_sandbox)
116
102
  def create_sandbox
117
103
  super
118
104
  prepare_json
119
105
  prepare_cache
120
106
  prepare_cookbooks
121
- prepare_data
122
- prepare_data_bags
123
- prepare_environments
124
- prepare_nodes
125
- prepare_roles
126
- prepare_clients
127
- prepare_secret
128
- end
129
-
130
- protected
131
-
107
+ prepare(:data)
108
+ prepare(:data_bags)
109
+ prepare(:environments)
110
+ prepare(:nodes)
111
+ prepare(:roles)
112
+ prepare(:clients)
113
+ prepare(
114
+ :secret,
115
+ :type => :file,
116
+ :dest_name => "encrypted_data_bag_secret",
117
+ :key_name => :encrypted_data_bag_secret_key_path
118
+ )
119
+ end
120
+
121
+ private
122
+
123
+ # Load cookbook dependency resolver code, if required.
124
+ #
125
+ # (see Base#load_needed_dependencies!)
132
126
  def load_needed_dependencies!
133
- if File.exists?(berksfile)
127
+ if File.exist?(berksfile)
134
128
  debug("Berksfile found at #{berksfile}, loading Berkshelf")
135
129
  Chef::Berkshelf.load!(logger)
136
- elsif File.exists?(cheffile)
130
+ elsif File.exist?(cheffile)
137
131
  debug("Cheffile found at #{cheffile}, loading Librarian-Chef")
138
132
  Chef::Librarian.load!(logger)
139
133
  end
140
134
  end
141
135
 
136
+ # Returns shell code with chef-related functions.
137
+ #
138
+ # @return [String] shell code
139
+ # @api private
140
+ def chef_shell_helpers
141
+ IO.read(File.join(
142
+ File.dirname(__FILE__), %w[.. .. .. support chef_helpers.sh]
143
+ ))
144
+ end
145
+
146
+ # Generates the shell code to conditionally install a Chef Omnibus
147
+ # package onto an instance.
148
+ #
149
+ # @return [String] shell code
150
+ # @api private
151
+ def chef_install_function
152
+ version = config[:require_chef_omnibus].to_s.downcase
153
+ pretty_version = case version
154
+ when "true" then "install only if missing"
155
+ when "latest" then "always install latest version"
156
+ else version
157
+ end
158
+ install_flags = %w[latest true].include?(version) ? "" : "-v #{version}"
159
+ if config[:chef_omnibus_install_options]
160
+ install_flags += config[:chef_omnibus_install_options]
161
+ end
162
+
163
+ <<-INSTALL.gsub(/^ {10}/, "")
164
+ if should_update_chef "#{config[:chef_omnibus_root]}" "#{version}" ; then
165
+ echo "-----> Installing Chef Omnibus (#{pretty_version})"
166
+ do_download #{config[:chef_omnibus_url]} /tmp/install.sh
167
+ #{sudo("sh")} /tmp/install.sh #{install_flags}
168
+ else
169
+ echo "-----> Chef Omnibus installation detected (#{pretty_version})"
170
+ fi
171
+ INSTALL
172
+ end
173
+
174
+ # Generates a rendered client.rb/solo.rb/knife.rb formatted file as a
175
+ # String.
176
+ #
177
+ # @param data [Hash] a key/value pair hash of configuration
178
+ # @return [String] a rendered Chef config file as a String
179
+ # @api private
142
180
  def format_config_file(data)
143
181
  data.each.map { |attr, value|
144
- [attr, (value.is_a?(Array) ? value.to_s : %{"#{value}"})].join(" ")
182
+ [attr, value.inspect].join(" ")
145
183
  }.join("\n")
146
184
  end
147
185
 
186
+ # Generates a Hash with default values for a solo.rb or client.rb Chef
187
+ # configuration file.
188
+ #
189
+ # @return [Hash] a configuration hash
190
+ # @api private
148
191
  def default_config_rb
149
192
  root = config[:root_path]
150
193
 
@@ -163,105 +206,78 @@ module Kitchen
163
206
  :validation_key => "#{root}/validation.pem",
164
207
  :client_key => "#{root}/client.pem",
165
208
  :chef_server_url => "http://127.0.0.1:8889",
166
- :encrypted_data_bag_secret => "#{root}/encrypted_data_bag_secret",
209
+ :encrypted_data_bag_secret => "#{root}/encrypted_data_bag_secret"
167
210
  }
168
211
  end
169
212
 
170
- def prepare_json
171
- dna = config[:attributes].merge({ :run_list => config[:run_list] })
172
-
173
- File.open(File.join(sandbox_path, "dna.json"), "wb") do |file|
174
- file.write(dna.to_json)
213
+ # Prepares a generic Chef component source directory or file for
214
+ # inclusion in the sandbox path. These components might includes nodes,
215
+ # roles, etc.
216
+ #
217
+ # @param component [Symbol,String] a component name such as `:node`
218
+ # @param opts [Hash] optional configuration
219
+ # @option opts [Symbol] :type whether the component is a directory or
220
+ # file (default: `:directory`)
221
+ # @option opts [Symbol] :key_name the key name in the config hash from
222
+ # which to pull the source path (default: `"#{component}_path"`)
223
+ # @option opts [String] :dest_name the destination file or directory
224
+ # basename in the sandbox path (default: `component.to_s`)
225
+ # @api private
226
+ def prepare(component, opts = {})
227
+ opts = { :type => :directory }.merge(opts)
228
+ key_name = opts.fetch(:key_name, "#{component}_path")
229
+ src = config[key_name.to_sym]
230
+ return if src.nil?
231
+
232
+ info("Preparing #{component}")
233
+ debug("Using #{component} from #{src}")
234
+
235
+ dest = File.join(sandbox_path, opts.fetch(:dest_name, component.to_s))
236
+
237
+ case opts[:type]
238
+ when :directory
239
+ FileUtils.mkdir_p(dest)
240
+ FileUtils.cp_r(Dir.glob("#{src}/*"), dest)
241
+ when :file
242
+ FileUtils.mkdir_p(File.dirname(dest))
243
+ FileUtils.cp_r(src, dest)
175
244
  end
176
245
  end
177
246
 
178
- def prepare_data
179
- return unless data
180
-
181
- info("Preparing data")
182
- debug("Using data from #{data}")
183
-
184
- tmpdata_dir = File.join(sandbox_path, "data")
185
- FileUtils.mkdir_p(tmpdata_dir)
186
- FileUtils.cp_r(Dir.glob("#{data}/*"), tmpdata_dir)
187
- end
188
-
189
- def prepare_data_bags
190
- return unless data_bags
191
-
192
- info("Preparing data bags")
193
- debug("Using data bags from #{data_bags}")
194
-
195
- tmpbags_dir = File.join(sandbox_path, "data_bags")
196
- FileUtils.mkdir_p(tmpbags_dir)
197
- FileUtils.cp_r(Dir.glob("#{data_bags}/*"), tmpbags_dir)
198
- end
199
-
200
- def prepare_roles
201
- return unless roles
202
-
203
- info("Preparing roles")
204
- debug("Using roles from #{roles}")
205
-
206
- tmproles_dir = File.join(sandbox_path, "roles")
207
- FileUtils.mkdir_p(tmproles_dir)
208
- FileUtils.cp_r(Dir.glob("#{roles}/*"), tmproles_dir)
209
- end
210
-
211
- def prepare_clients
212
- return unless clients
213
-
214
- info("Preparing clients")
215
- debug("Using roles from #{clients}")
216
-
217
- tmpclients_dir = File.join(sandbox_path, "clients")
218
- FileUtils.mkdir_p(tmpclients_dir)
219
- FileUtils.cp_r(Dir.glob("#{clients}/*"), tmpclients_dir)
220
- end
221
-
222
- def prepare_nodes
223
- return unless nodes
224
-
225
- info("Preparing nodes")
226
- debug("Using nodes from #{nodes}")
227
-
228
- tmpnodes_dir = File.join(sandbox_path, "nodes")
229
- FileUtils.mkdir_p(tmpnodes_dir)
230
- FileUtils.cp_r(Dir.glob("#{nodes}/*"), tmpnodes_dir)
231
- end
232
-
233
- def prepare_environments
234
- return unless environments
235
-
236
- info("Preparing environments")
237
- debug("Using environments from #{environments}")
238
-
239
- tmpenvs_dir = File.join(sandbox_path, "environments")
240
- FileUtils.mkdir_p(tmpenvs_dir)
241
- FileUtils.cp_r(Dir.glob("#{environments}/*"), tmpenvs_dir)
242
- end
243
-
244
- def prepare_secret
245
- return unless secret
247
+ # Prepares a Chef JSON file, sometimes called a dna.json or
248
+ # first-boot.json, for inclusion in the sandbox path.
249
+ #
250
+ # @api private
251
+ def prepare_json
252
+ dna = config[:attributes].merge(:run_list => config[:run_list])
246
253
 
247
- info("Preparing encrypted data bag secret")
248
- debug("Using secret from #{secret}")
254
+ info("Preparing dna.json")
255
+ debug("Creating dna.json from #{dna.inspect}")
249
256
 
250
- FileUtils.cp_r(secret, File.join(sandbox_path, "encrypted_data_bag_secret"))
257
+ File.open(File.join(sandbox_path, "dna.json"), "wb") do |file|
258
+ file.write(dna.to_json)
259
+ end
251
260
  end
252
261
 
262
+ # Prepares a cache directory for inclusion in the sandbox path.
263
+ #
264
+ # @api private
253
265
  def prepare_cache
254
266
  FileUtils.mkdir_p(File.join(sandbox_path, "cache"))
255
267
  end
256
268
 
269
+ # Prepares Chef cookbooks for inclusion in the sandbox path.
270
+ #
271
+ # @api private
257
272
  def prepare_cookbooks
258
- if File.exists?(berksfile)
273
+ if File.exist?(berksfile)
259
274
  resolve_with_berkshelf
260
- elsif File.exists?(cheffile)
275
+ elsif File.exist?(cheffile)
261
276
  resolve_with_librarian
277
+ cp_site_cookbooks if File.directory?(site_cookbooks_dir)
262
278
  elsif File.directory?(cookbooks_dir)
263
279
  cp_cookbooks
264
- elsif File.exists?(metadata_rb)
280
+ elsif File.exist?(metadata_rb)
265
281
  cp_this_cookbook
266
282
  else
267
283
  make_fake_cookbook
@@ -270,79 +286,86 @@ module Kitchen
270
286
  filter_only_cookbook_files
271
287
  end
272
288
 
289
+ # Removes all non-cookbook files in the sandbox path.
290
+ #
291
+ # @api private
273
292
  def filter_only_cookbook_files
274
293
  info("Removing non-cookbook files before transfer")
275
294
  FileUtils.rm(all_files_in_cookbooks - only_cookbook_files)
276
295
  end
277
296
 
297
+ # Generates a list of all files in the cookbooks directory in the
298
+ # sandbox path.
299
+ #
300
+ # @return [Array<String>] an array of absolute paths to files
301
+ # @api private
278
302
  def all_files_in_cookbooks
279
303
  Dir.glob(File.join(tmpbooks_dir, "**/*"), File::FNM_DOTMATCH).
280
- select { |fn| File.file?(fn) && ! %w{. ..}.include?(fn) }
304
+ select { |fn| File.file?(fn) && ! %w[. ..].include?(fn) }
281
305
  end
282
306
 
307
+ # Generates a list of all typical cookbook files needed in a Chef run,
308
+ # located in the cookbooks directory in the sandbox path.
309
+ #
310
+ # @return [Array<String>] an array of absolute paths to files
311
+ # @api private
283
312
  def only_cookbook_files
284
313
  glob = File.join(tmpbooks_dir, "*", "{#{config[:cookbook_files_glob]}}")
285
314
 
286
315
  Dir.glob(glob, File::FNM_DOTMATCH).
287
- select { |fn| File.file?(fn) && ! %w{. ..}.include?(fn) }
316
+ select { |fn| File.file?(fn) && ! %w[. ..].include?(fn) }
288
317
  end
289
318
 
319
+ # @return [String] an absolute path to a Berksfile, relative to the
320
+ # kitchen root
321
+ # @api private
290
322
  def berksfile
291
323
  File.join(config[:kitchen_root], "Berksfile")
292
324
  end
293
325
 
326
+ # @return [String] an absolute path to a Cheffile, relative to the
327
+ # kitchen root
328
+ # @api private
294
329
  def cheffile
295
330
  File.join(config[:kitchen_root], "Cheffile")
296
331
  end
297
332
 
333
+ # @return [String] an absolute path to a metadata.rb, relative to the
334
+ # kitchen root
335
+ # @api private
298
336
  def metadata_rb
299
337
  File.join(config[:kitchen_root], "metadata.rb")
300
338
  end
301
339
 
340
+ # @return [String] an absolute path to a cookbooks/ directory, relative
341
+ # to the kitchen root
342
+ # @api private
302
343
  def cookbooks_dir
303
344
  File.join(config[:kitchen_root], "cookbooks")
304
345
  end
305
346
 
347
+ # @return [String] an absolute path to a site-cookbooks/ directory,
348
+ # relative to the kitchen root
349
+ # @api private
306
350
  def site_cookbooks_dir
307
351
  File.join(config[:kitchen_root], "site-cookbooks")
308
352
  end
309
353
 
310
- def data_bags
311
- config[:data_bags_path]
312
- end
313
-
314
- def roles
315
- config[:roles_path]
316
- end
317
-
318
- def clients
319
- config[:clients_path]
320
- end
321
-
322
- def nodes
323
- config[:nodes_path]
324
- end
325
-
326
- def data
327
- config[:data_path]
328
- end
329
-
330
- def environments
331
- config[:environments_path]
332
- end
333
-
334
- def secret
335
- config[:encrypted_data_bag_secret_key_path]
336
- end
337
-
354
+ # @return [String] an absolute path to a cookbooks/ directory in the
355
+ # sandbox path
356
+ # @api private
338
357
  def tmpbooks_dir
339
358
  File.join(sandbox_path, "cookbooks")
340
359
  end
341
360
 
361
+ # @return [String] an absolute path to a site cookbooks directory in the
362
+ # sandbox path
363
+ # @api private
342
364
  def tmpsitebooks_dir
343
365
  File.join(sandbox_path, "cookbooks")
344
366
  end
345
367
 
368
+ # Copies a cookbooks/ directory into the sandbox path.
346
369
  def cp_cookbooks
347
370
  info("Preparing cookbooks from project directory")
348
371
  debug("Using cookbooks from #{cookbooks_dir}")
@@ -351,9 +374,12 @@ module Kitchen
351
374
  FileUtils.cp_r(File.join(cookbooks_dir, "."), tmpbooks_dir)
352
375
 
353
376
  cp_site_cookbooks if File.directory?(site_cookbooks_dir)
354
- cp_this_cookbook if File.exists?(metadata_rb)
377
+ cp_this_cookbook if File.exist?(metadata_rb)
355
378
  end
356
379
 
380
+ # Copies a site-cookbooks/ directory into the sandbox path.
381
+ #
382
+ # @api private
357
383
  def cp_site_cookbooks
358
384
  info("Preparing site-cookbooks from project directory")
359
385
  debug("Using cookbooks from #{site_cookbooks_dir}")
@@ -362,12 +388,16 @@ module Kitchen
362
388
  FileUtils.cp_r(File.join(site_cookbooks_dir, "."), tmpsitebooks_dir)
363
389
  end
364
390
 
391
+ # Copies the current project, assumed to be a Chef cookbook into the
392
+ # sandbox path.
393
+ #
394
+ # @api private
365
395
  def cp_this_cookbook
366
396
  info("Preparing current project directory as a cookbook")
367
397
  debug("Using metadata.rb from #{metadata_rb}")
368
398
 
369
- cb_name = MetadataChopper.extract(metadata_rb).first or raise(UserError,
370
- "The metadata.rb does not define the 'name' key." +
399
+ cb_name = MetadataChopper.extract(metadata_rb).first || raise(UserError,
400
+ "The metadata.rb does not define the 'name' key." \
371
401
  " Please add: `name '<cookbook_name>'` to metadata.rb and retry")
372
402
 
373
403
  cb_path = File.join(tmpbooks_dir, cb_name)
@@ -378,23 +408,32 @@ module Kitchen
378
408
  FileUtils.cp_r(glob, cb_path)
379
409
  end
380
410
 
411
+ # Creates a minimal, no-op cookbook in the sandbox path.
412
+ #
413
+ # @api private
381
414
  def make_fake_cookbook
382
- info("Berksfile, Cheffile, cookbooks/, or metadata.rb not found " +
415
+ info("Berksfile, Cheffile, cookbooks/, or metadata.rb not found " \
383
416
  "so Chef will run with effectively no cookbooks. Is this intended?")
384
417
  name = File.basename(config[:kitchen_root])
385
418
  fake_cb = File.join(tmpbooks_dir, name)
386
419
  FileUtils.mkdir_p(fake_cb)
387
420
  File.open(File.join(fake_cb, "metadata.rb"), "wb") do |file|
388
- file.write(%{name "#{name}\n"})
421
+ file.write(%{name "#{name}"\n})
389
422
  end
390
423
  end
391
424
 
425
+ # Performs a Berkshelf cookbook resolution inside a common mutex.
426
+ #
427
+ # @api private
392
428
  def resolve_with_berkshelf
393
429
  Kitchen.mutex.synchronize do
394
430
  Chef::Berkshelf.new(berksfile, tmpbooks_dir, logger).resolve
395
431
  end
396
432
  end
397
433
 
434
+ # Performs a Librarin-Chef cookbook resolution inside a common mutex.
435
+ #
436
+ # @api private
398
437
  def resolve_with_librarian
399
438
  Kitchen.mutex.synchronize do
400
439
  Chef::Librarian.new(cheffile, tmpbooks_dir, logger).resolve