Class: Chef::Node

Inherits:
Object show all
Includes:
IndexQueue::Indexable, 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

Attributes included from IndexQueue::Indexable

#index_id

Class Method Summary collapse

Instance Method Summary collapse

Methods included from IndexQueue::Indexable

#add_to_index, #delete_from_index, included, #index_object_type, #with_indexer_metadata

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

#initialize(couchdb = nil) ⇒ Node

Create a new Chef::Node object.



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/chef/node.rb', line 131

def initialize(couchdb=nil)
  @name = nil
  @node = self

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

  @couchdb_rev = nil
  @couchdb_id = nil
  @couchdb = 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.



251
252
253
# File 'lib/chef/node.rb', line 251

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

Instance Attribute Details

#attributeObject

Returns the value of attribute attribute.



37
38
39
# File 'lib/chef/node.rb', line 37

def attribute
  @attribute
end

#cookbook_loaderObject

Returns the value of attribute cookbook_loader.



37
38
39
# File 'lib/chef/node.rb', line 37

def cookbook_loader
  @cookbook_loader
end

#couchdbObject

Returns the value of attribute couchdb.



37
38
39
# File 'lib/chef/node.rb', line 37

def couchdb
  @couchdb
end

#couchdb_idObject

Returns the value of attribute couchdb_id.



39
40
41
# File 'lib/chef/node.rb', line 39

def couchdb_id
  @couchdb_id
end

#couchdb_revObject

Returns the value of attribute couchdb_rev.



37
38
39
# File 'lib/chef/node.rb', line 37

def couchdb_rev
  @couchdb_rev
end

#default_attrsObject

Returns the value of attribute default_attrs.



37
38
39
# File 'lib/chef/node.rb', line 37

def default_attrs
  @default_attrs
end

#nodeObject (readonly)

Returns the value of attribute node.



38
39
40
# File 'lib/chef/node.rb', line 38

def node
  @node
end

#override_attrsObject

Returns the value of attribute override_attrs.



37
38
39
# File 'lib/chef/node.rb', line 37

def override_attrs
  @override_attrs
end

#recipe_listObject

Returns the value of attribute recipe_list.



37
38
39
# File 'lib/chef/node.rb', line 37

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.



267
268
269
# File 'lib/chef/node.rb', line 267

def run_list
  @run_list
end

#run_stateObject

Returns the value of attribute run_state.



37
38
39
# File 'lib/chef/node.rb', line 37

def run_state
  @run_state
end

Class Method Details

.cdb_list(inflate = false, couchdb = nil) ⇒ 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.



347
348
349
350
351
# File 'lib/chef/node.rb', line 347

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

.cdb_load(name, couchdb = nil) ⇒ Object

Load a node by name from CouchDB



366
367
368
# File 'lib/chef/node.rb', line 366

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

.chef_server_restObject



160
161
162
# File 'lib/chef/node.rb', line 160

def self.chef_server_rest
  Chef::REST.new(Chef::Config[:chef_server_url])
end

.create_design_document(couchdb = nil) ⇒ Object

Set up our CouchDB design document



416
417
418
# File 'lib/chef/node.rb', line 416

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

.exists?(nodename, couchdb) ⇒ Boolean

Returns:

  • (Boolean)


370
371
372
373
374
375
376
# File 'lib/chef/node.rb', line 370

def self.exists?(nodename, couchdb)
  begin
    self.cdb_load(nodename, couchdb)
  rescue Chef::Exceptions::CouchDBNotFound
    nil
  end
end

.json_create(o) ⇒ Object

Create a Chef::Node from JSON



326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
# File 'lib/chef/node.rb', line 326

def self.json_create(o)
  node = new
  node.name(o["name"])
  o["attributes"].each { |k,v| node[k] = v }

  node.default_attrs = Mash.new(o["defaults"]) if o.has_key?("defaults")
  node.override_attrs = Mash.new(o["overrides"]) if o.has_key?("overrides")

  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.index_id = node.couchdb_id
  node
end

.list(inflate = false) ⇒ Object



353
354
355
356
357
358
359
360
361
362
363
# File 'lib/chef/node.rb', line 353

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

.load(name) ⇒ Object

Load a node by name



379
380
381
# File 'lib/chef/node.rb', line 379

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

Instance Method Details

#[](attrib) ⇒ Object

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



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

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

#[]=(attrib, value) ⇒ Object

Set an attribute of this node



202
203
204
# File 'lib/chef/node.rb', line 202

def []=(attrib, value)
  Chef::Node::Attribute.new(@attribute, @default_attrs, @override_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)


234
235
236
# File 'lib/chef/node.rb', line 234

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

#cdb_destroyObject

Remove this node from the CouchDB



384
385
386
# File 'lib/chef/node.rb', line 384

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

#cdb_saveObject

Save this node to the CouchDB



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

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

#chef_server_restObject



156
157
158
# File 'lib/chef/node.rb', line 156

def chef_server_rest
  Chef::REST.new(Chef::Config[:chef_server_url])
end

#consume_attributes(attrs) ⇒ Object



281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/chef/node.rb', line 281

def consume_attributes(attrs)
  attrs ||= {}
  Chef::Log.debug("Adding JSON Attributes")
  if new_run_list = attrs.delete("recipes") || attrs.delete("run_list")
    if attrs.key?("recipes") || attrs.key?("run_list")
      raise Chef::Exceptions::AmbiguousRunlistSpecification, "please set the node's run list using the 'run_list' attribute only."
    end
    Chef::Log.info("Replacing the run_list with #{new_run_list.inspect} from JSON")
    run_list(new_run_list)
  end
  Chef::Mixin::DeepMerge.merge(@attribute, attrs)

  self[:tags] = Array.new unless attribute?(:tags)
end

#createObject

Create the node via the REST API



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

def create
  chef_server_rest.post_rest("nodes", self)
  self
end

#destroyObject

Remove this node via the REST API



389
390
391
# File 'lib/chef/node.rb', line 389

def destroy
  chef_server_rest.delete_rest("nodes/#{@name}")
end

#each(&block) ⇒ Object

Yield each key of the top level to the block.



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

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

#each_attribute(&block) ⇒ Object

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



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

def each_attribute(&block)
  Chef::Node::Attribute.new(@attribute, @default_attrs, @override_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.

Raises:

  • (ArgumentError)


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

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

  [fqdn, hostname, "default"].each { |fname|
   node_file = File.join(Chef::Config[:node_path], "#{fname.to_s}.rb")
   return self.from_file(node_file) if File.exists?(node_file)
 }

  raise ArgumentError, "Cannot find a node matching #{fqdn}, not even with default.rb!"
end

#name(arg = nil) ⇒ Object

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



183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/chef/node.rb', line 183

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

#recipe?(recipe_name) ⇒ Boolean

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

Returns:

  • (Boolean)


256
257
258
# File 'lib/chef/node.rb', line 256

def recipe?(recipe_name)
  @run_list.include?(recipe_name) || @run_state[:seen_recipes].include?(recipe_name)
end

#recipes(*args) ⇒ Object



271
272
273
274
# File 'lib/chef/node.rb', line 271

def recipes(*args)
  Chef::Log.warn "Chef::Node#recipes method is deprecated.  Please use Chef::Node#run_list"
  run_list(*args)
end

#role?(role_name) ⇒ Boolean

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

Returns:

  • (Boolean)


261
262
263
# File 'lib/chef/node.rb', line 261

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)


277
278
279
# File 'lib/chef/node.rb', line 277

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

#saveObject

Save this node via the REST API



399
400
401
402
403
404
405
406
407
# File 'lib/chef/node.rb', line 399

def save
  begin
    chef_server_rest.put_rest("nodes/#{@name}", self)
  rescue Net::HTTPServerException => e
    raise e unless e.response.code == "404"
    chef_server_rest.post_rest("nodes", self)
  end
  self
end

#setObject

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



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

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



220
221
222
223
224
225
# File 'lib/chef/node.rb', line 220

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



206
207
208
# File 'lib/chef/node.rb', line 206

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

#to_hashObject

Transform the node to a Hash



297
298
299
300
301
302
303
304
305
306
307
308
# File 'lib/chef/node.rb', line 297

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



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

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



421
422
423
# File 'lib/chef/node.rb', line 421

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