Class: Chef::Node::Attribute

Inherits:
Mash
  • Object
show all
Includes:
Immutablize, 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__

Instance Method Summary collapse

Methods included from Mixin::StateTracking

#[]=

Methods included from Immutablize

#convert_value

Methods inherited from Mash

#[]=, #delete, #except, #fetch, from_hash, #initialize_copy, #internal_set, #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.



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

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)

  @deep_merge_cache = ImmutableMash.new({}, self, node, :merged)
  @__node__ = node
end

Instance Attribute Details

#automaticObject

return the automatic level attribute component



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

def automatic
  @automatic
end

#deep_merge_cacheObject (readonly)

return the immutablemash deep merge cache



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

def deep_merge_cache
  @deep_merge_cache
end

#defaultObject

return the cookbook level default attribute component



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

def default
  @default
end

#env_defaultObject

return the environment level default attribute component



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

def env_default
  @env_default
end

#env_overrideObject

return the enviroment level override attribute component



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

def env_override
  @env_override
end

#force_defaultObject

return the force_default level attribute component



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

def force_default
  @force_default
end

#force_overrideObject

return the force override level attribute component



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

def force_override
  @force_override
end

#normalObject

return the “normal” level attribute component



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

def normal
  @normal
end

#overrideObject

return the cookbook level override attribute component



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

def override
  @override
end

#role_defaultObject

return the role level default attribute component



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

def role_default
  @role_default
end

#role_overrideObject

return the role level override attribute component



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

def role_override
  @role_override
end

Instance Method Details

#[](key) ⇒ Object



500
501
502
# File 'lib/chef/node/attribute.rb', line 500

def [](key)
  @deep_merge_cache[key]
end

#combined_all(*path) ⇒ Object



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

def combined_all(*path)
  path.empty? ? self : read(*path)
end

#combined_default(*path) ⇒ Object



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

def combined_default(*path)
  merge_defaults(path)
end

#combined_override(*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’].



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

def combined_override(*path)
  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[: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.



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

def debug_value(*args)
  COMPONENTS.map do |component|
    value =
      begin
        instance_variable_get(component).read!(*args)
      rescue
        :not_present
      end
    [component.to_s.sub(/^@/, ""), value]
  end
end

#default!(*args) ⇒ Object

sets default attributes without merging

  • this API autovivifies (and cannot trainwreck)



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

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

#default_unless(*args) ⇒ Object



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

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)


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

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)



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

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



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

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)


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

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

#inspectObject



508
509
510
511
512
# File 'lib/chef/node/attribute.rb', line 508

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

#merged_attributesObject



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

def merged_attributes
  @deep_merge_cache
end

#normal!(*args) ⇒ Object

sets normal attributes without merging

  • this API autovivifies (and cannot trainwreck)



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

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

#normal_unless(*args) ⇒ Object



434
435
436
437
# File 'lib/chef/node/attribute.rb', line 434

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)



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

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

#override_unless(*args) ⇒ Object



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

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)



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

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

#read!(*path) ⇒ Object



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

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

#resetObject



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

def reset
  @deep_merge_cache = ImmutableMash.new({}, self, @__node__, :merged)
end

#reset_cache(*path) ⇒ Object



235
236
237
238
239
240
241
242
243
244
245
# File 'lib/chef/node/attribute.rb', line 235

def reset_cache(*path)
  if path.empty?
    reset
  else
    container = read(*path)
    case container
    when Hash, Array
      container.reset
    end
  end
end

#rm(*args) ⇒ Object

clears attributes from all precedence levels



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

def rm(*args)
  with_deep_merged_return_value(combined_all, *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



323
324
325
326
327
328
329
330
# File 'lib/chef/node/attribute.rb', line 323

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



337
338
339
# File 'lib/chef/node/attribute.rb', line 337

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



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

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



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

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



496
497
498
# File 'lib/chef/node/attribute.rb', line 496

def to_s
  merged_attributes.to_s
end


481
482
483
# File 'lib/chef/node/attribute.rb', line 481

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

#unlink!(level, *path) ⇒ Object



485
486
487
# File 'lib/chef/node/attribute.rb', line 485

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

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



473
474
475
# File 'lib/chef/node/attribute.rb', line 473

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

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



477
478
479
# File 'lib/chef/node/attribute.rb', line 477

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