chef 0.7.10
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of chef might be problematic. Click here for more details.
- data/LICENSE +201 -0
- data/README.rdoc +135 -0
- data/bin/chef-client +26 -0
- data/bin/chef-solo +26 -0
- data/lib/chef.rb +49 -0
- data/lib/chef/application.rb +98 -0
- data/lib/chef/application/agent.rb +18 -0
- data/lib/chef/application/client.rb +209 -0
- data/lib/chef/application/indexer.rb +141 -0
- data/lib/chef/application/server.rb +18 -0
- data/lib/chef/application/solo.rb +214 -0
- data/lib/chef/client.rb +396 -0
- data/lib/chef/compile.rb +138 -0
- data/lib/chef/config.rb +141 -0
- data/lib/chef/cookbook.rb +144 -0
- data/lib/chef/cookbook/metadata.rb +407 -0
- data/lib/chef/cookbook/metadata/version.rb +87 -0
- data/lib/chef/cookbook_loader.rb +168 -0
- data/lib/chef/couchdb.rb +172 -0
- data/lib/chef/daemon.rb +170 -0
- data/lib/chef/exceptions.rb +36 -0
- data/lib/chef/file_cache.rb +205 -0
- data/lib/chef/log.rb +39 -0
- data/lib/chef/mixin/check_helper.rb +31 -0
- data/lib/chef/mixin/checksum.rb +37 -0
- data/lib/chef/mixin/command.rb +351 -0
- data/lib/chef/mixin/create_path.rb +56 -0
- data/lib/chef/mixin/deep_merge.rb +36 -0
- data/lib/chef/mixin/find_preferred_file.rb +99 -0
- data/lib/chef/mixin/from_file.rb +36 -0
- data/lib/chef/mixin/generate_url.rb +48 -0
- data/lib/chef/mixin/language.rb +79 -0
- data/lib/chef/mixin/params_validate.rb +197 -0
- data/lib/chef/mixin/template.rb +84 -0
- data/lib/chef/node.rb +406 -0
- data/lib/chef/node/attribute.rb +412 -0
- data/lib/chef/openid_registration.rb +181 -0
- data/lib/chef/platform.rb +253 -0
- data/lib/chef/provider.rb +40 -0
- data/lib/chef/provider/cron.rb +137 -0
- data/lib/chef/provider/directory.rb +72 -0
- data/lib/chef/provider/execute.rb +58 -0
- data/lib/chef/provider/file.rb +191 -0
- data/lib/chef/provider/group.rb +120 -0
- data/lib/chef/provider/group/groupadd.rb +92 -0
- data/lib/chef/provider/group/pw.rb +88 -0
- data/lib/chef/provider/http_request.rb +102 -0
- data/lib/chef/provider/ifconfig.rb +131 -0
- data/lib/chef/provider/link.rb +157 -0
- data/lib/chef/provider/mount.rb +121 -0
- data/lib/chef/provider/mount/mount.rb +208 -0
- data/lib/chef/provider/package.rb +160 -0
- data/lib/chef/provider/package/apt.rb +110 -0
- data/lib/chef/provider/package/dpkg.rb +113 -0
- data/lib/chef/provider/package/freebsd.rb +153 -0
- data/lib/chef/provider/package/macports.rb +105 -0
- data/lib/chef/provider/package/portage.rb +124 -0
- data/lib/chef/provider/package/rpm.rb +99 -0
- data/lib/chef/provider/package/rubygems.rb +130 -0
- data/lib/chef/provider/package/yum-dump.py +104 -0
- data/lib/chef/provider/package/yum.rb +175 -0
- data/lib/chef/provider/remote_directory.rb +126 -0
- data/lib/chef/provider/remote_file.rb +134 -0
- data/lib/chef/provider/route.rb +118 -0
- data/lib/chef/provider/ruby_block.rb +15 -0
- data/lib/chef/provider/script.rb +42 -0
- data/lib/chef/provider/service.rb +129 -0
- data/lib/chef/provider/service/debian.rb +64 -0
- data/lib/chef/provider/service/freebsd.rb +157 -0
- data/lib/chef/provider/service/gentoo.rb +54 -0
- data/lib/chef/provider/service/init.rb +126 -0
- data/lib/chef/provider/service/redhat.rb +62 -0
- data/lib/chef/provider/template.rb +141 -0
- data/lib/chef/provider/user.rb +170 -0
- data/lib/chef/provider/user/pw.rb +113 -0
- data/lib/chef/provider/user/useradd.rb +107 -0
- data/lib/chef/queue.rb +145 -0
- data/lib/chef/recipe.rb +210 -0
- data/lib/chef/resource.rb +256 -0
- data/lib/chef/resource/apt_package.rb +34 -0
- data/lib/chef/resource/bash.rb +33 -0
- data/lib/chef/resource/cron.rb +143 -0
- data/lib/chef/resource/csh.rb +33 -0
- data/lib/chef/resource/directory.rb +76 -0
- data/lib/chef/resource/dpkg_package.rb +34 -0
- data/lib/chef/resource/execute.rb +127 -0
- data/lib/chef/resource/file.rb +84 -0
- data/lib/chef/resource/gem_package.rb +41 -0
- data/lib/chef/resource/group.rb +68 -0
- data/lib/chef/resource/http_request.rb +52 -0
- data/lib/chef/resource/ifconfig.rb +134 -0
- data/lib/chef/resource/link.rb +78 -0
- data/lib/chef/resource/macports_package.rb +29 -0
- data/lib/chef/resource/mount.rb +135 -0
- data/lib/chef/resource/package.rb +80 -0
- data/lib/chef/resource/perl.rb +33 -0
- data/lib/chef/resource/portage_package.rb +33 -0
- data/lib/chef/resource/python.rb +33 -0
- data/lib/chef/resource/remote_directory.rb +91 -0
- data/lib/chef/resource/remote_file.rb +60 -0
- data/lib/chef/resource/route.rb +135 -0
- data/lib/chef/resource/ruby.rb +33 -0
- data/lib/chef/resource/ruby_block.rb +20 -0
- data/lib/chef/resource/script.rb +51 -0
- data/lib/chef/resource/service.rb +134 -0
- data/lib/chef/resource/template.rb +60 -0
- data/lib/chef/resource/user.rb +98 -0
- data/lib/chef/resource_collection.rb +176 -0
- data/lib/chef/resource_definition.rb +67 -0
- data/lib/chef/rest.rb +238 -0
- data/lib/chef/role.rb +231 -0
- data/lib/chef/run_list.rb +156 -0
- data/lib/chef/runner.rb +123 -0
- data/lib/chef/search.rb +88 -0
- data/lib/chef/search/result.rb +64 -0
- data/lib/chef/search_index.rb +77 -0
- data/lib/chef/tasks/chef_repo.rake +345 -0
- data/lib/chef/util/file_edit.rb +125 -0
- data/lib/chef/util/fileedit.rb +121 -0
- metadata +262 -0
@@ -0,0 +1,412 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Adam Jacob (<adam@opscode.com>)
|
3
|
+
# Author:: AJ Christensen (<aj@opscode.com>)
|
4
|
+
# Copyright:: Copyright (c) 2008 Opscode, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'chef/mixin/deep_merge'
|
21
|
+
require 'chef/log'
|
22
|
+
|
23
|
+
class Chef
|
24
|
+
class Node
|
25
|
+
class Attribute
|
26
|
+
attr_accessor :attribute,
|
27
|
+
:default,
|
28
|
+
:override,
|
29
|
+
:state,
|
30
|
+
:current_attribute,
|
31
|
+
:current_default,
|
32
|
+
:current_override,
|
33
|
+
:auto_vivifiy_on_read,
|
34
|
+
:set_unless_value_present,
|
35
|
+
:has_been_read
|
36
|
+
|
37
|
+
include Enumerable
|
38
|
+
|
39
|
+
def initialize(attribute, default, override, state=[])
|
40
|
+
@attribute = attribute
|
41
|
+
@current_attribute = attribute
|
42
|
+
@default = default
|
43
|
+
@current_default = default
|
44
|
+
@override = override
|
45
|
+
@current_override = override
|
46
|
+
@state = state
|
47
|
+
@auto_vivifiy_on_read = false
|
48
|
+
@set_unless_value_present = false
|
49
|
+
@has_been_read = false
|
50
|
+
end
|
51
|
+
|
52
|
+
# Reset our internal state to the top of every tree
|
53
|
+
def reset
|
54
|
+
@current_attribute = @attribute
|
55
|
+
@current_default = @default
|
56
|
+
@current_override = @override
|
57
|
+
@has_been_read = false
|
58
|
+
@state = []
|
59
|
+
end
|
60
|
+
|
61
|
+
def [](key)
|
62
|
+
@state << key
|
63
|
+
|
64
|
+
# We set this to so that we can cope with ||= as a setting.
|
65
|
+
# See the comments in []= for more details.
|
66
|
+
@has_been_read = true
|
67
|
+
|
68
|
+
o_value = value_or_descend(current_override, key, auto_vivifiy_on_read)
|
69
|
+
a_value = value_or_descend(current_attribute, key, auto_vivifiy_on_read)
|
70
|
+
d_value = value_or_descend(current_default, key, auto_vivifiy_on_read)
|
71
|
+
|
72
|
+
determine_value(o_value, a_value, d_value)
|
73
|
+
end
|
74
|
+
|
75
|
+
def attribute?(key)
|
76
|
+
return true if get_value(override, key)
|
77
|
+
return true if get_value(attribute, key)
|
78
|
+
return true if get_value(default, key)
|
79
|
+
false
|
80
|
+
end
|
81
|
+
|
82
|
+
def has_key?(key)
|
83
|
+
attribute?(key)
|
84
|
+
end
|
85
|
+
|
86
|
+
alias :include? :has_key?
|
87
|
+
alias :key? :has_key?
|
88
|
+
alias :member? :has_key?
|
89
|
+
|
90
|
+
def each(&block)
|
91
|
+
get_keys.each do |key|
|
92
|
+
value = determine_value(
|
93
|
+
get_value(override, key),
|
94
|
+
get_value(attribute, key),
|
95
|
+
get_value(default, key)
|
96
|
+
)
|
97
|
+
block.call([key, value])
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def each_pair(&block)
|
102
|
+
get_keys.each do |key|
|
103
|
+
value = determine_value(
|
104
|
+
get_value(override, key),
|
105
|
+
get_value(attribute, key),
|
106
|
+
get_value(default, key)
|
107
|
+
)
|
108
|
+
block.call(key, value)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def each_attribute(&block)
|
113
|
+
get_keys.each do |key|
|
114
|
+
value = determine_value(
|
115
|
+
get_value(override, key),
|
116
|
+
get_value(attribute, key),
|
117
|
+
get_value(default, key)
|
118
|
+
)
|
119
|
+
block.call(key, value)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def each_key(&block)
|
124
|
+
get_keys.each do |key|
|
125
|
+
block.call(key)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def each_value(&block)
|
130
|
+
get_keys.each do |key|
|
131
|
+
value = determine_value(
|
132
|
+
get_value(override, key),
|
133
|
+
get_value(attribute, key),
|
134
|
+
get_value(default, key)
|
135
|
+
)
|
136
|
+
block.call(value)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def empty?
|
141
|
+
get_keys.empty?
|
142
|
+
end
|
143
|
+
|
144
|
+
def fetch(key, default_value=nil, &block)
|
145
|
+
if get_keys.include? key
|
146
|
+
determine_value(
|
147
|
+
get_value(override, key),
|
148
|
+
get_value(attribute, key),
|
149
|
+
get_value(default, key)
|
150
|
+
)
|
151
|
+
elsif default_value
|
152
|
+
default_value
|
153
|
+
elsif block_given?
|
154
|
+
block.call(key)
|
155
|
+
else
|
156
|
+
raise IndexError, "Key #{key} does not exist"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# Writing this method hurts me a little bit.
|
161
|
+
#
|
162
|
+
# TODO: Refactor all this stuff so this kind of horror is no longer needed
|
163
|
+
#
|
164
|
+
# We have invented a new kind of duck-typing, we call it Madoff typing.
|
165
|
+
# We just lie and hope we die before you recognize our scheme. :)
|
166
|
+
def kind_of?(klass)
|
167
|
+
if klass == Hash || klass == Mash || klass == Chef::Node::Attribute
|
168
|
+
true
|
169
|
+
else
|
170
|
+
false
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def has_value?(value)
|
175
|
+
self.any? do |k,v|
|
176
|
+
value == v
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
alias :value? :has_value?
|
181
|
+
|
182
|
+
def index(value)
|
183
|
+
index = self.find do |h|
|
184
|
+
value == h[1]
|
185
|
+
end
|
186
|
+
index.first if index.is_a? Array || nil
|
187
|
+
end
|
188
|
+
|
189
|
+
def values
|
190
|
+
self.collect { |h| h[1] }
|
191
|
+
end
|
192
|
+
|
193
|
+
def size
|
194
|
+
self.collect{}.length
|
195
|
+
end
|
196
|
+
|
197
|
+
alias :length :size
|
198
|
+
|
199
|
+
def get_keys
|
200
|
+
keys
|
201
|
+
end
|
202
|
+
|
203
|
+
def keys
|
204
|
+
tkeys = []
|
205
|
+
if current_override
|
206
|
+
tkeys = current_override.keys
|
207
|
+
end
|
208
|
+
if current_attribute
|
209
|
+
current_attribute.keys.each do |key|
|
210
|
+
tkeys << key unless tkeys.include?(key)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
if current_default
|
214
|
+
current_default.keys.each do |key|
|
215
|
+
tkeys << key unless tkeys.include?(key)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
tkeys
|
219
|
+
end
|
220
|
+
|
221
|
+
def get_value(data_hash, key)
|
222
|
+
last = nil
|
223
|
+
|
224
|
+
if state.length == 0
|
225
|
+
if data_hash.has_key?(key) && ! data_hash[key].nil?
|
226
|
+
return data_hash[key]
|
227
|
+
else
|
228
|
+
return nil
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
0.upto(state.length) do |i|
|
233
|
+
if i == 0
|
234
|
+
last = auto_vivifiy(data_hash, state[i])
|
235
|
+
elsif i == state.length
|
236
|
+
fk = last[state[i - 1]]
|
237
|
+
if fk.has_key?(key) && ! fk[key].nil?
|
238
|
+
return fk[key]
|
239
|
+
else
|
240
|
+
return nil
|
241
|
+
end
|
242
|
+
else
|
243
|
+
last = auto_vivifiy(last[state[i - 1]], state[i])
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
def hash_and_not_cna?(to_check)
|
249
|
+
(! to_check.kind_of?(Chef::Node::Attribute)) && to_check.respond_to?(:has_key?)
|
250
|
+
end
|
251
|
+
|
252
|
+
def determine_value(o_value, a_value, d_value)
|
253
|
+
# If all three have hash values, merge them
|
254
|
+
if hash_and_not_cna?(o_value) && hash_and_not_cna?(a_value) && hash_and_not_cna?(d_value)
|
255
|
+
value = Chef::Mixin::DeepMerge.merge(d_value, a_value)
|
256
|
+
value = Chef::Mixin::DeepMerge.merge(value, o_value)
|
257
|
+
value
|
258
|
+
# If only the override and attributes have values, merge them
|
259
|
+
elsif hash_and_not_cna?(o_value) && hash_and_not_cna?(a_value)
|
260
|
+
Chef::Mixin::DeepMerge.merge(a_value, o_value)
|
261
|
+
# If only the override and default attributes have values, merge them
|
262
|
+
elsif hash_and_not_cna?(o_value) && hash_and_not_cna?(d_value)
|
263
|
+
Chef::Mixin::DeepMerge.merge(d_value, o_value)
|
264
|
+
# If only the override attribute has a value (any value) use it
|
265
|
+
elsif ! o_value.nil?
|
266
|
+
o_value
|
267
|
+
# If the attributes is a hash, and the default is a hash, merge them
|
268
|
+
elsif hash_and_not_cna?(a_value) && hash_and_not_cna?(d_value)
|
269
|
+
Chef::Mixin::DeepMerge.merge(d_value, a_value)
|
270
|
+
# If we have an attribute value, use it
|
271
|
+
elsif ! a_value.nil?
|
272
|
+
a_value
|
273
|
+
# If we have a default value, use it
|
274
|
+
elsif ! d_value.nil?
|
275
|
+
d_value
|
276
|
+
else
|
277
|
+
nil
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def []=(key, value)
|
282
|
+
if set_unless_value_present
|
283
|
+
if get_value(@default, key) != nil
|
284
|
+
Chef::Log.debug("Not setting #{state.join("/")}/#{key} to #{value.inspect} because it has a default value already")
|
285
|
+
return false
|
286
|
+
end
|
287
|
+
if get_value(@attribute, key) != nil
|
288
|
+
Chef::Log.debug("Not setting #{state.join("/")}/#{key} to #{value.inspect} because it has a node attribute value already")
|
289
|
+
return false
|
290
|
+
end
|
291
|
+
if get_value(@override, key) != nil
|
292
|
+
Chef::Log.debug("Not setting #{state.join("/")}/#{key} to #{value.inspect} because it has an override value already")
|
293
|
+
return false
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
# If we have been read, and the key we are writing is the same
|
298
|
+
# as our parent, we have most like been ||='ed. So we need to
|
299
|
+
# just rewind a bit.
|
300
|
+
#
|
301
|
+
# In practice, these objects are single use - this is just
|
302
|
+
# supporting one more single-use style.
|
303
|
+
@state.pop if @has_been_read && @state.last == key
|
304
|
+
|
305
|
+
set_value(@attribute, key, value)
|
306
|
+
set_value(@override, key, value)
|
307
|
+
value
|
308
|
+
end
|
309
|
+
|
310
|
+
def set_value(data_hash, key, value)
|
311
|
+
last = nil
|
312
|
+
|
313
|
+
# If there is no state, just set the value
|
314
|
+
if state.length == 0
|
315
|
+
data_hash[key] = value
|
316
|
+
return data_hash
|
317
|
+
end
|
318
|
+
|
319
|
+
# Walk all the previous places we have been
|
320
|
+
0.upto(state.length) do |i|
|
321
|
+
# If we are the first, we are top level, and should vivifiy the data_hash
|
322
|
+
if i == 0
|
323
|
+
last = auto_vivifiy(data_hash, state[i])
|
324
|
+
# If we are one past the last state, we are adding a key to that hash with a value
|
325
|
+
elsif i == state.length
|
326
|
+
last[state[i - 1]][key] = value
|
327
|
+
# Otherwise, we're auto-vivifiy-ing an interim mash
|
328
|
+
else
|
329
|
+
last = auto_vivifiy(last[state[i - 1]], state[i])
|
330
|
+
end
|
331
|
+
end
|
332
|
+
data_hash
|
333
|
+
end
|
334
|
+
|
335
|
+
def auto_vivifiy(data_hash, key)
|
336
|
+
if data_hash.has_key?(key)
|
337
|
+
unless data_hash[key].respond_to?(:has_key?)
|
338
|
+
raise ArgumentError, "You tried to set a nested key, where the parent is not a hash-like object: #{@state.join("/")}/#{key} " unless auto_vivifiy_on_read
|
339
|
+
end
|
340
|
+
else
|
341
|
+
data_hash[key] = Mash.new
|
342
|
+
end
|
343
|
+
data_hash
|
344
|
+
end
|
345
|
+
|
346
|
+
def value_or_descend(data_hash, key, auto_vivifiy=false)
|
347
|
+
|
348
|
+
if auto_vivifiy
|
349
|
+
data_hash = auto_vivifiy(data_hash, key)
|
350
|
+
unless current_attribute.has_key?(key)
|
351
|
+
current_attribute[key] = data_hash[key]
|
352
|
+
end
|
353
|
+
unless current_default.has_key?(key)
|
354
|
+
current_default[key] = data_hash[key]
|
355
|
+
end
|
356
|
+
unless current_override.has_key?(key)
|
357
|
+
current_override[key] = data_hash[key]
|
358
|
+
end
|
359
|
+
else
|
360
|
+
return nil if data_hash == nil
|
361
|
+
return nil unless data_hash.has_key?(key)
|
362
|
+
end
|
363
|
+
|
364
|
+
if data_hash[key].respond_to?(:has_key?)
|
365
|
+
cna = Chef::Node::Attribute.new(@attribute, @default, @override, @state)
|
366
|
+
cna.current_attribute = current_attribute.nil? ? Mash.new : current_attribute[key]
|
367
|
+
cna.current_default = current_default.nil? ? Mash.new : current_default[key]
|
368
|
+
cna.current_override = current_override.nil? ? Mash.new : current_override[key]
|
369
|
+
cna.auto_vivifiy_on_read = auto_vivifiy_on_read
|
370
|
+
cna.set_unless_value_present = set_unless_value_present
|
371
|
+
cna
|
372
|
+
else
|
373
|
+
data_hash[key]
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
def method_missing(symbol, *args)
|
378
|
+
by = symbol
|
379
|
+
if self.attribute?(symbol)
|
380
|
+
by = symbol
|
381
|
+
elsif self.attribute?(symbol.to_s)
|
382
|
+
by = symbol.to_s
|
383
|
+
else
|
384
|
+
if args.length != 0
|
385
|
+
by = symbol
|
386
|
+
else
|
387
|
+
raise ArgumentError, "Attribute #{symbol.to_s} is not defined!" unless auto_vivifiy_on_read
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
if args.length != 0
|
392
|
+
if by.to_s =~ /^(.+)=$/
|
393
|
+
by = $1
|
394
|
+
end
|
395
|
+
self[by] = args.length == 1 ? args[0] : args
|
396
|
+
else
|
397
|
+
self[by]
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
def to_hash
|
402
|
+
result = determine_value(current_override, current_attribute, current_default)
|
403
|
+
if result.class == Hash
|
404
|
+
result
|
405
|
+
else
|
406
|
+
result.to_hash
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Adam Jacob (<adam@opscode.com>)
|
3
|
+
# Copyright:: Copyright (c) 2008 Opscode, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'chef/config'
|
20
|
+
require 'chef/mixin/params_validate'
|
21
|
+
require 'chef/couchdb'
|
22
|
+
require 'digest/sha1'
|
23
|
+
require 'rubygems'
|
24
|
+
require 'json'
|
25
|
+
|
26
|
+
class Chef
|
27
|
+
class OpenIDRegistration
|
28
|
+
|
29
|
+
attr_accessor :name, :salt, :validated, :password, :couchdb_rev, :admin
|
30
|
+
|
31
|
+
include Chef::Mixin::ParamsValidate
|
32
|
+
|
33
|
+
DESIGN_DOCUMENT = {
|
34
|
+
"version" => 3,
|
35
|
+
"language" => "javascript",
|
36
|
+
"views" => {
|
37
|
+
"all" => {
|
38
|
+
"map" => <<-EOJS
|
39
|
+
function(doc) {
|
40
|
+
if (doc.chef_type == "openid_registration") {
|
41
|
+
emit(doc.name, doc);
|
42
|
+
}
|
43
|
+
}
|
44
|
+
EOJS
|
45
|
+
},
|
46
|
+
"all_id" => {
|
47
|
+
"map" => <<-EOJS
|
48
|
+
function(doc) {
|
49
|
+
if (doc.chef_type == "openid_registration") {
|
50
|
+
emit(doc.name, doc.name);
|
51
|
+
}
|
52
|
+
}
|
53
|
+
EOJS
|
54
|
+
},
|
55
|
+
"validated" => {
|
56
|
+
"map" => <<-EOJS
|
57
|
+
function(doc) {
|
58
|
+
if (doc.chef_type == "openid_registration") {
|
59
|
+
if (doc.validated == true) {
|
60
|
+
emit(doc.name, doc);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
EOJS
|
65
|
+
},
|
66
|
+
"unvalidated" => {
|
67
|
+
"map" => <<-EOJS
|
68
|
+
function(doc) {
|
69
|
+
if (doc.chef_type == "openid_registration") {
|
70
|
+
if (doc.validated == false) {
|
71
|
+
emit(doc.name, doc);
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
EOJS
|
76
|
+
},
|
77
|
+
},
|
78
|
+
}
|
79
|
+
|
80
|
+
# Create a new Chef::OpenIDRegistration object.
|
81
|
+
def initialize()
|
82
|
+
@name = nil
|
83
|
+
@salt = nil
|
84
|
+
@password = nil
|
85
|
+
@validated = false
|
86
|
+
@admin = false
|
87
|
+
@couchdb_rev = nil
|
88
|
+
@couchdb = Chef::CouchDB.new
|
89
|
+
end
|
90
|
+
|
91
|
+
def name=(n)
|
92
|
+
@name = n.gsub(/\./, '_')
|
93
|
+
end
|
94
|
+
|
95
|
+
# Set the password for this object.
|
96
|
+
def set_password(password)
|
97
|
+
@salt = generate_salt
|
98
|
+
@password = encrypt_password(@salt, password)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Serialize this object as a hash
|
102
|
+
def to_json(*a)
|
103
|
+
attributes = Hash.new
|
104
|
+
recipes = Array.new
|
105
|
+
result = {
|
106
|
+
'name' => @name,
|
107
|
+
'json_class' => self.class.name,
|
108
|
+
'salt' => @salt,
|
109
|
+
'password' => @password,
|
110
|
+
'validated' => @validated,
|
111
|
+
'admin' => @admin,
|
112
|
+
'chef_type' => 'openid_registration',
|
113
|
+
}
|
114
|
+
result["_rev"] = @couchdb_rev if @couchdb_rev
|
115
|
+
result.to_json(*a)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Create a Chef::Node from JSON
|
119
|
+
def self.json_create(o)
|
120
|
+
me = new
|
121
|
+
me.name = o["name"]
|
122
|
+
me.salt = o["salt"]
|
123
|
+
me.password = o["password"]
|
124
|
+
me.validated = o["validated"]
|
125
|
+
me.admin = o["admin"]
|
126
|
+
me.couchdb_rev = o["_rev"] if o.has_key?("_rev")
|
127
|
+
me
|
128
|
+
end
|
129
|
+
|
130
|
+
# List all the Chef::OpenIDRegistration objects in the CouchDB. If inflate is set to true, you will get
|
131
|
+
# the full list of all registration objects. Otherwise, you'll just get the IDs
|
132
|
+
def self.list(inflate=false)
|
133
|
+
rs = Chef::CouchDB.new.list("registrations", inflate)
|
134
|
+
if inflate
|
135
|
+
rs["rows"].collect { |r| r["value"] }
|
136
|
+
else
|
137
|
+
rs["rows"].collect { |r| r["key"] }
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Load an OpenIDRegistration by name from CouchDB
|
142
|
+
def self.load(name)
|
143
|
+
Chef::CouchDB.new.load("openid_registration", name)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Whether or not there is an OpenID Registration with this key.
|
147
|
+
def self.has_key?(name)
|
148
|
+
Chef::CouchDB.new.has_key?("openid_registration", name)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Remove this node from the CouchDB
|
152
|
+
def destroy
|
153
|
+
@couchdb.delete("openid_registration", @name, @couchdb_rev)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Save this node to the CouchDB
|
157
|
+
def save
|
158
|
+
results = @couchdb.store("openid_registration", @name, self)
|
159
|
+
@couchdb_rev = results["rev"]
|
160
|
+
end
|
161
|
+
|
162
|
+
# Set up our CouchDB design document
|
163
|
+
def self.create_design_document
|
164
|
+
Chef::CouchDB.new.create_design_document("registrations", DESIGN_DOCUMENT)
|
165
|
+
end
|
166
|
+
|
167
|
+
protected
|
168
|
+
|
169
|
+
def generate_salt
|
170
|
+
salt = Time.now.to_s
|
171
|
+
chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
|
172
|
+
1.upto(30) { |i| salt << chars[rand(chars.size-1)] }
|
173
|
+
salt
|
174
|
+
end
|
175
|
+
|
176
|
+
def encrypt_password(salt, password)
|
177
|
+
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
end
|