Class: Chef::Node

Inherits:
Object show all
Extended by:
Forwardable
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

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.



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/chef/node.rb', line 58

def initialize()
  @name = nil

  @chef_environment = '_default'
  @normal_attrs = Mash.new
  @override_attrs = Mash.new
  @default_attrs = Mash.new
  @automatic_attrs = Mash.new
  @run_list = Chef::RunList.new

  @run_state = {
    :template_cache => Hash.new,
    :seen_recipes => Hash.new,
    :seen_attributes => Hash.new
  }
  # TODO: 5/20/2010 need this here as long as other objects try to access
  # the cookbook collection via Node, otherwise get NoMethodError on nil.
  @cookbook_collection = CookbookCollection.new
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(symbol, *args) ⇒ Object

Encouraged to only get used for lookups - while you can do sets from here, it’s not as explicit as using the normal/default/override interface.



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

def method_missing(symbol, *args)
  attrs = construct_attributes
  attrs.send(symbol, *args)
end

Instance Attribute Details

#automatic_attrsObject

Returns the value of attribute automatic_attrs.



45
46
47
# File 'lib/chef/node.rb', line 45

def automatic_attrs
  @automatic_attrs
end

#cookbook_collectionObject

TODO: 5/18/2010 cw/timh. cookbook_collection should be removed from here and for any place it’s needed, it should be accessed through a Chef::RunContext



50
51
52
# File 'lib/chef/node.rb', line 50

def cookbook_collection
  @cookbook_collection
end

#default_attrsObject

Returns the value of attribute default_attrs.



45
46
47
# File 'lib/chef/node.rb', line 45

def default_attrs
  @default_attrs
end

#normal_attrsObject

Returns the value of attribute normal_attrs.



45
46
47
# File 'lib/chef/node.rb', line 45

def normal_attrs
  @normal_attrs
end

#override_attrsObject

Returns the value of attribute override_attrs.



45
46
47
# File 'lib/chef/node.rb', line 45

def override_attrs
  @override_attrs
end

#recipe_listObject

Returns the value of attribute recipe_list.



44
45
46
# File 'lib/chef/node.rb', line 44

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.



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

def run_list
  @run_list
end

#run_stateObject

Returns the value of attribute run_state.



44
45
46
# File 'lib/chef/node.rb', line 44

def run_state
  @run_state
end

Class Method Details

.build(node_name) ⇒ Object



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

def self.build(node_name)
  node = new
  node.name(node_name)
  node.chef_environment(Chef::Config[:environment]) unless Chef::Config[:environment].nil? || Chef::Config[:environment].chop.empty?
  node
end

Instance Method Details

#[](attrib) ⇒ Object

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



138
139
140
# File 'lib/chef/node.rb', line 138

def [](attrib)
  construct_attributes[attrib]
end

#[]=(attrib, value) ⇒ Object

Set an attribute of this node



143
144
145
# File 'lib/chef/node.rb', line 143

def []=(attrib, value)
  construct_attributes[attrib] = value
end

#apply_expansion_attributes(expansion) ⇒ Object

Apply the default and overrides attributes from the expansion passed in, which came from roles.



338
339
340
341
342
343
344
345
346
# File 'lib/chef/node.rb', line 338

def apply_expansion_attributes(expansion)
  load_chef_environment_object = (chef_environment == "_default" ? nil : Chef::Environment.load(chef_environment))
  environment_default_attrs = load_chef_environment_object.nil? ? {} : load_chef_environment_object.default_attributes
  default_before_roles = Chef::Mixin::DeepMerge.merge(default_attrs, environment_default_attrs)
  @default_attrs = Chef::Mixin::DeepMerge.merge(default_before_roles, expansion.default_attrs)
  environment_override_attrs = load_chef_environment_object.nil? ? {} : load_chef_environment_object.override_attributes
  overrides_before_environments = Chef::Mixin::DeepMerge.merge(override_attrs, expansion.override_attrs)
  @override_attrs = Chef::Mixin::DeepMerge.merge(overrides_before_environments, environment_override_attrs)
end

#attributeObject

Used by the DSL



125
126
127
# File 'lib/chef/node.rb', line 125

def attribute
  construct_attributes
end

#attribute=(value) ⇒ Object



133
134
135
# File 'lib/chef/node.rb', line 133

def attribute=(value)
  self.normal_attrs = 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?()



216
217
218
# File 'lib/chef/node.rb', line 216

def attribute?(attrib)
  construct_attributes.attribute?(attrib)
end

#chef_environment(arg = nil) ⇒ Object



116
117
118
119
120
121
122
# File 'lib/chef/node.rb', line 116

def chef_environment(arg=nil)
  set_or_return(
    :chef_environment,
    arg,
    { :regex => /^[\-[:alnum:]_]+$/, :kind_of => String }
  )
end

#construct_attributesObject



129
130
131
# File 'lib/chef/node.rb', line 129

def construct_attributes
  Chef::Node::Attribute.new(normal_attrs, default_attrs, override_attrs, automatic_attrs)
end

#consume_attributes(attrs) ⇒ Object

Consumes the combined run_list and other attributes in attrs



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

def consume_attributes(attrs)
  normal_attrs_to_merge = consume_run_list(attrs)
  Chef::Log.debug("Applying attributes from json file")
  @normal_attrs = Chef::Mixin::DeepMerge.merge(@normal_attrs,normal_attrs_to_merge)
  self.tags # make sure they're defined
end

#consume_external_attrs(ohai_data, json_cli_attrs) ⇒ Object

Consume data from ohai and Attributes provided as JSON on the command line.



266
267
268
269
270
271
272
273
274
275
276
# File 'lib/chef/node.rb', line 266

def consume_external_attrs(ohai_data, json_cli_attrs)
  Chef::Log.debug("Extracting run list from JSON attributes provided on command line")
  consume_attributes(json_cli_attrs)

  @automatic_attrs = ohai_data

  platform, version = Chef::Platform.find_platform_and_version(self)
  Chef::Log.debug("Platform is #{platform} version #{version}")
  @automatic_attrs[:platform] = platform
  @automatic_attrs[:platform_version] = version
end

#consume_run_list(attrs) ⇒ Object

Extracts the run list from attrs and applies it. Returns the remaining attributes



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

def consume_run_list(attrs)
  attrs = attrs ? attrs.dup : {}
  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("Setting the run_list to #{new_run_list.inspect} from JSON")
    run_list(new_run_list)
  end
  attrs
end

#defaultObject

Set a default of this node, but auto-vivifiy any Mashes that might be missing



175
176
177
178
179
180
# File 'lib/chef/node.rb', line 175

def default
  attrs = construct_attributes
  attrs.set_type = :default
  attrs.auto_vivifiy_on_read = true
  attrs
end

#default_unlessObject

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



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

def default_unless
  attrs = construct_attributes
  attrs.set_type = :default
  attrs.auto_vivifiy_on_read = true
  attrs.set_unless_value_present = true
  attrs
end

#display_hashObject



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

def display_hash
  display = {}
  display["name"]             = name
  display["chef_environment"] = chef_environment
  display["automatic"]        = automatic_attrs
  display["normal"]           = normal_attrs
  display["default"]          = default_attrs
  display["override"]         = override_attrs
  display["run_list"]         = run_list.run_list
  display
end

#each(&block) ⇒ Object

Yield each key of the top level to the block.



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

def each(&block)
  construct_attributes.each(&block)
end

#each_attribute(&block) ⇒ Object

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



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

def each_attribute(&block)
  construct_attributes.each_attribute(&block)
end

#expand!(data_source = 'disk') ⇒ Object

Expands the node’s run list and sets the default and override attributes. Also applies stored attributes (from json provided on the command line)

Returns the fully-expanded list of recipes, a RunListExpansion.

– TODO: timh/cw, 5-14-2010: Should this method exist? Should we instead modify default_attrs and override_attrs whenever our run_list is mutated? Or perhaps do something smarter like on-demand generation of default_attrs and override_attrs, invalidated only when run_list is mutated?



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

def expand!(data_source = 'disk')
  expansion = run_list.expand(chef_environment, data_source)
  raise Chef::Exceptions::MissingRole if expansion.errors?

  self.tags # make sure they're defined

  @automatic_attrs[:recipes] = expansion.recipes
  @automatic_attrs[:roles] = expansion.roles

  expansion
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)


89
90
91
92
93
94
95
96
97
98
99
# File 'lib/chef/node.rb', line 89

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

#load_attribute_by_short_filename(name, src_cookbook_name) ⇒ Object

Used by DSL. Loads the attribute file specified by the short name of the file, e.g., loads specified cookbook’s

"attributes/mailservers.rb"

if passed

"mailservers"


429
430
431
432
433
434
435
436
437
438
# File 'lib/chef/node.rb', line 429

def load_attribute_by_short_filename(name, src_cookbook_name)
  src_cookbook = cookbook_collection[src_cookbook_name]
  raise Chef::Exceptions::CookbookNotFound, "could not find cookbook #{src_cookbook_name} while loading attribute #{name}" unless src_cookbook

  attribute_filename = src_cookbook.attribute_filenames_by_short_filename[name]
  raise Chef::Exceptions::AttributeNotFound, "could not find filename for attribute #{name} in cookbook #{src_cookbook_name}" unless attribute_filename

  self.from_file(attribute_filename)
  self
end

#load_attributesObject

Load all attribute files for all cookbooks associated with this node.



414
415
416
417
418
419
420
421
# File 'lib/chef/node.rb', line 414

def load_attributes
  cookbook_collection.values.each do |cookbook|
    cookbook.segment_filenames(:attributes).each do |segment_filename|
      Chef::Log.debug("Node #{name} loading cookbook #{cookbook.name}'s attribute file #{segment_filename}")
      self.from_file(segment_filename)
    end
  end
end

#name(arg = nil) ⇒ Object

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



102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/chef/node.rb', line 102

def name(arg=nil)
  if arg != nil
    validate(
             {:name => arg },
             {:name => { :kind_of => String,
                 :cannot_be => :blank,
                 :regex => /^[\-[:alnum:]_:.]+$/}
             })
    @name = arg
  else
    @name
  end
end

#nodeObject

Used by DSL



79
80
81
# File 'lib/chef/node.rb', line 79

def node
  self
end

#normalObject Also known as: set

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



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

def normal
  attrs = construct_attributes
  attrs.set_type = :normal
  attrs.auto_vivifiy_on_read = true
  attrs
end

#normal_unlessObject Also known as: set_unless

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



164
165
166
167
168
169
170
# File 'lib/chef/node.rb', line 164

def normal_unless
  attrs = construct_attributes
  attrs.set_type = :normal
  attrs.auto_vivifiy_on_read = true
  attrs.set_unless_value_present = true
  attrs
end

#overrideObject

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



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

def override
  attrs = construct_attributes
  attrs.set_type = :override
  attrs.auto_vivifiy_on_read = true
  attrs
end

#override_unlessObject

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



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

def override_unless
  attrs = construct_attributes
  attrs.set_type = :override
  attrs.auto_vivifiy_on_read = true
  attrs.set_unless_value_present = true
  attrs
end

#recipe?(recipe_name) ⇒ Boolean

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

First, the run list is consulted to see whether the recipe is explicitly included. If it’s not there, it looks in run_state, which is populated by include_recipe statements in the DSL (and thus would not be in the run list).

NOTE: It’s used by cookbook authors



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

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

#reset_defaults_and_overridesObject

Clear defaults and overrides, so that any deleted attributes between runs are still gone.



307
308
309
310
# File 'lib/chef/node.rb', line 307

def reset_defaults_and_overrides
  @default_attrs = Mash.new
  @override_attrs = Mash.new
end

#role?(role_name) ⇒ Boolean

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



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

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.



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

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

#store(attrib, value) ⇒ Object



147
148
149
# File 'lib/chef/node.rb', line 147

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

#tagsObject

Lazy initializer for tags attribute



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

def tags
  self[:tags] = [] unless attribute?(:tags)
  self[:tags]
end

#to_hashObject

Transform the node to a Hash



349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/chef/node.rb', line 349

def to_hash
  index_hash = Hash.new
  index_hash["chef_type"] = "node"
  index_hash["name"] = name
  index_hash["chef_environment"] = chef_environment
  attribute.each do |key, value|
    index_hash[key] = value
  end
  index_hash["recipe"] = run_list.recipe_names if run_list.recipe_names.length > 0
  index_hash["role"] = run_list.role_names if run_list.role_names.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



376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'lib/chef/node.rb', line 376

def to_json(*a)
  result = {
    "name" => name,
    "chef_environment" => chef_environment,
    'json_class' => self.class.name,
    "automatic" => automatic_attrs,
    "normal" => normal_attrs,
    "chef_type" => "node",
    "default" => default_attrs,
    "override" => override_attrs,
    "run_list" => run_list.run_list
  }
  result.to_json(*a)
end

#to_sObject



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

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

#update_from!(o) ⇒ Object



391
392
393
394
395
396
397
398
399
# File 'lib/chef/node.rb', line 391

def update_from!(o)
  run_list.reset!(o.run_list)
  @automatic_attrs = o.automatic_attrs
  @normal_attrs = o.normal_attrs
  @override_attrs = o.override_attrs
  @default_attrs = o.default_attrs
  chef_environment(o.chef_environment)
  self
end