knife-essentials 1.0.0 → 1.1

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.
@@ -45,6 +45,9 @@ class Chef
45
45
  chef_rest = Chef::REST.new(Chef::Config[:chef_server_url])
46
46
  begin
47
47
  output ChefFS::RawRequest.api_request(chef_rest, config[:method].to_sym, chef_rest.create_url(name_args[0]), {}, data)
48
+ rescue Timeout::Error => e
49
+ ui.error "Server timeout"
50
+ exit 1
48
51
  rescue Net::HTTPServerException => e
49
52
  ui.error "Server responded with error #{e.response.code} \"#{e.response.message}\""
50
53
  ui.error "Error Body: #{e.response.body}" if e.response.body && e.response.body != ''
@@ -0,0 +1,397 @@
1
+ require 'chef_fs/knife'
2
+ require 'chef_zero/server'
3
+ require 'chef_zero/data_store/memory_store'
4
+
5
+ # For ChefFSStore
6
+ require 'chef_fs/file_pattern'
7
+ require 'chef_fs/file_system'
8
+ require 'chef_fs/file_system/not_found_error'
9
+ require 'chef_fs/file_system/memory_root'
10
+ require 'chef_zero/data_store/data_already_exists_error'
11
+ require 'chef_zero/data_store/data_not_found_error'
12
+
13
+ class Chef
14
+ class Knife
15
+ remove_const(:Serve) if const_defined?(:Serve) && Serve.name == 'Chef::Knife::Serve' # override Chef's version
16
+ class Serve < ::ChefFS::Knife
17
+ ChefFS = ::ChefFS
18
+ banner "knife show [PATTERN1 ... PATTERNn]"
19
+
20
+ common_options
21
+
22
+ option :remote,
23
+ :long => '--remote',
24
+ :boolean => true,
25
+ :description => "Proxy the remote server instead of the local filesystem"
26
+
27
+ option :host,
28
+ :short => '-H',
29
+ :long => '--host=HOST',
30
+ :description => "Host to bind to (default: 127.0.0.1)"
31
+
32
+ option :port,
33
+ :short => '-p',
34
+ :long => '--port=PORT',
35
+ :description => "Port to listen on (default: 4000)"
36
+
37
+ option :generate_real_keys,
38
+ :long => '--[no-]generate-keys',
39
+ :boolean => true,
40
+ :description => "Whether to generate actual keys or fake it (faster). Default: false."
41
+
42
+ def run
43
+ server_options = {}
44
+ server_options[:data_store] = ChefFSDataStore.new(proc { config[:remote] ? create_chef_fs : create_local_fs })
45
+ server_options[:log_level] = Chef::Log.level
46
+ server_options[:host] = config[:host] if config[:host]
47
+ server_options[:port] = config[:port] ? config[:port].to_i : 4000
48
+ server_options[:generate_real_keys] = config[:generate_real_keys] if config[:generate_real_keys]
49
+
50
+ ChefZero::Server.new(server_options).start(:publish => true)
51
+ end
52
+
53
+ class ChefFSDataStore
54
+ def initialize(chef_fs)
55
+ @chef_fs = chef_fs
56
+ @memory_store = ChefZero::DataStore::MemoryStore.new
57
+ end
58
+
59
+ def chef_fs
60
+ @chef_fs.call
61
+ end
62
+
63
+ MEMORY_PATHS = %w(sandboxes file_store)
64
+
65
+ def create_dir(path, name, *options)
66
+ if use_memory_store?(path)
67
+ @memory_store.create_dir(path, name, *options)
68
+ else
69
+ with_dir(path) do |parent|
70
+ parent.create_child(chef_fs_filename(path + [name]), nil)
71
+ end
72
+ end
73
+ end
74
+
75
+ def create(path, name, data, *options)
76
+ if use_memory_store?(path)
77
+ @memory_store.create(path, name, data, *options)
78
+
79
+ elsif path[0] == 'cookbooks' && path.length == 2
80
+ # Do nothing. The entry gets created when the cookbook is created.
81
+
82
+ else
83
+ if !data.is_a?(String)
84
+ raise "set only works with strings"
85
+ end
86
+
87
+ with_dir(path) do |parent|
88
+ parent.create_child(chef_fs_filename(path + [name]), data)
89
+ end
90
+ end
91
+ end
92
+
93
+ def get(path, request=nil)
94
+ if use_memory_store?(path)
95
+ @memory_store.get(path)
96
+
97
+ elsif path[0] == 'file_store' && path[1] == 'repo'
98
+ entry = ChefFS::FileSystem.resolve_path(chef_fs, path[2..-1].join('/'))
99
+ begin
100
+ entry.read
101
+ rescue ChefFS::FileSystem::NotFoundError => e
102
+ raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
103
+ end
104
+
105
+ else
106
+ with_entry(path) do |entry|
107
+ if path[0] == 'cookbooks' && path.length == 3
108
+ # get /cookbooks/NAME/version
109
+ result = entry.chef_object.to_hash
110
+ result.each_pair do |key, value|
111
+ if value.is_a?(Array)
112
+ value.each do |file|
113
+ if file.is_a?(Hash) && file.has_key?('checksum')
114
+ relative = ['file_store', 'repo', 'cookbooks']
115
+ if Chef::Config.versioned_cookbooks
116
+ relative << "#{path[1]}-#{path[2]}"
117
+ else
118
+ relative << path[1]
119
+ end
120
+ relative = relative + file[:path].split('/')
121
+ file['url'] = ChefZero::RestBase::build_uri(request.base_uri, relative)
122
+ end
123
+ end
124
+ end
125
+ end
126
+ JSON.pretty_generate(result)
127
+
128
+ else
129
+ entry.read
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ def set(path, data, *options)
136
+ if use_memory_store?(path)
137
+ @memory_store.set(path, data, *options)
138
+ else
139
+ if !data.is_a?(String)
140
+ raise "set only works with strings: #{path} = #{data.inspect}"
141
+ end
142
+
143
+ # Write out the files!
144
+ if path[0] == 'cookbooks' && path.length == 3
145
+ write_cookbook(path, data, *options)
146
+ else
147
+ with_dir(path[0..-2]) do |parent|
148
+ parent.create_child(chef_fs_filename(path), data)
149
+ end
150
+ end
151
+ end
152
+ end
153
+
154
+ def delete(path)
155
+ if use_memory_store?(path)
156
+ @memory_store.delete(path)
157
+ else
158
+ with_entry(path) do |entry|
159
+ if path[0] == 'cookbooks' && path.length >= 3
160
+ entry.delete(true)
161
+ else
162
+ entry.delete
163
+ end
164
+ end
165
+ end
166
+ end
167
+
168
+ def delete_dir(path, *options)
169
+ if use_memory_store?(path)
170
+ @memory_store.delete_dir(path, *options)
171
+ else
172
+ with_entry(path) do |entry|
173
+ entry.delete(options.include?(:recursive))
174
+ end
175
+ end
176
+ end
177
+
178
+ def list(path)
179
+ if use_memory_store?(path)
180
+ @memory_store.list(path)
181
+
182
+ elsif path[0] == 'cookbooks' && path.length == 1
183
+ with_entry(path) do |entry|
184
+ begin
185
+ if Chef::Config.versioned_cookbooks
186
+ # /cookbooks/name-version -> /cookbooks/name
187
+ entry.children.map { |child| split_name_version(child.name)[0] }.uniq
188
+ else
189
+ entry.children.map { |child| child.name }
190
+ end
191
+ rescue ChefFS::FileSystem::NotFoundError
192
+ # If the cookbooks dir doesn't exist, we have no cookbooks (not 404)
193
+ []
194
+ end
195
+ end
196
+
197
+ elsif path[0] == 'cookbooks' && path.length == 2
198
+ if Chef::Config.versioned_cookbooks
199
+ # list /cookbooks/name = filter /cookbooks/name-version down to name
200
+ entry.children.map { |child| split_name_version(child.name) }.
201
+ select { |name, version| name == path[1] }.
202
+ map { |name, version| version }.to_a
203
+ else
204
+ # list /cookbooks/name = <single version>
205
+ version = get_single_cookbook_version(path)
206
+ [version]
207
+ end
208
+
209
+ else
210
+ with_entry(path) do |entry|
211
+ begin
212
+ entry.children.map { |c| zero_filename(c) }.sort
213
+ rescue ChefFS::FileSystem::NotFoundError
214
+ # /cookbooks, /data, etc. never return 404
215
+ if path_always_exists?(path)
216
+ []
217
+ else
218
+ raise
219
+ end
220
+ end
221
+ end
222
+ end
223
+ end
224
+
225
+ def exists?(path)
226
+ if use_memory_store?(path)
227
+ @memory_store.exists?(path)
228
+ else
229
+ path_always_exists?(path) || ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path)).exists?
230
+ end
231
+ end
232
+
233
+ def exists_dir?(path)
234
+ if use_memory_store?(path)
235
+ @memory_store.exists_dir?(path)
236
+ elsif path[0] == 'cookbooks' && path.length == 2
237
+ list([ path[0] ]).include?(path[1])
238
+ else
239
+ ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path)).exists?
240
+ end
241
+ end
242
+
243
+ private
244
+
245
+ def use_memory_store?(path)
246
+ return path[0] == 'sandboxes' || path[0] == 'file_store' && path[1] == 'checksums' || path == [ 'environments', '_default' ]
247
+ end
248
+
249
+ def write_cookbook(path, data, *options)
250
+ # Create a little ChefFS memory filesystem with the data
251
+ if Chef::Config.versioned_cookbooks
252
+ cookbook_path = "cookbooks/#{path[1]}-#{path[2]}"
253
+ else
254
+ cookbook_path = "cookbooks/#{path[1]}"
255
+ end
256
+ puts "Write cookbook #{cookbook_path}"
257
+ cookbook_fs = ChefFS::FileSystem::MemoryRoot.new('uploading')
258
+ cookbook = JSON.parse(data, :create_additions => false)
259
+ cookbook.each_pair do |key, value|
260
+ if value.is_a?(Array)
261
+ value.each do |file|
262
+ if file.is_a?(Hash) && file.has_key?('checksum')
263
+ file_data = @memory_store.get(['file_store', 'checksums', file['checksum']])
264
+ cookbook_fs.add_file("#{cookbook_path}/#{file['path']}", file_data)
265
+ end
266
+ end
267
+ end
268
+ end
269
+
270
+ # Use the copy/diff algorithm to copy it down so we don't destroy
271
+ # chefignored data. This is terribly un-thread-safe.
272
+ ChefFS::FileSystem.copy_to(ChefFS::FilePattern.new("/#{cookbook_path}"), cookbook_fs, chef_fs, nil, {:purge => true})
273
+ end
274
+
275
+ def split_name_version(entry_name)
276
+ name_version = entry_name.split('-')
277
+ name = name_version[0..-2].join('-')
278
+ version = name_version[-1]
279
+ [name,version]
280
+ end
281
+
282
+ def to_chef_fs_path(path)
283
+ _to_chef_fs_path(path).join('/')
284
+ end
285
+
286
+ def chef_fs_filename(path)
287
+ _to_chef_fs_path(path)[-1]
288
+ end
289
+
290
+ def _to_chef_fs_path(path)
291
+ if path[0] == 'data'
292
+ path = path.dup
293
+ path[0] = 'data_bags'
294
+ if path.length >= 3
295
+ path[2] = "#{path[2]}.json"
296
+ end
297
+ elsif path[0] == 'cookbooks'
298
+ if path.length == 2
299
+ raise ChefZero::DataStore::DataNotFoundError.new(path)
300
+ elsif Chef::Config.versioned_cookbooks
301
+ if path.length >= 3
302
+ # cookbooks/name/version -> cookbooks/name-version
303
+ path = [ path[0], "#{path[1]}-#{path[2]}" ] + path[3..-1]
304
+ end
305
+ else
306
+ if path.length >= 3
307
+ # cookbooks/name/version/... -> /cookbooks/name/... iff metadata says so
308
+ version = get_single_cookbook_version(path)
309
+ if path[2] == version
310
+ path = path[0..1] + path[3..-1]
311
+ else
312
+ raise ChefZero::DataStore::DataNotFoundError.new(path)
313
+ end
314
+ end
315
+ end
316
+ elsif path.length == 2
317
+ path = path.dup
318
+ path[1] = "#{path[1]}.json"
319
+ end
320
+ path
321
+ end
322
+
323
+ def to_zero_path(entry)
324
+ path = entry.path.split('/')[1..-1]
325
+ if path[0] == 'data_bags'
326
+ path = path.dup
327
+ path[0] = 'data'
328
+ if path.length >= 3
329
+ path[2] = path[2][0..-6]
330
+ end
331
+
332
+ elsif path[0] == 'cookbooks'
333
+ if Chef::Config.versioned_cookbooks
334
+ # cookbooks/name-version/... -> cookbooks/name/version/...
335
+ if path.length >= 2
336
+ name, version = split_name_version(path[1])
337
+ path = [ path[0], name, version ] + path[2..-1]
338
+ end
339
+ else
340
+ if path.length >= 2
341
+ # cookbooks/name/... -> cookbooks/name/version/...
342
+ version = get_single_cookbook_version(path)
343
+ path = path[0..1] + [version] + path[2..-1]
344
+ end
345
+ end
346
+
347
+ elsif path.length == 2 && path[0] != 'cookbooks'
348
+ path = path.dup
349
+ path[1] = path[1][0..-6]
350
+ end
351
+ path
352
+ end
353
+
354
+ def zero_filename(entry)
355
+ to_zero_path(entry)[-1]
356
+ end
357
+
358
+ def path_always_exists?(path)
359
+ return path.length == 1 && %w(clients cookbooks data environments nodes roles users).include?(path[0])
360
+ end
361
+
362
+ def with_entry(path)
363
+ begin
364
+ yield ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path))
365
+ rescue ChefFS::FileSystem::NotFoundError => e
366
+ raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
367
+ end
368
+ end
369
+
370
+ def with_dir(path)
371
+ begin
372
+ yield get_dir(_to_chef_fs_path(path), true)
373
+ rescue ChefFS::FileSystem::NotFoundError => e
374
+ raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
375
+ end
376
+ end
377
+
378
+ def get_dir(path, create=false)
379
+ result = ChefFS::FileSystem.resolve_path(chef_fs, path.join('/'))
380
+ if result.exists?
381
+ result
382
+ elsif create
383
+ get_dir(path[0..-2], create).create_child(result.name, nil)
384
+ else
385
+ raise ChefZero::DataStore::DataNotFoundError.new(path)
386
+ end
387
+ end
388
+
389
+ def get_single_cookbook_version(path)
390
+ dir = ChefFS::FileSystem.resolve_path(chef_fs, path[0..1].join('/'))
391
+ metadata = ChefZero::CookbookData.metadata_from(dir, path[1], nil, [])
392
+ metadata[:version] || '0.0.0'
393
+ end
394
+ end
395
+ end
396
+ end
397
+ end
@@ -90,6 +90,7 @@ module ChefFS
90
90
  else
91
91
  yield "Only in #{format_path.call(new_entry.parent)}: #{new_entry.name}\n"
92
92
  end
93
+
93
94
  when :modified
94
95
  next if diff_filter && diff_filter !~ /M/
95
96
  if output_mode == :name_only
@@ -101,6 +102,7 @@ module ChefFS
101
102
  result << diff_text(old_path, new_path, old_value, new_value)
102
103
  yield result
103
104
  end
105
+
104
106
  when :both_nonexistent
105
107
  when :added_cannot_upload
106
108
  when :deleted_cannot_download
@@ -232,23 +234,6 @@ module ChefFS
232
234
  return [ [ :error, old_entry, new_entry, nil, nil, e ] ]
233
235
  end
234
236
 
235
- class Differ
236
- def initialize(old_entry, new_entry, recurse_depth, get_content)
237
- @old_entry = old_entry
238
- @new_entry = new_entry
239
- @recurse_depth = recurse_depth
240
- @get_content = get_content
241
- end
242
-
243
- attr_reader :old_entry
244
- attr_reader :new_entry
245
- attr_reader :recurse_depth
246
- attr_reader :get_content
247
-
248
- def each
249
- end
250
- end
251
-
252
237
  private
253
238
 
254
239
  def self.sort_keys(json_object)
@@ -135,7 +135,7 @@ module ChefFS
135
135
  # puts message
136
136
  # end
137
137
  #
138
- def self.copy_to(pattern, src_root, dest_root, recurse_depth, options, ui, format_path)
138
+ def self.copy_to(pattern, src_root, dest_root, recurse_depth, options, ui = nil, format_path = nil)
139
139
  found_result = false
140
140
  error = false
141
141
  parallel_do(list_pairs(pattern, src_root, dest_root)) do |src, dest|
@@ -145,7 +145,7 @@ module ChefFS
145
145
  error ||= child_error
146
146
  end
147
147
  if !found_result && pattern.exact_path
148
- ui.error "#{pattern}: No such file or directory on remote or local"
148
+ ui.error "#{pattern}: No such file or directory on remote or local" if ui
149
149
  error = true
150
150
  end
151
151
  error
@@ -275,20 +275,20 @@ module ChefFS
275
275
 
276
276
  error = false
277
277
  begin
278
- dest_path = format_path.call(dest_entry)
279
- src_path = format_path.call(src_entry)
278
+ dest_path = format_path.call(dest_entry) if ui
279
+ src_path = format_path.call(src_entry) if ui
280
280
  if !src_entry.exists?
281
281
  if options[:purge]
282
282
  # If we would not have uploaded it, we will not purge it.
283
283
  if src_entry.parent.can_have_child?(dest_entry.name, dest_entry.dir?)
284
284
  if options[:dry_run]
285
- ui.output "Would delete #{dest_path}"
285
+ ui.output "Would delete #{dest_path}" if ui
286
286
  else
287
287
  dest_entry.delete(true)
288
- ui.output "Deleted extra entry #{dest_path} (purge is on)"
288
+ ui.output "Deleted extra entry #{dest_path} (purge is on)" if ui
289
289
  end
290
290
  else
291
- Chef::Log.info("Not deleting extra entry #{dest_path} (purge is off)")
291
+ Chef::Log.info("Not deleting extra entry #{dest_path} (purge is off)") if ui
292
292
  end
293
293
  end
294
294
 
@@ -297,21 +297,21 @@ module ChefFS
297
297
  # If the entry can do a copy directly from filesystem, do that.
298
298
  if new_dest_parent.respond_to?(:create_child_from)
299
299
  if options[:dry_run]
300
- ui.output "Would create #{dest_path}"
300
+ ui.output "Would create #{dest_path}" if ui
301
301
  else
302
302
  new_dest_parent.create_child_from(src_entry)
303
- ui.output "Created #{dest_path}"
303
+ ui.output "Created #{dest_path}" if ui
304
304
  end
305
305
  return
306
306
  end
307
307
 
308
308
  if src_entry.dir?
309
309
  if options[:dry_run]
310
- ui.output "Would create #{dest_path}"
310
+ ui.output "Would create #{dest_path}" if ui
311
311
  new_dest_dir = new_dest_parent.child(src_entry.name)
312
312
  else
313
313
  new_dest_dir = new_dest_parent.create_child(src_entry.name, nil)
314
- ui.output "Created #{dest_path}"
314
+ ui.output "Created #{dest_path}" if ui
315
315
  end
316
316
  # Directory creation is recursive.
317
317
  if recurse_depth != 0
@@ -323,10 +323,10 @@ module ChefFS
323
323
  end
324
324
  else
325
325
  if options[:dry_run]
326
- ui.output "Would create #{dest_path}"
326
+ ui.output "Would create #{dest_path}" if ui
327
327
  else
328
328
  new_dest_parent.create_child(src_entry.name, src_entry.read)
329
- ui.output "Created #{dest_path}"
329
+ ui.output "Created #{dest_path}" if ui
330
330
  end
331
331
  end
332
332
  end
@@ -338,10 +338,10 @@ module ChefFS
338
338
  if dest_entry.respond_to?(:copy_from)
339
339
  if options[:force] || compare(src_entry, dest_entry)[0] == false
340
340
  if options[:dry_run]
341
- ui.output "Would update #{dest_path}"
341
+ ui.output "Would update #{dest_path}" if ui
342
342
  else
343
343
  dest_entry.copy_from(src_entry)
344
- ui.output "Updated #{dest_path}"
344
+ ui.output "Updated #{dest_path}" if ui
345
345
  end
346
346
  end
347
347
  return
@@ -359,12 +359,12 @@ module ChefFS
359
359
  end
360
360
  else
361
361
  # If they are different types.
362
- ui.error("File #{src_path} is a directory while file #{dest_path} is a regular file\n")
362
+ ui.error("File #{src_path} is a directory while file #{dest_path} is a regular file\n") if ui
363
363
  return
364
364
  end
365
365
  else
366
366
  if dest_entry.dir?
367
- ui.error("File #{src_path} is a directory while file #{dest_path} is a regular file\n")
367
+ ui.error("File #{src_path} is a directory while file #{dest_path} is a regular file\n") if ui
368
368
  return
369
369
  else
370
370
 
@@ -380,23 +380,23 @@ module ChefFS
380
380
  end
381
381
  if should_copy
382
382
  if options[:dry_run]
383
- ui.output "Would update #{dest_path}"
383
+ ui.output "Would update #{dest_path}" if ui
384
384
  else
385
385
  src_value = src_entry.read if src_value.nil?
386
386
  dest_entry.write(src_value)
387
- ui.output "Updated #{dest_path}"
387
+ ui.output "Updated #{dest_path}" if ui
388
388
  end
389
389
  end
390
390
  end
391
391
  end
392
392
  end
393
393
  rescue DefaultEnvironmentCannotBeModifiedError => e
394
- ui.warn "#{format_path.call(e.entry)} #{e.reason}."
394
+ ui.warn "#{format_path.call(e.entry)} #{e.reason}." if ui
395
395
  rescue OperationFailedError => e
396
- ui.error "#{format_path.call(e.entry)} failed to #{e.operation}: #{e.message}"
396
+ ui.error "#{format_path.call(e.entry)} failed to #{e.operation}: #{e.message}" if ui
397
397
  error = true
398
398
  rescue OperationNotAllowedError => e
399
- ui.error "#{format_path.call(e.entry)} #{e.reason}."
399
+ ui.error "#{format_path.call(e.entry)} #{e.reason}." if ui
400
400
  error = true
401
401
  end
402
402
  error
@@ -405,13 +405,13 @@ module ChefFS
405
405
  def self.get_or_create_parent(entry, options, ui, format_path)
406
406
  parent = entry.parent
407
407
  if parent && !parent.exists?
408
- parent_path = format_path.call(parent)
408
+ parent_path = format_path.call(parent) if ui
409
409
  parent_parent = get_or_create_parent(entry.parent, options, ui, format_path)
410
410
  if options[:dry_run]
411
- ui.output "Would create #{parent_path}"
411
+ ui.output "Would create #{parent_path}" if ui
412
412
  else
413
413
  parent = parent_parent.create_child(parent.name, nil)
414
- ui.output "Created #{parent_path}"
414
+ ui.output "Created #{parent_path}" if ui
415
415
  end
416
416
  end
417
417
  return parent
@@ -40,6 +40,8 @@ module ChefFS
40
40
  PERMISSIONS.each do |permission|
41
41
  begin
42
42
  rest.put_rest("#{api_path}/#{permission}", { permission => acls[permission] })
43
+ rescue Timeout::Error => e
44
+ raise ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Timeout writing: #{e}"
43
45
  rescue Net::HTTPServerException => e
44
46
  if e.response.code == "404"
45
47
  raise ChefFS::FileSystem::NotFoundError.new(self, e)
@@ -125,9 +125,13 @@ module ChefFS
125
125
  if recurse
126
126
  begin
127
127
  rest.delete_rest(api_path)
128
+ rescue Timeout::Error => e
129
+ raise ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}"
128
130
  rescue Net::HTTPServerException
129
131
  if $!.response.code == "404"
130
132
  raise ChefFS::FileSystem::NotFoundError.new(self, $!)
133
+ else
134
+ raise ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "HTTP error deleting: #{e}"
131
135
  end
132
136
  end
133
137
  else
@@ -189,22 +193,26 @@ module ChefFS
189
193
  ensure
190
194
  Chef::Config[:http_retry_count] = old_retry_count
191
195
  end
192
- rescue Net::HTTPServerException
193
- if $!.response.code == "404"
194
- @could_not_get_chef_object = $!
196
+
197
+ rescue Timeout::Error => e
198
+ raise ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "Timeout reading: #{e}"
199
+
200
+ rescue Net::HTTPServerException => e
201
+ if e.response.code == "404"
202
+ @could_not_get_chef_object = e
195
203
  raise ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object)
196
204
  else
197
- raise
205
+ raise ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "HTTP error reading: #{e}"
198
206
  end
199
207
 
200
208
  # Chef bug http://tickets.opscode.com/browse/CHEF-3066 ... instead of 404 we get 500 right now.
201
209
  # Remove this when that bug is fixed.
202
- rescue Net::HTTPFatalError
203
- if $!.response.code == "500"
204
- @could_not_get_chef_object = $!
210
+ rescue Net::HTTPFatalError => e
211
+ if e.response.code == "500"
212
+ @could_not_get_chef_object = e
205
213
  raise ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object)
206
214
  else
207
- raise
215
+ raise ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "HTTP error reading: #{e}"
208
216
  end
209
217
  end
210
218
  end
@@ -38,6 +38,8 @@ module ChefFS
38
38
  rest.sign_on_redirect = false
39
39
  begin
40
40
  tmpfile = rest.get_rest(file[:url], true)
41
+ rescue Timeout::Error => e
42
+ raise ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "Timeout reading #{file[:url]}: #{e}"
41
43
  rescue Net::HTTPServerException => e
42
44
  raise ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "#{e.message} retrieving #{file[:url]}"
43
45
  ensure
@@ -64,6 +64,8 @@ module ChefFS
64
64
 
65
65
  def upload_cookbook_from(other)
66
66
  Chef::Config[:versioned_cookbooks] ? upload_versioned_cookbook(other) : upload_unversioned_cookbook(other)
67
+ rescue Timeout::Error => e
68
+ raise ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Timeout writing: #{e}"
67
69
  rescue Net::HTTPServerException => e
68
70
  case e.response.code
69
71
  when "409"
@@ -71,7 +73,7 @@ module ChefFS
71
73
  Chef::Log.debug(e)
72
74
  raise Exceptions::CookbookFrozen
73
75
  else
74
- raise
76
+ raise ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "HTTP error writing: #{e}"
75
77
  end
76
78
  end
77
79
 
@@ -52,9 +52,13 @@ module ChefFS
52
52
  end
53
53
  begin
54
54
  rest.delete_rest(api_path)
55
- rescue Net::HTTPServerException
56
- if $!.response.code == "404"
57
- raise ChefFS::FileSystem::NotFoundError.new(self, $!)
55
+ rescue Timeout::Error => e
56
+ raise ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}"
57
+ rescue Net::HTTPServerException => e
58
+ if e.response.code == "404"
59
+ raise ChefFS::FileSystem::NotFoundError.new(self, e)
60
+ else
61
+ raise ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "HTTP error deleting: #{e}"
58
62
  end
59
63
  end
60
64
  end
@@ -36,11 +36,13 @@ module ChefFS
36
36
  @children ||= ChefFS::RawRequest.raw_json(rest, api_path).keys.sort.map do |entry|
37
37
  DataBagDir.new(entry, self, true)
38
38
  end
39
- rescue Net::HTTPServerException
40
- if $!.response.code == "404"
41
- raise ChefFS::FileSystem::NotFoundError.new(self, $!)
39
+ rescue Timeout::Error => e
40
+ raise ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "Timeout getting children: #{e}"
41
+ rescue Net::HTTPServerException => e
42
+ if e.response.code == "404"
43
+ raise ChefFS::FileSystem::NotFoundError.new(self, e)
42
44
  else
43
- raise
45
+ raise ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "HTTP error getting children: #{e}"
44
46
  end
45
47
  end
46
48
  end
@@ -52,9 +54,11 @@ module ChefFS
52
54
  def create_child(name, file_contents)
53
55
  begin
54
56
  rest.post_rest(api_path, { 'name' => name })
55
- rescue Net::HTTPServerException
56
- if $!.response.code != "409"
57
- raise
57
+ rescue Timeout::Error => e
58
+ raise ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "Timeout creating child '#{name}': #{e}"
59
+ rescue Net::HTTPServerException => e
60
+ if e.response.code != "409"
61
+ raise ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "HTTP error creating child '#{name}': #{e}"
58
62
  end
59
63
  end
60
64
  DataBagDir.new(name, self, true)
@@ -0,0 +1,50 @@
1
+ require 'chef_fs/file_system/base_fs_dir'
2
+ require 'chef_fs/file_system/nonexistent_fs_object'
3
+ require 'chef_fs/file_system/memory_file'
4
+
5
+ module ChefFS
6
+ module FileSystem
7
+ class MemoryDir < ChefFS::FileSystem::BaseFSDir
8
+ def initialize(name, parent)
9
+ super(name, parent)
10
+ @children = []
11
+ end
12
+
13
+ attr_reader :children
14
+
15
+ def child(name)
16
+ @children.select { |child| child.name == name }.first || ChefFS::FileSystem::NonexistentFSObject.new(name, self)
17
+ end
18
+
19
+ def add_child(child)
20
+ @children.push(child)
21
+ end
22
+
23
+ def can_have_child?(name, is_dir)
24
+ root.cannot_be_in_regex ? (name !~ root.cannot_be_in_regex) : true
25
+ end
26
+
27
+ def add_file(path, value)
28
+ path_parts = path.split('/')
29
+ dir = add_dir(path_parts[0..-2].join('/'))
30
+ file = MemoryFile.new(path_parts[-1], dir, value)
31
+ dir.add_child(file)
32
+ file
33
+ end
34
+
35
+ def add_dir(path)
36
+ path_parts = path.split('/')
37
+ dir = self
38
+ path_parts.each do |path_part|
39
+ subdir = dir.child(path_part)
40
+ if !subdir.exists?
41
+ subdir = MemoryDir.new(path_part, dir)
42
+ dir.add_child(subdir)
43
+ end
44
+ dir = subdir
45
+ end
46
+ dir
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,15 @@
1
+ require 'chef_fs/file_system/base_fs_object'
2
+
3
+ module ChefFS
4
+ module FileSystem
5
+ class MemoryFile < ChefFS::FileSystem::BaseFSObject
6
+ def initialize(name, parent, value)
7
+ super(name, parent)
8
+ @value = value
9
+ end
10
+ def read
11
+ return @value
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ require 'chef_fs/file_system/memory_dir'
2
+
3
+ module ChefFS
4
+ module FileSystem
5
+ class MemoryRoot < MemoryDir
6
+ def initialize(pretty_name, cannot_be_in_regex = nil)
7
+ super('', nil)
8
+ @pretty_name = pretty_name
9
+ @cannot_be_in_regex = cannot_be_in_regex
10
+ end
11
+
12
+ attr_reader :cannot_be_in_regex
13
+
14
+ def path_for_printing
15
+ @pretty_name
16
+ end
17
+ end
18
+ end
19
+ end
@@ -34,6 +34,8 @@ module ChefFS
34
34
  @children ||= ChefFS::RawRequest.raw_json(rest, env_api_path).keys.sort.map do |key|
35
35
  _make_child_entry("#{key}.json", true)
36
36
  end
37
+ rescue Timeout::Error => e
38
+ raise ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "Timeout retrieving children: #{e}"
37
39
  rescue Net::HTTPServerException => e
38
40
  if $!.response.code == "404"
39
41
  raise ChefFS::FileSystem::NotFoundError.new(self, $!)
@@ -47,6 +47,8 @@ module ChefFS
47
47
  @children ||= ChefFS::RawRequest.raw_json(rest, api_path).keys.sort.map do |key|
48
48
  _make_child_entry("#{key}.json", true)
49
49
  end
50
+ rescue Timeout::Error => e
51
+ raise ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "Timeout retrieving children: #{e}"
50
52
  rescue Net::HTTPServerException => e
51
53
  if $!.response.code == "404"
52
54
  raise ChefFS::FileSystem::NotFoundError.new(self, $!)
@@ -74,6 +76,8 @@ module ChefFS
74
76
 
75
77
  begin
76
78
  rest.post_rest(api_path, object)
79
+ rescue Timeout::Error => e
80
+ raise ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "Timeout creating '#{name}': #{e}"
77
81
  rescue Net::HTTPServerException => e
78
82
  if e.response.code == "404"
79
83
  raise ChefFS::FileSystem::NotFoundError.new(self, e)
@@ -68,11 +68,13 @@ module ChefFS
68
68
  def delete(recurse)
69
69
  begin
70
70
  rest.delete_rest(api_path)
71
- rescue Net::HTTPServerException
72
- if $!.response.code == "404"
73
- raise ChefFS::FileSystem::NotFoundError.new(self, $!)
71
+ rescue Timeout::Error => e
72
+ raise ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}"
73
+ rescue Net::HTTPServerException => e
74
+ if e.response.code == "404"
75
+ raise ChefFS::FileSystem::NotFoundError.new(self, e)
74
76
  else
75
- raise
77
+ raise ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}"
76
78
  end
77
79
  end
78
80
  end
@@ -84,9 +86,11 @@ module ChefFS
84
86
  def _read_hash
85
87
  begin
86
88
  json = ChefFS::RawRequest.raw_request(rest, api_path)
89
+ rescue Timeout::Error => e
90
+ raise ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "Timeout reading: #{e}"
87
91
  rescue Net::HTTPServerException => e
88
92
  if $!.response.code == "404"
89
- raise ChefFS::FileSystem::NotFoundError.new(self, $!)
93
+ raise ChefFS::FileSystem::NotFoundError.new(self, e)
90
94
  else
91
95
  raise ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "HTTP error reading: #{e}"
92
96
  end
@@ -125,7 +129,6 @@ module ChefFS
125
129
  value = minimize_value(value)
126
130
  value_json = Chef::JSONCompat.to_json_pretty(value)
127
131
  begin
128
- #other_value = Chef::JSONCompat.from_json(other_value_json, :create_additions => false)
129
132
  other_value = JSON.parse(other_value_json, :create_additions => false)
130
133
  rescue JSON::ParserError => e
131
134
  Chef::Log.warn("Parse error reading #{other.path_for_printing} as JSON: #{e}")
@@ -143,7 +146,6 @@ module ChefFS
143
146
 
144
147
  def write(file_contents)
145
148
  begin
146
- #object = Chef::JSONCompat.from_json(file_contents).to_hash
147
149
  object = JSON.parse(file_contents, :create_additions => false)
148
150
  rescue JSON::ParserError => e
149
151
  raise ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Parse error reading JSON: #{e}"
@@ -158,6 +160,8 @@ module ChefFS
158
160
 
159
161
  begin
160
162
  rest.put_rest(api_path, object)
163
+ rescue Timeout::Error => e
164
+ raise ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Timeout writing: #{e}"
161
165
  rescue Net::HTTPServerException => e
162
166
  if e.response.code == "404"
163
167
  raise ChefFS::FileSystem::NotFoundError.new(self, e)
@@ -96,7 +96,11 @@ module ChefFS
96
96
  end
97
97
 
98
98
  def chef_fs
99
- @chef_fs ||= ChefFS::FileSystem::ChefServerRootDir.new("remote", Chef::Config)
99
+ @chef_fs ||= create_chef_fs
100
+ end
101
+
102
+ def create_chef_fs
103
+ ChefFS::FileSystem::ChefServerRootDir.new("remote", Chef::Config)
100
104
  end
101
105
 
102
106
  def object_paths
@@ -193,7 +197,11 @@ module ChefFS
193
197
  end
194
198
 
195
199
  def local_fs
196
- @local_fs ||= ChefFS::FileSystem::ChefRepositoryFileSystemRootDir.new(object_paths)
200
+ @local_fs ||= create_local_fs
201
+ end
202
+
203
+ def create_local_fs
204
+ ChefFS::FileSystem::ChefRepositoryFileSystemRootDir.new(object_paths)
197
205
  end
198
206
 
199
207
  def pattern_args
@@ -1,3 +1,3 @@
1
1
  module ChefFS
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1"
3
3
  end
@@ -17,56 +17,16 @@
17
17
  #
18
18
 
19
19
  require 'chef_fs/file_system'
20
- require 'chef_fs/file_system/base_fs_dir'
21
- require 'chef_fs/file_system/base_fs_object'
20
+ require 'chef_fs/file_system/memory_root'
21
+ require 'chef_fs/file_system/memory_dir'
22
+ require 'chef_fs/file_system/memory_file'
22
23
 
23
24
  module FileSystemSupport
24
- class MemoryFile < ChefFS::FileSystem::BaseFSObject
25
- def initialize(name, parent, value)
26
- super(name, parent)
27
- @value = value
28
- end
29
- def read
30
- return @value
31
- end
32
- end
33
-
34
- class MemoryDir < ChefFS::FileSystem::BaseFSDir
35
- def initialize(name, parent)
36
- super(name, parent)
37
- @children = []
38
- end
39
- attr_reader :children
40
- def child(name)
41
- @children.select { |child| child.name == name }.first || ChefFS::FileSystem::NonexistentFSObject.new(name, self)
42
- end
43
- def add_child(child)
44
- @children.push(child)
45
- end
46
- def can_have_child?(name, is_dir)
47
- root.cannot_be_in_regex ? (name !~ root.cannot_be_in_regex) : true
48
- end
49
- end
50
-
51
- class MemoryRoot < MemoryDir
52
- def initialize(pretty_name, cannot_be_in_regex = nil)
53
- super('', nil)
54
- @pretty_name = pretty_name
55
- @cannot_be_in_regex = cannot_be_in_regex
56
- end
57
-
58
- attr_reader :cannot_be_in_regex
59
-
60
- def path_for_printing
61
- @pretty_name
62
- end
63
- end
64
-
65
25
  def memory_fs(pretty_name, value, cannot_be_in_regex = nil)
66
26
  if !value.is_a?(Hash)
67
27
  raise "memory_fs() must take a Hash"
68
28
  end
69
- dir = MemoryRoot.new(pretty_name, cannot_be_in_regex)
29
+ dir = ChefFS::FileSystem::MemoryRoot.new(pretty_name, cannot_be_in_regex)
70
30
  value.each do |key, child|
71
31
  dir.add_child(memory_fs_value(child, key.to_s, dir))
72
32
  end
@@ -75,13 +35,13 @@ module FileSystemSupport
75
35
 
76
36
  def memory_fs_value(value, name = '', parent = nil)
77
37
  if value.is_a?(Hash)
78
- dir = MemoryDir.new(name, parent)
38
+ dir = ChefFS::FileSystem::MemoryDir.new(name, parent)
79
39
  value.each do |key, child|
80
40
  dir.add_child(memory_fs_value(child, key.to_s, dir))
81
41
  end
82
42
  dir
83
43
  else
84
- MemoryFile.new(name, parent, value || "#{name}\n")
44
+ ChefFS::FileSystem::MemoryFile.new(name, parent, value || "#{name}\n")
85
45
  end
86
46
  end
87
47
 
@@ -94,7 +54,7 @@ module FileSystemSupport
94
54
  end
95
55
 
96
56
  def no_blocking_calls_allowed
97
- [ MemoryFile, MemoryDir ].each do |c|
57
+ [ ChefFS::FileSystem::MemoryFile, ChefFS::FileSystem::MemoryDir ].each do |c|
98
58
  [ :children, :exists?, :read ].each do |m|
99
59
  c.any_instance.stub(m).and_raise("#{m.to_s} should not be called")
100
60
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-essentials
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: '1.1'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-05-20 00:00:00.000000000 Z
12
+ date: 2013-05-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: chef
@@ -125,6 +125,7 @@ files:
125
125
  - lib/chef/knife/edit_essentials.rb
126
126
  - lib/chef/knife/list_essentials.rb
127
127
  - lib/chef/knife/raw_essentials.rb
128
+ - lib/chef/knife/serve_essentials.rb
128
129
  - lib/chef/knife/show_essentials.rb
129
130
  - lib/chef/knife/upload_essentials.rb
130
131
  - lib/chef/knife/xargs_essentials.rb
@@ -163,6 +164,9 @@ files:
163
164
  - lib/chef_fs/file_system/file_system_entry.rb
164
165
  - lib/chef_fs/file_system/file_system_error.rb
165
166
  - lib/chef_fs/file_system/file_system_root_dir.rb
167
+ - lib/chef_fs/file_system/memory_dir.rb
168
+ - lib/chef_fs/file_system/memory_file.rb
169
+ - lib/chef_fs/file_system/memory_root.rb
166
170
  - lib/chef_fs/file_system/multiplexed_dir.rb
167
171
  - lib/chef_fs/file_system/must_delete_recursively_error.rb
168
172
  - lib/chef_fs/file_system/nodes_dir.rb