Class: Chef::Node::Attribute

Inherits:
Mash
  • Object
show all
Includes:
Immutablize, Mixin::DeepMergeCache, Mixin::ImmutablizeHash, Mixin::StateTracking, Enumerable
Defined in:
lib/chef/node/attribute.rb

Overview

Attribute

Attribute implements a nested key-value (Hash) and flat collection (Array) data structure supporting multiple levels of precedence, such that a given key may have multiple values internally, but will only return the highest precedence value when reading.

Constant Summary collapse

COMPONENTS =

List of the component attribute hashes, in order of precedence, low to high.

[
  :@default,
  :@env_default,
  :@role_default,
  :@force_default,
  :@normal,
  :@override,
  :@role_override,
  :@env_override,
  :@force_override,
  :@automatic,
].freeze
DEFAULT_COMPONENTS =
[
  :@default,
  :@env_default,
  :@role_default,
  :@force_default,
]
OVERRIDE_COMPONENTS =
[
  :@override,
  :@role_override,
  :@env_override,
  :@force_override,
]

Constants included from Mixin::ImmutablizeHash

Mixin::ImmutablizeHash::DISALLOWED_MUTATOR_METHODS

Instance Attribute Summary collapse

Attributes included from Mixin::StateTracking

#__node__, #__path__, #__precedence__, #__root__

Attributes included from Mixin::DeepMergeCache

#deep_merge_cache

Instance Method Summary collapse

Methods included from Mixin::StateTracking

#[], #[]=

Methods included from Mixin::DeepMergeCache

#[], #reset_cache

Methods included from Immutablize

#immutablize

Methods inherited from Mash

#[]=, #delete, #except, #fetch, from_hash, #initialize_copy, #merge, #regular_update, #regular_writer, #stringify_keys!, #symbolize_keys, #to_hash, #update, #values_at

Constructor Details

#initialize(normal, default, override, automatic, node = nil) ⇒ Attribute

Returns a new instance of Attribute.



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/chef/node/attribute.rb', line 190

def initialize(normal, default, override, automatic, node = nil)
  @default        = VividMash.new(default, self, node, :default)
  @env_default    = VividMash.new({}, self, node, :env_default)
  @role_default   = VividMash.new({}, self, node, :role_default)
  @force_default  = VividMash.new({}, self, node, :force_default)

  @normal         = VividMash.new(normal, self, node, :normal)

  @override       = VividMash.new(override, self, node, :override)
  @role_override  = VividMash.new({}, self, node, :role_override)
  @env_override   = VividMash.new({}, self, node, :env_override)
  @force_override = VividMash.new({}, self, node, :force_override)

  @automatic      = VividMash.new(automatic, self, node, :automatic)

  super(nil, self, node, :merged)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(symbol, *args) ⇒ Object



479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
# File 'lib/chef/node/attribute.rb', line 479

def method_missing(symbol, *args)
  if symbol == :to_ary
    merged_attributes.send(symbol, *args)
  elsif args.empty?
    Chef.deprecated(:attributes, %q{method access to node attributes (node.foo.bar) is deprecated and will be removed in Chef 13, please use bracket syntax (node["foo"]["bar"])})
    if key?(symbol)
      self[symbol]
    else
      raise NoMethodError, "Undefined method or attribute `#{symbol}' on `node'"
    end
  elsif symbol.to_s =~ /=$/
    Chef.deprecated(:attributes, %q{method setting of node attributes (node.foo="bar") is deprecated and will be removed in Chef 13, please use bracket syntax (node["foo"]="bar")})
    key_to_set = symbol.to_s[/^(.+)=$/, 1]
    self[key_to_set] = (args.length == 1 ? args[0] : args)
  else
    raise NoMethodError, "Undefined node attribute or method `#{symbol}' on `node'"
  end
end

Instance Attribute Details

#automaticObject

return the automatic level attribute component



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

def automatic
  @automatic
end

#defaultObject

return the cookbook level default attribute component



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

def default
  @default
end

#env_defaultObject

return the environment level default attribute component



167
168
169
# File 'lib/chef/node/attribute.rb', line 167

def env_default
  @env_default
end

#env_overrideObject

return the enviroment level override attribute component



182
183
184
# File 'lib/chef/node/attribute.rb', line 182

def env_override
  @env_override
end

#force_defaultObject

return the force_default level attribute component



170
171
172
# File 'lib/chef/node/attribute.rb', line 170

def force_default
  @force_default
end

#force_overrideObject

return the force override level attribute component



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

def force_override
  @force_override
end

#normalObject

return the “normal” level attribute component



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

def normal
  @normal
end

#overrideObject

return the cookbook level override attribute component



176
177
178
# File 'lib/chef/node/attribute.rb', line 176

def override
  @override
end

#role_defaultObject

return the role level default attribute component



164
165
166
# File 'lib/chef/node/attribute.rb', line 164

def role_default
  @role_default
end

#role_overrideObject

return the role level override attribute component



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

def role_override
  @role_override
end

Instance Method Details

#combined_default(*path) ⇒ Object



413
414
415
# File 'lib/chef/node/attribute.rb', line 413

def combined_default(*path)
  immutablize(merge_defaults(path))
end

#combined_override(*path) ⇒ Object



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

def combined_override(*path)
  immutablize(merge_overrides(path))
end

#debug_value(*args) ⇒ Object

Debug what’s going on with an attribute. args is a path spec to the attribute you’re interested in. For example, to debug where the value of node[:network][:default_interface] is coming from, use:

debug_value(:network, :default_interface).

The return value is an Array of Arrays. The Arrays are pairs of ‘[“precedence_level”, value]`, where precedence level is the component, such as role default, normal, etc. and value is the attribute value set at that precedence level. If there is no value at that precedence level, value will be the symbol :not_present.



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/chef/node/attribute.rb', line 217

def debug_value(*args)
  COMPONENTS.map do |component|
    ivar = instance_variable_get(component)
    value = args.inject(ivar) do |so_far, key|
      if so_far == :not_present
        :not_present
      elsif so_far.has_key?(key)
        so_far[key]
      else
        :not_present
      end
    end
    [component.to_s.sub(/^@/, ""), value]
  end
end

#default!(*args) ⇒ Object

sets default attributes without merging

  • this API autovivifies (and cannot trainwreck)



358
359
360
361
# File 'lib/chef/node/attribute.rb', line 358

def default!(*args)
  return Decorator::Unchain.new(self, :default!) unless args.length > 0
  write(:default, *args)
end

#default_unless(*args) ⇒ Object



422
423
424
425
# File 'lib/chef/node/attribute.rb', line 422

def default_unless(*args)
  return Decorator::Unchain.new(self, :default_unless) unless args.length > 0
  write(:default, *args) if default.read(*args[0...-1]).nil?
end

#exist?(*path) ⇒ Boolean

Returns:

  • (Boolean)


452
453
454
# File 'lib/chef/node/attribute.rb', line 452

def exist?(*path)
  merged_attributes.exist?(*path)
end

#force_default!(*args) ⇒ Object

clears from all default precedence levels and then sets force_default

  • this API autovivifies (and cannot trainwreck)



382
383
384
385
386
387
# File 'lib/chef/node/attribute.rb', line 382

def force_default!(*args)
  return Decorator::Unchain.new(self, :force_default!) unless args.length > 0
  value = args.pop
  rm_default(*args)
  write(:force_default, *args, value)
end

#force_override!(*args) ⇒ Object

clears from all override precedence levels and then sets force_override



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

def force_override!(*args)
  return Decorator::Unchain.new(self, :force_override!) unless args.length > 0
  value = args.pop
  rm_override(*args)
  write(:force_override, *args, value)
end

#has_key?(key) ⇒ Boolean Also known as: attribute?, member?, include?, key?

Returns:

  • (Boolean)


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

def has_key?(key)
  COMPONENTS.any? do |component_ivar|
    instance_variable_get(component_ivar).has_key?(key)
  end
end

#inspectObject



502
503
504
505
506
# File 'lib/chef/node/attribute.rb', line 502

def inspect
  "#<#{self.class} " << (COMPONENTS + [:@merged_attributes, :@properties]).map do |iv|
    "#{iv}=#{instance_variable_get(iv).inspect}"
  end.join(", ") << ">"
end

#merged_attributes(*path) ⇒ Object

Accessing merged attributes.

Note that merged_attributes(‘foo’, ‘bar’, ‘baz’) can be called to compute only the deep merge of node[‘bar’], but in practice we currently always compute all of node even if the user only requires node[’bar’].



405
406
407
# File 'lib/chef/node/attribute.rb', line 405

def merged_attributes(*path)
  immutablize(merge_all(path))
end

#normal!(*args) ⇒ Object

sets normal attributes without merging

  • this API autovivifies (and cannot trainwreck)



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

def normal!(*args)
  return Decorator::Unchain.new(self, :normal!) unless args.length > 0
  write(:normal, *args)
end

#normal_unless(*args) ⇒ Object



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

def normal_unless(*args)
  return Decorator::Unchain.new(self, :normal_unless) unless args.length > 0
  write(:normal, *args) if normal.read(*args[0...-1]).nil?
end

#override!(*args) ⇒ Object

sets override attributes without merging

  • this API autovivifies (and cannot trainwreck)



374
375
376
377
# File 'lib/chef/node/attribute.rb', line 374

def override!(*args)
  return Decorator::Unchain.new(self, :override!) unless args.length > 0
  write(:override, *args)
end

#override_unless(*args) ⇒ Object



427
428
429
430
# File 'lib/chef/node/attribute.rb', line 427

def override_unless(*args)
  return Decorator::Unchain.new(self, :override_unless) unless args.length > 0
  write(:override, *args) if override.read(*args[0...-1]).nil?
end

#read(*path) ⇒ Object

method-style access to attributes (has to come after the prepended ImmutablizeHash)



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

def read(*path)
  merged_attributes.read(*path)
end

#read!(*path) ⇒ Object



448
449
450
# File 'lib/chef/node/attribute.rb', line 448

def read!(*path)
  merged_attributes.read!(*path)
end

#rm(*args) ⇒ Object

clears attributes from all precedence levels



296
297
298
299
300
301
302
# File 'lib/chef/node/attribute.rb', line 296

def rm(*args)
  with_deep_merged_return_value(self, *args) do
    rm_default(*args)
    rm_normal(*args)
    rm_override(*args)
  end
end

#rm_default(*args) ⇒ Object

clears attributes from all default precedence levels

similar to: force_default![‘bar’].delete(‘baz’)

  • does not autovivify

  • does not trainwreck if interior keys do not exist



309
310
311
312
313
314
315
316
# File 'lib/chef/node/attribute.rb', line 309

def rm_default(*args)
  with_deep_merged_return_value(combined_default, *args) do
    default.unlink(*args)
    role_default.unlink(*args)
    env_default.unlink(*args)
    force_default.unlink(*args)
  end
end

#rm_normal(*args) ⇒ Object

clears attributes from normal precedence

equivalent to: normal![‘bar’].delete(‘baz’)

  • does not autovivify

  • does not trainwreck if interior keys do not exist



323
324
325
# File 'lib/chef/node/attribute.rb', line 323

def rm_normal(*args)
  normal.unlink(*args)
end

#rm_override(*args) ⇒ Object

clears attributes from all override precedence levels

equivalent to: force_override![‘bar’].delete(‘baz’)

  • does not autovivify

  • does not trainwreck if interior keys do not exist



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

def rm_override(*args)
  with_deep_merged_return_value(combined_override, *args) do
    override.unlink(*args)
    role_override.unlink(*args)
    env_override.unlink(*args)
    force_override.unlink(*args)
  end
end

#set_unless(*args) ⇒ Object



432
433
434
435
# File 'lib/chef/node/attribute.rb', line 432

def set_unless(*args)
  Chef.deprecated(:attributes, "node.set_unless is deprecated and will be removed in Chef 14, please use node.default_unless/node.override_unless (or node.normal_unless if you really need persistence)")
  normal_unless(*args)
end

#to_sObject



498
499
500
# File 'lib/chef/node/attribute.rb', line 498

def to_s
  merged_attributes.to_s
end


464
465
466
# File 'lib/chef/node/attribute.rb', line 464

def unlink(level, *path)
  self.send(level).unlink(*path)
end

#unlink!(level, *path) ⇒ Object



468
469
470
# File 'lib/chef/node/attribute.rb', line 468

def unlink!(level, *path)
  self.send(level).unlink!(*path)
end

#write(level, *args, &block) ⇒ Object



456
457
458
# File 'lib/chef/node/attribute.rb', line 456

def write(level, *args, &block)
  self.send(level).write(*args, &block)
end

#write!(level, *args, &block) ⇒ Object



460
461
462
# File 'lib/chef/node/attribute.rb', line 460

def write!(level, *args, &block)
  self.send(level).write!(*args, &block)
end