cheffish 1.6.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/cheffish.gemspec +1 -0
  3. data/lib/chef/resource/chef_acl.rb +440 -20
  4. data/lib/chef/resource/chef_client.rb +50 -25
  5. data/lib/chef/resource/chef_container.rb +44 -11
  6. data/lib/chef/resource/chef_data_bag.rb +43 -10
  7. data/lib/chef/resource/chef_data_bag_item.rb +292 -82
  8. data/lib/chef/resource/chef_environment.rb +79 -27
  9. data/lib/chef/resource/chef_group.rb +77 -40
  10. data/lib/chef/resource/chef_mirror.rb +170 -21
  11. data/lib/chef/resource/chef_node.rb +77 -11
  12. data/lib/chef/resource/chef_organization.rb +153 -43
  13. data/lib/chef/resource/chef_resolved_cookbooks.rb +40 -9
  14. data/lib/chef/resource/chef_role.rb +81 -29
  15. data/lib/chef/resource/chef_user.rb +64 -33
  16. data/lib/chef/resource/private_key.rb +230 -17
  17. data/lib/chef/resource/public_key.rb +88 -9
  18. data/lib/cheffish/array_property.rb +29 -0
  19. data/lib/cheffish/base_resource.rb +254 -0
  20. data/lib/cheffish/chef_actor_base.rb +135 -0
  21. data/lib/cheffish/node_properties.rb +107 -0
  22. data/lib/cheffish/recipe_dsl.rb +0 -14
  23. data/lib/cheffish/version.rb +1 -1
  24. data/lib/cheffish.rb +4 -108
  25. data/spec/integration/chef_acl_spec.rb +0 -2
  26. data/spec/integration/chef_client_spec.rb +0 -1
  27. data/spec/integration/chef_container_spec.rb +0 -2
  28. data/spec/integration/chef_group_spec.rb +0 -2
  29. data/spec/integration/chef_mirror_spec.rb +0 -2
  30. data/spec/integration/chef_node_spec.rb +0 -2
  31. data/spec/integration/chef_organization_spec.rb +1 -3
  32. data/spec/integration/chef_role_spec.rb +0 -2
  33. data/spec/integration/chef_user_spec.rb +0 -2
  34. data/spec/integration/private_key_spec.rb +0 -4
  35. data/spec/integration/recipe_dsl_spec.rb +0 -2
  36. data/spec/support/spec_support.rb +0 -1
  37. data/spec/unit/get_private_key_spec.rb +13 -0
  38. metadata +22 -20
  39. data/lib/chef/provider/chef_acl.rb +0 -446
  40. data/lib/chef/provider/chef_client.rb +0 -53
  41. data/lib/chef/provider/chef_container.rb +0 -55
  42. data/lib/chef/provider/chef_data_bag.rb +0 -55
  43. data/lib/chef/provider/chef_data_bag_item.rb +0 -278
  44. data/lib/chef/provider/chef_environment.rb +0 -83
  45. data/lib/chef/provider/chef_group.rb +0 -83
  46. data/lib/chef/provider/chef_mirror.rb +0 -169
  47. data/lib/chef/provider/chef_node.rb +0 -87
  48. data/lib/chef/provider/chef_organization.rb +0 -155
  49. data/lib/chef/provider/chef_resolved_cookbooks.rb +0 -46
  50. data/lib/chef/provider/chef_role.rb +0 -84
  51. data/lib/chef/provider/chef_user.rb +0 -59
  52. data/lib/chef/provider/private_key.rb +0 -225
  53. data/lib/chef/provider/public_key.rb +0 -88
  54. data/lib/cheffish/actor_provider_base.rb +0 -131
  55. data/lib/cheffish/chef_provider_base.rb +0 -246
@@ -1,446 +0,0 @@
1
- require 'cheffish/chef_provider_base'
2
- require 'chef/resource/chef_acl'
3
- require 'chef/chef_fs/data_handler/acl_data_handler'
4
- require 'chef/chef_fs/parallelizer'
5
- require 'uri'
6
-
7
- class Chef
8
- class Provider
9
- class ChefAcl < Cheffish::ChefProviderBase
10
- provides :chef_acl
11
-
12
- def whyrun_supported?
13
- true
14
- end
15
-
16
- action :create do
17
- if new_resource.remove_rights && new_resource.complete
18
- Chef::Log.warn("'remove_rights' is redundant when 'complete' is specified: all rights not specified in a 'rights' declaration will be removed.")
19
- end
20
- # Verify that we're not destroying all hope of ACL recovery here
21
- if new_resource.complete && (!new_resource.rights || !new_resource.rights.any? { |r| r[:permissions].include?(:all) || r[:permissions].include?(:grant) })
22
- # NOTE: if superusers exist, this should turn into a warning.
23
- raise "'complete' specified on chef_acl resource, but no GRANT permissions were granted. I'm sorry Dave, I can't let you remove all access to an object with no hope of recovery."
24
- end
25
-
26
- # Find all matching paths so we can update them (resolve * and **)
27
- paths = match_paths(new_resource.path)
28
- if paths.size == 0 && !new_resource.path.split('/').any? { |p| p == '*' }
29
- raise "Path #{new_resource.path} cannot have an ACL set on it!"
30
- end
31
-
32
- # Go through the matches and update the ACLs for them
33
- paths.each do |path|
34
- create_acl(path)
35
- end
36
- end
37
-
38
- # Update the ACL if necessary.
39
- def create_acl(path)
40
- changed = false
41
- # There may not be an ACL path for some valid paths (/ and /organizations,
42
- # for example). We want to recurse into these, but we don't want to try to
43
- # update nonexistent ACLs for them.
44
- acl = acl_path(path)
45
- if acl
46
- # It's possible to make a custom container
47
- current_json = current_acl(acl)
48
- if current_json
49
-
50
- # Compare the desired and current json for the ACL, and update if different.
51
- modify = {}
52
- desired_acl(acl).each do |permission, desired_json|
53
- differences = json_differences(sort_values(current_json[permission]), sort_values(desired_json))
54
-
55
- if differences.size > 0
56
- # Verify we aren't trying to destroy grant permissions
57
- if permission == 'grant' && desired_json['actors'] == [] && desired_json['groups'] == []
58
- # NOTE: if superusers exist, this should turn into a warning.
59
- raise "chef_acl attempted to remove all actors from GRANT! I'm sorry Dave, I can't let you remove access to an object with no hope of recovery."
60
- end
61
- modify[differences] ||= {}
62
- modify[differences][permission] = desired_json
63
- end
64
- end
65
-
66
- if modify.size > 0
67
- changed = true
68
- description = [ "update acl #{path} at #{rest_url(path)}" ] + modify.map do |diffs, permissions|
69
- diffs.map { |diff| " #{permissions.keys.join(', ')}:#{diff}" }
70
- end.flatten(1)
71
- converge_by description do
72
- modify.values.each do |permissions|
73
- permissions.each do |permission, desired_json|
74
- rest.put(rest_url("#{acl}/#{permission}"), { permission => desired_json })
75
- end
76
- end
77
- end
78
- end
79
- end
80
- end
81
-
82
- # If we have been asked to recurse, do so.
83
- # If recurse is on_change, then we will recurse if there is no ACL, or if
84
- # the ACL has changed.
85
- if new_resource.recursive == true || (new_resource.recursive == :on_change && (!acl || changed))
86
- children, error = list(path, '*')
87
- Chef::ChefFS::Parallelizer.parallel_do(children) do |child|
88
- next if child.split('/')[-1] == 'containers'
89
- create_acl(child)
90
- end
91
- # containers mess up our descent, so we do them last
92
- Chef::ChefFS::Parallelizer.parallel_do(children) do |child|
93
- next if child.split('/')[-1] != 'containers'
94
- create_acl(child)
95
- end
96
-
97
- end
98
- end
99
-
100
- # Get the current ACL for the given path
101
- def current_acl(acl_path)
102
- @current_acls ||= {}
103
- if !@current_acls.has_key?(acl_path)
104
- @current_acls[acl_path] = begin
105
- rest.get(rest_url(acl_path))
106
- rescue Net::HTTPServerException => e
107
- unless e.response.code == '404' && new_resource.path.split('/').any? { |p| p == '*' }
108
- raise
109
- end
110
- end
111
- end
112
- @current_acls[acl_path]
113
- end
114
-
115
- # Get the desired acl for the given acl path
116
- def desired_acl(acl_path)
117
- result = new_resource.raw_json ? new_resource.raw_json.dup : {}
118
-
119
- # Calculate the JSON based on rights
120
- add_rights(acl_path, result)
121
-
122
- if new_resource.complete
123
- result = Chef::ChefFS::DataHandler::AclDataHandler.new.normalize(result, nil)
124
- else
125
- # If resource is incomplete, use current json to fill any holes
126
- current_acl(acl_path).each do |permission, perm_hash|
127
- if !result[permission]
128
- result[permission] = perm_hash.dup
129
- else
130
- result[permission] = result[permission].dup
131
- perm_hash.each do |type, actors|
132
- if !result[permission][type]
133
- result[permission][type] = actors
134
- else
135
- result[permission][type] = result[permission][type].dup
136
- result[permission][type] |= actors
137
- end
138
- end
139
- end
140
- end
141
-
142
- remove_rights(result)
143
- end
144
- result
145
- end
146
-
147
- def sort_values(json)
148
- json.each do |key, value|
149
- json[key] = value.sort if value.is_a?(Array)
150
- end
151
- json
152
- end
153
-
154
- def add_rights(acl_path, json)
155
- if new_resource.rights
156
- new_resource.rights.each do |rights|
157
- if rights[:permissions].delete(:all)
158
- rights[:permissions] |= current_acl(acl_path).keys
159
- end
160
-
161
- Array(rights[:permissions]).each do |permission|
162
- ace = json[permission.to_s] ||= {}
163
- # WTF, no distinction between users and clients? The Chef API doesn't
164
- # let us distinguish, so we have no choice :/ This means that:
165
- # 1. If you specify :users => 'foo', and client 'foo' exists, it will
166
- # pick that (whether user 'foo' exists or not)
167
- # 2. If you specify :clients => 'foo', and user 'foo' exists but
168
- # client 'foo' does not, it will pick user 'foo' and put it in the
169
- # ACL
170
- # 3. If an existing item has user 'foo' on it and you specify :clients
171
- # => 'foo' instead, idempotence will not notice that anything needs
172
- # to be updated and nothing will happen.
173
- if rights[:users]
174
- ace['actors'] ||= []
175
- ace['actors'] |= Array(rights[:users])
176
- end
177
- if rights[:clients]
178
- ace['actors'] ||= []
179
- ace['actors'] |= Array(rights[:clients])
180
- end
181
- if rights[:groups]
182
- ace['groups'] ||= []
183
- ace['groups'] |= Array(rights[:groups])
184
- end
185
- end
186
- end
187
- end
188
- end
189
-
190
- def remove_rights(json)
191
- if new_resource.remove_rights
192
- new_resource.remove_rights.each do |rights|
193
- rights[:permissions].each do |permission|
194
- if permission == :all
195
- json.each_key do |key|
196
- ace = json[key] = json[key.dup]
197
- ace['actors'] = ace['actors'] - Array(rights[:users]) if rights[:users] && ace['actors']
198
- ace['actors'] = ace['actors'] - Array(rights[:clients]) if rights[:clients] && ace['actors']
199
- ace['groups'] = ace['groups'] - Array(rights[:groups]) if rights[:groups] && ace['groups']
200
- end
201
- else
202
- ace = json[permission.to_s] = json[permission.to_s].dup
203
- if ace
204
- ace['actors'] = ace['actors'] - Array(rights[:users]) if rights[:users] && ace['actors']
205
- ace['actors'] = ace['actors'] - Array(rights[:clients]) if rights[:clients] && ace['actors']
206
- ace['groups'] = ace['groups'] - Array(rights[:groups]) if rights[:groups] && ace['groups']
207
- end
208
- end
209
- end
210
- end
211
- end
212
- end
213
-
214
- def load_current_resource
215
- end
216
-
217
- #
218
- # Matches chef_acl paths like nodes, nodes/*.
219
- #
220
- # == Examples
221
- # match_paths('nodes'): [ 'nodes' ]
222
- # match_paths('nodes/*'): [ 'nodes/x', 'nodes/y', 'nodes/z' ]
223
- # match_paths('*'): [ 'clients', 'environments', 'nodes', 'roles', ... ]
224
- # match_paths('/'): [ '/' ]
225
- # match_paths(''): [ '' ]
226
- # match_paths('/*'): [ '/organizations', '/users' ]
227
- # match_paths('/organizations/*/*'): [ '/organizations/foo/clients', '/organizations/foo/environments', ..., '/organizations/bar/clients', '/organizations/bar/environments', ... ]
228
- #
229
- def match_paths(path)
230
- # Turn multiple slashes into one
231
- # nodes//x -> nodes/x
232
- path = path.gsub(/[\/]+/, '/')
233
- # If it's absolute, start the matching with /. If it's relative, start with '' (relative root).
234
- if path[0] == '/'
235
- matches = [ '/' ]
236
- else
237
- matches = [ '' ]
238
- end
239
-
240
- # Split the path, and get rid of the empty path at the beginning and end
241
- # (/a/b/c/ -> [ 'a', 'b', 'c' ])
242
- parts = path.split('/').select { |x| x != '' }.to_a
243
-
244
- # Descend until we find the matches:
245
- # path = 'a/b/c'
246
- # parts = [ 'a', 'b', 'c' ]
247
- # Starting matches = [ '' ]
248
- parts.each_with_index do |part, index|
249
- # For each match, list <match>/<part> and set matches to that.
250
- #
251
- # Example: /*/foo
252
- # 1. To start,
253
- # matches = [ '/' ], part = '*'.
254
- # list('/', '*') = [ '/organizations, '/users' ]
255
- # 2. matches = [ '/organizations', '/users' ], part = 'foo'
256
- # list('/organizations', 'foo') = [ '/organizations/foo' ]
257
- # list('/users', 'foo') = [ '/users/foo' ]
258
- #
259
- # Result: /*/foo = [ '/organizations/foo', '/users/foo' ]
260
- #
261
- matches = Chef::ChefFS::Parallelizer.parallelize(matches) do |path|
262
- found, error = list(path, part)
263
- if error
264
- if parts[0..index-1].all? { |p| p != '*' }
265
- raise error
266
- end
267
- []
268
- else
269
- found
270
- end
271
- end.flatten(1).to_a
272
- end
273
-
274
- matches
275
- end
276
-
277
- #
278
- # Takes a normal path and finds the Chef path to get / set its ACL.
279
- #
280
- # nodes/x -> nodes/x/_acl
281
- # nodes -> containers/nodes/_acl
282
- # '' -> organizations/_acl (the org acl)
283
- # /organizations/foo -> /organizations/foo/organizations/_acl
284
- # /users/foo -> /users/foo/_acl
285
- # /organizations/foo/nodes/x -> /organizations/foo/nodes/x/_acl
286
- #
287
- def acl_path(path)
288
- parts = path.split('/').select { |x| x != '' }.to_a
289
- prefix = (path[0] == '/') ? '/' : ''
290
-
291
- case parts.size
292
- when 0
293
- # /, empty (relative root)
294
- # The root of the server has no publicly visible ACLs. Only nodes/*, etc.
295
- if prefix == ''
296
- ::File.join('organizations', '_acl')
297
- end
298
-
299
- when 1
300
- # nodes, roles, etc.
301
- # The top level organizations and users containers have no publicly
302
- # visible ACLs. Only nodes/*, etc.
303
- if prefix == ''
304
- ::File.join('containers', path, '_acl')
305
- end
306
-
307
- when 2
308
- # /organizations/NAME, /users/NAME, nodes/NAME, roles/NAME, etc.
309
- if prefix == '/' && parts[0] == 'organizations'
310
- ::File.join(path, 'organizations', '_acl')
311
- else
312
- ::File.join(path, '_acl')
313
- end
314
-
315
- when 3
316
- # /organizations/NAME/nodes, cookbooks/NAME/VERSION, etc.
317
- if prefix == '/'
318
- ::File.join('/', parts[0], parts[1], 'containers', parts[2], '_acl')
319
- else
320
- ::File.join(parts[0], parts[1], '_acl')
321
- end
322
-
323
- when 4
324
- # /organizations/NAME/nodes/NAME, cookbooks/NAME/VERSION/BLAH
325
- # /organizations/NAME/nodes/NAME, cookbooks/NAME/VERSION, etc.
326
- if prefix == '/'
327
- ::File.join(path, '_acl')
328
- else
329
- ::File.join(parts[0], parts[1], '_acl')
330
- end
331
-
332
- else
333
- # /organizations/NAME/cookbooks/NAME/VERSION/..., cookbooks/NAME/VERSION/A/B/...
334
- if prefix == '/'
335
- ::File.join('/', parts[0], parts[1], parts[2], parts[3], '_acl')
336
- else
337
- ::File.join(parts[0], parts[1], '_acl')
338
- end
339
- end
340
- end
341
-
342
- #
343
- # Lists the securable children under a path (the ones that either have ACLs
344
- # or have children with ACLs).
345
- #
346
- # list('nodes', 'x') -> [ 'nodes/x' ]
347
- # list('nodes', '*') -> [ 'nodes/x', 'nodes/y', 'nodes/z' ]
348
- # list('', '*') -> [ 'clients', 'environments', 'nodes', 'roles', ... ]
349
- # list('/', '*') -> [ '/organizations']
350
- # list('cookbooks', 'x') -> [ 'cookbooks/x' ]
351
- # list('cookbooks/x', '*') -> [ ] # Individual cookbook versions do not have their own ACLs
352
- # list('/organizations/foo/nodes', '*') -> [ '/organizations/foo/nodes/x', '/organizations/foo/nodes/y' ]
353
- #
354
- # The list of children of an organization is == the list of containers. If new
355
- # containers are added, the list of children will grow. This allows the system
356
- # to extend to new types of objects and allow cheffish to work with them.
357
- #
358
- def list(path, child)
359
- # TODO make ChefFS understand top level organizations and stop doing this altogether.
360
- parts = path.split('/').select { |x| x != '' }.to_a
361
- absolute = (path[0] == '/')
362
- if absolute && parts[0] == 'organizations'
363
- return [ [], "ACLs cannot be set on children of #{path}" ] if parts.size > 3
364
- else
365
- return [ [], "ACLs cannot be set on children of #{path}" ] if parts.size > 1
366
- end
367
-
368
- error = nil
369
-
370
- if child == '*'
371
- case parts.size
372
- when 0
373
- # /*, *
374
- if absolute
375
- results = [ "/organizations", "/users" ]
376
- else
377
- results, error = rest_list("containers")
378
- end
379
-
380
- when 1
381
- # /organizations/*, /users/*, roles/*, nodes/*, etc.
382
- results, error = rest_list(path)
383
- if !error
384
- results = results.map { |result| ::File.join(path, result) }
385
- end
386
-
387
- when 2
388
- # /organizations/NAME/*
389
- results, error = rest_list(::File.join(path, 'containers'))
390
- if !error
391
- results = results.map { |result| ::File.join(path, result) }
392
- end
393
-
394
- when 3
395
- # /organizations/NAME/TYPE/*
396
- results, error = rest_list(path)
397
- if !error
398
- results = results.map { |result| ::File.join(path, result) }
399
- end
400
- end
401
-
402
- else
403
- if child == 'data_bags' &&
404
- (parts.size == 0 || (parts.size == 2 && parts[0] == 'organizations'))
405
- child = 'data'
406
- end
407
-
408
- if absolute
409
- # /<child>, /users/<child>, /organizations/<child>, /organizations/foo/<child>, /organizations/foo/nodes/<child> ...
410
- results = [ ::File.join('/', parts[0..2], child) ]
411
- elsif parts.size == 0
412
- # <child> (nodes, roles, etc.)
413
- results = [ child ]
414
- else
415
- # nodes/<child>, roles/<child>, etc.
416
- results = [ ::File.join(parts[0], child) ]
417
- end
418
- end
419
-
420
- [ results, error ]
421
- end
422
-
423
- def rest_url(path)
424
- path[0] == '/' ? URI.join(rest.url, path) : path
425
- end
426
-
427
- def rest_list(path)
428
- begin
429
- # All our rest lists are hashes where the keys are the names
430
- [ rest.get(rest_url(path)).keys, nil ]
431
- rescue Net::HTTPServerException => e
432
- if e.response.code == '405' || e.response.code == '404'
433
- parts = path.split('/').select { |p| p != '' }.to_a
434
-
435
- # We KNOW we expect these to exist. Other containers may or may not.
436
- unless (parts.size == 1 || (parts.size == 3 && parts[0] == 'organizations')) &&
437
- %w(clients containers cookbooks data environments groups nodes roles).include?(parts[-1])
438
- return [ [], "Cannot get list of #{path}: HTTP response code #{e.response.code}" ]
439
- end
440
- end
441
- raise
442
- end
443
- end
444
- end
445
- end
446
- end
@@ -1,53 +0,0 @@
1
- require 'cheffish/actor_provider_base'
2
- require 'chef/resource/chef_client'
3
- require 'chef/chef_fs/data_handler/client_data_handler'
4
-
5
- class Chef
6
- class Provider
7
- class ChefClient < Cheffish::ActorProviderBase
8
- provides :chef_client
9
-
10
- def whyrun_supported?
11
- true
12
- end
13
-
14
- def actor_type
15
- 'client'
16
- end
17
-
18
- def actor_path
19
- 'clients'
20
- end
21
-
22
- action :create do
23
- create_actor
24
- end
25
-
26
- action :delete do
27
- delete_actor
28
- end
29
-
30
- #
31
- # Helpers
32
- #
33
-
34
- def resource_class
35
- Chef::Resource::ChefClient
36
- end
37
-
38
- def data_handler
39
- Chef::ChefFS::DataHandler::ClientDataHandler.new
40
- end
41
-
42
- def keys
43
- {
44
- 'name' => :name,
45
- 'admin' => :admin,
46
- 'validator' => :validator,
47
- 'public_key' => :source_key
48
- }
49
- end
50
-
51
- end
52
- end
53
- end
@@ -1,55 +0,0 @@
1
- require 'cheffish/chef_provider_base'
2
- require 'chef/resource/chef_container'
3
- require 'chef/chef_fs/data_handler/container_data_handler'
4
-
5
- class Chef
6
- class Provider
7
- class ChefContainer < Cheffish::ChefProviderBase
8
- provides :chef_container
9
-
10
- def whyrun_supported?
11
- true
12
- end
13
-
14
- action :create do
15
- if !@current_exists
16
- converge_by "create container #{new_resource.name} at #{rest.url}" do
17
- rest.post("containers", normalize_for_post(new_json))
18
- end
19
- end
20
- end
21
-
22
- action :delete do
23
- if @current_exists
24
- converge_by "delete container #{new_resource.name} at #{rest.url}" do
25
- rest.delete("containers/#{new_resource.name}")
26
- end
27
- end
28
- end
29
-
30
- def load_current_resource
31
- begin
32
- @current_exists = rest.get("containers/#{new_resource.name}")
33
- rescue Net::HTTPServerException => e
34
- if e.response.code == "404"
35
- @current_exists = false
36
- else
37
- raise
38
- end
39
- end
40
- end
41
-
42
- def new_json
43
- {}
44
- end
45
-
46
- def data_handler
47
- Chef::ChefFS::DataHandler::ContainerDataHandler.new
48
- end
49
-
50
- def keys
51
- { 'containername' => :name, 'containerpath' => :name }
52
- end
53
- end
54
- end
55
- end
@@ -1,55 +0,0 @@
1
- require 'cheffish/chef_provider_base'
2
- require 'chef/resource/chef_data_bag'
3
-
4
- class Chef
5
- class Provider
6
- class ChefDataBag < Cheffish::ChefProviderBase
7
- provides :chef_data_bag
8
-
9
- def whyrun_supported?
10
- true
11
- end
12
-
13
- action :create do
14
- if !current_resource_exists?
15
- converge_by "create data bag #{new_resource.name} at #{rest.url}" do
16
- rest.post("data", { 'name' => new_resource.name })
17
- end
18
- end
19
- end
20
-
21
- action :delete do
22
- if current_resource_exists?
23
- converge_by "delete data bag #{new_resource.name} at #{rest.url}" do
24
- rest.delete("data/#{new_resource.name}")
25
- end
26
- end
27
- end
28
-
29
- def load_current_resource
30
- begin
31
- @current_resource = json_to_resource(rest.get("data/#{new_resource.name}"))
32
- rescue Net::HTTPServerException => e
33
- if e.response.code == "404"
34
- @current_resource = not_found_resource
35
- else
36
- raise
37
- end
38
- end
39
- end
40
-
41
- #
42
- # Helpers
43
- #
44
- # Gives us new_json, current_json, not_found_json, etc.
45
-
46
- def resource_class
47
- Chef::Resource::ChefDataBag
48
- end
49
-
50
- def json_to_resource(json)
51
- Chef::Resource::ChefDataBag.new(json['name'], run_context)
52
- end
53
- end
54
- end
55
- end