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,131 +0,0 @@
1
- require 'cheffish/key_formatter'
2
- require 'cheffish/chef_provider_base'
3
-
4
- class Cheffish::ActorProviderBase < Cheffish::ChefProviderBase
5
-
6
- def create_actor
7
- if new_resource.before
8
- new_resource.before.call(new_resource)
9
- end
10
-
11
- # Create or update the client/user
12
- current_public_key = new_json['public_key']
13
- differences = json_differences(current_json, new_json)
14
- if current_resource_exists?
15
- # Update the actor if it's different
16
- if differences.size > 0
17
- description = [ "update #{actor_type} #{new_resource.name} at #{actor_path}" ] + differences
18
- converge_by description do
19
- result = rest.put("#{actor_path}/#{new_resource.name}", normalize_for_put(new_json))
20
- current_public_key, current_public_key_format = Cheffish::KeyFormatter.decode(result['public_key']) if result['public_key']
21
- end
22
- end
23
- else
24
- # Create the actor if it's missing
25
- if !new_public_key
26
- raise "You must specify a public key to create a #{actor_type}! Use the private_key resource to create a key, and pass it in with source_key_path."
27
- end
28
- description = [ "create #{actor_type} #{new_resource.name} at #{actor_path}" ] + differences
29
- converge_by description do
30
- result = rest.post("#{actor_path}", normalize_for_post(new_json))
31
- current_public_key, current_public_key_format = Cheffish::KeyFormatter.decode(result['public_key']) if result['public_key']
32
- end
33
- end
34
-
35
- # Write out the public key
36
- if new_resource.output_key_path
37
- # TODO use inline_resource
38
- key_content = Cheffish::KeyFormatter.encode(current_public_key, { :format => new_resource.output_key_format })
39
- if !current_resource.output_key_path
40
- action = 'create'
41
- elsif key_content != IO.read(current_resource.output_key_path)
42
- action = 'overwrite'
43
- else
44
- action = nil
45
- end
46
- if action
47
- converge_by "#{action} public key #{new_resource.output_key_path}" do
48
- IO.write(new_resource.output_key_path, key_content)
49
- end
50
- end
51
- # TODO permissions?
52
- end
53
-
54
- if new_resource.after
55
- new_resource.after.call(self, new_json, server_private_key, server_public_key)
56
- end
57
- end
58
-
59
- def delete_actor
60
- if current_resource_exists?
61
- converge_by "delete #{actor_type} #{new_resource.name} at #{actor_path}" do
62
- rest.delete("#{actor_path}/#{new_resource.name}")
63
- Chef::Log.info("#{new_resource} deleted #{actor_type} #{new_resource.name} at #{rest.url}")
64
- end
65
- end
66
- if current_resource.output_key_path
67
- converge_by "delete public key #{current_resource.output_key_path}" do
68
- ::File.unlink(current_resource.output_key_path)
69
- end
70
- end
71
- end
72
-
73
- def new_public_key
74
- @new_public_key ||= begin
75
- if new_resource.source_key
76
- if new_resource.source_key.is_a?(String)
77
- key, key_format = Cheffish::KeyFormatter.decode(new_resource.source_key)
78
-
79
- if key.private?
80
- key.public_key
81
- else
82
- key
83
- end
84
- elsif new_resource.source_key.private?
85
- new_resource.source_key.public_key
86
- else
87
- new_resource.source_key
88
- end
89
- elsif new_resource.source_key_path
90
- source_key_path = new_resource.source_key_path
91
- if Pathname.new(source_key_path).relative?
92
- source_key_str, source_key_path = Cheffish.get_private_key_with_path(source_key_path, run_context.config)
93
- else
94
- source_key_str = IO.read(source_key_path)
95
- end
96
- source_key, source_key_format = Cheffish::KeyFormatter.decode(source_key_str, new_resource.source_key_pass_phrase, source_key_path)
97
- if source_key.private?
98
- source_key.public_key
99
- else
100
- source_key
101
- end
102
- else
103
- nil
104
- end
105
- end
106
- end
107
-
108
- def augment_new_json(json)
109
- if new_public_key
110
- json['public_key'] = new_public_key.to_pem
111
- end
112
- json
113
- end
114
-
115
- def load_current_resource
116
- begin
117
- json = rest.get("#{actor_path}/#{new_resource.name}")
118
- @current_resource = json_to_resource(json)
119
- rescue Net::HTTPServerException => e
120
- if e.response.code == "404"
121
- @current_resource = not_found_resource
122
- else
123
- raise
124
- end
125
- end
126
-
127
- if new_resource.output_key_path && ::File.exist?(new_resource.output_key_path)
128
- current_resource.output_key_path = new_resource.output_key_path
129
- end
130
- end
131
- end
@@ -1,246 +0,0 @@
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