cheffish 1.5.0 → 1.6.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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +10 -0
  3. data/LICENSE +201 -201
  4. data/README.md +120 -120
  5. data/Rakefile +23 -23
  6. data/cheffish.gemspec +26 -0
  7. data/lib/chef/provider/chef_acl.rb +446 -439
  8. data/lib/chef/provider/chef_client.rb +53 -53
  9. data/lib/chef/provider/chef_container.rb +55 -55
  10. data/lib/chef/provider/chef_data_bag.rb +55 -55
  11. data/lib/chef/provider/chef_data_bag_item.rb +278 -278
  12. data/lib/chef/provider/chef_environment.rb +83 -83
  13. data/lib/chef/provider/chef_group.rb +83 -83
  14. data/lib/chef/provider/chef_mirror.rb +169 -169
  15. data/lib/chef/provider/chef_node.rb +87 -87
  16. data/lib/chef/provider/chef_organization.rb +155 -155
  17. data/lib/chef/provider/chef_resolved_cookbooks.rb +46 -46
  18. data/lib/chef/provider/chef_role.rb +84 -84
  19. data/lib/chef/provider/chef_user.rb +59 -59
  20. data/lib/chef/provider/private_key.rb +225 -225
  21. data/lib/chef/provider/public_key.rb +88 -88
  22. data/lib/chef/resource/chef_acl.rb +69 -69
  23. data/lib/chef/resource/chef_client.rb +48 -48
  24. data/lib/chef/resource/chef_container.rb +22 -22
  25. data/lib/chef/resource/chef_data_bag.rb +22 -22
  26. data/lib/chef/resource/chef_data_bag_item.rb +121 -121
  27. data/lib/chef/resource/chef_environment.rb +77 -77
  28. data/lib/chef/resource/chef_group.rb +53 -53
  29. data/lib/chef/resource/chef_mirror.rb +52 -52
  30. data/lib/chef/resource/chef_node.rb +22 -22
  31. data/lib/chef/resource/chef_organization.rb +69 -69
  32. data/lib/chef/resource/chef_resolved_cookbooks.rb +35 -35
  33. data/lib/chef/resource/chef_role.rb +110 -110
  34. data/lib/chef/resource/chef_user.rb +56 -56
  35. data/lib/chef/resource/private_key.rb +48 -48
  36. data/lib/chef/resource/public_key.rb +25 -25
  37. data/lib/cheffish.rb +235 -235
  38. data/lib/cheffish/actor_provider_base.rb +131 -131
  39. data/lib/cheffish/basic_chef_client.rb +184 -184
  40. data/lib/cheffish/chef_provider_base.rb +246 -246
  41. data/lib/cheffish/chef_run.rb +162 -162
  42. data/lib/cheffish/chef_run_data.rb +19 -19
  43. data/lib/cheffish/chef_run_listener.rb +30 -30
  44. data/lib/cheffish/key_formatter.rb +113 -113
  45. data/lib/cheffish/merged_config.rb +98 -94
  46. data/lib/cheffish/recipe_dsl.rb +157 -157
  47. data/lib/cheffish/rspec.rb +8 -8
  48. data/lib/cheffish/rspec/chef_run_support.rb +83 -83
  49. data/lib/cheffish/rspec/matchers.rb +4 -4
  50. data/lib/cheffish/rspec/matchers/be_idempotent.rb +16 -16
  51. data/lib/cheffish/rspec/matchers/emit_no_warnings_or_errors.rb +15 -15
  52. data/lib/cheffish/rspec/matchers/have_updated.rb +37 -37
  53. data/lib/cheffish/rspec/matchers/partially_match.rb +63 -63
  54. data/lib/cheffish/rspec/recipe_run_wrapper.rb +78 -78
  55. data/lib/cheffish/rspec/repository_support.rb +108 -108
  56. data/lib/cheffish/server_api.rb +52 -52
  57. data/lib/cheffish/version.rb +3 -3
  58. data/lib/cheffish/with_pattern.rb +21 -21
  59. data/spec/functional/fingerprint_spec.rb +64 -64
  60. data/spec/functional/merged_config_spec.rb +19 -19
  61. data/spec/functional/server_api_spec.rb +13 -13
  62. data/spec/integration/chef_acl_spec.rb +892 -879
  63. data/spec/integration/chef_client_spec.rb +105 -105
  64. data/spec/integration/chef_container_spec.rb +33 -33
  65. data/spec/integration/chef_group_spec.rb +309 -309
  66. data/spec/integration/chef_mirror_spec.rb +491 -491
  67. data/spec/integration/chef_node_spec.rb +786 -786
  68. data/spec/integration/chef_organization_spec.rb +226 -226
  69. data/spec/integration/chef_role_spec.rb +78 -78
  70. data/spec/integration/chef_user_spec.rb +85 -85
  71. data/spec/integration/private_key_spec.rb +399 -399
  72. data/spec/integration/recipe_dsl_spec.rb +28 -28
  73. data/spec/integration/rspec/converge_spec.rb +183 -183
  74. data/spec/support/key_support.rb +29 -29
  75. data/spec/support/spec_support.rb +15 -15
  76. data/spec/unit/get_private_key_spec.rb +131 -131
  77. data/spec/unit/recipe_run_wrapper_spec.rb +37 -37
  78. metadata +7 -5
@@ -1,246 +1,246 @@
1
- require 'chef/config'
2
- require 'chef/run_list'
3
- require 'chef/provider/lwrp_base'
4
-
5
- module Cheffish
6
- class ChefProviderBase < Chef::Provider::LWRPBase
7
- def rest
8
- @rest ||= Cheffish.chef_server_api(new_resource.chef_server)
9
- end
10
-
11
- def current_resource_exists?
12
- Array(current_resource.action) != [ :delete ]
13
- end
14
-
15
- def not_found_resource
16
- resource = resource_class.new(new_resource.name, run_context)
17
- resource.action :delete
18
- resource
19
- end
20
-
21
- def normalize_for_put(json)
22
- data_handler.normalize_for_put(json, fake_entry)
23
- end
24
-
25
- def normalize_for_post(json)
26
- data_handler.normalize_for_post(json, fake_entry)
27
- end
28
-
29
- def new_json
30
- @new_json ||= begin
31
- if new_resource.complete
32
- result = normalize(resource_to_json(new_resource))
33
- else
34
- # If the resource is incomplete, we use the current json to fill any holes
35
- result = current_json.merge(resource_to_json(new_resource))
36
- end
37
- augment_new_json(result)
38
- end
39
- end
40
-
41
- # Meant to be overridden
42
- def augment_new_json(json)
43
- json
44
- end
45
-
46
- def current_json
47
- @current_json ||= begin
48
- result = normalize(resource_to_json(current_resource))
49
- result = augment_current_json(result)
50
- result
51
- end
52
- end
53
-
54
- # Meant to be overridden
55
- def augment_current_json(json)
56
- json
57
- end
58
-
59
- def resource_to_json(resource)
60
- json = resource.raw_json || {}
61
- keys.each do |json_key, resource_key|
62
- value = resource.send(resource_key)
63
- # This takes care of Chef ImmutableMash and ImmutableArray
64
- value = value.to_hash if value.is_a?(Hash)
65
- value = value.to_a if value.is_a?(Array)
66
- json[json_key] = value if value
67
- end
68
- json
69
- end
70
-
71
- def json_to_resource(json)
72
- resource = resource_class.new(new_resource.name, run_context)
73
- keys.each do |json_key, resource_key|
74
- resource.send(resource_key, json.delete(json_key))
75
- end
76
- # Set the leftover to raw_json
77
- resource.raw_json json
78
- resource
79
- end
80
-
81
- def normalize(json)
82
- data_handler.normalize(json, fake_entry)
83
- end
84
-
85
- def json_differences(old_json, new_json, print_values=true, name = '', result = nil)
86
- result ||= []
87
- json_differences_internal(old_json, new_json, print_values, name, result)
88
- result
89
- end
90
-
91
- def json_differences_internal(old_json, new_json, print_values, name, result)
92
- if old_json.kind_of?(Hash) && new_json.kind_of?(Hash)
93
- removed_keys = old_json.keys.inject({}) { |hash, key| hash[key] = true; hash }
94
- new_json.each_pair do |new_key, new_value|
95
- if old_json.has_key?(new_key)
96
- removed_keys.delete(new_key)
97
- if new_value != old_json[new_key]
98
- json_differences_internal(old_json[new_key], new_value, print_values, name == '' ? new_key : "#{name}.#{new_key}", result)
99
- end
100
- else
101
- if print_values
102
- result << " add #{name == '' ? new_key : "#{name}.#{new_key}"} = #{new_value.inspect}"
103
- else
104
- result << " add #{name == '' ? new_key : "#{name}.#{new_key}"}"
105
- end
106
- end
107
- end
108
- removed_keys.keys.each do |removed_key|
109
- result << " remove #{name == '' ? removed_key : "#{name}.#{removed_key}"}"
110
- end
111
- else
112
- old_json = old_json.to_s if old_json.kind_of?(Symbol)
113
- new_json = new_json.to_s if new_json.kind_of?(Symbol)
114
- if old_json != new_json
115
- if print_values
116
- result << " update #{name} from #{old_json.inspect} to #{new_json.inspect}"
117
- else
118
- result << " update #{name}"
119
- end
120
- end
121
- end
122
- end
123
-
124
- def apply_modifiers(modifiers, json)
125
- return json if !modifiers || modifiers.size == 0
126
-
127
- # If the attributes have nothing, set them to {} so we have something to add to
128
- if json
129
- json = Marshal.load(Marshal.dump(json)) # Deep copy
130
- else
131
- json = {}
132
- end
133
-
134
- modifiers.each do |path, value|
135
- path = [path] if !path.kind_of?(Array)
136
- path = path.map { |path_part| path_part.to_s }
137
- parent = 0.upto(path.size-2).inject(json) do |hash, index|
138
- if hash.nil?
139
- nil
140
- elsif !hash.is_a?(Hash)
141
- raise "Attempt to set #{path} to #{value} when #{path[0..index-1]} is not a hash"
142
- else
143
- hash[path[index]]
144
- end
145
- end
146
- if !parent.nil? && !parent.is_a?(Hash)
147
- raise "Attempt to set #{path} to #{value} when #{path[0..-2]} is not a hash"
148
- end
149
- existing_value = parent ? parent[path[-1]] : nil
150
-
151
- if value.is_a?(Proc)
152
- value = value.call(existing_value)
153
- end
154
- if value == :delete
155
- parent.delete(path[-1]) if parent
156
- else
157
- # Create parent if necessary, overwriting values
158
- parent = path[0..-2].inject(json) do |hash, path_part|
159
- hash[path_part] = {} if !hash[path_part]
160
- hash[path_part]
161
- end
162
- if path.size > 0
163
- parent[path[-1]] = value
164
- else
165
- json = value
166
- end
167
- end
168
- end
169
- json
170
- end
171
-
172
- def apply_run_list_modifiers(add_to_run_list, delete_from_run_list, run_list)
173
- return run_list if (!add_to_run_list || add_to_run_list.size == 0) && (!delete_from_run_list || !delete_from_run_list.size)
174
- delete_from_run_list ||= []
175
- add_to_run_list ||= []
176
-
177
- run_list = Chef::RunList.new(*run_list)
178
-
179
- result = []
180
- add_to_run_list_index = 0
181
- run_list_index = 0
182
- while run_list_index < run_list.run_list_items.size do
183
- # See if the desired run list has this item
184
- found_desired = add_to_run_list.index { |item| same_run_list_item(item, run_list[run_list_index]) }
185
- if found_desired
186
- # If so, copy all items up to that desired run list (to preserve order).
187
- # If a run list item is out of order (run_list = X, B, Y, A, Z and desired = A, B)
188
- # then this will give us X, A, B. When A is found later, nothing will be copied
189
- # because found_desired will be less than add_to_run_list_index. The result will
190
- # be X, A, B, Y, Z.
191
- if found_desired >= add_to_run_list_index
192
- result += add_to_run_list[add_to_run_list_index..found_desired].map { |item| item.to_s }
193
- add_to_run_list_index = found_desired+1
194
- end
195
- else
196
- # If not, just copy it in
197
- unless delete_from_run_list.index { |item| same_run_list_item(item, run_list[run_list_index]) }
198
- result << run_list[run_list_index].to_s
199
- end
200
- end
201
- run_list_index += 1
202
- end
203
-
204
- # Copy any remaining desired items at the end
205
- result += add_to_run_list[add_to_run_list_index..-1].map { |item| item.to_s }
206
- result
207
- end
208
-
209
- def same_run_list_item(a, b)
210
- a_name = a.name
211
- b_name = b.name
212
- # Handle "a::default" being the same as "a"
213
- if a.type == :recipe && a_name =~ /(.+)::default$/
214
- a_name = $1
215
- elsif b.type == :recipe && b_name =~ /(.+)::default$/
216
- b_name = $1
217
- end
218
-
219
- a_name == b_name && a.type == b.type # We want to replace things with same name and different version
220
- end
221
-
222
- private
223
-
224
- # Needed to be able to use DataHandler classes
225
- def fake_entry
226
- FakeEntry.new("#{new_resource.send(keys.values.first)}.json")
227
- end
228
-
229
- class FakeEntry
230
- def initialize(name, parent = nil)
231
- @name = name
232
- @parent = parent
233
- @org = nil
234
- end
235
-
236
- attr_reader :name
237
- attr_reader :parent
238
- attr_reader :org
239
- end
240
- end
241
-
242
- # We are not interested in Chef's cloning behavior here.
243
- def load_prior_resource(*args)
244
- Chef::Log.debug("Overloading #{resource_name}.load_prior_resource with NOOP")
245
- end
246
- end
1
+ require 'chef/config'
2
+ require 'chef/run_list'
3
+ require 'chef/provider/lwrp_base'
4
+
5
+ module Cheffish
6
+ class ChefProviderBase < Chef::Provider::LWRPBase
7
+ def rest
8
+ @rest ||= Cheffish.chef_server_api(new_resource.chef_server)
9
+ end
10
+
11
+ def current_resource_exists?
12
+ Array(current_resource.action) != [ :delete ]
13
+ end
14
+
15
+ def not_found_resource
16
+ resource = resource_class.new(new_resource.name, run_context)
17
+ resource.action :delete
18
+ resource
19
+ end
20
+
21
+ def normalize_for_put(json)
22
+ data_handler.normalize_for_put(json, fake_entry)
23
+ end
24
+
25
+ def normalize_for_post(json)
26
+ data_handler.normalize_for_post(json, fake_entry)
27
+ end
28
+
29
+ def new_json
30
+ @new_json ||= begin
31
+ if new_resource.complete
32
+ result = normalize(resource_to_json(new_resource))
33
+ else
34
+ # If the resource is incomplete, we use the current json to fill any holes
35
+ result = current_json.merge(resource_to_json(new_resource))
36
+ end
37
+ augment_new_json(result)
38
+ end
39
+ end
40
+
41
+ # Meant to be overridden
42
+ def augment_new_json(json)
43
+ json
44
+ end
45
+
46
+ def current_json
47
+ @current_json ||= begin
48
+ result = normalize(resource_to_json(current_resource))
49
+ result = augment_current_json(result)
50
+ result
51
+ end
52
+ end
53
+
54
+ # Meant to be overridden
55
+ def augment_current_json(json)
56
+ json
57
+ end
58
+
59
+ def resource_to_json(resource)
60
+ json = resource.raw_json || {}
61
+ keys.each do |json_key, resource_key|
62
+ value = resource.send(resource_key)
63
+ # This takes care of Chef ImmutableMash and ImmutableArray
64
+ value = value.to_hash if value.is_a?(Hash)
65
+ value = value.to_a if value.is_a?(Array)
66
+ json[json_key] = value if value
67
+ end
68
+ json
69
+ end
70
+
71
+ def json_to_resource(json)
72
+ resource = resource_class.new(new_resource.name, run_context)
73
+ keys.each do |json_key, resource_key|
74
+ resource.send(resource_key, json.delete(json_key))
75
+ end
76
+ # Set the leftover to raw_json
77
+ resource.raw_json json
78
+ resource
79
+ end
80
+
81
+ def normalize(json)
82
+ data_handler.normalize(json, fake_entry)
83
+ end
84
+
85
+ def json_differences(old_json, new_json, print_values=true, name = '', result = nil)
86
+ result ||= []
87
+ json_differences_internal(old_json, new_json, print_values, name, result)
88
+ result
89
+ end
90
+
91
+ def json_differences_internal(old_json, new_json, print_values, name, result)
92
+ if old_json.kind_of?(Hash) && new_json.kind_of?(Hash)
93
+ removed_keys = old_json.keys.inject({}) { |hash, key| hash[key] = true; hash }
94
+ new_json.each_pair do |new_key, new_value|
95
+ if old_json.has_key?(new_key)
96
+ removed_keys.delete(new_key)
97
+ if new_value != old_json[new_key]
98
+ json_differences_internal(old_json[new_key], new_value, print_values, name == '' ? new_key : "#{name}.#{new_key}", result)
99
+ end
100
+ else
101
+ if print_values
102
+ result << " add #{name == '' ? new_key : "#{name}.#{new_key}"} = #{new_value.inspect}"
103
+ else
104
+ result << " add #{name == '' ? new_key : "#{name}.#{new_key}"}"
105
+ end
106
+ end
107
+ end
108
+ removed_keys.keys.each do |removed_key|
109
+ result << " remove #{name == '' ? removed_key : "#{name}.#{removed_key}"}"
110
+ end
111
+ else
112
+ old_json = old_json.to_s if old_json.kind_of?(Symbol)
113
+ new_json = new_json.to_s if new_json.kind_of?(Symbol)
114
+ if old_json != new_json
115
+ if print_values
116
+ result << " update #{name} from #{old_json.inspect} to #{new_json.inspect}"
117
+ else
118
+ result << " update #{name}"
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ def apply_modifiers(modifiers, json)
125
+ return json if !modifiers || modifiers.size == 0
126
+
127
+ # If the attributes have nothing, set them to {} so we have something to add to
128
+ if json
129
+ json = Marshal.load(Marshal.dump(json)) # Deep copy
130
+ else
131
+ json = {}
132
+ end
133
+
134
+ modifiers.each do |path, value|
135
+ path = [path] if !path.kind_of?(Array)
136
+ path = path.map { |path_part| path_part.to_s }
137
+ parent = 0.upto(path.size-2).inject(json) do |hash, index|
138
+ if hash.nil?
139
+ nil
140
+ elsif !hash.is_a?(Hash)
141
+ raise "Attempt to set #{path} to #{value} when #{path[0..index-1]} is not a hash"
142
+ else
143
+ hash[path[index]]
144
+ end
145
+ end
146
+ if !parent.nil? && !parent.is_a?(Hash)
147
+ raise "Attempt to set #{path} to #{value} when #{path[0..-2]} is not a hash"
148
+ end
149
+ existing_value = parent ? parent[path[-1]] : nil
150
+
151
+ if value.is_a?(Proc)
152
+ value = value.call(existing_value)
153
+ end
154
+ if value == :delete
155
+ parent.delete(path[-1]) if parent
156
+ else
157
+ # Create parent if necessary, overwriting values
158
+ parent = path[0..-2].inject(json) do |hash, path_part|
159
+ hash[path_part] = {} if !hash[path_part]
160
+ hash[path_part]
161
+ end
162
+ if path.size > 0
163
+ parent[path[-1]] = value
164
+ else
165
+ json = value
166
+ end
167
+ end
168
+ end
169
+ json
170
+ end
171
+
172
+ def apply_run_list_modifiers(add_to_run_list, delete_from_run_list, run_list)
173
+ return run_list if (!add_to_run_list || add_to_run_list.size == 0) && (!delete_from_run_list || !delete_from_run_list.size)
174
+ delete_from_run_list ||= []
175
+ add_to_run_list ||= []
176
+
177
+ run_list = Chef::RunList.new(*run_list)
178
+
179
+ result = []
180
+ add_to_run_list_index = 0
181
+ run_list_index = 0
182
+ while run_list_index < run_list.run_list_items.size do
183
+ # See if the desired run list has this item
184
+ found_desired = add_to_run_list.index { |item| same_run_list_item(item, run_list[run_list_index]) }
185
+ if found_desired
186
+ # If so, copy all items up to that desired run list (to preserve order).
187
+ # If a run list item is out of order (run_list = X, B, Y, A, Z and desired = A, B)
188
+ # then this will give us X, A, B. When A is found later, nothing will be copied
189
+ # because found_desired will be less than add_to_run_list_index. The result will
190
+ # be X, A, B, Y, Z.
191
+ if found_desired >= add_to_run_list_index
192
+ result += add_to_run_list[add_to_run_list_index..found_desired].map { |item| item.to_s }
193
+ add_to_run_list_index = found_desired+1
194
+ end
195
+ else
196
+ # If not, just copy it in
197
+ unless delete_from_run_list.index { |item| same_run_list_item(item, run_list[run_list_index]) }
198
+ result << run_list[run_list_index].to_s
199
+ end
200
+ end
201
+ run_list_index += 1
202
+ end
203
+
204
+ # Copy any remaining desired items at the end
205
+ result += add_to_run_list[add_to_run_list_index..-1].map { |item| item.to_s }
206
+ result
207
+ end
208
+
209
+ def same_run_list_item(a, b)
210
+ a_name = a.name
211
+ b_name = b.name
212
+ # Handle "a::default" being the same as "a"
213
+ if a.type == :recipe && a_name =~ /(.+)::default$/
214
+ a_name = $1
215
+ elsif b.type == :recipe && b_name =~ /(.+)::default$/
216
+ b_name = $1
217
+ end
218
+
219
+ a_name == b_name && a.type == b.type # We want to replace things with same name and different version
220
+ end
221
+
222
+ private
223
+
224
+ # Needed to be able to use DataHandler classes
225
+ def fake_entry
226
+ FakeEntry.new("#{new_resource.send(keys.values.first)}.json")
227
+ end
228
+
229
+ class FakeEntry
230
+ def initialize(name, parent = nil)
231
+ @name = name
232
+ @parent = parent
233
+ @org = nil
234
+ end
235
+
236
+ attr_reader :name
237
+ attr_reader :parent
238
+ attr_reader :org
239
+ end
240
+ end
241
+
242
+ # We are not interested in Chef's cloning behavior here.
243
+ def load_prior_resource(*args)
244
+ Chef::Log.debug("Overloading #{resource_name}.load_prior_resource with NOOP")
245
+ end
246
+ end