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,84 @@
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 'tempfile'
20
+ require 'erubis'
21
+
22
+ class Chef
23
+ module Mixin
24
+ module Template
25
+
26
+ # Render a template with Erubis. Takes a template as a string, and a
27
+ # context hash.
28
+ def render_template(template, context)
29
+ begin
30
+ eruby = Erubis::Eruby.new(template)
31
+ output = eruby.evaluate(context)
32
+ rescue Object => e
33
+ raise TemplateError.new(e, template, context)
34
+ end
35
+ final_tempfile = Tempfile.new("chef-rendered-template")
36
+ final_tempfile.print(output)
37
+ final_tempfile.close
38
+ final_tempfile
39
+ end
40
+
41
+ class TemplateError < RuntimeError
42
+ attr_reader :original_exception, :context
43
+ SOURCE_CONTEXT_WINDOW = 2 unless defined? SOURCE_CONTEXT_WINDOW
44
+
45
+ def initialize(original_exception, template, context)
46
+ @original_exception, @template, @context = original_exception, template, context
47
+ end
48
+
49
+ def message
50
+ @original_exception.message
51
+ end
52
+
53
+ def line_number
54
+ @line_number ||= $1.to_i if original_exception.backtrace.find {|line| line =~ /\(erubis\):(\d+)/ }
55
+ end
56
+
57
+ def source_location
58
+ "on line ##{line_number}"
59
+ end
60
+
61
+ def source_listing
62
+ @source_listing ||= begin
63
+ line_index = line_number - 1
64
+ beginning_line = line_index <= SOURCE_CONTEXT_WINDOW ? 0 : line_index - SOURCE_CONTEXT_WINDOW
65
+ source_size = SOURCE_CONTEXT_WINDOW * 2 + 1
66
+ lines = @template.split(/\n/)
67
+ contextual_lines = lines[beginning_line, source_size]
68
+ output = []
69
+ contextual_lines.each_with_index do |line, index|
70
+ line_number = (index+beginning_line+1).to_s.rjust(3)
71
+ output << "#{line_number}: #{line}"
72
+ end
73
+ output.join("\n")
74
+ end
75
+ end
76
+
77
+ def to_s
78
+ "\n\n#{self.class} (#{message}) #{source_location}:\n\n" +
79
+ "#{source_listing}\n\n #{original_exception.backtrace.join("\n ")}\n\n"
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
data/lib/chef/node.rb ADDED
@@ -0,0 +1,406 @@
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/check_helper'
21
+ require 'chef/mixin/params_validate'
22
+ require 'chef/mixin/from_file'
23
+ require 'chef/couchdb'
24
+ require 'chef/queue'
25
+ require 'chef/run_list'
26
+ require 'chef/node/attribute'
27
+ require 'extlib'
28
+ require 'json'
29
+
30
+ class Chef
31
+ class Node
32
+
33
+ attr_accessor :attribute, :recipe_list, :couchdb_rev, :run_state, :run_list, :override, :default
34
+
35
+ include Chef::Mixin::CheckHelper
36
+ include Chef::Mixin::FromFile
37
+ include Chef::Mixin::ParamsValidate
38
+
39
+ DESIGN_DOCUMENT = {
40
+ "version" => 8,
41
+ "language" => "javascript",
42
+ "views" => {
43
+ "all" => {
44
+ "map" => <<-EOJS
45
+ function(doc) {
46
+ if (doc.chef_type == "node") {
47
+ emit(doc.name, doc);
48
+ }
49
+ }
50
+ EOJS
51
+ },
52
+ "all_id" => {
53
+ "map" => <<-EOJS
54
+ function(doc) {
55
+ if (doc.chef_type == "node") {
56
+ emit(doc.name, doc.name);
57
+ }
58
+ }
59
+ EOJS
60
+ },
61
+ "status" => {
62
+ "map" => <<-EOJS
63
+ function(doc) {
64
+ if (doc.chef_type == "node") {
65
+ var to_emit = { "name": doc.name };
66
+ if (doc["attributes"]["fqdn"]) {
67
+ to_emit["fqdn"] = doc["attributes"]["fqdn"];
68
+ } else {
69
+ to_emit["fqdn"] = "Undefined";
70
+ }
71
+ if (doc["attributes"]["ipaddress"]) {
72
+ to_emit["ipaddress"] = doc["attributes"]["ipaddress"];
73
+ } else {
74
+ to_emit["ipaddress"] = "Undefined";
75
+ }
76
+ if (doc["attributes"]["ohai_time"]) {
77
+ to_emit["ohai_time"] = doc["attributes"]["ohai_time"];
78
+ } else {
79
+ to_emit["ohai_time"] = "Undefined";
80
+ }
81
+ if (doc["attributes"]["uptime"]) {
82
+ to_emit["uptime"] = doc["attributes"]["uptime"];
83
+ } else {
84
+ to_emit["uptime"] = "Undefined";
85
+ }
86
+ if (doc["attributes"]["platform"]) {
87
+ to_emit["platform"] = doc["attributes"]["platform"];
88
+ } else {
89
+ to_emit["platform"] = "Undefined";
90
+ }
91
+ if (doc["attributes"]["platform_version"]) {
92
+ to_emit["platform_version"] = doc["attributes"]["platform_version"];
93
+ } else {
94
+ to_emit["platform_version"] = "Undefined";
95
+ }
96
+ if (doc["run_list"]) {
97
+ to_emit["run_list"] = doc["run_list"];
98
+ } else {
99
+ to_emit["run_list"] = "Undefined";
100
+ }
101
+ emit(doc.name, to_emit);
102
+ }
103
+ }
104
+ EOJS
105
+ },
106
+ "by_run_list" => {
107
+ "map" => <<-EOJS
108
+ function(doc) {
109
+ if (doc.chef_type == "node") {
110
+ if (doc['run_list']) {
111
+ for (var i=0; i < doc.run_list.length; i++) {
112
+ emit(doc['run_list'][i], doc.name);
113
+ }
114
+ }
115
+ }
116
+ }
117
+ EOJS
118
+ }
119
+ },
120
+ }
121
+
122
+ # Create a new Chef::Node object.
123
+ def initialize()
124
+ @name = nil
125
+
126
+ @attribute = Mash.new
127
+ @override = Mash.new
128
+ @default = Mash.new
129
+ @run_list = Chef::RunList.new
130
+
131
+ @couchdb_rev = nil
132
+ @couchdb = Chef::CouchDB.new
133
+ @run_state = {
134
+ :template_cache => Hash.new,
135
+ :seen_recipes => Hash.new
136
+ }
137
+ end
138
+
139
+ # Find a recipe for this Chef::Node by fqdn. Will search first for
140
+ # Chef::Config["node_path"]/fqdn.rb, then hostname.rb, then default.rb.
141
+ #
142
+ # Returns a new Chef::Node object.
143
+ #
144
+ # Raises an ArgumentError if it cannot find the node.
145
+ def find_file(fqdn)
146
+ node_file = nil
147
+ host_parts = fqdn.split(".")
148
+ hostname = host_parts[0]
149
+
150
+ if File.exists?(File.join(Chef::Config[:node_path], "#{fqdn}.rb"))
151
+ node_file = File.join(Chef::Config[:node_path], "#{fqdn}.rb")
152
+ elsif File.exists?(File.join(Chef::Config[:node_path], "#{hostname}.rb"))
153
+ node_file = File.join(Chef::Config[:node_path], "#{hostname}.rb")
154
+ elsif File.exists?(File.join(Chef::Config[:node_path], "default.rb"))
155
+ node_file = File.join(Chef::Config[:node_path], "default.rb")
156
+ end
157
+ unless node_file
158
+ raise ArgumentError, "Cannot find a node matching #{fqdn}, not even with default.rb!"
159
+ end
160
+ self.from_file(node_file)
161
+ end
162
+
163
+ # Set the name of this Node, or return the current name.
164
+ def name(arg=nil)
165
+ if arg != nil
166
+ validate(
167
+ { :name => arg },
168
+ {
169
+ :name => {
170
+ :kind_of => String
171
+ }
172
+ }
173
+ )
174
+ @name = arg
175
+ else
176
+ @name
177
+ end
178
+ end
179
+
180
+ # Return an attribute of this node. Returns nil if the attribute is not found.
181
+ def [](attrib)
182
+ attrs = Chef::Node::Attribute.new(@attribute, @default, @override)
183
+ attrs[attrib]
184
+ end
185
+
186
+ # Set an attribute of this node
187
+ def []=(attrib, value)
188
+ attrs = Chef::Node::Attribute.new(@attribute, @default, @override)
189
+ attrs[attrib] = value
190
+ end
191
+
192
+ # Set an attribute of this node, but auto-vivifiy any Mashes that might
193
+ # be missing
194
+ def set
195
+ attrs = Chef::Node::Attribute.new(@attribute, @default, @override)
196
+ attrs.auto_vivifiy_on_read = true
197
+ attrs
198
+ end
199
+
200
+ # Set an attribute of this node, auto-vivifiying any mashes that are
201
+ # missing, but if the final value already exists, don't set it
202
+ def set_unless
203
+ attrs = Chef::Node::Attribute.new(@attribute, @default, @override)
204
+ attrs.auto_vivifiy_on_read = true
205
+ attrs.set_unless_value_present = true
206
+ attrs
207
+ end
208
+
209
+ alias_method :default, :set_unless
210
+
211
+ # Return true if this Node has a given attribute, false if not. Takes either a symbol or
212
+ # a string.
213
+ #
214
+ # Only works on the top level. Preferred way is to use the normal [] style
215
+ # lookup and call attribute?()
216
+ def attribute?(attrib)
217
+ attrs = Chef::Node::Attribute.new(@attribute, @default, @override)
218
+ attrs.attribute?(attrib)
219
+ end
220
+
221
+ # Yield each key of the top level to the block.
222
+ def each(&block)
223
+ attrs = Chef::Node::Attribute.new(@attribute, @default, @override)
224
+ attrs.each(&block)
225
+ end
226
+
227
+ # Iterates over each attribute, passing the attribute and value to the block.
228
+ def each_attribute(&block)
229
+ attrs = Chef::Node::Attribute.new(@attribute, @default, @override)
230
+ attrs.each_attribute(&block)
231
+ end
232
+
233
+ # Set an attribute based on the missing method. If you pass an argument, we'll use that
234
+ # to set the attribute values. Otherwise, we'll wind up just returning the attributes
235
+ # value.
236
+ def method_missing(symbol, *args)
237
+ attrs = Chef::Node::Attribute.new(@attribute, @default, @override)
238
+ attrs.send(symbol, *args)
239
+ end
240
+
241
+ # Returns true if this Node expects a given recipe, false if not.
242
+ def recipe?(recipe_name)
243
+ if @run_list.include?(recipe_name)
244
+ true
245
+ else
246
+ if @run_state[:seen_recipes].include?(recipe_name)
247
+ true
248
+ else
249
+ false
250
+ end
251
+ end
252
+ end
253
+
254
+ # Returns an Array of recipes. If you call it with arguments, they will become the new
255
+ # list of recipes.
256
+ def recipes(*args)
257
+ if args.length > 0
258
+ @run_list.reset(args)
259
+ else
260
+ @run_list
261
+ end
262
+ end
263
+
264
+ # Returns true if this Node expects a given role, false if not.
265
+ def role?(role_name)
266
+ @run_list.include?("role[#{role_name}]")
267
+ end
268
+
269
+ # Returns an Array of roles and recipes, in the order they will be applied.
270
+ # If you call it with arguments, they will become the new list of roles and recipes.
271
+ def run_list(*args)
272
+ if args.length > 0
273
+ @run_list.reset(args)
274
+ else
275
+ @run_list
276
+ end
277
+ end
278
+
279
+ # Returns true if this Node expects a given role, false if not.
280
+ def run_list?(item)
281
+ @run_list.detect { |r| r == item } ? true : false
282
+ end
283
+
284
+ # Turns the node into an object that we can index. I apologize up front for the
285
+ # super confusion that is the recursive index_flatten hash, which comes up next.
286
+ # Faith, young one, faith.
287
+ #
288
+ # === Returns
289
+ # index_hash<Hash>:: A flattened hash of all the nodes attributes, suitable for indexing.
290
+ def to_index
291
+ index_hash = {
292
+ "index_name" => "node",
293
+ "id" => "node_#{@name}",
294
+ "name" => @name,
295
+ }
296
+ @attribute.each do |key, value|
297
+ if value.kind_of?(Hash) || value.kind_of?(Mash)
298
+ index_flatten_hash(key, value).each do |to_index|
299
+ to_index.each do |nk, nv|
300
+ index_hash[nk] = nv
301
+ end
302
+ end
303
+ else
304
+ index_hash[key] = value
305
+ end
306
+ end
307
+ index_hash["recipe"] = @run_list.recipes if @run_list.recipes.length > 0
308
+ index_hash["roles"] = @run_list.roles if @run_list.roles.length > 0
309
+ index_hash["run_list"] = @run_list.run_list if @run_list.run_list.length > 0
310
+ index_hash
311
+ end
312
+
313
+ # Ah, song of my heart, index_flatten_hash. This method flattens a hash in preparation
314
+ # for indexing, by appending the name of it's parent to a current key with an _. Hence,
315
+ # node[:bar][:baz] = 'monkey' becomes bar_baz:monkey.
316
+ #
317
+ # === Returns
318
+ # results<Array>:: An array of hashes with one element.
319
+ def index_flatten_hash(parent_name, hash)
320
+ results = Array.new
321
+ hash.each do |k, v|
322
+ if v.kind_of?(Hash) || v.kind_of?(Mash)
323
+ results << index_flatten_hash("#{parent_name}_#{k}", v)
324
+ else
325
+ results << { "#{parent_name}_#{k}", v }
326
+ end
327
+ end
328
+ results.flatten
329
+ end
330
+
331
+ # Serialize this object as a hash
332
+ def to_json(*a)
333
+ result = {
334
+ "name" => @name,
335
+ 'json_class' => self.class.name,
336
+ "attributes" => @attribute,
337
+ "chef_type" => "node",
338
+ "run_list" => @run_list.run_list,
339
+ }
340
+ result["_rev"] = @couchdb_rev if @couchdb_rev
341
+ result.to_json(*a)
342
+ end
343
+
344
+ # Create a Chef::Node from JSON
345
+ def self.json_create(o)
346
+ node = new
347
+ node.name(o["name"])
348
+ o["attributes"].each do |k,v|
349
+ node[k] = v
350
+ end
351
+ if o.has_key?("defaults")
352
+ node.default = o["defaults"]
353
+ end
354
+ if o.has_key?("overrides")
355
+ node.override = o["overrides"]
356
+ end
357
+ if o.has_key?("run_list")
358
+ node.run_list.reset(o["run_list"])
359
+ else
360
+ o["recipes"].each { |r| node.recipes << r }
361
+ end
362
+ node.couchdb_rev = o["_rev"] if o.has_key?("_rev")
363
+ node
364
+ end
365
+
366
+ # List all the Chef::Node objects in the CouchDB. If inflate is set to true, you will get
367
+ # the full list of all Nodes, fully inflated.
368
+ def self.list(inflate=false)
369
+ rs = Chef::CouchDB.new.list("nodes", inflate)
370
+ if inflate
371
+ rs["rows"].collect { |r| r["value"] }
372
+ else
373
+ rs["rows"].collect { |r| r["key"] }
374
+ end
375
+ end
376
+
377
+ # Load a node by name from CouchDB
378
+ def self.load(name)
379
+ Chef::CouchDB.new.load("node", name)
380
+ end
381
+
382
+ # Remove this node from the CouchDB
383
+ def destroy
384
+ Chef::Queue.send_msg(:queue, :remove, self)
385
+ @couchdb.delete("node", @name, @couchdb_rev)
386
+ end
387
+
388
+ # Save this node to the CouchDB
389
+ def save
390
+ Chef::Queue.send_msg(:queue, :index, self)
391
+ results = @couchdb.store("node", @name, self)
392
+ @couchdb_rev = results["rev"]
393
+ end
394
+
395
+ # Set up our CouchDB design document
396
+ def self.create_design_document
397
+ Chef::CouchDB.new.create_design_document("nodes", DESIGN_DOCUMENT)
398
+ end
399
+
400
+ # As a string
401
+ def to_s
402
+ "node[#{@name}]"
403
+ end
404
+
405
+ end
406
+ end