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

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


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

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

#combined_override(*path) ⇒ Object


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

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
# File 'lib/chef/node/attribute.rb', line 217

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)

354
355
356
357
# File 'lib/chef/node/attribute.rb', line 354

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

#default_unless(*args) ⇒ Object


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

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)

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

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)

378
379
380
381
382
383
# File 'lib/chef/node/attribute.rb', line 378

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


386
387
388
389
390
391
# File 'lib/chef/node/attribute.rb', line 386

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)

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

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

#inspectObject


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

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['foo']['bar']['baz'], but in practice we currently always compute all of node['foo'] even if the user only requires node['foo']['bar']['baz'].


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

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

#normal!(*args) ⇒ Object

sets normal attributes without merging

  • this API autovivifies (and cannot trainwreck)

362
363
364
365
# File 'lib/chef/node/attribute.rb', line 362

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

#normal_unless(*args) ⇒ Object


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

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)

370
371
372
373
# File 'lib/chef/node/attribute.rb', line 370

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

#override_unless(*args) ⇒ Object


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

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)


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

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

#read!(*path) ⇒ Object


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

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

#rm(*args) ⇒ Object

clears attributes from all precedence levels


292
293
294
295
296
297
298
# File 'lib/chef/node/attribute.rb', line 292

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!['foo']['bar'].delete('baz')

  • does not autovivify
  • does not trainwreck if interior keys do not exist

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

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!['foo']['bar'].delete('baz')

  • does not autovivify
  • does not trainwreck if interior keys do not exist

319
320
321
# File 'lib/chef/node/attribute.rb', line 319

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

#rm_override(*args) ⇒ Object

clears attributes from all override precedence levels

equivalent to: force_override!['foo']['bar'].delete('baz')

  • does not autovivify
  • does not trainwreck if interior keys do not exist

328
329
330
331
332
333
334
335
# File 'lib/chef/node/attribute.rb', line 328

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


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

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


475
476
477
# File 'lib/chef/node/attribute.rb', line 475

def to_s
  merged_attributes.to_s
end

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

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

#unlink!(level, *path) ⇒ Object


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

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

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


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

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

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


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

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