chef 0.9.18 → 0.10.0.beta.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 (177) hide show
  1. data/README.rdoc +0 -3
  2. data/distro/arch/etc/rc.d/chef-server +0 -4
  3. data/distro/arch/etc/rc.d/chef-server-webui +0 -4
  4. data/distro/arch/etc/rc.d/chef-solr +0 -4
  5. data/distro/arch/etc/rc.d/chef-solr-indexer +0 -4
  6. data/lib/chef.rb +3 -3
  7. data/lib/chef/api_client.rb +1 -1
  8. data/lib/chef/application.rb +11 -1
  9. data/lib/chef/application/client.rb +18 -22
  10. data/lib/chef/application/knife.rb +28 -29
  11. data/lib/chef/application/solo.rb +14 -12
  12. data/lib/chef/client.rb +112 -54
  13. data/lib/chef/config.rb +4 -0
  14. data/lib/chef/cookbook/chefignore.rb +66 -0
  15. data/lib/chef/cookbook/cookbook_collection.rb +6 -5
  16. data/lib/chef/cookbook/cookbook_version_loader.rb +151 -0
  17. data/lib/chef/cookbook/file_system_file_vendor.rb +10 -8
  18. data/lib/chef/cookbook/metadata.rb +200 -108
  19. data/lib/chef/cookbook_loader.rb +39 -163
  20. data/lib/chef/cookbook_uploader.rb +100 -78
  21. data/lib/chef/cookbook_version.rb +92 -47
  22. data/lib/chef/cookbook_version_selector.rb +163 -0
  23. data/lib/chef/couchdb.rb +9 -1
  24. data/lib/chef/data_bag.rb +1 -1
  25. data/lib/chef/data_bag_item.rb +1 -1
  26. data/lib/chef/encrypted_data_bag_item.rb +126 -0
  27. data/lib/chef/environment.rb +386 -0
  28. data/lib/chef/exceptions.rb +82 -1
  29. data/lib/chef/index_queue/amqp_client.rb +15 -12
  30. data/lib/chef/index_queue/indexable.rb +38 -4
  31. data/lib/chef/json_compat.rb +3 -3
  32. data/lib/chef/knife.rb +97 -202
  33. data/lib/chef/knife/bootstrap.rb +27 -61
  34. data/lib/chef/knife/bootstrap/archlinux-gems.erb +4 -2
  35. data/lib/chef/knife/bootstrap/centos5-gems.erb +6 -15
  36. data/lib/chef/knife/bootstrap/fedora13-gems.erb +3 -4
  37. data/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb +2 -2
  38. data/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb +6 -5
  39. data/lib/chef/knife/client_bulk_delete.rb +6 -3
  40. data/lib/chef/knife/client_create.rb +13 -10
  41. data/lib/chef/knife/client_delete.rb +10 -7
  42. data/lib/chef/knife/client_edit.rb +9 -6
  43. data/lib/chef/knife/client_list.rb +8 -5
  44. data/lib/chef/knife/client_reregister.rb +9 -6
  45. data/lib/chef/knife/client_show.rb +9 -6
  46. data/lib/chef/knife/configure.rb +15 -19
  47. data/lib/chef/knife/configure_client.rb +4 -4
  48. data/lib/chef/knife/cookbook_bulk_delete.rb +11 -8
  49. data/lib/chef/knife/cookbook_create.rb +120 -55
  50. data/lib/chef/knife/cookbook_delete.rb +18 -12
  51. data/lib/chef/knife/cookbook_download.rb +10 -6
  52. data/lib/chef/knife/cookbook_list.rb +15 -6
  53. data/lib/chef/knife/cookbook_metadata.rb +41 -21
  54. data/lib/chef/knife/cookbook_metadata_from_file.rb +4 -0
  55. data/lib/chef/knife/cookbook_show.rb +16 -5
  56. data/lib/chef/knife/cookbook_site_download.rb +2 -2
  57. data/lib/chef/knife/cookbook_site_share.rb +18 -13
  58. data/lib/chef/knife/cookbook_site_unshare.rb +7 -4
  59. data/lib/chef/knife/cookbook_site_vendor.rb +21 -18
  60. data/lib/chef/knife/cookbook_test.rb +14 -14
  61. data/lib/chef/knife/cookbook_upload.rb +91 -40
  62. data/lib/chef/knife/data_bag_create.rb +41 -6
  63. data/lib/chef/knife/data_bag_delete.rb +5 -3
  64. data/lib/chef/knife/data_bag_edit.rb +55 -11
  65. data/lib/chef/knife/data_bag_from_file.rb +47 -7
  66. data/lib/chef/knife/data_bag_list.rb +4 -1
  67. data/lib/chef/knife/data_bag_show.rb +44 -4
  68. data/lib/chef/knife/environment_create.rb +53 -0
  69. data/lib/chef/knife/environment_delete.rb +45 -0
  70. data/lib/chef/knife/environment_edit.rb +45 -0
  71. data/lib/chef/knife/environment_from_file.rb +39 -0
  72. data/lib/chef/knife/environment_list.rb +42 -0
  73. data/lib/chef/knife/environment_show.rb +46 -0
  74. data/lib/chef/knife/exec.rb +1 -1
  75. data/lib/chef/knife/index_rebuild.rb +8 -9
  76. data/lib/chef/knife/node_bulk_delete.rb +9 -6
  77. data/lib/chef/knife/node_create.rb +9 -6
  78. data/lib/chef/knife/node_delete.rb +10 -7
  79. data/lib/chef/knife/node_edit.rb +129 -10
  80. data/lib/chef/knife/node_from_file.rb +10 -7
  81. data/lib/chef/knife/node_list.rb +11 -6
  82. data/lib/chef/knife/node_run_list_add.rb +10 -7
  83. data/lib/chef/knife/node_run_list_remove.rb +9 -6
  84. data/lib/chef/knife/node_show.rb +15 -7
  85. data/lib/chef/knife/recipe_list.rb +4 -3
  86. data/lib/chef/knife/role_bulk_delete.rb +9 -6
  87. data/lib/chef/knife/role_create.rb +9 -6
  88. data/lib/chef/knife/role_delete.rb +10 -7
  89. data/lib/chef/knife/role_edit.rb +11 -8
  90. data/lib/chef/knife/role_from_file.rb +10 -7
  91. data/lib/chef/knife/role_list.rb +8 -5
  92. data/lib/chef/knife/role_show.rb +11 -8
  93. data/lib/chef/knife/search.rb +33 -10
  94. data/lib/chef/knife/ssh.rb +33 -61
  95. data/lib/chef/knife/status.rb +7 -4
  96. data/lib/chef/knife/subcommand_loader.rb +101 -0
  97. data/lib/chef/knife/tag_create.rb +31 -0
  98. data/lib/chef/knife/tag_delete.rb +31 -0
  99. data/lib/chef/knife/tag_list.rb +29 -0
  100. data/lib/chef/knife/ui.rb +229 -0
  101. data/lib/chef/knife/windows_bootstrap.rb +8 -5
  102. data/lib/chef/log.rb +5 -59
  103. data/lib/chef/mash.rb +211 -0
  104. data/lib/chef/mixins.rb +1 -2
  105. data/lib/chef/nil_argument.rb +3 -0
  106. data/lib/chef/node.rb +96 -34
  107. data/lib/chef/platform.rb +27 -0
  108. data/lib/chef/provider/cookbook_file.rb +21 -20
  109. data/lib/chef/provider/deploy/revision.rb +3 -0
  110. data/lib/chef/provider/file.rb +20 -11
  111. data/lib/chef/provider/git.rb +26 -26
  112. data/lib/chef/provider/group/aix.rb +70 -0
  113. data/lib/chef/provider/group/groupadd.rb +7 -4
  114. data/lib/chef/provider/group/usermod.rb +1 -1
  115. data/lib/chef/provider/package.rb +28 -28
  116. data/lib/chef/provider/package/dpkg.rb +1 -1
  117. data/lib/chef/provider/package/portage.rb +50 -39
  118. data/lib/chef/provider/package/rubygems.rb +1 -1
  119. data/lib/chef/provider/package/zypper.rb +3 -20
  120. data/lib/chef/provider/remote_directory.rb +0 -2
  121. data/lib/chef/provider/remote_file.rb +2 -3
  122. data/lib/chef/provider/service/arch.rb +28 -35
  123. data/lib/chef/provider/service/simple.rb +1 -1
  124. data/lib/chef/provider/subversion.rb +22 -22
  125. data/lib/chef/providers.rb +1 -0
  126. data/lib/chef/recipe.rb +10 -12
  127. data/lib/chef/resource.rb +49 -42
  128. data/lib/chef/resource/gem_package.rb +7 -3
  129. data/lib/chef/resource/git.rb +5 -5
  130. data/lib/chef/resource/package.rb +7 -7
  131. data/lib/chef/resource/scm.rb +2 -1
  132. data/lib/chef/resource/solaris_package.rb +0 -1
  133. data/lib/chef/resource/yum_package.rb +0 -1
  134. data/lib/chef/rest.rb +7 -16
  135. data/lib/chef/rest/rest_request.rb +0 -16
  136. data/lib/chef/role.rb +67 -13
  137. data/lib/chef/run_context.rb +37 -21
  138. data/lib/chef/run_list.rb +30 -15
  139. data/lib/chef/run_list/run_list_expansion.rb +41 -20
  140. data/lib/chef/run_list/run_list_item.rb +20 -6
  141. data/lib/chef/run_list/versioned_recipe_list.rb +68 -0
  142. data/lib/chef/runner.rb +7 -15
  143. data/lib/chef/search/query.rb +12 -7
  144. data/lib/chef/shef.rb +6 -7
  145. data/lib/chef/shef/shef_session.rb +40 -35
  146. data/lib/chef/shell_out.rb +22 -201
  147. data/lib/chef/shell_out/unix.rb +224 -0
  148. data/lib/chef/shell_out/windows.rb +95 -0
  149. data/lib/chef/solr_query.rb +187 -0
  150. data/lib/chef/solr_query/lucene.treetop +145 -0
  151. data/lib/chef/solr_query/lucene_nodes.rb +285 -0
  152. data/lib/chef/solr_query/query_transform.rb +65 -0
  153. data/lib/chef/solr_query/solr_http_request.rb +118 -0
  154. data/lib/chef/version.rb +4 -2
  155. data/lib/chef/version_class.rb +70 -0
  156. data/lib/chef/version_constraint.rb +116 -0
  157. metadata +68 -37
  158. data/lib/chef/cookbook/metadata/version.rb +0 -87
  159. data/lib/chef/knife/bluebox_images_list.rb +0 -54
  160. data/lib/chef/knife/bluebox_server_create.rb +0 -157
  161. data/lib/chef/knife/bluebox_server_delete.rb +0 -63
  162. data/lib/chef/knife/bluebox_server_list.rb +0 -59
  163. data/lib/chef/knife/ec2_instance_data.rb +0 -46
  164. data/lib/chef/knife/ec2_server_create.rb +0 -218
  165. data/lib/chef/knife/ec2_server_delete.rb +0 -87
  166. data/lib/chef/knife/ec2_server_list.rb +0 -89
  167. data/lib/chef/knife/rackspace_server_create.rb +0 -184
  168. data/lib/chef/knife/rackspace_server_delete.rb +0 -57
  169. data/lib/chef/knife/rackspace_server_list.rb +0 -59
  170. data/lib/chef/knife/slicehost_images_list.rb +0 -53
  171. data/lib/chef/knife/slicehost_server_create.rb +0 -103
  172. data/lib/chef/knife/slicehost_server_delete.rb +0 -61
  173. data/lib/chef/knife/slicehost_server_list.rb +0 -64
  174. data/lib/chef/knife/terremark_server_create.rb +0 -152
  175. data/lib/chef/knife/terremark_server_delete.rb +0 -87
  176. data/lib/chef/knife/terremark_server_list.rb +0 -77
  177. data/lib/chef/mixin/find_preferred_file.rb +0 -92
@@ -3,15 +3,15 @@
3
3
  # Author:: Christopher Walters (<cw@opscode.com>)
4
4
  # Author:: Christopher Brown (<cb@opscode.com>)
5
5
  # Author:: Tim Hinderliter (<tim@opscode.com>)
6
- # Copyright:: Copyright (c) 2008-2010 Opscode, Inc.
6
+ # Copyright:: Copyright (c) 2008-2011 Opscode, Inc.
7
7
  # License:: Apache License, Version 2.0
8
8
  #
9
9
  # Licensed under the Apache License, Version 2.0 (the "License");
10
10
  # you may not use this file except in compliance with the License.
11
11
  # You may obtain a copy of the License at
12
- #
12
+ #
13
13
  # http://www.apache.org/licenses/LICENSE-2.0
14
- #
14
+ #
15
15
  # Unless required by applicable law or agreed to in writing, software
16
16
  # distributed under the License is distributed on an "AS IS" BASIS,
17
17
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -28,6 +28,7 @@ require 'chef/role'
28
28
  require 'chef/file_cache'
29
29
  require 'chef/run_context'
30
30
  require 'chef/runner'
31
+ require 'chef/run_status'
31
32
  require 'chef/cookbook/cookbook_collection'
32
33
  require 'chef/cookbook/file_vendor'
33
34
  require 'chef/cookbook/file_system_file_vendor'
@@ -41,6 +42,8 @@ class Chef
41
42
  # syncs cookbooks if necessary, and triggers convergence.
42
43
  class Client
43
44
 
45
+ SANE_PATHS = %w[/usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin]
46
+
44
47
  # Clears all notifications for client run status events.
45
48
  # Primarily for testing purposes.
46
49
  def self.clear_notifications
@@ -126,7 +129,7 @@ class Chef
126
129
  @runner = nil
127
130
  @ohai = Ohai::System.new
128
131
  end
129
-
132
+
130
133
  # Do a full run for this Chef::Client. Calls:
131
134
  #
132
135
  # * run_ohai - Collect information about the system
@@ -140,39 +143,21 @@ class Chef
140
143
  def run
141
144
  run_context = nil
142
145
 
146
+ enforce_path_sanity
143
147
  run_ohai
144
148
  register unless Chef::Config[:solo]
145
149
  build_node
146
-
150
+
147
151
  begin
148
152
 
149
153
  run_status.start_clock
150
154
  Chef::Log.info("Starting Chef Run (Version #{Chef::VERSION})")
151
155
  run_started
152
-
153
- if Chef::Config[:solo]
154
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest) }
155
- run_context = Chef::RunContext.new(node, Chef::CookbookCollection.new(Chef::CookbookLoader.new))
156
- run_status.run_context = run_context
157
- assert_cookbook_path_not_empty(run_context)
158
- converge(run_context)
159
- else
160
- # Sync_cookbooks eagerly loads all files except files and templates.
161
- # It returns the cookbook_hash -- the return result from
162
- # /nodes/#{nodename}/cookbooks -- which we will use for our
163
- # run_context.
164
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::RemoteFileVendor.new(manifest, rest) }
165
- cookbook_hash = sync_cookbooks
166
- run_context = Chef::RunContext.new(node, Chef::CookbookCollection.new(cookbook_hash))
167
- run_status.run_context = run_context
168
-
169
- assert_cookbook_path_not_empty(run_context)
170
-
171
- converge(run_context)
172
- Chef::Log.debug("Saving the current state of node #{node_name}")
173
- @node.save
174
- end
175
-
156
+
157
+ run_context = setup_run_context
158
+ converge(run_context)
159
+ save_updated_node
160
+
176
161
  run_status.stop_clock
177
162
  Chef::Log.info("Chef Run complete in #{run_status.elapsed_time} seconds")
178
163
  run_completed_successfully
@@ -186,6 +171,35 @@ class Chef
186
171
  ensure
187
172
  run_status = nil
188
173
  end
174
+ true
175
+ end
176
+
177
+
178
+ # Configures the Chef::Cookbook::FileVendor class to fetch file from the
179
+ # server or disk as appropriate, creates the run context for this run, and
180
+ # sanity checks the cookbook collection.
181
+ #===Returns
182
+ # Chef::RunContext:: the run context for this run.
183
+ def setup_run_context
184
+ if Chef::Config[:solo]
185
+ Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, Chef::Config[:cookbook_path]) }
186
+ run_context = Chef::RunContext.new(node, Chef::CookbookCollection.new(Chef::CookbookLoader.new(Chef::Config[:cookbook_path])))
187
+ else
188
+ Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::RemoteFileVendor.new(manifest, rest) }
189
+ cookbook_hash = sync_cookbooks
190
+ run_context = Chef::RunContext.new(node, Chef::CookbookCollection.new(cookbook_hash))
191
+ end
192
+ run_status.run_context = run_context
193
+ run_context.load(@run_list_expansion)
194
+ assert_cookbook_path_not_empty(run_context)
195
+ run_context
196
+ end
197
+
198
+ def save_updated_node
199
+ unless Chef::Config[:solo]
200
+ Chef::Log.debug("Saving the current state of node #{node_name}")
201
+ @node.save
202
+ end
189
203
  end
190
204
 
191
205
  def run_ohai
@@ -203,14 +217,14 @@ class Chef
203
217
 
204
218
  name
205
219
  end
206
-
220
+
207
221
  # Builds a new node object for this client. Starts with querying for the FQDN of the current
208
222
  # host (unless it is supplied), then merges in the facts from Ohai.
209
223
  #
210
224
  # === Returns
211
225
  # node<Chef::Node>:: Returns the created node object, also stored in @node
212
226
  def build_node
213
- Chef::Log.debug("Building node object for #{@node_name}")
227
+ Chef::Log.debug("Building node object for #{node_name}")
214
228
 
215
229
  if Chef::Config[:solo]
216
230
  @node = Chef::Node.build(node_name)
@@ -218,46 +232,74 @@ class Chef
218
232
  @node = Chef::Node.find_or_create(node_name)
219
233
  end
220
234
 
235
+ # Allow user to override the environment of a node by specifying
236
+ # a config parameter.
237
+ if Chef::Config[:environment] && !Chef::Config[:environment].chop.empty?
238
+ @node.chef_environment(Chef::Config[:environment])
239
+ end
221
240
 
222
- @node.consume_external_attrs(ohai.data, @json_attribs)
223
- @node.expand!
224
- @node.save unless Chef::Config[:solo]
241
+ # consume_external_attrs may add items to the run_list. Save the
242
+ # expanded run_list, which we will pass to the server later to
243
+ # determine which versions of cookbooks to use.
225
244
  @node.reset_defaults_and_overrides
245
+ @node.consume_external_attrs(ohai.data, @json_attribs)
246
+ if Chef::Config[:solo]
247
+ @run_list_expansion = @node.expand!('disk')
248
+ else
249
+ @run_list_expansion = @node.expand!('server')
250
+ end
251
+
252
+ # @run_list_expansion is a RunListExpansion.
253
+ #
254
+ # Convert @expanded_run_list, which is an
255
+ # Array of Hashes of the form
256
+ # {:name => NAME, :version_constraint => Chef::VersionConstraint },
257
+ # into @expanded_run_list_with_versions, an
258
+ # Array of Strings of the form
259
+ # "#{NAME}@#{VERSION}"
260
+ @expanded_run_list_with_versions = @run_list_expansion.recipes.with_version_constraints_strings
261
+
262
+ Chef::Log.info("Run List is [#{@node.run_list}]")
263
+ Chef::Log.info("Run List expands (with versions) to [#{@expanded_run_list_with_versions.join(', ')}]")
226
264
 
227
265
  @run_status = Chef::RunStatus.new(@node)
228
266
 
229
267
  @node
230
268
  end
231
269
 
232
- #
270
+ #
233
271
  # === Returns
234
272
  # rest<Chef::REST>:: returns Chef::REST connection object
235
- def register
236
- if File.exists?(Chef::Config[:client_key])
237
- Chef::Log.debug("Client key #{Chef::Config[:client_key]} is present - skipping registration")
273
+ def register(client_name=node_name, config=Chef::Config)
274
+ if File.exists?(config[:client_key])
275
+ Chef::Log.debug("Client key #{config[:client_key]} is present - skipping registration")
238
276
  else
239
- Chef::Log.info("Client key #{Chef::Config[:client_key]} is not present - registering")
240
- Chef::REST.new(Chef::Config[:client_url], Chef::Config[:validation_client_name], Chef::Config[:validation_key]).register(node_name, Chef::Config[:client_key])
277
+ Chef::Log.info("Client key #{config[:client_key]} is not present - registering")
278
+ Chef::REST.new(config[:client_url], config[:validation_client_name], config[:validation_key]).register(client_name, config[:client_key])
241
279
  end
242
280
  # We now have the client key, and should use it from now on.
243
- self.rest = Chef::REST.new(Chef::Config[:chef_server_url], node_name, Chef::Config[:client_key])
281
+ self.rest = Chef::REST.new(config[:chef_server_url], client_name, config[:client_key])
244
282
  end
245
-
246
- # Synchronizes all the cookbooks from the chef-server.
283
+
284
+ # Sync_cookbooks eagerly loads all files except files and
285
+ # templates. It returns the cookbook_hash -- the return result
286
+ # from /environments/#{node.chef_environment}/cookbook_versions,
287
+ # which we will use for our run_context.
247
288
  #
248
289
  # === Returns
249
- # true:: Always returns true
290
+ # Hash:: The hash of cookbooks with download URLs as given by the server
250
291
  def sync_cookbooks
251
292
  Chef::Log.debug("Synchronizing cookbooks")
252
- cookbook_hash = rest.get_rest("nodes/#{node_name}/cookbooks")
293
+ cookbook_hash = rest.post_rest("environments/#{@node.chef_environment}/cookbook_versions",
294
+ {:run_list => @expanded_run_list_with_versions})
253
295
  Chef::CookbookVersion.sync_cookbooks(cookbook_hash)
254
296
 
255
297
  # register the file cache path in the cookbook path so that CookbookLoader actually picks up the synced cookbooks
256
298
  Chef::Config[:cookbook_path] = File.join(Chef::Config[:file_cache_path], "cookbooks")
257
-
299
+
258
300
  cookbook_hash
259
301
  end
260
-
302
+
261
303
  # Converges the node.
262
304
  #
263
305
  # === Returns
@@ -268,23 +310,35 @@ class Chef
268
310
  runner.converge
269
311
  true
270
312
  end
271
-
313
+
314
+ def enforce_path_sanity(env=ENV)
315
+ if Chef::Config[:enforce_path_sanity] && RUBY_PLATFORM !~ /mswin|mingw32|windows/
316
+ existing_paths = env["PATH"].split(':')
317
+ SANE_PATHS.each do |sane_path|
318
+ unless existing_paths.include?(sane_path)
319
+ env["PATH"] << ':' unless env["PATH"].empty?
320
+ env["PATH"] << sane_path
321
+ end
322
+ end
323
+ end
324
+ end
325
+
272
326
  private
273
-
327
+
274
328
  def directory_not_empty?(path)
275
329
  File.exists?(path) && (Dir.entries(path).size > 2)
276
330
  end
277
-
331
+
278
332
  def is_last_element?(index, object)
279
- object.kind_of?(Array) ? index == object.size - 1 : true
280
- end
281
-
333
+ object.kind_of?(Array) ? index == object.size - 1 : true
334
+ end
335
+
282
336
  def assert_cookbook_path_not_empty(run_context)
283
337
  if Chef::Config[:solo]
284
338
  # Check for cookbooks in the path given
285
339
  # Chef::Config[:cookbook_path] can be a string or an array
286
340
  # if it's an array, go through it and check each one, raise error at the last one if no files are found
287
- Chef::Log.debug "loading from cookbook_path: #{Array(Chef::Config[:cookbook_path]).map { |path| File.expand_path(path) }.join(', ')}"
341
+ Chef::Log.debug "loading from cookbook_path: #{Array(Chef::Config[:cookbook_path]).map { |path| File.expand_path(path) }.join(', ')}"
288
342
  Array(Chef::Config[:cookbook_path]).each_with_index do |cookbook_path, index|
289
343
  if directory_not_empty?(cookbook_path)
290
344
  break
@@ -302,3 +356,7 @@ class Chef
302
356
  end
303
357
  end
304
358
 
359
+ # HACK cannot load this first, but it must be loaded.
360
+ require 'chef/cookbook_loader'
361
+ require 'chef/cookbook_version'
362
+
@@ -82,6 +82,7 @@ class Chef
82
82
  #
83
83
  config_attr_writer :log_location do |location|
84
84
  if location.respond_to? :sync=
85
+ location.sync = true
85
86
  location
86
87
  elsif location.respond_to? :to_str
87
88
  f = File.new(location.to_str, "a")
@@ -100,6 +101,9 @@ class Chef
100
101
  providers
101
102
  end
102
103
 
104
+ # Turn on "path sanity" by default. See also: http://wiki.opscode.com/display/chef/User+Environment+PATH+Sanity
105
+ enforce_path_sanity(true)
106
+
103
107
  # Used when OpenID authentication is enabled in the Web UI
104
108
  authorized_openid_identifiers nil
105
109
  authorized_openid_providers nil
@@ -0,0 +1,66 @@
1
+ #--
2
+ # Author:: Daniel DeLeo (<dan@opscode.com>)
3
+ # Copyright:: Copyright (c) 2011 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ class Chef
20
+ class Cookbook
21
+ class Chefignore
22
+
23
+ COMMENTS_AND_WHITESPACE = /^\w*(?:#.*)?$/
24
+
25
+ attr_reader :ignores
26
+
27
+ def initialize(ignore_file_or_repo)
28
+ @ignore_file = find_ignore_file(ignore_file_or_repo)
29
+ @ignores = parse_ignore_file
30
+ end
31
+
32
+ def remove_ignores_from(file_list)
33
+ Array(file_list).inject([]) do |unignored, file|
34
+ ignored?(file) ? unignored : unignored << file
35
+ end
36
+ end
37
+
38
+ def ignored?(file_name)
39
+ @ignores.any? {|glob| File.fnmatch?(glob, file_name)}
40
+ end
41
+
42
+ private
43
+
44
+ def parse_ignore_file
45
+ ignore_globs = []
46
+ if File.exist?(@ignore_file) && File.readable?(@ignore_file)
47
+ File.foreach(@ignore_file) do |line|
48
+ ignore_globs << line.strip unless line =~ COMMENTS_AND_WHITESPACE
49
+ end
50
+ else
51
+ Chef::Log.debug("No chefignore file found at #@ignore_file no files will be ignored")
52
+ end
53
+ ignore_globs
54
+ end
55
+
56
+ def find_ignore_file(path)
57
+ if File.basename(path) =~ /chefignore/
58
+ path
59
+ else
60
+ File.join(path, 'chefignore')
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+
@@ -7,9 +7,9 @@
7
7
  # Licensed under the Apache License, Version 2.0 (the "License");
8
8
  # you may not use this file except in compliance with the License.
9
9
  # You may obtain a copy of the License at
10
- #
10
+ #
11
11
  # http://www.apache.org/licenses/LICENSE-2.0
12
- #
12
+ #
13
13
  # Unless required by applicable law or agreed to in writing, software
14
14
  # distributed under the License is distributed on an "AS IS" BASIS,
15
15
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -17,7 +17,7 @@
17
17
  # limitations under the License.
18
18
  #
19
19
 
20
- require 'extlib'
20
+ require 'chef/mash'
21
21
 
22
22
  class Chef
23
23
  # == Chef::CookbookCollection
@@ -35,10 +35,11 @@ class Chef
35
35
  # simply extract them
36
36
  def initialize(cookbook_versions={})
37
37
  super() do |hash, key|
38
- raise Chef::Exceptions::CookbookNotFound, "Cookbook #{key} not found"
38
+ raise Chef::Exceptions::CookbookNotFound, "Cookbook #{key} not found. " <<
39
+ "If you're loading #{key} from another cookbook, make sure you configure the dependency in your metadata"
39
40
  end
40
41
  cookbook_versions.each{ |cookbook_name, cookbook_version| self[cookbook_name] = cookbook_version }
41
42
  end
42
-
43
+
43
44
  end
44
45
  end
@@ -0,0 +1,151 @@
1
+
2
+ require 'chef/config'
3
+ require 'chef/cookbook_version'
4
+ require 'chef/cookbook/chefignore'
5
+ require 'chef/cookbook/metadata'
6
+
7
+ class Chef
8
+ class Cookbook
9
+ class CookbookVersionLoader
10
+
11
+ FILETYPES_SUBJECT_TO_IGNORE = [ :attribute_filenames,
12
+ :definition_filenames,
13
+ :recipe_filenames,
14
+ :template_filenames,
15
+ :file_filenames,
16
+ :library_filenames,
17
+ :resource_filenames,
18
+ :provider_filenames]
19
+
20
+
21
+ attr_reader :cookbook_name
22
+ attr_reader :cookbook_settings
23
+ attr_reader :metadata_filenames
24
+
25
+ def initialize(path, chefignore=nil)
26
+ @cookbook_path = File.expand_path( path )
27
+ @cookbook_name = File.basename( path )
28
+ @chefignore = chefignore
29
+ @metadata = Hash.new
30
+ @relative_path = /#{Regexp.escape(@cookbook_path)}\/(.+)$/
31
+ @cookbook_settings = {
32
+ :attribute_filenames => {},
33
+ :definition_filenames => {},
34
+ :recipe_filenames => {},
35
+ :template_filenames => {},
36
+ :file_filenames => {},
37
+ :library_filenames => {},
38
+ :resource_filenames => {},
39
+ :provider_filenames => {},
40
+ :root_filenames => {}
41
+ }
42
+
43
+ @metadata_filenames = []
44
+ end
45
+
46
+ def load_cookbooks
47
+ load_as(:attribute_filenames, 'attributes', '*.rb')
48
+ load_as(:definition_filenames, 'definitions', '*.rb')
49
+ load_as(:recipe_filenames, 'recipes', '*.rb')
50
+ load_as(:library_filenames, 'libraries', '*.rb')
51
+ load_recursively_as(:template_filenames, "templates", "*")
52
+ load_recursively_as(:file_filenames, "files", "*")
53
+ load_recursively_as(:resource_filenames, "resources", "*.rb")
54
+ load_recursively_as(:provider_filenames, "providers", "*.rb")
55
+ load_root_files
56
+
57
+ remove_ignored_files
58
+
59
+ if File.exists?(File.join(@cookbook_path, "metadata.json"))
60
+ @metadata_filenames << File.join(@cookbook_path, "metadata.json")
61
+ end
62
+
63
+ if empty?
64
+ Chef::Log.warn "found a directory #{cookbook_name} in the cookbook path, but it contains no cookbook files. skipping."
65
+ end
66
+ @cookbook_settings
67
+ end
68
+
69
+ def cookbook_version
70
+ return nil if empty?
71
+
72
+ Chef::CookbookVersion.new(@cookbook_name.to_sym).tap do |c|
73
+ c.root_dir = @cookbook_path
74
+ c.attribute_filenames = cookbook_settings[:attribute_filenames].values
75
+ c.definition_filenames = cookbook_settings[:definition_filenames].values
76
+ c.recipe_filenames = cookbook_settings[:recipe_filenames].values
77
+ c.template_filenames = cookbook_settings[:template_filenames].values
78
+ c.file_filenames = cookbook_settings[:file_filenames].values
79
+ c.library_filenames = cookbook_settings[:library_filenames].values
80
+ c.resource_filenames = cookbook_settings[:resource_filenames].values
81
+ c.provider_filenames = cookbook_settings[:provider_filenames].values
82
+ c.root_filenames = cookbook_settings[:root_filenames].values
83
+ c.metadata_filenames = @metadata_filenames
84
+ c.metadata = metadata(c)
85
+ end
86
+ end
87
+
88
+ # Generates the Cookbook::Metadata object
89
+ def metadata(cookbook_version)
90
+ @metadata = Chef::Cookbook::Metadata.new(cookbook_version)
91
+ @metadata_filenames.each do |meta_json|
92
+ begin
93
+ @metadata.from_json(IO.read(meta_json))
94
+ rescue JSON::ParserError
95
+ Chef::Log.error("Couldn't parse cookbook metadata JSON for #@cookbook_name in " + meta_json)
96
+ raise
97
+ end
98
+ end
99
+ @metadata
100
+ end
101
+
102
+ def empty?
103
+ cookbook_settings.inject(true) do |all_empty, files|
104
+ all_empty && files.last.empty?
105
+ end
106
+ end
107
+
108
+ def merge!(other_cookbook_loader)
109
+ other_cookbook_settings = other_cookbook_loader.cookbook_settings
110
+ @cookbook_settings.each do |file_type, file_list|
111
+ file_list.merge!(other_cookbook_settings[file_type])
112
+ end
113
+ @metadata_filenames.concat(other_cookbook_loader.metadata_filenames)
114
+ end
115
+
116
+ def chefignore
117
+ @chefignore ||= Chefignore.new(File.basename(@cookbook_path))
118
+ end
119
+
120
+ def load_root_files
121
+ Dir.glob(File.join(@cookbook_path, '*'), File::FNM_DOTMATCH).each do |file|
122
+ next if File.directory?(file)
123
+ @cookbook_settings[:root_filenames][file[@relative_path, 1]] = file
124
+ end
125
+ end
126
+
127
+ def load_recursively_as(category, category_dir, glob)
128
+ file_spec = File.join(@cookbook_path, category_dir, '**', glob)
129
+ Dir.glob(file_spec, File::FNM_DOTMATCH).each do |file|
130
+ next if File.directory?(file)
131
+ @cookbook_settings[category][file[@relative_path, 1]] = file
132
+ end
133
+ end
134
+
135
+ def load_as(category, *path_glob)
136
+ Dir[File.join(@cookbook_path, *path_glob)].each do |file|
137
+ @cookbook_settings[category][file[@relative_path, 1]] = file
138
+ end
139
+ end
140
+
141
+ def remove_ignored_files
142
+ @cookbook_settings.each_value do |file_list|
143
+ file_list.reject! do |relative_path, full_path|
144
+ chefignore.ignored?(relative_path)
145
+ end
146
+ end
147
+ end
148
+
149
+ end
150
+ end
151
+ end