chef 0.9.0.a91 → 0.9.0.a92
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of chef might be problematic. Click here for more details.
- data/lib/chef/application.rb +6 -0
- data/lib/chef/client.rb +96 -80
- data/lib/chef/cookbook/remote_file_vendor.rb +79 -0
- data/lib/chef/cookbook_version.rb +7 -3
- data/lib/chef/exceptions.rb +1 -0
- data/lib/chef/file_cache.rb +26 -13
- data/lib/chef/knife/cookbook_site_vendor.rb +6 -1
- data/lib/chef/knife/ec2_server_create.rb +20 -9
- data/lib/chef/node.rb +40 -12
- data/lib/chef/node/attribute.rb +20 -6
- data/lib/chef/platform.rb +6 -3
- data/lib/chef/provider.rb +5 -0
- data/lib/chef/provider/mount/windows.rb +80 -0
- data/lib/chef/provider/package/rubygems.rb +1 -1
- data/lib/chef/providers.rb +1 -0
- data/lib/chef/resource.rb +5 -0
- data/lib/chef/role.rb +0 -14
- data/lib/chef/run_context.rb +2 -1
- data/lib/chef/run_list.rb +3 -3
- data/lib/chef/run_list/run_list_expansion.rb +16 -4
- data/lib/chef/search/query.rb +1 -1
- data/lib/chef/shell_out.rb +13 -6
- data/lib/chef/util/windows/net_use.rb +121 -0
- data/lib/chef/util/windows/volume.rb +59 -0
- data/lib/chef/version.rb +1 -1
- metadata +7 -3
data/lib/chef/application.rb
CHANGED
@@ -66,6 +66,12 @@ class Chef::Application
|
|
66
66
|
def configure_chef
|
67
67
|
parse_options
|
68
68
|
|
69
|
+
unless config[:config_file] && File.file?(config[:config_file])
|
70
|
+
Chef::Log.warn("*****************************************")
|
71
|
+
Chef::Log.warn("Can not find config file: #{config[:config_file]}, using defaults.")
|
72
|
+
Chef::Log.warn("*****************************************")
|
73
|
+
end
|
74
|
+
|
69
75
|
Chef::Config.from_file(config[:config_file]) if !config[:config_file].nil? && File.exists?(config[:config_file]) && File.readable?(config[:config_file])
|
70
76
|
Chef::Config.merge!(config)
|
71
77
|
end
|
data/lib/chef/client.rb
CHANGED
@@ -31,6 +31,7 @@ require 'chef/runner'
|
|
31
31
|
require 'chef/cookbook/cookbook_collection'
|
32
32
|
require 'chef/cookbook/file_vendor'
|
33
33
|
require 'chef/cookbook/file_system_file_vendor'
|
34
|
+
require 'chef/cookbook/remote_file_vendor'
|
34
35
|
require 'ohai'
|
35
36
|
|
36
37
|
class Chef
|
@@ -82,22 +83,29 @@ class Chef
|
|
82
83
|
assert_cookbook_path_not_empty(run_context)
|
83
84
|
converge(run_context)
|
84
85
|
else
|
86
|
+
# Keep track of the filenames that we use in both eager cookbook
|
87
|
+
# downloading (during sync_cookbooks) and lazy (during the run
|
88
|
+
# itself, through FileVendor). After the run is over, clean up the
|
89
|
+
# cache.
|
90
|
+
valid_cache_entries = Hash.new
|
91
|
+
|
85
92
|
save_node
|
93
|
+
|
94
|
+
# Sync_cookbooks eagerly loads all files except files and templates.
|
95
|
+
# It returns the cookbook_hash -- the return result from
|
96
|
+
# /nodes/#{nodename}/cookbooks -- which we will use for our
|
97
|
+
# run_context.
|
98
|
+
Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::RemoteFileVendor.new(manifest, rest, valid_cache_entries) }
|
99
|
+
cookbook_hash = sync_cookbooks(valid_cache_entries)
|
100
|
+
run_context = Chef::RunContext.new(node, Chef::CookbookCollection.new(cookbook_hash))
|
86
101
|
|
87
|
-
# Note: When we move to lazily loading all cookbook files,
|
88
|
-
# replace sync_cookbooks with a method that simply gets the
|
89
|
-
# cookbook manifests from the remote server (and their
|
90
|
-
# download URLs) from the server and feeds them to
|
91
|
-
# RemoteFileVendors. [cw/tim-5/11/2010, 5/23/2010]
|
92
|
-
Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest) }
|
93
|
-
# Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::RemoteFileVendor.new(manifest) }
|
94
|
-
sync_cookbooks
|
95
|
-
run_context = Chef::RunContext.new(node, Chef::CookbookCollection.new(Chef::CookbookLoader.new))
|
96
102
|
assert_cookbook_path_not_empty(run_context)
|
97
103
|
save_node
|
98
104
|
|
99
105
|
converge(run_context)
|
100
106
|
save_node
|
107
|
+
|
108
|
+
cleanup_file_cache(valid_cache_entries)
|
101
109
|
end
|
102
110
|
|
103
111
|
end_time = Time.now
|
@@ -146,9 +154,9 @@ class Chef
|
|
146
154
|
def determine_node_name
|
147
155
|
unless node_name
|
148
156
|
if Chef::Config[:node_name]
|
149
|
-
|
157
|
+
@node_name = Chef::Config[:node_name]
|
150
158
|
else
|
151
|
-
|
159
|
+
@node_name = ohai[:fqdn] ? ohai[:fqdn] : ohai[:hostname]
|
152
160
|
Chef::Config[:node_name] = node_name
|
153
161
|
end
|
154
162
|
|
@@ -163,37 +171,29 @@ class Chef
|
|
163
171
|
# === Returns
|
164
172
|
# node<Chef::Node>:: Returns the created node object, also stored in @node
|
165
173
|
def build_node
|
166
|
-
Chef::Log.debug("Building node object for #{node_name}")
|
174
|
+
Chef::Log.debug("Building node object for #{@node_name}")
|
167
175
|
|
168
176
|
unless Chef::Config[:solo]
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
177
|
+
begin
|
178
|
+
@node = rest.get_rest("nodes/#{@node_name}")
|
179
|
+
rescue Net::HTTPServerException => e
|
180
|
+
raise unless e.message =~ /^404/
|
181
|
+
end
|
174
182
|
end
|
175
183
|
|
176
184
|
unless node
|
177
185
|
@node_exists = false
|
178
|
-
|
179
|
-
node.name(node_name)
|
186
|
+
@node = Chef::Node.new
|
187
|
+
@node.name(node_name)
|
180
188
|
end
|
181
189
|
|
182
|
-
node.
|
183
|
-
|
184
|
-
|
190
|
+
@node.prepare_for_run(ohai.data, @json_attribs)
|
191
|
+
# Need to nil-ify the json attribs so they are not applied on subsequent runs
|
192
|
+
@json_attribs = nil
|
185
193
|
|
186
|
-
platform, version = Chef::Platform.find_platform_and_version(node)
|
187
|
-
Chef::Log.debug("Platform is #{platform} version #{version}")
|
188
|
-
@node.automatic_attrs[:platform] = platform
|
189
|
-
@node.automatic_attrs[:platform_version] = version
|
190
|
-
# We clear defaults and overrides, so that any deleted attributes between runs are
|
191
|
-
# still gone.
|
192
|
-
@node.default_attrs = Mash.new
|
193
|
-
@node.override_attrs = Mash.new
|
194
194
|
@node
|
195
195
|
end
|
196
|
-
|
196
|
+
|
197
197
|
#
|
198
198
|
# === Returns
|
199
199
|
# rest<Chef::REST>:: returns Chef::REST connection object
|
@@ -208,19 +208,54 @@ class Chef
|
|
208
208
|
self.rest = Chef::REST.new(Chef::Config[:chef_server_url], node_name, Chef::Config[:client_key])
|
209
209
|
end
|
210
210
|
|
211
|
+
# Synchronizes all the cookbooks from the chef-server.
|
212
|
+
#
|
213
|
+
# === Returns
|
214
|
+
# true:: Always returns true
|
215
|
+
def sync_cookbooks(valid_cache_entries)
|
216
|
+
Chef::Log.debug("Synchronizing cookbooks")
|
217
|
+
cookbook_hash = rest.get_rest("nodes/#{node_name}/cookbooks")
|
218
|
+
Chef::Log.debug("Cookbooks to load: #{cookbook_hash.inspect}")
|
219
|
+
|
220
|
+
# Remove all cookbooks no longer relevant to this node
|
221
|
+
Chef::FileCache.find(File.join(%w{cookbooks ** *})).each do |cache_file|
|
222
|
+
cache_file =~ /^cookbooks\/([^\/]+)\//
|
223
|
+
unless cookbook_hash.has_key?($1)
|
224
|
+
Chef::Log.info("Removing #{cache_file} from the cache; its cookbook is no longer needed on this client.")
|
225
|
+
Chef::FileCache.delete(cache_file)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# Synchronize each of the node's cookbooks, and add to the
|
230
|
+
# valid_cache_entries hash.
|
231
|
+
cookbook_hash.values.each do |cookbook|
|
232
|
+
sync_cookbook_file_cache(cookbook, valid_cache_entries)
|
233
|
+
end
|
234
|
+
|
235
|
+
# register the file cache path in the cookbook path so that CookbookLoader actually picks up the synced cookbooks
|
236
|
+
Chef::Config[:cookbook_path] = File.join(Chef::Config[:file_cache_path], "cookbooks")
|
237
|
+
|
238
|
+
cookbook_hash
|
239
|
+
end
|
240
|
+
|
211
241
|
# Update the file caches for a given cache segment. Takes a segment name
|
212
242
|
# and a hash that matches one of the cookbooks/_attribute_files style
|
213
243
|
# remote file listings.
|
214
244
|
#
|
215
245
|
# === Parameters
|
216
|
-
#
|
217
|
-
#
|
218
|
-
|
246
|
+
# cookbook<Chef::Cookbook>:: The cookbook to update
|
247
|
+
# valid_cache_entries<Hash>:: Out-param; Added to this hash are the files that
|
248
|
+
# were referred to by this cookbook
|
249
|
+
def sync_cookbook_file_cache(cookbook, valid_cache_entries)
|
219
250
|
Chef::Log.debug("Synchronizing cookbook #{cookbook.name}")
|
220
251
|
|
221
|
-
|
222
|
-
|
223
|
-
|
252
|
+
# files and templates are lazily loaded, and will be done later.
|
253
|
+
eager_segments = Array(Chef::CookbookVersion::COOKBOOK_SEGMENTS)
|
254
|
+
eager_segments.delete(:files)
|
255
|
+
eager_segments.delete(:templates)
|
256
|
+
|
257
|
+
eager_segments.each do |segment|
|
258
|
+
segment_filenames = Array.new
|
224
259
|
cookbook.manifest[segment].each do |manifest_record|
|
225
260
|
# segment = cookbook segment
|
226
261
|
# remote_list = list of file hashes
|
@@ -229,7 +264,7 @@ class Chef
|
|
229
264
|
# just laying about.
|
230
265
|
|
231
266
|
cache_filename = File.join("cookbooks", cookbook.name, manifest_record['path'])
|
232
|
-
|
267
|
+
valid_cache_entries[cache_filename] = true
|
233
268
|
|
234
269
|
current_checksum = nil
|
235
270
|
if Chef::FileCache.has_key?(cache_filename)
|
@@ -245,17 +280,29 @@ class Chef
|
|
245
280
|
Chef::Log.info("Storing updated #{cache_filename} in the cache.")
|
246
281
|
Chef::FileCache.move_to(raw_file.path, cache_filename)
|
247
282
|
else
|
283
|
+
Chef::Log.debug("Not storing #{cache_filename}, as the cache is up to date.")
|
248
284
|
end
|
285
|
+
|
286
|
+
# make the segment filenames a full path.
|
287
|
+
full_path_cache_filename = Chef::FileCache.load(cache_filename, false)
|
288
|
+
segment_filenames << full_path_cache_filename
|
289
|
+
end
|
290
|
+
|
291
|
+
# replace segment filenames with a full-path one.
|
292
|
+
if segment.to_sym == :recipes
|
293
|
+
cookbook.recipe_filenames = segment_filenames
|
294
|
+
elsif segment.to_sym == :attributes
|
295
|
+
cookbook.attribute_filenames = segment_filenames
|
296
|
+
else
|
297
|
+
cookbook.segment_filenames(segment).replace(segment_filenames)
|
249
298
|
end
|
250
299
|
end
|
251
|
-
|
252
|
-
filenames_seen
|
253
300
|
end
|
254
301
|
|
255
302
|
def cleanup_file_cache(valid_cache_entries)
|
256
303
|
# Delete each file in the cache that we didn't encounter in the
|
257
304
|
# manifest.
|
258
|
-
Chef::FileCache.
|
305
|
+
Chef::FileCache.find(File.join(%w{cookbooks ** *})).each do |cache_filename|
|
259
306
|
unless valid_cache_entries[cache_filename]
|
260
307
|
Chef::Log.info("Removing #{cache_filename} from the cache; it is no longer on the server.")
|
261
308
|
Chef::FileCache.delete(cache_filename)
|
@@ -263,50 +310,19 @@ class Chef
|
|
263
310
|
end
|
264
311
|
end
|
265
312
|
|
266
|
-
# Synchronizes all the cookbooks from the chef-server.
|
267
|
-
#
|
268
|
-
# === Returns
|
269
|
-
# true:: Always returns true
|
270
|
-
def sync_cookbooks
|
271
|
-
Chef::Log.debug("Synchronizing cookbooks")
|
272
|
-
cookbook_hash = rest.get_rest("nodes/#{node_name}/cookbooks")
|
273
|
-
Chef::Log.debug("Cookbooks to load: #{cookbook_hash.inspect}")
|
274
|
-
|
275
|
-
# Remove all cookbooks no longer relevant to this node
|
276
|
-
Chef::FileCache.list.each do |cache_file|
|
277
|
-
if cache_file =~ /^cookbooks\/(.+?)\//
|
278
|
-
unless cookbook_hash.has_key?($1)
|
279
|
-
Chef::Log.info("Removing #{cache_file} from the cache; its cookbook is no longer needed on this client.")
|
280
|
-
Chef::FileCache.delete(cache_file)
|
281
|
-
end
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
# Synchronize each of the node's cookbooks
|
286
|
-
valid_cache_entries = cookbook_hash.values.inject({}) do |memo, cookbook|
|
287
|
-
memo.merge!(sync_cookbook_file_cache(cookbook))
|
288
|
-
memo
|
289
|
-
end
|
290
|
-
|
291
|
-
cleanup_file_cache(valid_cache_entries)
|
292
|
-
|
293
|
-
# register the file cache path in the cookbook path so that CookbookLoader actually picks up the synced cookbooks
|
294
|
-
Chef::Config[:cookbook_path] = File.join(Chef::Config[:file_cache_path], "cookbooks")
|
295
|
-
end
|
296
|
-
|
297
313
|
# Updates the current node configuration on the server.
|
298
314
|
#
|
299
315
|
# === Returns
|
300
|
-
#
|
316
|
+
# Chef::Node - the current node
|
301
317
|
def save_node
|
302
318
|
Chef::Log.debug("Saving the current state of node #{node_name}")
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
319
|
+
if node_exists
|
320
|
+
@node = @node.save
|
321
|
+
else
|
322
|
+
result = rest.post_rest("nodes", node)
|
323
|
+
@node_exists = true
|
324
|
+
@node = rest.get_rest(result['uri'])
|
325
|
+
end
|
310
326
|
end
|
311
327
|
|
312
328
|
# Converges the node.
|
@@ -0,0 +1,79 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Tim Hinderliter (<tim@opscode.com>)
|
3
|
+
# Copyright:: Copyright (c) 2010 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
|
+
require 'chef/cookbook/file_vendor'
|
20
|
+
|
21
|
+
# This FileVendor loads files by either fetching them from the local cache, or
|
22
|
+
# if not available, loading them from the remote server.
|
23
|
+
class Chef
|
24
|
+
class Cookbook
|
25
|
+
class RemoteFileVendor < FileVendor
|
26
|
+
|
27
|
+
def initialize(manifest, rest, valid_cache_entries)
|
28
|
+
@manifest = manifest
|
29
|
+
@cookbook_name = @manifest[:cookbook_name]
|
30
|
+
@rest = rest
|
31
|
+
@valid_cache_entries = valid_cache_entries
|
32
|
+
end
|
33
|
+
|
34
|
+
# Implements abstract base's requirement. It looks in the
|
35
|
+
# Chef::Config.cookbook_path file hierarchy for the requested
|
36
|
+
# file.
|
37
|
+
def get_filename(filename)
|
38
|
+
if filename =~ /([^\/]+)\/(.+)$/
|
39
|
+
segment = $1
|
40
|
+
else
|
41
|
+
raise "get_filename: Cannot determine segment/filename for incoming filename #{filename}"
|
42
|
+
end
|
43
|
+
|
44
|
+
raise "No such segment #{segment} in cookbook #{@cookbook_name}" unless @manifest[segment]
|
45
|
+
found_manifest_record = @manifest[segment].find {|manifest_record| manifest_record[:path] == filename }
|
46
|
+
raise "No such file #{filename} in #{@cookbook_name}" unless found_manifest_record
|
47
|
+
|
48
|
+
cache_filename = File.join("cookbooks", @cookbook_name, found_manifest_record['path'])
|
49
|
+
|
50
|
+
# update valid_cache_entries so the upstream cache cleaner knows what
|
51
|
+
# we've used.
|
52
|
+
@valid_cache_entries[cache_filename] = true
|
53
|
+
|
54
|
+
current_checksum = nil
|
55
|
+
if Chef::FileCache.has_key?(cache_filename)
|
56
|
+
current_checksum = Chef::CookbookVersion.checksum_cookbook_file(Chef::FileCache.load(cache_filename, false))
|
57
|
+
end
|
58
|
+
|
59
|
+
# If the checksums are different between on-disk (current) and on-server
|
60
|
+
# (remote, per manifest), do the update. This will also execute if there
|
61
|
+
# is no current checksum.
|
62
|
+
if current_checksum != found_manifest_record['checksum']
|
63
|
+
raw_file = @rest.get_rest(found_manifest_record[:url], true)
|
64
|
+
|
65
|
+
Chef::Log.info("Storing updated #{cache_filename} in the cache.")
|
66
|
+
Chef::FileCache.move_to(raw_file.path, cache_filename)
|
67
|
+
else
|
68
|
+
Chef::Log.debug("Not storing #{cache_filename}, as the cache is up to date.")
|
69
|
+
end
|
70
|
+
|
71
|
+
full_path_cache_filename = Chef::FileCache.load(cache_filename, false)
|
72
|
+
|
73
|
+
# return the filename, not the contents (second argument= false)
|
74
|
+
full_path_cache_filename
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -34,7 +34,6 @@ class Chef
|
|
34
34
|
:library_filenames, :resource_filenames, :provider_filenames, :root_filenames, :name,
|
35
35
|
:metadata, :metadata_filenames, :status, :couchdb_rev, :couchdb
|
36
36
|
attr_reader :couchdb_id
|
37
|
-
attr_reader :file_vendor
|
38
37
|
|
39
38
|
# attribute_filenames also has a setter that has non-default
|
40
39
|
# functionality.
|
@@ -380,7 +379,6 @@ class Chef
|
|
380
379
|
end
|
381
380
|
end
|
382
381
|
|
383
|
-
|
384
382
|
def relative_filenames_in_preferred_directory(node, segment, dirname)
|
385
383
|
preferences = preferences_for_path(node, segment, dirname)
|
386
384
|
filenames_by_pref = Hash.new
|
@@ -802,10 +800,16 @@ class Chef
|
|
802
800
|
manifest[:name] = full_name
|
803
801
|
|
804
802
|
@checksums = checksums_to_on_disk_paths
|
805
|
-
@file_vendor = Chef::Cookbook::FileVendor.create_from_manifest(manifest)
|
806
803
|
@manifest = manifest
|
807
804
|
@manifest_records_by_path = extract_manifest_records_by_path(manifest)
|
808
805
|
end
|
806
|
+
|
807
|
+
def file_vendor
|
808
|
+
unless @file_vendor
|
809
|
+
@file_vendor = Chef::Cookbook::FileVendor.create_from_manifest(manifest)
|
810
|
+
end
|
811
|
+
@file_vendor
|
812
|
+
end
|
809
813
|
|
810
814
|
def extract_checksums_from_manifest(manifest)
|
811
815
|
checksums = {}
|
data/lib/chef/exceptions.rb
CHANGED
@@ -29,6 +29,7 @@ class Chef
|
|
29
29
|
class Override < RuntimeError; end
|
30
30
|
class UnsupportedAction < RuntimeError; end
|
31
31
|
class MissingLibrary < RuntimeError; end
|
32
|
+
class MissingRole < RuntimeError; end
|
32
33
|
class User < RuntimeError; end
|
33
34
|
class Group < RuntimeError; end
|
34
35
|
class Link < RuntimeError; end
|
data/lib/chef/file_cache.rb
CHANGED
@@ -31,7 +31,7 @@ class Chef
|
|
31
31
|
#
|
32
32
|
# === Parameters
|
33
33
|
# path<String>:: The path to the file you want to put in the cache - should
|
34
|
-
# be relative to
|
34
|
+
# be relative to file_cache_path
|
35
35
|
# contents<String>:: A string with the contents you want written to the file
|
36
36
|
#
|
37
37
|
# === Returns
|
@@ -51,9 +51,9 @@ class Chef
|
|
51
51
|
file_path_array = File.split(path)
|
52
52
|
file_name = file_path_array.pop
|
53
53
|
cache_path = create_cache_path(File.join(file_path_array))
|
54
|
-
|
55
|
-
|
56
|
-
|
54
|
+
File.open(File.join(cache_path, file_name), "w") do |io|
|
55
|
+
io.print(contents)
|
56
|
+
end
|
57
57
|
true
|
58
58
|
end
|
59
59
|
|
@@ -90,7 +90,7 @@ class Chef
|
|
90
90
|
#
|
91
91
|
# === Parameters
|
92
92
|
# path<String>:: The path to the file you want to load - should
|
93
|
-
# be relative to
|
93
|
+
# be relative to file_cache_path
|
94
94
|
# read<True/False>:: Whether to return the file contents, or the path.
|
95
95
|
# Defaults to true.
|
96
96
|
#
|
@@ -121,7 +121,7 @@ class Chef
|
|
121
121
|
#
|
122
122
|
# === Parameters
|
123
123
|
# path<String>:: The path to the file you want to delete - should
|
124
|
-
# be relative to
|
124
|
+
# be relative to file_cache_path
|
125
125
|
#
|
126
126
|
# === Returns
|
127
127
|
# true
|
@@ -145,12 +145,19 @@ class Chef
|
|
145
145
|
#
|
146
146
|
# === Returns
|
147
147
|
# Array:: An array of files in the cache, suitable for use with load, delete and store
|
148
|
-
def list
|
148
|
+
def list
|
149
|
+
find("**#{File::Separator}*")
|
150
|
+
end
|
151
|
+
|
152
|
+
##
|
153
|
+
# Find files in the cache by +glob_pattern+
|
154
|
+
# === Returns
|
155
|
+
# [String] - An array of file cache keys matching the glob
|
156
|
+
def find(glob_pattern)
|
149
157
|
keys = Array.new
|
150
|
-
Dir[File.join(
|
158
|
+
Dir[File.join(file_cache_path, glob_pattern)].each do |f|
|
151
159
|
if File.file?(f)
|
152
|
-
|
153
|
-
keys << path
|
160
|
+
keys << f[/^#{Regexp.escape(Dir[file_cache_path].first) + File::Separator}(.+)/, 1]
|
154
161
|
end
|
155
162
|
end
|
156
163
|
keys
|
@@ -160,7 +167,7 @@ class Chef
|
|
160
167
|
#
|
161
168
|
# === Parameters
|
162
169
|
# path:: The path to the file you want to check - is relative
|
163
|
-
# to
|
170
|
+
# to file_cache_path
|
164
171
|
#
|
165
172
|
# === Returns
|
166
173
|
# True:: If the file exists
|
@@ -186,13 +193,13 @@ class Chef
|
|
186
193
|
# also creates the path if it does not exist.
|
187
194
|
#
|
188
195
|
# === Parameters
|
189
|
-
# path:: The path to create, relative to
|
196
|
+
# path:: The path to create, relative to file_cache_path
|
190
197
|
# create_if_missing:: True by default - whether to create the path if it does not exist
|
191
198
|
#
|
192
199
|
# === Returns
|
193
200
|
# String:: The fully expanded path
|
194
201
|
def create_cache_path(path, create_if_missing=true)
|
195
|
-
cache_dir = File.expand_path(File.join(
|
202
|
+
cache_dir = File.expand_path(File.join(file_cache_path, path))
|
196
203
|
if create_if_missing
|
197
204
|
create_path(cache_dir)
|
198
205
|
else
|
@@ -200,6 +207,12 @@ class Chef
|
|
200
207
|
end
|
201
208
|
end
|
202
209
|
|
210
|
+
private
|
211
|
+
|
212
|
+
def file_cache_path
|
213
|
+
Chef::Config[:file_cache_path]
|
214
|
+
end
|
215
|
+
|
203
216
|
end
|
204
217
|
end
|
205
218
|
end
|
@@ -32,7 +32,12 @@ class Chef
|
|
32
32
|
:description => "Grab dependencies automatically"
|
33
33
|
|
34
34
|
def run
|
35
|
-
|
35
|
+
if config[:cookbook_path]
|
36
|
+
vendor_path = File.expand_path(File.join(config[:cookbook_path].first))
|
37
|
+
else
|
38
|
+
Chef::Log.warn("cookbook path is not configured in your knife.rb, using the current directory for the cookbook repo")
|
39
|
+
vendor_path = Dir.pwd
|
40
|
+
end
|
36
41
|
cookbook_path = File.join(vendor_path, name_args[0])
|
37
42
|
upstream_file = File.join(vendor_path, "#{name_args[0]}.tar.gz")
|
38
43
|
branch_name = "chef-vendor-#{name_args[0]}"
|
@@ -73,6 +73,10 @@ class Chef
|
|
73
73
|
:description => "Your AWS API Secret Access Key",
|
74
74
|
:proc => Proc.new { |key| Chef::Config[:knife][:aws_secret_access_key] = key }
|
75
75
|
|
76
|
+
option :prerelease,
|
77
|
+
:long => "--prerelease",
|
78
|
+
:description => "Install the pre-release chef gems"
|
79
|
+
|
76
80
|
def h
|
77
81
|
@highline ||= HighLine.new
|
78
82
|
end
|
@@ -117,15 +121,22 @@ class Chef
|
|
117
121
|
puts "#{h.color("Private DNS Name", :cyan)}: #{server.private_dns_name}"
|
118
122
|
puts "#{h.color("Private IP Address", :cyan)}: #{server.private_ip_address}"
|
119
123
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
124
|
+
begin
|
125
|
+
bootstrap = Chef::Knife::Bootstrap.new
|
126
|
+
bootstrap.name_args = [ server.ip_address, @name_args ].flatten
|
127
|
+
bootstrap.config[:ssh_user] = config[:ssh_user]
|
128
|
+
bootstrap.config[:chef_node_name] = server.id
|
129
|
+
bootstrap.config[:prerelease] = config[:prerelease]
|
130
|
+
bootstrap.run
|
131
|
+
rescue Errno::ECONNREFUSED
|
132
|
+
puts h.color("Connection refused on SSH, retrying - CTRL-C to abort")
|
133
|
+
sleep 1
|
134
|
+
retry
|
135
|
+
rescue Errno::ETIMEDOUT
|
136
|
+
puts h.color("Connection timed out on SSH, retrying - CTRL-C to abort")
|
137
|
+
sleep 1
|
138
|
+
retry
|
139
|
+
end
|
129
140
|
|
130
141
|
puts "\n"
|
131
142
|
puts "#{h.color("Instance ID", :cyan)}: #{server.id}"
|
data/lib/chef/node.rb
CHANGED
@@ -315,7 +315,6 @@ class Chef
|
|
315
315
|
# as using the normal/default/override interface.
|
316
316
|
def method_missing(symbol, *args)
|
317
317
|
attrs = construct_attributes
|
318
|
-
attrs.set_type = :normal
|
319
318
|
attrs.send(symbol, *args)
|
320
319
|
end
|
321
320
|
|
@@ -353,18 +352,24 @@ class Chef
|
|
353
352
|
run_list.detect { |r| r == item } ? true : false
|
354
353
|
end
|
355
354
|
|
356
|
-
def
|
357
|
-
attrs
|
358
|
-
Chef::Log.debug("Adding JSON Attributes")
|
355
|
+
def consume_run_list(attrs)
|
356
|
+
attrs = attrs ? attrs.dup : {}
|
359
357
|
if new_run_list = attrs.delete("recipes") || attrs.delete("run_list")
|
360
358
|
if attrs.key?("recipes") || attrs.key?("run_list")
|
361
359
|
raise Chef::Exceptions::AmbiguousRunlistSpecification, "please set the node's run list using the 'run_list' attribute only."
|
362
360
|
end
|
363
|
-
Chef::Log.info("
|
361
|
+
Chef::Log.info("Setting the run_list to #{new_run_list.inspect} from JSON")
|
364
362
|
run_list(new_run_list)
|
365
363
|
end
|
366
|
-
|
364
|
+
attrs
|
365
|
+
end
|
367
366
|
|
367
|
+
# TODO: this code should be killed and removed, but it is used by shef and
|
368
|
+
# I don't have time to fix it right now. [Dan - 09/Jun/2010]
|
369
|
+
def consume_attributes(attrs)
|
370
|
+
attrs = consume_run_list(attrs)
|
371
|
+
Chef::Log.debug("Applying attributes from json file")
|
372
|
+
@normal_attrs = Chef::Mixin::DeepMerge.merge(@normal_attrs,attrs)
|
368
373
|
self[:tags] = Array.new unless attribute?(:tags)
|
369
374
|
end
|
370
375
|
|
@@ -531,8 +536,25 @@ class Chef
|
|
531
536
|
self
|
532
537
|
end
|
533
538
|
|
539
|
+
def prepare_for_run(ohai_data, json_cli_attrs)
|
540
|
+
Chef::Log.debug("Extracting run list from JSON attributes provided on command line")
|
541
|
+
@json_attrib_for_expansion = consume_run_list(json_cli_attrs)
|
542
|
+
|
543
|
+
node.automatic_attrs = ohai_data
|
544
|
+
|
545
|
+
platform, version = Chef::Platform.find_platform_and_version(self)
|
546
|
+
Chef::Log.debug("Platform is #{platform} version #{version}")
|
547
|
+
@automatic_attrs[:platform] = platform
|
548
|
+
@automatic_attrs[:platform_version] = version
|
549
|
+
# We clear defaults and overrides, so that any deleted attributes between runs are
|
550
|
+
# still gone.
|
551
|
+
@default_attrs = Mash.new
|
552
|
+
@override_attrs = Mash.new
|
553
|
+
end
|
554
|
+
|
534
555
|
# Expands the node's run list and deep merges the default and
|
535
|
-
# override attributes.
|
556
|
+
# override attributes. Also applies stored attributes (from json provided
|
557
|
+
# on the command line)
|
536
558
|
#
|
537
559
|
# Returns the fully-expanded list of recipes.
|
538
560
|
#
|
@@ -541,12 +563,18 @@ class Chef
|
|
541
563
|
# run_list is mutated? Or perhaps do something smarter like
|
542
564
|
# on-demand generation of default_attrs and override_attrs,
|
543
565
|
# invalidated only when run_list is mutated?
|
544
|
-
def
|
566
|
+
def expand!
|
545
567
|
# This call should only be called on a chef-client run.
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
568
|
+
expansion = run_list.expand('server')
|
569
|
+
raise Chef::Exceptions::MissingRole if expansion.errors?
|
570
|
+
|
571
|
+
Chef::Log.debug("Applying attributes from json file")
|
572
|
+
@normal_attrs = Chef::Mixin::DeepMerge.merge(@normal_attrs, @json_attrib_for_expansion)
|
573
|
+
self[:tags] = Array.new unless attribute?(:tags)
|
574
|
+
@default_attrs = Chef::Mixin::DeepMerge.merge(default_attrs, expansion.default_attrs)
|
575
|
+
@override_attrs = Chef::Mixin::DeepMerge.merge(override_attrs, expansion.override_attrs)
|
576
|
+
|
577
|
+
expansion.recipes
|
550
578
|
end
|
551
579
|
|
552
580
|
end
|
data/lib/chef/node/attribute.rb
CHANGED
@@ -51,7 +51,7 @@ class Chef
|
|
51
51
|
@state = state
|
52
52
|
@auto_vivifiy_on_read = false
|
53
53
|
@set_unless_value_present = false
|
54
|
-
@set_type =
|
54
|
+
@set_type = nil
|
55
55
|
@has_been_read = false
|
56
56
|
end
|
57
57
|
|
@@ -93,12 +93,23 @@ class Chef
|
|
93
93
|
# See the comments in []= for more details.
|
94
94
|
@has_been_read = true
|
95
95
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
96
|
+
# If we have a set type, our destiny is to write
|
97
|
+
if @set_type
|
98
|
+
a_value = @set_type == :automatic ? value_or_descend(current_automatic, key, auto_vivifiy_on_read) : nil
|
99
|
+
o_value = @set_type == :override ? value_or_descend(current_override, key, auto_vivifiy_on_read) : nil
|
100
|
+
n_value = @set_type == :normal ? value_or_descend(current_normal, key, auto_vivifiy_on_read) : nil
|
101
|
+
d_value = @set_type == :default ? value_or_descend(current_default, key, auto_vivifiy_on_read) : nil
|
100
102
|
|
101
|
-
|
103
|
+
determine_value(a_value, o_value, n_value, d_value)
|
104
|
+
# Our destiny is only to read, so we get the full list.
|
105
|
+
else
|
106
|
+
a_value = value_or_descend(current_automatic, key)
|
107
|
+
o_value = value_or_descend(current_override, key)
|
108
|
+
n_value = value_or_descend(current_normal, key)
|
109
|
+
d_value = value_or_descend(current_default, key)
|
110
|
+
|
111
|
+
determine_value(a_value, o_value, n_value, d_value)
|
112
|
+
end
|
102
113
|
end
|
103
114
|
|
104
115
|
def attribute?(key)
|
@@ -309,6 +320,9 @@ class Chef
|
|
309
320
|
end
|
310
321
|
|
311
322
|
def []=(key, value)
|
323
|
+
# If we don't have one, then we'll pretend we're normal
|
324
|
+
@set_type ||= :normal
|
325
|
+
|
312
326
|
if set_unless_value_present
|
313
327
|
if get_value(set_type_hash, key) != nil
|
314
328
|
Chef::Log.debug("Not setting #{state.join("/")}/#{key} to #{value.inspect} because it has a #{@set_type} value already")
|
data/lib/chef/platform.rb
CHANGED
@@ -132,7 +132,8 @@ class Chef
|
|
132
132
|
:env => Chef::Provider::Env::Windows,
|
133
133
|
:service => Chef::Provider::Service::Windows,
|
134
134
|
:user => Chef::Provider::User::Windows,
|
135
|
-
:group => Chef::Provider::Group::Windows
|
135
|
+
:group => Chef::Provider::Group::Windows,
|
136
|
+
:mount => Chef::Provider::Mount::Windows
|
136
137
|
}
|
137
138
|
},
|
138
139
|
:mingw32 => {
|
@@ -140,7 +141,8 @@ class Chef
|
|
140
141
|
:env => Chef::Provider::Env::Windows,
|
141
142
|
:service => Chef::Provider::Service::Windows,
|
142
143
|
:user => Chef::Provider::User::Windows,
|
143
|
-
:group => Chef::Provider::Group::Windows
|
144
|
+
:group => Chef::Provider::Group::Windows,
|
145
|
+
:mount => Chef::Provider::Mount::Windows
|
144
146
|
}
|
145
147
|
},
|
146
148
|
:windows => {
|
@@ -148,7 +150,8 @@ class Chef
|
|
148
150
|
:env => Chef::Provider::Env::Windows,
|
149
151
|
:service => Chef::Provider::Service::Windows,
|
150
152
|
:user => Chef::Provider::User::Windows,
|
151
|
-
:group => Chef::Provider::Group::Windows
|
153
|
+
:group => Chef::Provider::Group::Windows,
|
154
|
+
:mount => Chef::Provider::Mount::Windows
|
152
155
|
}
|
153
156
|
},
|
154
157
|
:solaris => {},
|
data/lib/chef/provider.rb
CHANGED
@@ -84,6 +84,11 @@ class Chef
|
|
84
84
|
def build_from_file(cookbook_name, filename)
|
85
85
|
pname = filename_to_qualified_string(cookbook_name, filename)
|
86
86
|
|
87
|
+
# Add log entry if we override an existing light-weight provider.
|
88
|
+
class_name = convert_to_class_name(pname)
|
89
|
+
overriding = Chef::Provider.const_defined?(class_name)
|
90
|
+
Chef::Log.info("#{class_name} light-weight provider already initialized -- overriding!") if overriding
|
91
|
+
|
87
92
|
new_provider_class = Class.new self do |cls|
|
88
93
|
|
89
94
|
def load_current_resource
|
@@ -0,0 +1,80 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Doug MacEachern (<dougm@vmware.com>)
|
3
|
+
# Copyright:: Copyright (c) 2010 VMware, 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
|
+
require 'chef/provider/mount'
|
20
|
+
if RUBY_PLATFORM =~ /mswin|mingw32|windows/
|
21
|
+
require 'chef/util/windows/net_use'
|
22
|
+
require 'chef/util/windows/volume'
|
23
|
+
end
|
24
|
+
|
25
|
+
class Chef
|
26
|
+
class Provider
|
27
|
+
class Mount
|
28
|
+
class Windows < Chef::Provider::Mount
|
29
|
+
|
30
|
+
def is_volume(name)
|
31
|
+
name =~ /^\\\\\?\\Volume\{[\w-]+\}\\$/ ? true : false
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(new_resource, run_context)
|
35
|
+
super
|
36
|
+
@mount = nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def load_current_resource
|
40
|
+
if is_volume(@new_resource.device)
|
41
|
+
@mount = Chef::Util::Windows::Volume.new(@new_resource.name)
|
42
|
+
else #assume network drive
|
43
|
+
@mount = Chef::Util::Windows::NetUse.new(@new_resource.name)
|
44
|
+
end
|
45
|
+
|
46
|
+
@current_resource = Chef::Resource::Mount.new(@new_resource.name)
|
47
|
+
@current_resource.mount_point(@new_resource.mount_point)
|
48
|
+
Chef::Log.debug("Checking for mount point #{@current_resource.mount_point}")
|
49
|
+
|
50
|
+
begin
|
51
|
+
@current_resource.device(@mount.device)
|
52
|
+
Chef::Log.debug("#{@current_resource.device} mounted on #{@new_resource.mount_point}")
|
53
|
+
@current_resource.mounted(true)
|
54
|
+
rescue ArgumentError => e
|
55
|
+
@current_resource.mounted(false)
|
56
|
+
Chef::Log.debug("#{@new_resource.mount_point} is not mounted: #{e.message}")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def mount_fs
|
61
|
+
unless @current_resource.mounted
|
62
|
+
@mount.add(@new_resource.device)
|
63
|
+
else
|
64
|
+
Chef::Log.debug("#{@new_resource.mount_point} is already mounted.")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def umount_fs
|
69
|
+
if @current_resource.mounted
|
70
|
+
@mount.delete
|
71
|
+
Chef::Log.info("Unmounted #{@new_resource.mount_point}")
|
72
|
+
else
|
73
|
+
Chef::Log.debug("#{@new_resource.mount_point} is not mounted.")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -348,7 +348,7 @@ class Chef
|
|
348
348
|
|
349
349
|
def all_installed_versions
|
350
350
|
@all_installed_versions ||= begin
|
351
|
-
@gem_env.installed_versions(Gem::Dependency.new(gem_dependency.name))
|
351
|
+
@gem_env.installed_versions(Gem::Dependency.new(gem_dependency.name, '>= 0'))
|
352
352
|
end
|
353
353
|
end
|
354
354
|
|
data/lib/chef/providers.rb
CHANGED
data/lib/chef/resource.rb
CHANGED
@@ -295,6 +295,11 @@ class Chef
|
|
295
295
|
|
296
296
|
def build_from_file(cookbook_name, filename)
|
297
297
|
rname = filename_to_qualified_string(cookbook_name, filename)
|
298
|
+
|
299
|
+
# Add log entry if we override an existing light-weight resource.
|
300
|
+
class_name = convert_to_class_name(rname)
|
301
|
+
overriding = Chef::Resource.const_defined?(class_name)
|
302
|
+
Chef::Log.info("#{class_name} light-weight resource already initialized -- overriding!") if overriding
|
298
303
|
|
299
304
|
new_resource_class = Class.new self do |cls|
|
300
305
|
|
data/lib/chef/role.rb
CHANGED
@@ -209,25 +209,11 @@ class Chef
|
|
209
209
|
# Remove this role from the CouchDB
|
210
210
|
def cdb_destroy
|
211
211
|
couchdb.delete("role", @name, couchdb_rev)
|
212
|
-
|
213
|
-
rs = couchdb.get_view("nodes", "by_run_list", :startkey => "role[#{@name}]", :endkey => "role[#{@name}]", :include_docs => true)
|
214
|
-
rs["rows"].each do |row|
|
215
|
-
node = row["doc"]
|
216
|
-
node.run_list.remove("role[#{@name}]")
|
217
|
-
node.cdb_save
|
218
|
-
end
|
219
212
|
end
|
220
213
|
|
221
214
|
# Remove this role via the REST API
|
222
215
|
def destroy
|
223
216
|
chef_server_rest.delete_rest("roles/#{@name}")
|
224
|
-
|
225
|
-
Chef::Node.list.each do |node|
|
226
|
-
n = Chef::Node.load(node[0])
|
227
|
-
n.run_list.remove("role[#{@name}]")
|
228
|
-
n.save
|
229
|
-
end
|
230
|
-
|
231
217
|
end
|
232
218
|
|
233
219
|
# Save this role to the CouchDB
|
data/lib/chef/run_context.rb
CHANGED
@@ -85,7 +85,8 @@ class Chef
|
|
85
85
|
# Retrieve the fully expanded list of recipes for the node by
|
86
86
|
# resolving roles; this step also merges attributes into the
|
87
87
|
# node from the roles/recipes included.
|
88
|
-
recipe_names = node.
|
88
|
+
recipe_names = node.expand!
|
89
|
+
|
89
90
|
recipe_names.each do |recipe_name|
|
90
91
|
# TODO: timh/cw, 5-14-2010: It's distasteful to be including
|
91
92
|
# the DSL in a class outside the context of the DSL
|
data/lib/chef/run_list.rb
CHANGED
@@ -66,8 +66,8 @@ class Chef
|
|
66
66
|
if other.kind_of?(Chef::RunList)
|
67
67
|
other.run_list_items == @run_list_items
|
68
68
|
else
|
69
|
-
|
70
|
-
|
69
|
+
return false unless other.respond_to?(:size) && (other.size == @run_list_items.size)
|
70
|
+
other_run_list_items = other.dup
|
71
71
|
|
72
72
|
other_run_list_items.map! { |item| item.kind_of?(RunListItem) ? item : RunListItem.new(item) }
|
73
73
|
other_run_list_items == @run_list_items
|
@@ -124,7 +124,7 @@ class Chef
|
|
124
124
|
|
125
125
|
expansion = expansion_for_data_source(data_source, :couchdb => couchdb, :rest => rest)
|
126
126
|
expansion.expand
|
127
|
-
|
127
|
+
expansion
|
128
128
|
end
|
129
129
|
|
130
130
|
# Converts a string run list entry to a RunListItem object.
|
@@ -37,12 +37,16 @@ class Chef
|
|
37
37
|
|
38
38
|
attr_reader :override_attrs
|
39
39
|
|
40
|
+
attr_reader :errors
|
41
|
+
|
40
42
|
# The data source passed to the constructor. Not used in this class.
|
41
43
|
# In subclasses, this is a couchdb or Chef::REST object pre-configured
|
42
44
|
# to fetch roles from their correct location.
|
43
45
|
attr_reader :source
|
44
46
|
|
45
47
|
def initialize(run_list_items, source=nil)
|
48
|
+
@errors = Array.new
|
49
|
+
|
46
50
|
@run_list_items = run_list_items.dup
|
47
51
|
@source = source
|
48
52
|
|
@@ -54,8 +58,15 @@ class Chef
|
|
54
58
|
@applied_roles = {}
|
55
59
|
end
|
56
60
|
|
61
|
+
# Did we find any errors (expanding roles)?
|
62
|
+
def errors?
|
63
|
+
@errors.length > 0
|
64
|
+
end
|
65
|
+
|
66
|
+
alias :invalid? :errors?
|
67
|
+
|
57
68
|
# Iterates over the run list items, expanding roles. After this,
|
58
|
-
# +recipes+ will the fully expanded recipe list
|
69
|
+
# +recipes+ will contain the fully expanded recipe list
|
59
70
|
def expand
|
60
71
|
@run_list_items.each_with_index do |entry, index|
|
61
72
|
case entry.type
|
@@ -99,12 +110,13 @@ class Chef
|
|
99
110
|
raise NotImplementedError
|
100
111
|
end
|
101
112
|
|
102
|
-
# When a role is not found, an error message
|
103
|
-
# exception
|
113
|
+
# When a role is not found, an error message is logged, but no
|
114
|
+
# exception is raised. We do add an entry in the errors collection.
|
104
115
|
# === Returns
|
105
116
|
# nil
|
106
117
|
def role_not_found(name)
|
107
118
|
Chef::Log.error("Role #{name} is in the runlist but does not exist. Skipping expand.")
|
119
|
+
@errors << name
|
108
120
|
nil
|
109
121
|
end
|
110
122
|
end
|
@@ -153,4 +165,4 @@ class Chef
|
|
153
165
|
|
154
166
|
end
|
155
167
|
end
|
156
|
-
end
|
168
|
+
end
|
data/lib/chef/search/query.rb
CHANGED
@@ -31,7 +31,7 @@ class Chef
|
|
31
31
|
|
32
32
|
# Search Solr for objects of a given type, for a given query. If you give
|
33
33
|
# it a block, it will handle the paging for you dynamically.
|
34
|
-
def search(type, query="*:*", sort=
|
34
|
+
def search(type, query="*:*", sort='X_CHEF_id_CHEF_X asc', start=0, rows=1000, &block)
|
35
35
|
raise ArgumentError, "Type must be a string or a symbol!" unless (type.kind_of?(String) || type.kind_of?(Symbol))
|
36
36
|
|
37
37
|
response = @rest.get_rest("search/#{type}?q=#{escape(query)}&sort=#{escape(sort)}&start=#{escape(start)}&rows=#{escape(rows)}")
|
data/lib/chef/shell_out.rb
CHANGED
@@ -35,6 +35,7 @@ class Chef
|
|
35
35
|
# or jruby.
|
36
36
|
class ShellOut
|
37
37
|
READ_WAIT_TIME = 0.01
|
38
|
+
READ_SIZE = 4096
|
38
39
|
DEFAULT_READ_TIMEOUT = 60
|
39
40
|
DEFAULT_ENVIRONMENT = {'LC_ALL' => 'C'}
|
40
41
|
|
@@ -129,7 +130,6 @@ class Chef
|
|
129
130
|
# within +timeout+ seconds (default: 60s)
|
130
131
|
def run_command
|
131
132
|
Chef::Log.debug("sh(#{@command})")
|
132
|
-
|
133
133
|
@child_pid = fork_subprocess
|
134
134
|
|
135
135
|
configure_parent_process_file_descriptors
|
@@ -138,6 +138,11 @@ class Chef
|
|
138
138
|
@result = nil
|
139
139
|
read_time = 0
|
140
140
|
|
141
|
+
# Ruby 1.8.7 and 1.8.6 from mid 2009 try to allocate objects during GC
|
142
|
+
# when calling IO.select and IO#read. Some OS Vendors are not interested
|
143
|
+
# in updating their ruby packages (Apple, *cough*) and we *have to*
|
144
|
+
# make it work. So I give you this epic hack:
|
145
|
+
GC.disable
|
141
146
|
until @status
|
142
147
|
ready = IO.select(open_pipes, nil, nil, READ_WAIT_TIME)
|
143
148
|
unless ready
|
@@ -169,6 +174,10 @@ class Chef
|
|
169
174
|
Process.waitpid2(@child_pid, Process::WNOHANG) rescue nil
|
170
175
|
raise
|
171
176
|
ensure
|
177
|
+
# no matter what happens, turn the GC back on, and hope whatever busted
|
178
|
+
# version of ruby we're on doesn't allocate some objects during the next
|
179
|
+
# GC run.
|
180
|
+
GC.enable
|
172
181
|
close_all_pipes
|
173
182
|
end
|
174
183
|
|
@@ -303,9 +312,7 @@ class Chef
|
|
303
312
|
# Get output as it happens rather than buffered
|
304
313
|
child_stdout.sync = true
|
305
314
|
child_stderr.sync = true
|
306
|
-
|
307
|
-
child_stdout.fcntl(Fcntl::F_SETFL, child_stdout.fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK)
|
308
|
-
child_stderr.fcntl(Fcntl::F_SETFL, child_stderr.fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK)
|
315
|
+
|
309
316
|
true
|
310
317
|
end
|
311
318
|
|
@@ -316,7 +323,7 @@ class Chef
|
|
316
323
|
end
|
317
324
|
|
318
325
|
def read_stdout_to_buffer
|
319
|
-
while chunk = child_stdout.
|
326
|
+
while chunk = child_stdout.read_nonblock(READ_SIZE)
|
320
327
|
@stdout << chunk
|
321
328
|
end
|
322
329
|
rescue Errno::EAGAIN
|
@@ -325,7 +332,7 @@ class Chef
|
|
325
332
|
end
|
326
333
|
|
327
334
|
def read_stderr_to_buffer
|
328
|
-
while chunk = child_stderr.
|
335
|
+
while chunk = child_stderr.read_nonblock(READ_SIZE)
|
329
336
|
@stderr << chunk
|
330
337
|
end
|
331
338
|
rescue Errno::EAGAIN
|
@@ -0,0 +1,121 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Doug MacEachern (<dougm@vmware.com>)
|
3
|
+
# Copyright:: Copyright (c) 2010 VMware, 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
|
+
#the Win32 Volume APIs do not support mapping network drives. not supported by WMI either.
|
20
|
+
#see also: WNetAddConnection2 and WNetAddConnection3
|
21
|
+
#see also cmd.exe: net use /?
|
22
|
+
|
23
|
+
require 'chef/util/windows'
|
24
|
+
|
25
|
+
class Chef::Util::Windows::NetUse < Chef::Util::Windows
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
USE_NOFORCE = 0
|
30
|
+
USE_FORCE = 1
|
31
|
+
USE_LOTS_OF_FORCE = 2 #every windows API should support this flag
|
32
|
+
|
33
|
+
USE_INFO_2 = [
|
34
|
+
[:local, nil],
|
35
|
+
[:remote, nil],
|
36
|
+
[:password, nil],
|
37
|
+
[:status, 0],
|
38
|
+
[:asg_type, 0],
|
39
|
+
[:refcount, 0],
|
40
|
+
[:usecount, 0],
|
41
|
+
[:username, nil],
|
42
|
+
[:domainname, nil]
|
43
|
+
]
|
44
|
+
|
45
|
+
USE_INFO_2_TEMPLATE =
|
46
|
+
USE_INFO_2.collect { |field| field[1].class == Fixnum ? 'i' : 'L' }.join
|
47
|
+
|
48
|
+
SIZEOF_USE_INFO_2 = #sizeof(USE_INFO_2)
|
49
|
+
USE_INFO_2.inject(0){|sum,item|
|
50
|
+
sum + (item[1].class == Fixnum ? 4 : PTR_SIZE)
|
51
|
+
}
|
52
|
+
|
53
|
+
def use_info_2(args)
|
54
|
+
USE_INFO_2.collect { |field|
|
55
|
+
args.include?(field[0]) ? args[field[0]] : field[1]
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def use_info_2_pack(use)
|
60
|
+
use.collect { |v|
|
61
|
+
v.class == Fixnum ? v : str_to_ptr(multi_to_wide(v))
|
62
|
+
}.pack(USE_INFO_2_TEMPLATE)
|
63
|
+
end
|
64
|
+
|
65
|
+
def use_info_2_unpack(buffer)
|
66
|
+
use = Hash.new
|
67
|
+
USE_INFO_2.each_with_index do |field,offset|
|
68
|
+
use[field[0]] = field[1].class == Fixnum ?
|
69
|
+
dword_to_i(buffer, offset) : lpwstr_to_s(buffer, offset)
|
70
|
+
end
|
71
|
+
use
|
72
|
+
end
|
73
|
+
|
74
|
+
public
|
75
|
+
|
76
|
+
def initialize(localname)
|
77
|
+
@localname = localname
|
78
|
+
@name = multi_to_wide(localname)
|
79
|
+
end
|
80
|
+
|
81
|
+
def add(args)
|
82
|
+
if args.class == String
|
83
|
+
remote = args
|
84
|
+
args = Hash.new(USE_INFO_2)
|
85
|
+
args[:remote] = remote
|
86
|
+
end
|
87
|
+
args[:local] ||= @localname
|
88
|
+
use = use_info_2(args)
|
89
|
+
buffer = use_info_2_pack(use)
|
90
|
+
rc = NetUseAdd.call(nil, 2, buffer, nil)
|
91
|
+
if rc != NERR_Success
|
92
|
+
raise ArgumentError, get_last_error(rc)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def get_info
|
97
|
+
ptr = 0.chr * PTR_SIZE
|
98
|
+
rc = NetUseGetInfo.call(nil, @name, 2, ptr)
|
99
|
+
|
100
|
+
if rc != NERR_Success
|
101
|
+
raise ArgumentError, get_last_error(rc)
|
102
|
+
end
|
103
|
+
|
104
|
+
ptr = ptr.unpack('L')[0]
|
105
|
+
buffer = 0.chr * SIZEOF_USE_INFO_2
|
106
|
+
memcpy(buffer, ptr, buffer.size)
|
107
|
+
NetApiBufferFree(ptr)
|
108
|
+
use_info_2_unpack(buffer)
|
109
|
+
end
|
110
|
+
|
111
|
+
def device
|
112
|
+
get_info()[:remote]
|
113
|
+
end
|
114
|
+
#XXX should we use some FORCE here?
|
115
|
+
def delete
|
116
|
+
rc = NetUseDel.call(nil, @name, USE_NOFORCE)
|
117
|
+
if rc != NERR_Success
|
118
|
+
raise ArgumentError, get_last_error(rc)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Doug MacEachern (<dougm@vmware.com>)
|
3
|
+
# Copyright:: Copyright (c) 2010 VMware, 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
|
+
#simple wrapper around Volume APIs. might be possible with WMI, but possibly more complex.
|
20
|
+
|
21
|
+
require 'chef/util/windows'
|
22
|
+
require 'windows/volume'
|
23
|
+
|
24
|
+
class Chef::Util::Windows::Volume < Chef::Util::Windows
|
25
|
+
|
26
|
+
private
|
27
|
+
include Windows::Volume
|
28
|
+
#XXX not defined in the current windows-pr release
|
29
|
+
DeleteVolumeMountPoint =
|
30
|
+
Windows::API.new('DeleteVolumeMountPoint', 'S', 'B') unless defined? DeleteVolumeMountPoint
|
31
|
+
|
32
|
+
public
|
33
|
+
|
34
|
+
def initialize(name)
|
35
|
+
name += "\\" unless name =~ /\\$/ #trailing slash required
|
36
|
+
@name = name
|
37
|
+
end
|
38
|
+
|
39
|
+
def device
|
40
|
+
buffer = 0.chr * 256
|
41
|
+
if GetVolumeNameForVolumeMountPoint(@name, buffer, buffer.size)
|
42
|
+
return buffer[0,buffer.size].unpack("Z*")[0]
|
43
|
+
else
|
44
|
+
raise ArgumentError, get_last_error
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def delete
|
49
|
+
unless DeleteVolumeMountPoint.call(@name)
|
50
|
+
raise ArgumentError, get_last_error
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def add(device)
|
55
|
+
unless SetVolumeMountPoint(@name, device)
|
56
|
+
raise ArgumentError, get_last_error
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/chef/version.rb
CHANGED
metadata
CHANGED
@@ -6,8 +6,8 @@ version: !ruby/object:Gem::Version
|
|
6
6
|
- 0
|
7
7
|
- 9
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.9.0.
|
9
|
+
- a92
|
10
|
+
version: 0.9.0.a92
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Adam Jacob
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-06-
|
18
|
+
date: 2010-06-11 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -282,6 +282,7 @@ files:
|
|
282
282
|
- lib/chef/cookbook/file_vendor.rb
|
283
283
|
- lib/chef/cookbook/metadata/version.rb
|
284
284
|
- lib/chef/cookbook/metadata.rb
|
285
|
+
- lib/chef/cookbook/remote_file_vendor.rb
|
285
286
|
- lib/chef/cookbook_loader.rb
|
286
287
|
- lib/chef/cookbook_version.rb
|
287
288
|
- lib/chef/couchdb.rb
|
@@ -406,6 +407,7 @@ files:
|
|
406
407
|
- lib/chef/provider/log.rb
|
407
408
|
- lib/chef/provider/mdadm.rb
|
408
409
|
- lib/chef/provider/mount/mount.rb
|
410
|
+
- lib/chef/provider/mount/windows.rb
|
409
411
|
- lib/chef/provider/mount.rb
|
410
412
|
- lib/chef/provider/package/apt.rb
|
411
413
|
- lib/chef/provider/package/dpkg.rb
|
@@ -516,7 +518,9 @@ files:
|
|
516
518
|
- lib/chef/tasks/chef_repo.rake
|
517
519
|
- lib/chef/util/file_edit.rb
|
518
520
|
- lib/chef/util/windows/net_group.rb
|
521
|
+
- lib/chef/util/windows/net_use.rb
|
519
522
|
- lib/chef/util/windows/net_user.rb
|
523
|
+
- lib/chef/util/windows/volume.rb
|
520
524
|
- lib/chef/util/windows.rb
|
521
525
|
- lib/chef/version.rb
|
522
526
|
- lib/chef/webui_user.rb
|