knife-essentials 1.0.0 → 1.1

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