cheffish 1.6.0 → 2.0.0

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