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,67 @@
|
|
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/mixin/from_file'
|
20
|
+
require 'chef/mixin/params_validate'
|
21
|
+
|
22
|
+
class Chef
|
23
|
+
class ResourceDefinition
|
24
|
+
|
25
|
+
include Chef::Mixin::FromFile
|
26
|
+
include Chef::Mixin::ParamsValidate
|
27
|
+
|
28
|
+
attr_accessor :name, :params, :recipe, :node
|
29
|
+
|
30
|
+
def initialize(node=nil)
|
31
|
+
@name = nil
|
32
|
+
@params = Hash.new
|
33
|
+
@recipe = nil
|
34
|
+
@node = node
|
35
|
+
end
|
36
|
+
|
37
|
+
def define(resource_name, prototype_params=nil, &block)
|
38
|
+
unless resource_name.kind_of?(Symbol)
|
39
|
+
raise ArgumentError, "You must use a symbol when defining a new resource!"
|
40
|
+
end
|
41
|
+
@name = resource_name
|
42
|
+
if prototype_params
|
43
|
+
unless prototype_params.kind_of?(Hash)
|
44
|
+
raise ArgumentError, "You must pass a hash as the prototype parameters for a definition."
|
45
|
+
end
|
46
|
+
@params = prototype_params
|
47
|
+
end
|
48
|
+
if Kernel.block_given?
|
49
|
+
@recipe = block
|
50
|
+
else
|
51
|
+
raise ArgumentError, "You must pass a block to a definition."
|
52
|
+
end
|
53
|
+
true
|
54
|
+
end
|
55
|
+
|
56
|
+
# When we do the resource definition, we're really just setting new values for
|
57
|
+
# the paramaters we prototyped at the top. This method missing is as simple as
|
58
|
+
# it gets.
|
59
|
+
def method_missing(symbol, *args)
|
60
|
+
@params[symbol] = args.length == 1 ? args[0] : args
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_s
|
64
|
+
"#{name.to_s}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/chef/rest.rb
ADDED
@@ -0,0 +1,238 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Adam Jacob (<adam@opscode.com>)
|
3
|
+
# Author:: Thom May (<thom@clearairturbulence.org>)
|
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/params_validate'
|
21
|
+
require 'chef/openid_registration'
|
22
|
+
require 'net/https'
|
23
|
+
require 'uri'
|
24
|
+
require 'json'
|
25
|
+
require 'tempfile'
|
26
|
+
require 'singleton'
|
27
|
+
|
28
|
+
class Chef
|
29
|
+
class REST
|
30
|
+
|
31
|
+
class CookieJar < Hash
|
32
|
+
include Singleton
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_accessor :url, :cookies
|
36
|
+
|
37
|
+
def initialize(url)
|
38
|
+
@url = url
|
39
|
+
@cookies = CookieJar.instance
|
40
|
+
end
|
41
|
+
|
42
|
+
# Register for an OpenID
|
43
|
+
def register(user, pass, validation_token=nil)
|
44
|
+
Chef::Log.debug("Registering #{user} for an openid")
|
45
|
+
registration = nil
|
46
|
+
begin
|
47
|
+
registration = get_rest("registrations/#{user}")
|
48
|
+
rescue Net::HTTPServerException => e
|
49
|
+
unless e.message =~ /^404/
|
50
|
+
raise e
|
51
|
+
end
|
52
|
+
end
|
53
|
+
unless registration
|
54
|
+
post_rest(
|
55
|
+
"registrations",
|
56
|
+
{
|
57
|
+
:id => user,
|
58
|
+
:password => pass,
|
59
|
+
:validation_token => validation_token
|
60
|
+
}
|
61
|
+
)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Authenticate
|
66
|
+
def authenticate(user, pass)
|
67
|
+
Chef::Log.debug("Authenticating #{user} via openid")
|
68
|
+
response = post_rest('openid/consumer/start', {
|
69
|
+
"openid_identifier" => "#{Chef::Config[:openid_url]}/openid/server/node/#{user}",
|
70
|
+
"submit" => "Verify"
|
71
|
+
})
|
72
|
+
post_rest(
|
73
|
+
"#{Chef::Config[:openid_url]}#{response["action"]}",
|
74
|
+
{ "password" => pass }
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Send an HTTP GET request to the path
|
79
|
+
#
|
80
|
+
# === Parameters
|
81
|
+
# path:: The path to GET
|
82
|
+
# raw:: Whether you want the raw body returned, or JSON inflated. Defaults
|
83
|
+
# to JSON inflated.
|
84
|
+
def get_rest(path, raw=false)
|
85
|
+
run_request(:GET, create_url(path), false, 10, raw)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Send an HTTP DELETE request to the path
|
89
|
+
def delete_rest(path)
|
90
|
+
run_request(:DELETE, create_url(path))
|
91
|
+
end
|
92
|
+
|
93
|
+
# Send an HTTP POST request to the path
|
94
|
+
def post_rest(path, json)
|
95
|
+
run_request(:POST, create_url(path), json)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Send an HTTP PUT request to the path
|
99
|
+
def put_rest(path, json)
|
100
|
+
run_request(:PUT, create_url(path), json)
|
101
|
+
end
|
102
|
+
|
103
|
+
def create_url(path)
|
104
|
+
if path =~ /^(http|https):\/\//
|
105
|
+
URI.parse(path)
|
106
|
+
else
|
107
|
+
URI.parse("#{@url}/#{path}")
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Actually run an HTTP request. First argument is the HTTP method,
|
112
|
+
# which should be one of :GET, :PUT, :POST or :DELETE. Next is the
|
113
|
+
# URL, then an object to include in the body (which will be converted with
|
114
|
+
# .to_json) and finally, the limit of HTTP Redirects to follow (10).
|
115
|
+
#
|
116
|
+
# Typically, you won't use this method -- instead, you'll use one of
|
117
|
+
# the helper methods (get_rest, post_rest, etc.)
|
118
|
+
#
|
119
|
+
# Will return the body of the response on success.
|
120
|
+
def run_request(method, url, data=false, limit=10, raw=false)
|
121
|
+
http_retry_delay = Chef::Config[:http_retry_delay]
|
122
|
+
http_retry_count = Chef::Config[:http_retry_count]
|
123
|
+
|
124
|
+
raise ArgumentError, 'HTTP redirect too deep' if limit == 0
|
125
|
+
|
126
|
+
http = Net::HTTP.new(url.host, url.port)
|
127
|
+
if url.scheme == "https"
|
128
|
+
http.use_ssl = true
|
129
|
+
if Chef::Config[:ssl_verify_mode] == :verify_none
|
130
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
131
|
+
end
|
132
|
+
if File.exists?(Chef::Config[:ssl_client_cert])
|
133
|
+
http.cert = OpenSSL::X509::Certificate.new(File.read(Chef::Config[:ssl_client_cert]))
|
134
|
+
http.key = OpenSSL::PKey::RSA.new(File.read(Chef::Config[:ssl_client_key]))
|
135
|
+
end
|
136
|
+
end
|
137
|
+
http.read_timeout = Chef::Config[:rest_timeout]
|
138
|
+
headers = Hash.new
|
139
|
+
unless raw
|
140
|
+
headers = {
|
141
|
+
'Accept' => "application/json",
|
142
|
+
}
|
143
|
+
end
|
144
|
+
if @cookies.has_key?("#{url.host}:#{url.port}")
|
145
|
+
headers['Cookie'] = @cookies["#{url.host}:#{url.port}"]
|
146
|
+
end
|
147
|
+
req = nil
|
148
|
+
case method
|
149
|
+
when :GET
|
150
|
+
req_path = "#{url.path}"
|
151
|
+
req_path << "?#{url.query}" if url.query
|
152
|
+
req = Net::HTTP::Get.new(req_path, headers)
|
153
|
+
when :POST
|
154
|
+
headers["Content-Type"] = 'application/json' if data
|
155
|
+
req = Net::HTTP::Post.new(url.path, headers)
|
156
|
+
req.body = data.to_json if data
|
157
|
+
when :PUT
|
158
|
+
headers["Content-Type"] = 'application/json' if data
|
159
|
+
req = Net::HTTP::Put.new(url.path, headers)
|
160
|
+
req.body = data.to_json if data
|
161
|
+
when :DELETE
|
162
|
+
req_path = "#{url.path}"
|
163
|
+
req_path << "?#{url.query}" if url.query
|
164
|
+
req = Net::HTTP::Delete.new(req_path, headers)
|
165
|
+
else
|
166
|
+
raise ArgumentError, "You must provide :GET, :PUT, :POST or :DELETE as the method"
|
167
|
+
end
|
168
|
+
|
169
|
+
# Optionally handle HTTP Basic Authentication
|
170
|
+
req.basic_auth(url.user, url.password) if url.user
|
171
|
+
|
172
|
+
Chef::Log.debug("Sending HTTP Request via #{req.method} to #{req.path}")
|
173
|
+
res = nil
|
174
|
+
tf = nil
|
175
|
+
http_retries = 1
|
176
|
+
|
177
|
+
begin
|
178
|
+
res = http.request(req) do |response|
|
179
|
+
if raw
|
180
|
+
tf = Tempfile.new("chef-rest")
|
181
|
+
# Stolen from http://www.ruby-forum.com/topic/166423
|
182
|
+
# Kudos to _why!
|
183
|
+
size, total = 0, response.header['Content-Length'].to_i
|
184
|
+
response.read_body do |chunk|
|
185
|
+
tf.write(chunk)
|
186
|
+
size += chunk.size
|
187
|
+
if size == 0
|
188
|
+
Chef::Log.debug("#{req.path} done (0 length file)")
|
189
|
+
elsif total == 0
|
190
|
+
Chef::Log.debug("#{req.path} (zero content length)")
|
191
|
+
else
|
192
|
+
Chef::Log.debug("#{req.path}" + " %d%% done (%d of %d)" % [(size * 100) / total, size, total])
|
193
|
+
end
|
194
|
+
end
|
195
|
+
tf.close
|
196
|
+
tf
|
197
|
+
else
|
198
|
+
response.read_body
|
199
|
+
end
|
200
|
+
response
|
201
|
+
end
|
202
|
+
rescue Errno::ECONNREFUSED
|
203
|
+
Chef::Log.error("Connection refused connecting to #{url.host}:#{url.port} for #{req.path} #{http_retries}/#{http_retry_count}")
|
204
|
+
sleep(http_retry_delay)
|
205
|
+
retry if (http_retries += 1) < http_retry_count
|
206
|
+
raise Errno::ECONNREFUSED, "Connection refused connecting to #{url.host}:#{url.port} for #{req.path}, giving up"
|
207
|
+
rescue Timeout::Error
|
208
|
+
Chef::Log.error("Timeout connecting to #{url.host}:#{url.port} for #{req.path}, retry #{http_retries}/#{http_retry_count}")
|
209
|
+
sleep(http_retry_delay)
|
210
|
+
retry if (http_retries += 1) < http_retry_count
|
211
|
+
raise Timeout::Error, "Timeout connecting to #{url.host}:#{url.port} for #{req.path}, giving up"
|
212
|
+
end
|
213
|
+
|
214
|
+
if res.kind_of?(Net::HTTPSuccess)
|
215
|
+
if res['set-cookie']
|
216
|
+
@cookies["#{url.host}:#{url.port}"] = res['set-cookie']
|
217
|
+
end
|
218
|
+
if res['content-type'] =~ /json/
|
219
|
+
JSON.parse(res.body)
|
220
|
+
else
|
221
|
+
if raw
|
222
|
+
tf
|
223
|
+
else
|
224
|
+
res.body
|
225
|
+
end
|
226
|
+
end
|
227
|
+
elsif res.kind_of?(Net::HTTPFound) or res.kind_of?(Net::HTTPMovedPermanently)
|
228
|
+
if res['set-cookie']
|
229
|
+
@cookies["#{url.host}:#{url.port}"] = res['set-cookie']
|
230
|
+
end
|
231
|
+
run_request(:GET, create_url(res['location']), false, limit - 1, raw)
|
232
|
+
else
|
233
|
+
res.error!
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
238
|
+
end
|
data/lib/chef/role.rb
ADDED
@@ -0,0 +1,231 @@
|
|
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/mixin/from_file'
|
22
|
+
require 'chef/couchdb'
|
23
|
+
require 'extlib'
|
24
|
+
require 'json'
|
25
|
+
|
26
|
+
class Chef
|
27
|
+
class Role
|
28
|
+
|
29
|
+
include Chef::Mixin::FromFile
|
30
|
+
include Chef::Mixin::ParamsValidate
|
31
|
+
|
32
|
+
DESIGN_DOCUMENT = {
|
33
|
+
"version" => 3,
|
34
|
+
"language" => "javascript",
|
35
|
+
"views" => {
|
36
|
+
"all" => {
|
37
|
+
"map" => <<-EOJS
|
38
|
+
function(doc) {
|
39
|
+
if (doc.chef_type == "role") {
|
40
|
+
emit(doc.name, doc);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
EOJS
|
44
|
+
},
|
45
|
+
"all_id" => {
|
46
|
+
"map" => <<-EOJS
|
47
|
+
function(doc) {
|
48
|
+
if (doc.chef_type == "role") {
|
49
|
+
emit(doc.name, doc.name);
|
50
|
+
}
|
51
|
+
}
|
52
|
+
EOJS
|
53
|
+
},
|
54
|
+
},
|
55
|
+
}
|
56
|
+
|
57
|
+
attr_accessor :couchdb_rev
|
58
|
+
|
59
|
+
# Create a new Chef::Role object.
|
60
|
+
def initialize()
|
61
|
+
@name = ''
|
62
|
+
@description = ''
|
63
|
+
@default_attributes = Mash.new
|
64
|
+
@override_attributes = Mash.new
|
65
|
+
@recipes = Array.new
|
66
|
+
@couchdb_rev = nil
|
67
|
+
@couchdb = Chef::CouchDB.new
|
68
|
+
end
|
69
|
+
|
70
|
+
def name(arg=nil)
|
71
|
+
set_or_return(
|
72
|
+
:name,
|
73
|
+
arg,
|
74
|
+
:regex => /^[\-[:alnum:]_]+$/
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
def description(arg=nil)
|
79
|
+
set_or_return(
|
80
|
+
:description,
|
81
|
+
arg,
|
82
|
+
:kind_of => String
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
86
|
+
def recipes(*arg)
|
87
|
+
arg.flatten!
|
88
|
+
if arg.length == 0
|
89
|
+
@recipes
|
90
|
+
else
|
91
|
+
arg.each do |entry|
|
92
|
+
raise ArgumentError, 'Recipes must be strings!' unless entry.kind_of?(String)
|
93
|
+
end
|
94
|
+
@recipes = arg
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def default_attributes(arg=nil)
|
99
|
+
set_or_return(
|
100
|
+
:default_attributes,
|
101
|
+
arg,
|
102
|
+
:kind_of => Hash
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
106
|
+
def override_attributes(arg=nil)
|
107
|
+
set_or_return(
|
108
|
+
:override_attributes,
|
109
|
+
arg,
|
110
|
+
:kind_of => Hash
|
111
|
+
)
|
112
|
+
end
|
113
|
+
|
114
|
+
def to_hash
|
115
|
+
result = {
|
116
|
+
"name" => @name,
|
117
|
+
"description" => @description,
|
118
|
+
'json_class' => self.class.name,
|
119
|
+
"default_attributes" => @default_attributes,
|
120
|
+
"override_attributes" => @override_attributes,
|
121
|
+
"chef_type" => "role",
|
122
|
+
"recipes" => @recipes,
|
123
|
+
}
|
124
|
+
result["_rev"] = @couchdb_rev if @couchdb_rev
|
125
|
+
result
|
126
|
+
end
|
127
|
+
|
128
|
+
# Serialize this object as a hash
|
129
|
+
def to_json(*a)
|
130
|
+
to_hash.to_json(*a)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Create a Chef::Role from JSON
|
134
|
+
def self.json_create(o)
|
135
|
+
role = new
|
136
|
+
role.name(o["name"])
|
137
|
+
role.description(o["description"])
|
138
|
+
role.default_attributes(o["default_attributes"])
|
139
|
+
role.override_attributes(o["override_attributes"])
|
140
|
+
role.recipes(o["recipes"])
|
141
|
+
role.couchdb_rev = o["_rev"] if o.has_key?("_rev")
|
142
|
+
role
|
143
|
+
end
|
144
|
+
|
145
|
+
# List all the Chef::Role objects in the CouchDB. If inflate is set to true, you will get
|
146
|
+
# the full list of all Roles, fully inflated.
|
147
|
+
def self.list(inflate=false)
|
148
|
+
rs = Chef::CouchDB.new.list("roles", inflate)
|
149
|
+
if inflate
|
150
|
+
rs["rows"].collect { |r| r["value"] }
|
151
|
+
else
|
152
|
+
rs["rows"].collect { |r| r["key"] }
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Load a role by name from CouchDB
|
157
|
+
def self.load(name)
|
158
|
+
Chef::CouchDB.new.load("role", name)
|
159
|
+
end
|
160
|
+
|
161
|
+
# Remove this role from the CouchDB
|
162
|
+
def destroy
|
163
|
+
@couchdb.delete("role", @name, @couchdb_rev)
|
164
|
+
|
165
|
+
if Chef::Config[:couchdb_version] == 0.9
|
166
|
+
rs = @couchdb.get_view("nodes", "by_run_list", :startkey => "role[#{@name}]", :endkey => "role[#{@name}]", :include_docs => true)
|
167
|
+
rs["rows"].each do |row|
|
168
|
+
node = row["doc"]
|
169
|
+
node.run_list.remove("role[#{@name}]")
|
170
|
+
node.save
|
171
|
+
end
|
172
|
+
else
|
173
|
+
Chef::Node.list.each do |node|
|
174
|
+
n = Chef::Node.load(node)
|
175
|
+
n.run_list.remove("role[#{@name}]")
|
176
|
+
n.save
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Save this role to the CouchDB
|
182
|
+
def save
|
183
|
+
results = @couchdb.store("role", @name, self)
|
184
|
+
@couchdb_rev = results["rev"]
|
185
|
+
end
|
186
|
+
|
187
|
+
# Set up our CouchDB design document
|
188
|
+
def self.create_design_document
|
189
|
+
Chef::CouchDB.new.create_design_document("roles", DESIGN_DOCUMENT)
|
190
|
+
end
|
191
|
+
|
192
|
+
# As a string
|
193
|
+
def to_s
|
194
|
+
"role[#{@name}]"
|
195
|
+
end
|
196
|
+
|
197
|
+
# Load a role from disk - prefers to load the JSON, but will happily load
|
198
|
+
# the raw rb files as well.
|
199
|
+
def self.from_disk(name, force=nil)
|
200
|
+
js_file = File.join(Chef::Config[:role_path], "#{name}.json")
|
201
|
+
rb_file = File.join(Chef::Config[:role_path], "#{name}.rb")
|
202
|
+
|
203
|
+
if File.exists?(js_file) || force == "json"
|
204
|
+
JSON.parse(IO.read(js_file))
|
205
|
+
elsif File.exists?(rb_file) || force == "ruby"
|
206
|
+
role = Chef::Role.new
|
207
|
+
role.name(name)
|
208
|
+
role.from_file(rb_file)
|
209
|
+
role
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# Sync all the json roles with couchdb from disk
|
214
|
+
def self.sync_from_disk_to_couchdb
|
215
|
+
Dir[File.join(Chef::Config[:role_path], "*.json")].each do |role_file|
|
216
|
+
short_name = File.basename(role_file, ".json")
|
217
|
+
Chef::Log.warn("Loading #{short_name}")
|
218
|
+
r = Chef::Role.from_disk(short_name, "json")
|
219
|
+
begin
|
220
|
+
couch_role = Chef::Role.load(short_name)
|
221
|
+
r.couchdb_rev = couch_role.couchdb_rev
|
222
|
+
Chef::Log.debug("Replacing role #{short_name} with data from #{role_file}")
|
223
|
+
rescue Net::HTTPServerException
|
224
|
+
Chef::Log.debug("Creating role #{short_name} with data from #{role_file}")
|
225
|
+
end
|
226
|
+
r.save
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
end
|