Class: Chef::Node

Inherits:
Object show all
Includes:
Mixin::CheckHelper, Mixin::FromFile, Mixin::LanguageIncludeAttribute, Mixin::ParamsValidate
Defined in:
lib/chef/node.rb,
lib/chef/node/attribute.rb

Defined Under Namespace

Classes: Attribute

Constant Summary collapse

DESIGN_DOCUMENT =
{
  "version" => 9,
  "language" => "javascript",
  "views" => {
    "all" => {
      "map" => <<-EOJS
      function(doc) { 
        if (doc.chef_type == "node") {
          emit(doc.name, doc);
        }
      }
      EOJS
    },
    "all_id" => {
      "map" => <<-EOJS
      function(doc) { 
        if (doc.chef_type == "node") {
          emit(doc.name, doc.name);
        }
      }
      EOJS
    },
    "status" => {
      "map" => <<-EOJS
        function(doc) {
          if (doc.chef_type == "node") {
            var to_emit = { "name": doc.name };
            if (doc["attributes"]["fqdn"]) {
              to_emit["fqdn"] = doc["attributes"]["fqdn"];
            } else {
              to_emit["fqdn"] = "Undefined";
            }
            if (doc["attributes"]["ipaddress"]) {
              to_emit["ipaddress"] = doc["attributes"]["ipaddress"];
            } else {
              to_emit["ipaddress"] = "Undefined";
            }
            if (doc["attributes"]["ohai_time"]) {
              to_emit["ohai_time"] = doc["attributes"]["ohai_time"];
            } else {
              to_emit["ohai_time"] = "Undefined";
            } 
            if (doc["attributes"]["uptime"]) {
              to_emit["uptime"] = doc["attributes"]["uptime"];
            } else {
              to_emit["uptime"] = "Undefined";
            }
            if (doc["attributes"]["platform"]) {
              to_emit["platform"] = doc["attributes"]["platform"];
            } else {
              to_emit["platform"] = "Undefined";
            }
            if (doc["attributes"]["platform_version"]) {
              to_emit["platform_version"] = doc["attributes"]["platform_version"];
            } else {
              to_emit["platform_version"] = "Undefined";
            }
            if (doc["run_list"]) {
              to_emit["run_list"] = doc["run_list"];
            } else {
              to_emit["run_list"] = "Undefined";
            }
            emit(doc.name, to_emit);
          }
        }
      EOJS
    },
    "by_run_list" => {
      "map" => <<-EOJS
        function(doc) {
          if (doc.chef_type == "node") {
            if (doc['run_list']) {
              for (var i=0; i < doc.run_list.length; i++) {
                emit(doc['run_list'][i], doc.name);
              }
            }
          }
        }
      EOJS
    }
  },
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Mixin::LanguageIncludeAttribute

#include_attribute

Methods included from Mixin::ParamsValidate

#set_or_return, #validate

Methods included from Mixin::FromFile

#class_from_file, #from_file

Methods included from Mixin::CheckHelper

#set_if_args

Constructor Details

#initializeNode

Create a new Chef::Node object.



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/chef/node.rb', line 125

def initialize
  @name = nil

  @attribute = Mash.new
  @override_attrs = Mash.new
  @default_attrs = Mash.new
  @run_list = Chef::RunList.new 

  @couchdb_rev = nil
  @couchdb_id = nil
  @couchdb = Chef::CouchDB.new

  @run_state = {
    :template_cache => Hash.new,
    :seen_recipes => Hash.new,
    :seen_attributes => Hash.new
  }
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(symbol, *args) ⇒ Object

Set an attribute based on the missing method. If you pass an argument, we’ll use that to set the attribute values. Otherwise, we’ll wind up just returning the attributes value.



245
246
247
248
# File 'lib/chef/node.rb', line 245

def method_missing(symbol, *args)
  attrs = Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)
  attrs.send(symbol, *args)
end

Instance Attribute Details

#attributeObject

Returns the value of attribute attribute.



34
35
36
# File 'lib/chef/node.rb', line 34

def attribute
  @attribute
end

#cookbook_loaderObject

Returns the value of attribute cookbook_loader.



34
35
36
# File 'lib/chef/node.rb', line 34

def cookbook_loader
  @cookbook_loader
end

#couchdb_idObject

Returns the value of attribute couchdb_id.



34
35
36
# File 'lib/chef/node.rb', line 34

def couchdb_id
  @couchdb_id
end

#couchdb_revObject

Returns the value of attribute couchdb_rev.



34
35
36
# File 'lib/chef/node.rb', line 34

def couchdb_rev
  @couchdb_rev
end

#default_attrsObject

Returns the value of attribute default_attrs.



34
35
36
# File 'lib/chef/node.rb', line 34

def default_attrs
  @default_attrs
end

#override_attrsObject

Returns the value of attribute override_attrs.



34
35
36
# File 'lib/chef/node.rb', line 34

def override_attrs
  @override_attrs
end

#recipe_listObject

Returns the value of attribute recipe_list.



34
35
36
# File 'lib/chef/node.rb', line 34

def recipe_list
  @recipe_list
end

#run_list(*args) ⇒ Object

Returns an Array of roles and recipes, in the order they will be applied. If you call it with arguments, they will become the new list of roles and recipes.



280
281
282
# File 'lib/chef/node.rb', line 280

def run_list
  @run_list
end

#run_stateObject

Returns the value of attribute run_state.



34
35
36
# File 'lib/chef/node.rb', line 34

def run_state
  @run_state
end

Class Method Details

.cdb_list(inflate = false) ⇒ Object

List all the Chef::Node objects in the CouchDB. If inflate is set to true, you will get the full list of all Nodes, fully inflated.



362
363
364
365
366
367
368
369
370
# File 'lib/chef/node.rb', line 362

def self.cdb_list(inflate=false)
  couchdb = Chef::CouchDB.new
  rs = couchdb.list("nodes", inflate)
  if inflate
    rs["rows"].collect { |r| r["value"] }
  else
    rs["rows"].collect { |r| r["key"] }
  end
end

.cdb_load(name) ⇒ Object

Load a node by name from CouchDB



386
387
388
389
# File 'lib/chef/node.rb', line 386

def self.cdb_load(name)
  couchdb = Chef::CouchDB.new
  couchdb.load("node", name)
end

.create_design_documentObject

Set up our CouchDB design document



437
438
439
440
# File 'lib/chef/node.rb', line 437

def self.create_design_document
  couchdb = Chef::CouchDB.new
  couchdb.create_design_document("nodes", DESIGN_DOCUMENT)
end

.json_create(o) ⇒ Object

Create a Chef::Node from JSON



338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
# File 'lib/chef/node.rb', line 338

def self.json_create(o)
  node = new
  node.name(o["name"])
  o["attributes"].each do |k,v|
    node[k] = v
  end
  if o.has_key?("defaults")
    node.default_attrs = Mash.new(o["defaults"])
  end
  if o.has_key?("overrides")
    node.override_attrs = Mash.new(o["overrides"])
  end
  if o.has_key?("run_list")
    node.run_list.reset(o["run_list"])
  else
    o["recipes"].each { |r| node.recipes << r }
  end
  node.couchdb_rev = o["_rev"] if o.has_key?("_rev")
  node.couchdb_id = o["_id"] if o.has_key?("_id")
  node
end

.list(inflate = false) ⇒ Object



372
373
374
375
376
377
378
379
380
381
382
383
# File 'lib/chef/node.rb', line 372

def self.list(inflate=false)
  r = Chef::REST.new(Chef::Config[:chef_server_url])
  if inflate
    response = Hash.new
    Chef::Search::Query.new.search(:node) do |n|
      response[n.name] = n unless n.nil?
    end
    response
  else
    r.get_rest("nodes")
  end
end

.load(name) ⇒ Object

Load a node by name



392
393
394
395
# File 'lib/chef/node.rb', line 392

def self.load(name)
  r = Chef::REST.new(Chef::Config[:chef_server_url])
  r.get_rest("nodes/#{escape_node_id(name)}")
end

Instance Method Details

#[](attrib) ⇒ Object

Return an attribute of this node. Returns nil if the attribute is not found.



186
187
188
189
# File 'lib/chef/node.rb', line 186

def [](attrib)
  attrs = Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)
  attrs[attrib] 
end

#[]=(attrib, value) ⇒ Object

Set an attribute of this node



192
193
194
195
# File 'lib/chef/node.rb', line 192

def []=(attrib, value)
  attrs = Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)
  attrs[attrib] = value
end

#attribute?(attrib) ⇒ Boolean

Return true if this Node has a given attribute, false if not. Takes either a symbol or a string.

Only works on the top level. Preferred way is to use the normal [] style lookup and call attribute?()

Returns:

  • (Boolean)


225
226
227
228
# File 'lib/chef/node.rb', line 225

def attribute?(attrib)
  attrs = Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)
  attrs.attribute?(attrib)
end

#cdb_destroyObject

Remove this node from the CouchDB



398
399
400
# File 'lib/chef/node.rb', line 398

def cdb_destroy
  @couchdb.delete("node", @name, @couchdb_rev)
end

#cdb_saveObject

Save this node to the CouchDB



409
410
411
412
# File 'lib/chef/node.rb', line 409

def cdb_save
  results = @couchdb.store("node", @name, self)
  @couchdb_rev = results["rev"]
end

#consume_attributes(attrs) ⇒ Object



293
294
295
296
297
298
299
300
301
302
303
304
305
306
# File 'lib/chef/node.rb', line 293

def consume_attributes(attrs)
  attrs ||= {}
  Chef::Log.debug("Adding JSON Attributes")
  attrs.each do |key, value|
    if ["recipes", "run_list"].include?(key)
      append_recipes(value)
    else
      Chef::Log.debug("JSON Attribute: #{key} - #{value.inspect}")
      store(key, value)
    end
  end
  self[:tags] = Array.new unless attribute?(:tags)
  
end

#createObject

Create the node via the REST API



430
431
432
433
434
# File 'lib/chef/node.rb', line 430

def create
  r = Chef::REST.new(Chef::Config[:chef_server_url])
  r.post_rest("nodes", self)
  self
end

#destroyObject

Remove this node via the REST API



403
404
405
406
# File 'lib/chef/node.rb', line 403

def destroy
  r = Chef::REST.new(Chef::Config[:chef_server_url])
  r.delete_rest("nodes/#{Chef::Node.escape_node_id(@name)}")
end

#each(&block) ⇒ Object

Yield each key of the top level to the block.



231
232
233
234
# File 'lib/chef/node.rb', line 231

def each(&block)
  attrs = Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)
  attrs.each(&block)
end

#each_attribute(&block) ⇒ Object

Iterates over each attribute, passing the attribute and value to the block.



237
238
239
240
# File 'lib/chef/node.rb', line 237

def each_attribute(&block)
  attrs = Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)
  attrs.each_attribute(&block)
end

#find_file(fqdn) ⇒ Object

Find a recipe for this Chef::Node by fqdn. Will search first for Chef::Config/fqdn.rb, then hostname.rb, then default.rb.

Returns a new Chef::Node object.

Raises an ArgumentError if it cannot find the node.



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/chef/node.rb', line 150

def find_file(fqdn)
  node_file = nil
  host_parts = fqdn.split(".")
  hostname = host_parts[0]

  if File.exists?(File.join(Chef::Config[:node_path], "#{fqdn}.rb"))
    node_file = File.join(Chef::Config[:node_path], "#{fqdn}.rb")
  elsif File.exists?(File.join(Chef::Config[:node_path], "#{hostname}.rb"))
    node_file = File.join(Chef::Config[:node_path], "#{hostname}.rb")
  elsif File.exists?(File.join(Chef::Config[:node_path], "default.rb"))
    node_file = File.join(Chef::Config[:node_path], "default.rb")
  end
  unless node_file
    raise ArgumentError, "Cannot find a node matching #{fqdn}, not even with default.rb!" 
  end
  self.from_file(node_file)
end

#name(arg = nil) ⇒ Object

Set the name of this Node, or return the current name.



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/chef/node.rb', line 169

def name(arg=nil)
  if arg != nil
    validate(
      { :name => arg }, 
      {
        :name => {
          :kind_of => String
        }
      }
    )
    @name = arg
  else
    @name
  end
end

#recipe?(recipe_name) ⇒ Boolean

Returns true if this Node expects a given recipe, false if not.

Returns:

  • (Boolean)


251
252
253
254
255
256
257
258
259
260
261
# File 'lib/chef/node.rb', line 251

def recipe?(recipe_name)
  if @run_list.include?(recipe_name)
    true
  else
    if @run_state[:seen_recipes].include?(recipe_name)
      true
    else
      false
    end
  end
end

#recipes(*args) ⇒ Object

Returns an Array of recipes. If you call it with arguments, they will become the new list of recipes.



265
266
267
268
269
270
271
# File 'lib/chef/node.rb', line 265

def recipes(*args)
  if args.length > 0
    @run_list.reset(args)
  else
    @run_list
  end
end

#role?(role_name) ⇒ Boolean

Returns true if this Node expects a given role, false if not.

Returns:

  • (Boolean)


274
275
276
# File 'lib/chef/node.rb', line 274

def role?(role_name)
  @run_list.include?("role[#{role_name}]")
end

#run_list?(item) ⇒ Boolean

Returns true if this Node expects a given role, false if not.

Returns:

  • (Boolean)


289
290
291
# File 'lib/chef/node.rb', line 289

def run_list?(item)
  @run_list.detect { |r| r == item } ? true : false
end

#saveObject

Save this node via the REST API



415
416
417
418
419
420
421
422
423
424
425
426
427
# File 'lib/chef/node.rb', line 415

def save
  r = Chef::REST.new(Chef::Config[:chef_server_url])
  begin
    r.put_rest("nodes/#{Chef::Node.escape_node_id(@name)}", self)
  rescue Net::HTTPServerException => e
    if e.response.code == "404"
      r.post_rest("nodes", self)
    else
      raise e
    end
  end
  self
end

#setObject

Set an attribute of this node, but auto-vivifiy any Mashes that might be missing



203
204
205
206
207
# File 'lib/chef/node.rb', line 203

def set
  attrs = Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)
  attrs.auto_vivifiy_on_read = true
  attrs
end

#set_unlessObject Also known as: default

Set an attribute of this node, auto-vivifiying any mashes that are missing, but if the final value already exists, don’t set it



211
212
213
214
215
216
# File 'lib/chef/node.rb', line 211

def set_unless
  attrs = Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)
  attrs.auto_vivifiy_on_read = true
  attrs.set_unless_value_present = true
  attrs
end

#store(attrib, value) ⇒ Object



197
198
199
# File 'lib/chef/node.rb', line 197

def store(attrib, value)
  self[attrib] = value
end

#to_hashObject

Transform the node to a Hash



309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/chef/node.rb', line 309

def to_hash
  index_hash = Hash.new
  self.each do |k, v|
    index_hash[k] = v
  end
  index_hash["chef_type"] = "node"
  index_hash["name"] = @name
  index_hash["recipe"] = @run_list.recipes if @run_list.recipes.length > 0
  index_hash["role"] = @run_list.roles if @run_list.roles.length > 0
  index_hash["run_list"] = @run_list.run_list if @run_list.run_list.length > 0
  index_hash
end

#to_json(*a) ⇒ Object

Serialize this object as a hash



323
324
325
326
327
328
329
330
331
332
333
334
335
# File 'lib/chef/node.rb', line 323

def to_json(*a)
  result = {
    "name" => @name,
    'json_class' => self.class.name,
    "attributes" => @attribute,
    "chef_type" => "node",
    "defaults" => @default_attrs,
    "overrides" => @override_attrs,
    "run_list" => @run_list.run_list,
  }
  result["_rev"] = @couchdb_rev if @couchdb_rev
  result.to_json(*a)
end

#to_sObject

As a string



443
444
445
# File 'lib/chef/node.rb', line 443

def to_s
  "node[#{@name}]"
end