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.
- checksums.yaml +4 -4
- data/cheffish.gemspec +1 -0
- data/lib/chef/resource/chef_acl.rb +440 -20
- data/lib/chef/resource/chef_client.rb +50 -25
- data/lib/chef/resource/chef_container.rb +44 -11
- data/lib/chef/resource/chef_data_bag.rb +43 -10
- data/lib/chef/resource/chef_data_bag_item.rb +292 -82
- data/lib/chef/resource/chef_environment.rb +79 -27
- data/lib/chef/resource/chef_group.rb +77 -40
- data/lib/chef/resource/chef_mirror.rb +170 -21
- data/lib/chef/resource/chef_node.rb +77 -11
- data/lib/chef/resource/chef_organization.rb +153 -43
- data/lib/chef/resource/chef_resolved_cookbooks.rb +40 -9
- data/lib/chef/resource/chef_role.rb +81 -29
- data/lib/chef/resource/chef_user.rb +64 -33
- data/lib/chef/resource/private_key.rb +230 -17
- data/lib/chef/resource/public_key.rb +88 -9
- data/lib/cheffish/array_property.rb +29 -0
- data/lib/cheffish/base_resource.rb +254 -0
- data/lib/cheffish/chef_actor_base.rb +135 -0
- data/lib/cheffish/node_properties.rb +107 -0
- data/lib/cheffish/recipe_dsl.rb +0 -14
- data/lib/cheffish/version.rb +1 -1
- data/lib/cheffish.rb +4 -108
- data/spec/integration/chef_acl_spec.rb +0 -2
- data/spec/integration/chef_client_spec.rb +0 -1
- data/spec/integration/chef_container_spec.rb +0 -2
- data/spec/integration/chef_group_spec.rb +0 -2
- data/spec/integration/chef_mirror_spec.rb +0 -2
- data/spec/integration/chef_node_spec.rb +0 -2
- data/spec/integration/chef_organization_spec.rb +1 -3
- data/spec/integration/chef_role_spec.rb +0 -2
- data/spec/integration/chef_user_spec.rb +0 -2
- data/spec/integration/private_key_spec.rb +0 -4
- data/spec/integration/recipe_dsl_spec.rb +0 -2
- data/spec/support/spec_support.rb +0 -1
- data/spec/unit/get_private_key_spec.rb +13 -0
- metadata +22 -20
- data/lib/chef/provider/chef_acl.rb +0 -446
- data/lib/chef/provider/chef_client.rb +0 -53
- data/lib/chef/provider/chef_container.rb +0 -55
- data/lib/chef/provider/chef_data_bag.rb +0 -55
- data/lib/chef/provider/chef_data_bag_item.rb +0 -278
- data/lib/chef/provider/chef_environment.rb +0 -83
- data/lib/chef/provider/chef_group.rb +0 -83
- data/lib/chef/provider/chef_mirror.rb +0 -169
- data/lib/chef/provider/chef_node.rb +0 -87
- data/lib/chef/provider/chef_organization.rb +0 -155
- data/lib/chef/provider/chef_resolved_cookbooks.rb +0 -46
- data/lib/chef/provider/chef_role.rb +0 -84
- data/lib/chef/provider/chef_user.rb +0 -59
- data/lib/chef/provider/private_key.rb +0 -225
- data/lib/chef/provider/public_key.rb +0 -88
- data/lib/cheffish/actor_provider_base.rb +0 -131
- 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
|