chef 0.9.18 → 0.10.0.beta.0

Sign up to get free protection for your applications and to get access to all the features.
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