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.

Files changed (120) hide show
  1. data/LICENSE +201 -0
  2. data/README.rdoc +135 -0
  3. data/bin/chef-client +26 -0
  4. data/bin/chef-solo +26 -0
  5. data/lib/chef.rb +49 -0
  6. data/lib/chef/application.rb +98 -0
  7. data/lib/chef/application/agent.rb +18 -0
  8. data/lib/chef/application/client.rb +209 -0
  9. data/lib/chef/application/indexer.rb +141 -0
  10. data/lib/chef/application/server.rb +18 -0
  11. data/lib/chef/application/solo.rb +214 -0
  12. data/lib/chef/client.rb +396 -0
  13. data/lib/chef/compile.rb +138 -0
  14. data/lib/chef/config.rb +141 -0
  15. data/lib/chef/cookbook.rb +144 -0
  16. data/lib/chef/cookbook/metadata.rb +407 -0
  17. data/lib/chef/cookbook/metadata/version.rb +87 -0
  18. data/lib/chef/cookbook_loader.rb +168 -0
  19. data/lib/chef/couchdb.rb +172 -0
  20. data/lib/chef/daemon.rb +170 -0
  21. data/lib/chef/exceptions.rb +36 -0
  22. data/lib/chef/file_cache.rb +205 -0
  23. data/lib/chef/log.rb +39 -0
  24. data/lib/chef/mixin/check_helper.rb +31 -0
  25. data/lib/chef/mixin/checksum.rb +37 -0
  26. data/lib/chef/mixin/command.rb +351 -0
  27. data/lib/chef/mixin/create_path.rb +56 -0
  28. data/lib/chef/mixin/deep_merge.rb +36 -0
  29. data/lib/chef/mixin/find_preferred_file.rb +99 -0
  30. data/lib/chef/mixin/from_file.rb +36 -0
  31. data/lib/chef/mixin/generate_url.rb +48 -0
  32. data/lib/chef/mixin/language.rb +79 -0
  33. data/lib/chef/mixin/params_validate.rb +197 -0
  34. data/lib/chef/mixin/template.rb +84 -0
  35. data/lib/chef/node.rb +406 -0
  36. data/lib/chef/node/attribute.rb +412 -0
  37. data/lib/chef/openid_registration.rb +181 -0
  38. data/lib/chef/platform.rb +253 -0
  39. data/lib/chef/provider.rb +40 -0
  40. data/lib/chef/provider/cron.rb +137 -0
  41. data/lib/chef/provider/directory.rb +72 -0
  42. data/lib/chef/provider/execute.rb +58 -0
  43. data/lib/chef/provider/file.rb +191 -0
  44. data/lib/chef/provider/group.rb +120 -0
  45. data/lib/chef/provider/group/groupadd.rb +92 -0
  46. data/lib/chef/provider/group/pw.rb +88 -0
  47. data/lib/chef/provider/http_request.rb +102 -0
  48. data/lib/chef/provider/ifconfig.rb +131 -0
  49. data/lib/chef/provider/link.rb +157 -0
  50. data/lib/chef/provider/mount.rb +121 -0
  51. data/lib/chef/provider/mount/mount.rb +208 -0
  52. data/lib/chef/provider/package.rb +160 -0
  53. data/lib/chef/provider/package/apt.rb +110 -0
  54. data/lib/chef/provider/package/dpkg.rb +113 -0
  55. data/lib/chef/provider/package/freebsd.rb +153 -0
  56. data/lib/chef/provider/package/macports.rb +105 -0
  57. data/lib/chef/provider/package/portage.rb +124 -0
  58. data/lib/chef/provider/package/rpm.rb +99 -0
  59. data/lib/chef/provider/package/rubygems.rb +130 -0
  60. data/lib/chef/provider/package/yum-dump.py +104 -0
  61. data/lib/chef/provider/package/yum.rb +175 -0
  62. data/lib/chef/provider/remote_directory.rb +126 -0
  63. data/lib/chef/provider/remote_file.rb +134 -0
  64. data/lib/chef/provider/route.rb +118 -0
  65. data/lib/chef/provider/ruby_block.rb +15 -0
  66. data/lib/chef/provider/script.rb +42 -0
  67. data/lib/chef/provider/service.rb +129 -0
  68. data/lib/chef/provider/service/debian.rb +64 -0
  69. data/lib/chef/provider/service/freebsd.rb +157 -0
  70. data/lib/chef/provider/service/gentoo.rb +54 -0
  71. data/lib/chef/provider/service/init.rb +126 -0
  72. data/lib/chef/provider/service/redhat.rb +62 -0
  73. data/lib/chef/provider/template.rb +141 -0
  74. data/lib/chef/provider/user.rb +170 -0
  75. data/lib/chef/provider/user/pw.rb +113 -0
  76. data/lib/chef/provider/user/useradd.rb +107 -0
  77. data/lib/chef/queue.rb +145 -0
  78. data/lib/chef/recipe.rb +210 -0
  79. data/lib/chef/resource.rb +256 -0
  80. data/lib/chef/resource/apt_package.rb +34 -0
  81. data/lib/chef/resource/bash.rb +33 -0
  82. data/lib/chef/resource/cron.rb +143 -0
  83. data/lib/chef/resource/csh.rb +33 -0
  84. data/lib/chef/resource/directory.rb +76 -0
  85. data/lib/chef/resource/dpkg_package.rb +34 -0
  86. data/lib/chef/resource/execute.rb +127 -0
  87. data/lib/chef/resource/file.rb +84 -0
  88. data/lib/chef/resource/gem_package.rb +41 -0
  89. data/lib/chef/resource/group.rb +68 -0
  90. data/lib/chef/resource/http_request.rb +52 -0
  91. data/lib/chef/resource/ifconfig.rb +134 -0
  92. data/lib/chef/resource/link.rb +78 -0
  93. data/lib/chef/resource/macports_package.rb +29 -0
  94. data/lib/chef/resource/mount.rb +135 -0
  95. data/lib/chef/resource/package.rb +80 -0
  96. data/lib/chef/resource/perl.rb +33 -0
  97. data/lib/chef/resource/portage_package.rb +33 -0
  98. data/lib/chef/resource/python.rb +33 -0
  99. data/lib/chef/resource/remote_directory.rb +91 -0
  100. data/lib/chef/resource/remote_file.rb +60 -0
  101. data/lib/chef/resource/route.rb +135 -0
  102. data/lib/chef/resource/ruby.rb +33 -0
  103. data/lib/chef/resource/ruby_block.rb +20 -0
  104. data/lib/chef/resource/script.rb +51 -0
  105. data/lib/chef/resource/service.rb +134 -0
  106. data/lib/chef/resource/template.rb +60 -0
  107. data/lib/chef/resource/user.rb +98 -0
  108. data/lib/chef/resource_collection.rb +176 -0
  109. data/lib/chef/resource_definition.rb +67 -0
  110. data/lib/chef/rest.rb +238 -0
  111. data/lib/chef/role.rb +231 -0
  112. data/lib/chef/run_list.rb +156 -0
  113. data/lib/chef/runner.rb +123 -0
  114. data/lib/chef/search.rb +88 -0
  115. data/lib/chef/search/result.rb +64 -0
  116. data/lib/chef/search_index.rb +77 -0
  117. data/lib/chef/tasks/chef_repo.rake +345 -0
  118. data/lib/chef/util/file_edit.rb +125 -0
  119. data/lib/chef/util/fileedit.rb +121 -0
  120. 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