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,278 +0,0 @@
|
|
1
|
-
require 'cheffish/chef_provider_base'
|
2
|
-
require 'chef/resource/chef_data_bag_item'
|
3
|
-
require 'chef/chef_fs/data_handler/data_bag_item_data_handler'
|
4
|
-
require 'chef/encrypted_data_bag_item'
|
5
|
-
|
6
|
-
class Chef
|
7
|
-
class Provider
|
8
|
-
class ChefDataBagItem < Cheffish::ChefProviderBase
|
9
|
-
provides :chef_data_bag_item
|
10
|
-
|
11
|
-
def whyrun_supported?
|
12
|
-
true
|
13
|
-
end
|
14
|
-
|
15
|
-
action :create do
|
16
|
-
differences = calculate_differences
|
17
|
-
|
18
|
-
if current_resource_exists?
|
19
|
-
if differences.size > 0
|
20
|
-
description = [ "update data bag item #{new_resource.id} at #{rest.url}" ] + differences
|
21
|
-
converge_by description do
|
22
|
-
rest.put("data/#{new_resource.data_bag}/#{new_resource.id}", normalize_for_put(new_json))
|
23
|
-
end
|
24
|
-
end
|
25
|
-
else
|
26
|
-
description = [ "create data bag item #{new_resource.id} at #{rest.url}" ] + differences
|
27
|
-
converge_by description do
|
28
|
-
rest.post("data/#{new_resource.data_bag}", normalize_for_post(new_json))
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
action :delete do
|
34
|
-
if current_resource_exists?
|
35
|
-
converge_by "delete data bag item #{new_resource.id} at #{rest.url}" do
|
36
|
-
rest.delete("data/#{new_resource.data_bag}/#{new_resource.id}")
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def load_current_resource
|
42
|
-
begin
|
43
|
-
json = rest.get("data/#{new_resource.data_bag}/#{new_resource.id}")
|
44
|
-
resource = Chef::Resource::ChefDataBagItem.new(new_resource.name, run_context)
|
45
|
-
resource.raw_data json
|
46
|
-
@current_resource = resource
|
47
|
-
rescue Net::HTTPServerException => e
|
48
|
-
if e.response.code == "404"
|
49
|
-
@current_resource = not_found_resource
|
50
|
-
else
|
51
|
-
raise
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
# Determine if data bag is encrypted and if so, what its version is
|
56
|
-
first_real_key, first_real_value = (current_resource.raw_data || {}).select { |key, value| key != 'id' && !value.nil? }.first
|
57
|
-
if first_real_value
|
58
|
-
if first_real_value.is_a?(Hash) &&
|
59
|
-
first_real_value['version'].is_a?(Integer) &&
|
60
|
-
first_real_value['version'] > 0 &&
|
61
|
-
first_real_value.has_key?('encrypted_data')
|
62
|
-
|
63
|
-
current_resource.encrypt true
|
64
|
-
current_resource.encryption_version first_real_value['version']
|
65
|
-
|
66
|
-
decrypt_error = nil
|
67
|
-
|
68
|
-
# Check if the desired secret is the one (which it generally should be)
|
69
|
-
|
70
|
-
if new_resource.secret || new_resource.secret_path
|
71
|
-
begin
|
72
|
-
Chef::EncryptedDataBagItem::Decryptor.for(first_real_value, new_secret).for_decrypted_item
|
73
|
-
current_resource.secret new_secret
|
74
|
-
rescue Chef::EncryptedDataBagItem::DecryptionFailure
|
75
|
-
decrypt_error = $!
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
# If the current secret doesn't work, look through the specified old secrets
|
80
|
-
|
81
|
-
if !current_resource.secret
|
82
|
-
old_secrets = []
|
83
|
-
if new_resource.old_secret
|
84
|
-
old_secrets += Array(new_resource.old_secret)
|
85
|
-
end
|
86
|
-
if new_resource.old_secret_path
|
87
|
-
old_secrets += Array(new_resource.old_secret_path).map do |secret_path|
|
88
|
-
Chef::EncryptedDataBagItem.load_secret(new_resource.old_secret_file)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
old_secrets.each do |secret|
|
92
|
-
begin
|
93
|
-
Chef::EncryptedDataBagItem::Decryptor.for(first_real_value, secret).for_decrypted_item
|
94
|
-
current_resource.secret secret
|
95
|
-
rescue Chef::EncryptedDataBagItem::DecryptionFailure
|
96
|
-
decrypt_error = $!
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
# If we couldn't figure out the secret, emit a warning (this isn't a fatal flaw unless we
|
101
|
-
# need to reuse one of the values from the data bag)
|
102
|
-
if !current_resource.secret
|
103
|
-
if decrypt_error
|
104
|
-
Chef::Log.warn "Existing data bag is encrypted, but could not decrypt: #{decrypt_error.message}."
|
105
|
-
else
|
106
|
-
Chef::Log.warn "Existing data bag is encrypted, but no secret was specified."
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
else
|
112
|
-
|
113
|
-
# There are no encryptable values, so pretend encryption is the same as desired
|
114
|
-
|
115
|
-
current_resource.encrypt new_resource.encrypt
|
116
|
-
current_resource.encryption_version new_resource.encryption_version
|
117
|
-
if new_resource.secret || new_resource.secret_path
|
118
|
-
current_resource.secret new_secret
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def new_json
|
124
|
-
@new_json ||= begin
|
125
|
-
if new_encrypt
|
126
|
-
# Encrypt new stuff
|
127
|
-
result = encrypt(new_decrypted, new_secret, new_resource.encryption_version)
|
128
|
-
else
|
129
|
-
result = new_decrypted
|
130
|
-
end
|
131
|
-
result
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
def new_encrypt
|
136
|
-
new_resource.encrypt.nil? ? current_resource.encrypt : new_resource.encrypt
|
137
|
-
end
|
138
|
-
|
139
|
-
def new_secret
|
140
|
-
@new_secret ||= begin
|
141
|
-
if new_resource.secret
|
142
|
-
new_resource.secret
|
143
|
-
elsif new_resource.secret_path
|
144
|
-
Chef::EncryptedDataBagItem.load_secret(new_resource.secret_path)
|
145
|
-
elsif new_resource.encrypt.nil?
|
146
|
-
current_resource.secret
|
147
|
-
else
|
148
|
-
raise "Data bag item #{new_resource.name} has encryption on but no secret or secret_path is specified"
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
def decrypt(json, secret)
|
154
|
-
Chef::EncryptedDataBagItem.new(json, secret).to_hash
|
155
|
-
end
|
156
|
-
|
157
|
-
def encrypt(json, secret, version)
|
158
|
-
old_version = run_context.config[:data_bag_encrypt_version]
|
159
|
-
run_context.config[:data_bag_encrypt_version] = version
|
160
|
-
begin
|
161
|
-
Chef::EncryptedDataBagItem.encrypt_data_bag_item(json, secret)
|
162
|
-
ensure
|
163
|
-
run_context.config[:data_bag_encrypt_version] = old_version
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
# Get the desired (new) json pre-encryption, for comparison purposes
|
168
|
-
def new_decrypted
|
169
|
-
@new_decrypted ||= begin
|
170
|
-
if new_resource.complete
|
171
|
-
result = new_resource.raw_data || {}
|
172
|
-
else
|
173
|
-
result = current_decrypted.merge(new_resource.raw_data || {})
|
174
|
-
end
|
175
|
-
result['id'] = new_resource.id
|
176
|
-
result = apply_modifiers(new_resource.raw_data_modifiers, result)
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
# Get the current json decrypted, for comparison purposes
|
181
|
-
def current_decrypted
|
182
|
-
@current_decrypted ||= begin
|
183
|
-
if current_resource.secret
|
184
|
-
decrypt(current_resource.raw_data || { 'id' => new_resource.id }, current_resource.secret)
|
185
|
-
elsif current_resource.encrypt
|
186
|
-
raise "Could not decrypt current data bag item #{current_resource.name}"
|
187
|
-
else
|
188
|
-
current_resource.raw_data || { 'id' => new_resource.id }
|
189
|
-
end
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
# Figure out the differences between new and current
|
194
|
-
def calculate_differences
|
195
|
-
if new_encrypt
|
196
|
-
if current_resource.encrypt
|
197
|
-
# Both are encrypted, check if the encryption type is the same
|
198
|
-
description = ''
|
199
|
-
if new_secret != current_resource.secret
|
200
|
-
description << ' with new secret'
|
201
|
-
end
|
202
|
-
if new_resource.encryption_version != current_resource.encryption_version
|
203
|
-
description << " from v#{current_resource.encryption_version} to v#{new_resource.encryption_version} encryption"
|
204
|
-
end
|
205
|
-
|
206
|
-
if description != ''
|
207
|
-
# Encryption is different, we're reencrypting
|
208
|
-
differences = [ "re-encrypt#{description}"]
|
209
|
-
else
|
210
|
-
# Encryption is the same, we're just updating
|
211
|
-
differences = []
|
212
|
-
end
|
213
|
-
else
|
214
|
-
# New stuff should be encrypted, old is not. Encrypting.
|
215
|
-
differences = [ "encrypt with v#{new_resource.encryption_version} encryption" ]
|
216
|
-
end
|
217
|
-
|
218
|
-
# Get differences in the actual json
|
219
|
-
if current_resource.secret
|
220
|
-
json_differences(current_decrypted, new_decrypted, false, '', differences)
|
221
|
-
elsif current_resource.encrypt
|
222
|
-
# Encryption is different and we can't read the old values. Only allow the change
|
223
|
-
# if we're overwriting the data bag item
|
224
|
-
if !new_resource.complete
|
225
|
-
raise "Cannot encrypt #{new_resource.name} due to failure to decrypt existing resource. Set 'complete true' to overwrite or add the old secret as old_secret / old_secret_path."
|
226
|
-
end
|
227
|
-
differences = [ "overwrite data bag item (cannot decrypt old data bag item)"]
|
228
|
-
differences = (new_resource.raw_data.keys & current_resource.raw_data.keys).map { |key| "overwrite #{key}"}
|
229
|
-
differences += (new_resource.raw_data.keys - current_resource.raw_data.keys).map { |key| "add #{key}"}
|
230
|
-
differences += (current_resource.raw_data.keys - new_resource.raw_data.keys).map { |key| "remove #{key}" }
|
231
|
-
else
|
232
|
-
json_differences(current_decrypted, new_decrypted, false, '', differences)
|
233
|
-
end
|
234
|
-
else
|
235
|
-
if current_resource.encrypt
|
236
|
-
# New stuff should not be encrypted, old is. Decrypting.
|
237
|
-
differences = [ "decrypt data bag item to plaintext" ]
|
238
|
-
else
|
239
|
-
differences = []
|
240
|
-
end
|
241
|
-
json_differences(current_decrypted, new_decrypted, true, '', differences)
|
242
|
-
end
|
243
|
-
differences
|
244
|
-
end
|
245
|
-
|
246
|
-
#
|
247
|
-
# Helpers
|
248
|
-
#
|
249
|
-
|
250
|
-
def resource_class
|
251
|
-
Chef::Resource::ChefDataBagItem
|
252
|
-
end
|
253
|
-
|
254
|
-
def data_handler
|
255
|
-
Chef::ChefFS::DataHandler::DataBagItemDataHandler.new
|
256
|
-
end
|
257
|
-
|
258
|
-
def keys
|
259
|
-
{
|
260
|
-
'id' => :id,
|
261
|
-
'data_bag' => :data_bag,
|
262
|
-
'raw_data' => :raw_data
|
263
|
-
}
|
264
|
-
end
|
265
|
-
|
266
|
-
def not_found_resource
|
267
|
-
resource = super
|
268
|
-
resource.data_bag new_resource.data_bag
|
269
|
-
resource
|
270
|
-
end
|
271
|
-
|
272
|
-
def fake_entry
|
273
|
-
FakeEntry.new("#{new_resource.id}.json", FakeEntry.new(new_resource.data_bag))
|
274
|
-
end
|
275
|
-
|
276
|
-
end
|
277
|
-
end
|
278
|
-
end
|
@@ -1,83 +0,0 @@
|
|
1
|
-
require 'cheffish/chef_provider_base'
|
2
|
-
require 'chef/resource/chef_environment'
|
3
|
-
require 'chef/chef_fs/data_handler/environment_data_handler'
|
4
|
-
|
5
|
-
class Chef
|
6
|
-
class Provider
|
7
|
-
class ChefEnvironment < Cheffish::ChefProviderBase
|
8
|
-
provides :chef_environment
|
9
|
-
|
10
|
-
def whyrun_supported?
|
11
|
-
true
|
12
|
-
end
|
13
|
-
|
14
|
-
action :create do
|
15
|
-
differences = json_differences(current_json, new_json)
|
16
|
-
|
17
|
-
if current_resource_exists?
|
18
|
-
if differences.size > 0
|
19
|
-
description = [ "update environment #{new_resource.name} at #{rest.url}" ] + differences
|
20
|
-
converge_by description do
|
21
|
-
rest.put("environments/#{new_resource.name}", normalize_for_put(new_json))
|
22
|
-
end
|
23
|
-
end
|
24
|
-
else
|
25
|
-
description = [ "create environment #{new_resource.name} at #{rest.url}" ] + differences
|
26
|
-
converge_by description do
|
27
|
-
rest.post("environments", normalize_for_post(new_json))
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
action :delete do
|
33
|
-
if current_resource_exists?
|
34
|
-
converge_by "delete environment #{new_resource.name} at #{rest.url}" do
|
35
|
-
rest.delete("environments/#{new_resource.name}")
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def load_current_resource
|
41
|
-
begin
|
42
|
-
@current_resource = json_to_resource(rest.get("environments/#{new_resource.name}"))
|
43
|
-
rescue Net::HTTPServerException => e
|
44
|
-
if e.response.code == "404"
|
45
|
-
@current_resource = not_found_resource
|
46
|
-
else
|
47
|
-
raise
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def augment_new_json(json)
|
53
|
-
# Apply modifiers
|
54
|
-
json['default_attributes'] = apply_modifiers(new_resource.default_attribute_modifiers, json['default_attributes'])
|
55
|
-
json['override_attributes'] = apply_modifiers(new_resource.override_attribute_modifiers, json['override_attributes'])
|
56
|
-
json
|
57
|
-
end
|
58
|
-
|
59
|
-
#
|
60
|
-
# Helpers
|
61
|
-
#
|
62
|
-
|
63
|
-
def resource_class
|
64
|
-
Chef::Resource::ChefEnvironment
|
65
|
-
end
|
66
|
-
|
67
|
-
def data_handler
|
68
|
-
Chef::ChefFS::DataHandler::EnvironmentDataHandler.new
|
69
|
-
end
|
70
|
-
|
71
|
-
def keys
|
72
|
-
{
|
73
|
-
'name' => :name,
|
74
|
-
'description' => :description,
|
75
|
-
'cookbook_versions' => :cookbook_versions,
|
76
|
-
'default_attributes' => :default_attributes,
|
77
|
-
'override_attributes' => :override_attributes
|
78
|
-
}
|
79
|
-
end
|
80
|
-
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
@@ -1,83 +0,0 @@
|
|
1
|
-
require 'cheffish/chef_provider_base'
|
2
|
-
require 'chef/resource/chef_group'
|
3
|
-
require 'chef/chef_fs/data_handler/group_data_handler'
|
4
|
-
|
5
|
-
class Chef
|
6
|
-
class Provider
|
7
|
-
class ChefGroup < Cheffish::ChefProviderBase
|
8
|
-
provides :chef_group
|
9
|
-
|
10
|
-
def whyrun_supported?
|
11
|
-
true
|
12
|
-
end
|
13
|
-
|
14
|
-
action :create do
|
15
|
-
differences = json_differences(current_json, new_json)
|
16
|
-
|
17
|
-
if current_resource_exists?
|
18
|
-
if differences.size > 0
|
19
|
-
description = [ "update group #{new_resource.name} at #{rest.url}" ] + differences
|
20
|
-
converge_by description do
|
21
|
-
rest.put("groups/#{new_resource.name}", normalize_for_put(new_json))
|
22
|
-
end
|
23
|
-
end
|
24
|
-
else
|
25
|
-
description = [ "create group #{new_resource.name} at #{rest.url}" ] + differences
|
26
|
-
converge_by description do
|
27
|
-
rest.post("groups", normalize_for_post(new_json))
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
action :delete do
|
33
|
-
if current_resource_exists?
|
34
|
-
converge_by "delete group #{new_resource.name} at #{rest.url}" do
|
35
|
-
rest.delete("groups/#{new_resource.name}")
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def load_current_resource
|
41
|
-
begin
|
42
|
-
@current_resource = json_to_resource(rest.get("groups/#{new_resource.name}"))
|
43
|
-
rescue Net::HTTPServerException => e
|
44
|
-
if e.response.code == "404"
|
45
|
-
@current_resource = not_found_resource
|
46
|
-
else
|
47
|
-
raise
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def augment_new_json(json)
|
53
|
-
# Apply modifiers
|
54
|
-
json['users'] |= new_resource.users
|
55
|
-
json['clients'] |= new_resource.clients
|
56
|
-
json['groups'] |= new_resource.groups
|
57
|
-
json['users'] -= new_resource.remove_users
|
58
|
-
json['clients'] -= new_resource.remove_clients
|
59
|
-
json['groups'] -= new_resource.remove_groups
|
60
|
-
json
|
61
|
-
end
|
62
|
-
|
63
|
-
#
|
64
|
-
# Helpers
|
65
|
-
#
|
66
|
-
|
67
|
-
def resource_class
|
68
|
-
Chef::Resource::ChefGroup
|
69
|
-
end
|
70
|
-
|
71
|
-
def data_handler
|
72
|
-
Chef::ChefFS::DataHandler::GroupDataHandler.new
|
73
|
-
end
|
74
|
-
|
75
|
-
def keys
|
76
|
-
{
|
77
|
-
'name' => :name,
|
78
|
-
'groupname' => :name
|
79
|
-
}
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
@@ -1,169 +0,0 @@
|
|
1
|
-
require 'chef/provider/lwrp_base'
|
2
|
-
require 'chef/chef_fs/file_pattern'
|
3
|
-
require 'chef/chef_fs/file_system'
|
4
|
-
require 'chef/chef_fs/parallelizer'
|
5
|
-
require 'chef/chef_fs/file_system/chef_server_root_dir'
|
6
|
-
require 'chef/chef_fs/file_system/chef_repository_file_system_root_dir'
|
7
|
-
|
8
|
-
class Chef
|
9
|
-
class Provider
|
10
|
-
class ChefMirror < Chef::Provider::LWRPBase
|
11
|
-
provides :chef_mirror
|
12
|
-
|
13
|
-
def whyrun_supported?
|
14
|
-
true
|
15
|
-
end
|
16
|
-
|
17
|
-
action :upload do
|
18
|
-
with_modified_config do
|
19
|
-
copy_to(local_fs, remote_fs)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
action :download do
|
24
|
-
with_modified_config do
|
25
|
-
copy_to(remote_fs, local_fs)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def with_modified_config
|
30
|
-
# pre-Chef-12 ChefFS reads versioned_cookbooks out of Chef::Config instead of
|
31
|
-
# taking it as an input, so we need to modify it for the duration of copy_to
|
32
|
-
@old_versioned_cookbooks = Chef::Config.versioned_cookbooks
|
33
|
-
# If versioned_cookbooks is explicitly set, set it.
|
34
|
-
if !new_resource.versioned_cookbooks.nil?
|
35
|
-
Chef::Config.versioned_cookbooks = new_resource.versioned_cookbooks
|
36
|
-
|
37
|
-
# If new_resource.chef_repo_path is set, versioned_cookbooks defaults to true.
|
38
|
-
# Otherwise, it stays at its current Chef::Config value.
|
39
|
-
elsif new_resource.chef_repo_path
|
40
|
-
Chef::Config.versioned_cookbooks = true
|
41
|
-
end
|
42
|
-
|
43
|
-
begin
|
44
|
-
yield
|
45
|
-
ensure
|
46
|
-
Chef::Config.versioned_cookbooks = @old_versioned_cookbooks
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def copy_to(src_root, dest_root)
|
51
|
-
if new_resource.concurrency && new_resource.concurrency <= 0
|
52
|
-
raise "chef_mirror.concurrency must be above 0! Was set to #{new_resource.concurrency}"
|
53
|
-
end
|
54
|
-
# Honor concurrency
|
55
|
-
Chef::ChefFS::Parallelizer.threads = (new_resource.concurrency || 10) - 1
|
56
|
-
|
57
|
-
# We don't let the user pass absolute paths; we want to reserve those for
|
58
|
-
# multi-org support (/organizations/foo).
|
59
|
-
if new_resource.path[0] == '/'
|
60
|
-
raise "Absolute paths in chef_mirror not yet supported."
|
61
|
-
end
|
62
|
-
# Copy!
|
63
|
-
path = Chef::ChefFS::FilePattern.new("/#{new_resource.path}")
|
64
|
-
ui = CopyListener.new(self)
|
65
|
-
error = Chef::ChefFS::FileSystem.copy_to(path, src_root, dest_root, nil, options, ui, proc { |p| p.path })
|
66
|
-
|
67
|
-
if error
|
68
|
-
raise "Errors while copying:#{ui.errors.map { |e| "#{e}\n" }.join('')}"
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def local_fs
|
73
|
-
# If chef_repo_path is set to a string, put it in the form it usually is in
|
74
|
-
# chef config (:chef_repo_path, :node_path, etc.)
|
75
|
-
path_config = new_resource.chef_repo_path
|
76
|
-
if path_config.is_a?(Hash)
|
77
|
-
chef_repo_path = path_config.delete(:chef_repo_path)
|
78
|
-
elsif path_config
|
79
|
-
chef_repo_path = path_config
|
80
|
-
path_config = {}
|
81
|
-
else
|
82
|
-
chef_repo_path = Chef::Config.chef_repo_path
|
83
|
-
path_config = Chef::Config
|
84
|
-
end
|
85
|
-
chef_repo_path = Array(chef_repo_path).flatten
|
86
|
-
|
87
|
-
# Go through the expected object paths and figure out the local paths for each.
|
88
|
-
case repo_mode
|
89
|
-
when 'hosted_everything'
|
90
|
-
object_names = %w(acls clients cookbooks containers data_bags environments groups nodes roles)
|
91
|
-
else
|
92
|
-
object_names = %w(clients cookbooks data_bags environments nodes roles users)
|
93
|
-
end
|
94
|
-
|
95
|
-
object_paths = {}
|
96
|
-
object_names.each do |object_name|
|
97
|
-
variable_name = "#{object_name[0..-2]}_path" # cookbooks -> cookbook_path
|
98
|
-
if path_config[variable_name.to_sym]
|
99
|
-
paths = Array(path_config[variable_name.to_sym]).flatten
|
100
|
-
else
|
101
|
-
paths = chef_repo_path.map { |path| ::File.join(path, object_name) }
|
102
|
-
end
|
103
|
-
object_paths[object_name] = paths.map { |path| ::File.expand_path(path) }
|
104
|
-
end
|
105
|
-
|
106
|
-
# Set up the root dir
|
107
|
-
Chef::ChefFS::FileSystem::ChefRepositoryFileSystemRootDir.new(object_paths)
|
108
|
-
end
|
109
|
-
|
110
|
-
def remote_fs
|
111
|
-
config = {
|
112
|
-
:chef_server_url => new_resource.chef_server[:chef_server_url],
|
113
|
-
:node_name => new_resource.chef_server[:options][:client_name],
|
114
|
-
:client_key => new_resource.chef_server[:options][:signing_key_filename],
|
115
|
-
:repo_mode => repo_mode,
|
116
|
-
:versioned_cookbooks => Chef::Config.versioned_cookbooks
|
117
|
-
}
|
118
|
-
Chef::ChefFS::FileSystem::ChefServerRootDir.new("remote", config)
|
119
|
-
end
|
120
|
-
|
121
|
-
def repo_mode
|
122
|
-
new_resource.chef_server[:chef_server_url] =~ /\/organizations\// ? 'hosted_everything' : 'everything'
|
123
|
-
end
|
124
|
-
|
125
|
-
def options
|
126
|
-
result = {
|
127
|
-
:purge => new_resource.purge,
|
128
|
-
:freeze => new_resource.freeze,
|
129
|
-
:diff => new_resource.no_diff,
|
130
|
-
:dry_run => whyrun_mode?
|
131
|
-
}
|
132
|
-
result[:diff] = !result[:diff]
|
133
|
-
result[:repo_mode] = repo_mode
|
134
|
-
result[:concurrency] = new_resource.concurrency if new_resource.concurrency
|
135
|
-
result
|
136
|
-
end
|
137
|
-
|
138
|
-
def load_current_resource
|
139
|
-
end
|
140
|
-
|
141
|
-
class CopyListener
|
142
|
-
def initialize(mirror)
|
143
|
-
@mirror = mirror
|
144
|
-
@errors = []
|
145
|
-
end
|
146
|
-
|
147
|
-
attr_reader :mirror
|
148
|
-
attr_reader :errors
|
149
|
-
|
150
|
-
# TODO output is not *always* indicative of a change. We may want to give
|
151
|
-
# ChefFS the ability to tell us that info. For now though, assuming any output
|
152
|
-
# means change is pretty damn close to the truth.
|
153
|
-
def output(str)
|
154
|
-
mirror.converge_by str do
|
155
|
-
end
|
156
|
-
end
|
157
|
-
def warn(str)
|
158
|
-
mirror.converge_by "WARNING: #{str}" do
|
159
|
-
end
|
160
|
-
end
|
161
|
-
def error(str)
|
162
|
-
mirror.converge_by "ERROR: #{str}" do
|
163
|
-
end
|
164
|
-
@errors << str
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
@@ -1,87 +0,0 @@
|
|
1
|
-
require 'cheffish/chef_provider_base'
|
2
|
-
require 'chef/resource/chef_node'
|
3
|
-
require 'chef/chef_fs/data_handler/node_data_handler'
|
4
|
-
|
5
|
-
class Chef
|
6
|
-
class Provider
|
7
|
-
class ChefNode < Cheffish::ChefProviderBase
|
8
|
-
provides :chef_node
|
9
|
-
|
10
|
-
def whyrun_supported?
|
11
|
-
true
|
12
|
-
end
|
13
|
-
|
14
|
-
action :create do
|
15
|
-
differences = json_differences(current_json, new_json)
|
16
|
-
|
17
|
-
if current_resource_exists?
|
18
|
-
if differences.size > 0
|
19
|
-
description = [ "update node #{new_resource.name} at #{rest.url}" ] + differences
|
20
|
-
converge_by description do
|
21
|
-
rest.put("nodes/#{new_resource.name}", normalize_for_put(new_json))
|
22
|
-
end
|
23
|
-
end
|
24
|
-
else
|
25
|
-
description = [ "create node #{new_resource.name} at #{rest.url}" ] + differences
|
26
|
-
converge_by description do
|
27
|
-
rest.post("nodes", normalize_for_post(new_json))
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
action :delete do
|
33
|
-
if current_resource_exists?
|
34
|
-
converge_by "delete node #{new_resource.name} at #{rest.url}" do
|
35
|
-
rest.delete("nodes/#{new_resource.name}")
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def load_current_resource
|
41
|
-
begin
|
42
|
-
@current_resource = json_to_resource(rest.get("nodes/#{new_resource.name}"))
|
43
|
-
rescue Net::HTTPServerException => e
|
44
|
-
if e.response.code == "404"
|
45
|
-
@current_resource = not_found_resource
|
46
|
-
else
|
47
|
-
raise
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def augment_new_json(json)
|
53
|
-
# Preserve tags even if "attributes" was overwritten directly
|
54
|
-
json['normal']['tags'] = current_json['normal']['tags'] unless json['normal']['tags']
|
55
|
-
# Apply modifiers
|
56
|
-
json['run_list'] = apply_run_list_modifiers(new_resource.run_list_modifiers, new_resource.run_list_removers, json['run_list'])
|
57
|
-
json['normal'] = apply_modifiers(new_resource.attribute_modifiers, json['normal'])
|
58
|
-
# Preserve default/override/automatic even when "complete true"
|
59
|
-
json['default'] = current_json['default']
|
60
|
-
json['override'] = current_json['override']
|
61
|
-
json['automatic'] = current_json['automatic']
|
62
|
-
json
|
63
|
-
end
|
64
|
-
|
65
|
-
#
|
66
|
-
# Helpers
|
67
|
-
#
|
68
|
-
|
69
|
-
def resource_class
|
70
|
-
Chef::Resource::ChefNode
|
71
|
-
end
|
72
|
-
|
73
|
-
def data_handler
|
74
|
-
Chef::ChefFS::DataHandler::NodeDataHandler.new
|
75
|
-
end
|
76
|
-
|
77
|
-
def keys
|
78
|
-
{
|
79
|
-
'name' => :name,
|
80
|
-
'chef_environment' => :chef_environment,
|
81
|
-
'run_list' => :run_list,
|
82
|
-
'normal' => :attributes
|
83
|
-
}
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|