Class: Chef::Node

Inherits:
Object show all
Extended by:
Forwardable
Includes:
DSL::IncludeAttribute, DSL::PlatformIntrospection, Mixin::FromFile, Mixin::ParamsValidate
Defined in:
lib/chef/node.rb,
lib/chef/node/attribute.rb,
lib/chef/node/immutable_collections.rb,
lib/chef/node/attribute_collections.rb

Defined Under Namespace

Modules: Immutablize Classes: AttrArray, Attribute, ImmutableArray, ImmutableMash, VividMash

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

Methods included from Mixin::ParamsValidate

#lazy, #set_or_return, #validate

Methods included from DSL::PlatformIntrospection

#platform?, #platform_family?, #value_for_platform, #value_for_platform_family

Methods included from DSL::IncludeAttribute

#include_attribute, #parse_attribute_file_spec

Methods included from Mixin::FromFile

#class_from_file, #from_file

Constructor Details

- (Node) initialize

Create a new Chef::Node object.



63
64
65
66
67
68
69
70
71
72
73
# File 'lib/chef/node.rb', line 63

def initialize
  @name = nil

  @chef_environment = '_default'
  @primary_runlist = Chef::RunList.new
  @override_runlist = Chef::RunList.new

  @attributes = Chef::Node::Attribute.new({}, {}, {}, {})

  @run_state = {}
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

- (Object) method_missing(symbol, *args)

Only works for attribute fetches, setting is no longer supported



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

def method_missing(symbol, *args)
  attributes.send(symbol, *args)
end

Instance Attribute Details

- (Object) override_runlist(*args)

Returns the value of attribute override_runlist



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

def override_runlist
  @override_runlist
end

- (Object) recipe_list

Returns the value of attribute recipe_list



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

def recipe_list
  @recipe_list
end

- (Object) run_context

RunContext will set itself as run_context via this setter when initialized. This is needed so DSL::IncludeAttribute (in particular, #include_recipe) can access the run_context to determine if an attributes file has been seen yet. – TODO: This is a pretty ugly way to solve that problem.



54
55
56
# File 'lib/chef/node.rb', line 54

def run_context
  @run_context
end

- (Object) run_state

Returns the value of attribute run_state



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

def run_state
  @run_state
end

Class Method Details

+ (Object) build(node_name)



499
500
501
502
503
504
# File 'lib/chef/node.rb', line 499

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].chomp.empty?
  node
end

+ (Object) find_or_create(node_name)



491
492
493
494
495
496
497
# File 'lib/chef/node.rb', line 491

def self.find_or_create(node_name)
  load(node_name)
rescue Net::HTTPServerException => e
  raise unless e.response.code == '404'
  node = build(node_name)
  node.create
end

+ (Object) json_create(o)

Create a Chef::Node from JSON



449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
# File 'lib/chef/node.rb', line 449

def self.json_create(o)
  node = new
  node.name(o["name"])
  node.chef_environment(o["chef_environment"])
  if o.has_key?("attributes")
    node.normal_attrs = o["attributes"]
  end
  node.automatic_attrs = Mash.new(o["automatic"]) if o.has_key?("automatic")
  node.normal_attrs = Mash.new(o["normal"]) if o.has_key?("normal")
  node.default_attrs = Mash.new(o["default"]) if o.has_key?("default")
  node.override_attrs = Mash.new(o["override"]) if o.has_key?("override")

  if o.has_key?("run_list")
    node.run_list.reset!(o["run_list"])
  else
    o["recipes"].each { |r| node.recipes << r }
  end
  node
end

+ (Object) list(inflate = false)



479
480
481
482
483
484
485
486
487
488
489
# File 'lib/chef/node.rb', line 479

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

+ (Object) list_by_environment(environment, inflate = false)



469
470
471
472
473
474
475
476
477
# File 'lib/chef/node.rb', line 469

def self.list_by_environment(environment, inflate=false)
  if inflate
    response = Hash.new
    Chef::Search::Query.new.search(:node, "chef_environment:#{environment}") {|n| response[n.name] = n unless n.nil?}
    response
  else
    Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("environments/#{environment}/nodes")
  end
end

+ (Object) load(name)

Load a node by name



507
508
509
# File 'lib/chef/node.rb', line 507

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

Instance Method Details

- (Object) <=>(other_node)



543
544
545
# File 'lib/chef/node.rb', line 543

def <=>(other_node)
  self.name <=> other_node.name
end

- (Object) [](attrib)

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



121
122
123
# File 'lib/chef/node.rb', line 121

def [](attrib)
  attributes[attrib]
end

- (Object) apply_expansion_attributes(expansion)

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



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

def apply_expansion_attributes(expansion)
  loaded_environment = if chef_environment == "_default"
                         Chef::Environment.new.tap {|e| e.name("_default")}
                       else
                         Chef::Environment.load(chef_environment)
                       end

  attributes.env_default = loaded_environment.default_attributes
  attributes.env_override = loaded_environment.override_attributes

  attribute.role_default = expansion.default_attrs
  attributes.role_override = expansion.override_attrs
end

- (Boolean) attribute?(attrib)

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?()



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

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

- (Object) attributes Also known as: attribute, construct_attributes



113
114
115
# File 'lib/chef/node.rb', line 113

def attributes
  @attributes
end

- (Object) automatic_attrs



209
210
211
# File 'lib/chef/node.rb', line 209

def automatic_attrs
  attributes.automatic
end

- (Object) automatic_attrs=(new_values)



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

def automatic_attrs=(new_values)
  attributes.automatic = new_values
end

- (Object) chef_environment(arg = nil) Also known as: environment



99
100
101
102
103
104
105
# File 'lib/chef/node.rb', line 99

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

- (Object) chef_environment=(environment)



107
108
109
# File 'lib/chef/node.rb', line 107

def chef_environment=(environment)
  chef_environment(environment)
end

- (Object) chef_server_rest



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

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

- (Object) consume_attributes(attrs)

Consumes the combined run_list and other attributes in attrs



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

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

- (Object) consume_external_attrs(ohai_data, json_cli_attrs)

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



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

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)

  self.automatic_attrs = ohai_data

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

- (Object) consume_run_list(attrs)

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



329
330
331
332
333
334
335
336
337
338
339
# File 'lib/chef/node.rb', line 329

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 CLI options")
    run_list(new_run_list)
  end
  attrs
end

- (Object) create

Create the node via the REST API



534
535
536
537
# File 'lib/chef/node.rb', line 534

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

- (Object) default

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



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

def default
  attributes.set_unless_value_present = false
  attributes.default
end

- (Object) default!

Set a force default attribute. Intermediate mashes will be created by auto-vivify if necessary.



151
152
153
154
# File 'lib/chef/node.rb', line 151

def default!
  attributes.set_unless_value_present = false
  attributes.default!
end

- (Object) default_attrs



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

def default_attrs
  attributes.default
end

- (Object) default_attrs=(new_values)



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

def default_attrs=(new_values)
  attributes.default = new_values
end

- (Object) default_unless

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



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

def default_unless
  attributes.set_unless_value_present = true
  attributes.default
end

- (Object) destroy

Remove this node via the REST API



512
513
514
# File 'lib/chef/node.rb', line 512

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

- (Object) display_hash



405
406
407
408
409
410
411
412
413
414
415
# File 'lib/chef/node.rb', line 405

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

- (Object) each(&block)

Yield each key of the top level to the block.



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

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

- (Object) each_attribute(&block)

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



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

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

- (Object) expand!(data_source = 'server')

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?



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

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

  self.tags # make sure they're defined

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

  apply_expansion_attributes(expansion)

  expansion
end

- (Object) for_json



422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
# File 'lib/chef/node.rb', line 422

def for_json
  result = {
    "name" => name,
    "chef_environment" => chef_environment,
    'json_class' => self.class.name,
    "automatic" => attributes.automatic,
    "normal" => attributes.normal,
    "chef_type" => "node",
    "default" => attributes.combined_default,
    "override" => attributes.combined_override,
    #Render correctly for run_list items so malformed json does not result
    "run_list" => @primary_runlist.run_list.map { |item| item.to_s }
  }
  result
end

- (Object) loaded_recipe(cookbook, recipe)

used by include_recipe to add recipes to the expanded run_list to be saved back to the node and be searchable



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

def loaded_recipe(cookbook, recipe)
  fully_qualified_recipe = "#{cookbook}::#{recipe}"
  automatic_attrs[:recipes] << fully_qualified_recipe unless Array(self[:recipes]).include?(fully_qualified_recipe)
end

- (Object) name(arg = nil)

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



85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/chef/node.rb', line 85

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

- (Object) node

Used by DSL



76
77
78
# File 'lib/chef/node.rb', line 76

def node
  self
end

- (Object) normal Also known as: set

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



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

def normal
  attributes.set_unless_value_present = false
  attributes.normal
end

- (Object) normal_attrs



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

def normal_attrs
  attributes.normal
end

- (Object) normal_attrs=(new_values)



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

def normal_attrs=(new_values)
  attributes.normal = new_values
end

- (Object) normal_unless Also known as: set_unless

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



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

def normal_unless
  attributes.set_unless_value_present = true
  attributes.normal
end

- (Object) override

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



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

def override
  attributes.set_unless_value_present = false
  attributes.override
end

- (Object) override!

Set a force override attribute. Intermediate mashes will be created by auto-vivify if needed.



172
173
174
175
# File 'lib/chef/node.rb', line 172

def override!
  attributes.set_unless_value_present = false
  attributes.override!
end

- (Object) override_attrs



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

def override_attrs
 attributes.override
end

- (Object) override_attrs=(new_values)



189
190
191
# File 'lib/chef/node.rb', line 189

def override_attrs=(new_values)
  attributes.override = new_values
end

- (Object) override_unless

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



179
180
181
182
# File 'lib/chef/node.rb', line 179

def override_unless
  attributes.set_unless_value_present = true
  attributes.override
end

- (Object) primary_runlist



264
265
266
# File 'lib/chef/node.rb', line 264

def primary_runlist
  @primary_runlist
end

- (Boolean) recipe?(recipe_name)

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 `node`, which is populated when the run_list is expanded

NOTE: It's used by cookbook authors



248
249
250
# File 'lib/chef/node.rb', line 248

def recipe?(recipe_name)
  run_list.include?(recipe_name) || Array(self[:recipes]).include?(recipe_name)
end

- (Object) reset_defaults_and_overrides

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



343
344
345
346
# File 'lib/chef/node.rb', line 343

def reset_defaults_and_overrides
  self.default.clear
  self.override.clear
end

- (Boolean) role?(role_name)

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



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

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

- (Object) run_list(*args)

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.



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

def run_list(*args)
  rl = select_run_list
  args.length > 0 ? rl.reset!(args) : rl
end

- (Object) run_list=(list)



283
284
285
286
# File 'lib/chef/node.rb', line 283

def run_list=(list)
  rl = select_run_list
  rl = list
end

- (Boolean) run_list?(item)

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



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

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

- (Object) save

Save this node via the REST API



517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
# File 'lib/chef/node.rb', line 517

def save
  # Try PUT. If the node doesn't yet exist, PUT will return 404,
  # so then POST to create.
  begin
    if Chef::Config[:why_run]
      Chef::Log.warn("In whyrun mode, so NOT performing node save.")
    else
      chef_server_rest.put_rest("nodes/#{name}", data_for_save)
    end
  rescue Net::HTTPServerException => e
    raise e unless e.response.code == "404"
    chef_server_rest.post_rest("nodes", data_for_save)
  end
  self
end

- (Object) select_run_list



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

def select_run_list
  @override_runlist.empty? ? @primary_runlist : @override_runlist
end

- (Object) tag(*tags)



320
321
322
323
324
325
326
# File 'lib/chef/node.rb', line 320

def tag(*tags)
  tags.each do |tag|
    self.normal[:tags].push(tag.to_s) unless self[:tags].include? tag.to_s
  end

  self[:tags]
end

- (Object) tags

Lazy initializer for tags attribute



315
316
317
318
# File 'lib/chef/node.rb', line 315

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

- (Object) to_hash

Transform the node to a Hash



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

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

- (Object) to_json(*a)

Serialize this object as a hash



418
419
420
# File 'lib/chef/node.rb', line 418

def to_json(*a)
  for_json.to_json(*a)
end

- (Object) to_s



539
540
541
# File 'lib/chef/node.rb', line 539

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

- (Object) update_from!(o)



438
439
440
441
442
443
444
445
446
# File 'lib/chef/node.rb', line 438

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