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.

%i{
  @default
  @env_default
  @role_default
  @force_default
  @normal
  @override
  @role_override
  @env_override
  @force_override
  @automatic
}.freeze
DEFAULT_COMPONENTS =
%i{
  @default
  @env_default
  @role_default
  @force_default
}.freeze
OVERRIDE_COMPONENTS =
%i{
  @override
  @role_override
  @env_override
  @force_override
}.freeze
ENUM_METHODS =
%i{
  all?
  any?
  assoc
  chunk
  collect
  collect_concat
  compare_by_identity
  compare_by_identity?
  count
  cycle
  detect
  drop
  drop_while
  each
  each_cons
  each_entry
  each_key
  each_pair
  each_slice
  each_value
  each_with_index
  each_with_object
  empty?
  entries
  except
  fetch
  find
  find_all
  find_index
  first
  flat_map
  flatten
  grep
  group_by
  has_value?
  include?
  index
  inject
  invert
  key
  keys
  length
  map
  max
  max_by
  merge
  min
  min_by
  minmax
  minmax_by
  none?
  one?
  partition
  rassoc
  reduce
  reject
  reverse_each
  select
  size
  slice_before
  sort
  sort_by
  store
  symbolize_keys
  take
  take_while
  to_a
  to_h
  to_hash
  to_json
  to_set
  to_yaml
  value?
  values
  values_at
  zip
}.freeze

Constants included from Mixin::ImmutablizeHash

Mixin::ImmutablizeHash::ALLOWED_METHODS, 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

#convert_value, #immutablize

Constructor Details

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

Returns a new instance of Attribute.



198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/chef/node/attribute.rb', line 198

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



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

def automatic
  @automatic
end

#defaultObject

return the cookbook level default attribute component



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

def default
  @default
end

#env_defaultObject

return the environment level default attribute component



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

def env_default
  @env_default
end

#env_overrideObject

return the environment level override attribute component



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

def env_override
  @env_override
end

#force_defaultObject

return the force_default level attribute component



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

def force_default
  @force_default
end

#force_overrideObject

return the force override level attribute component



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

def force_override
  @force_override
end

#normalObject

return the “normal” level attribute component



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

def normal
  @normal
end

#overrideObject

return the cookbook level override attribute component



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

def override
  @override
end

#role_defaultObject

return the role level default attribute component



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

def role_default
  @role_default
end

#role_overrideObject

return the role level override attribute component



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

def role_override
  @role_override
end

Instance Method Details

#combined_default(*path) ⇒ Object



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

def combined_default(*path)
  ret = merge_defaults(path)
  ret == NIL ? nil : ret
end

#combined_override(*path) ⇒ Object



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

def combined_override(*path)
  ret = merge_overrides(path)
  ret == NIL ? nil : ret
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.



225
226
227
228
229
230
231
232
233
234
235
# File 'lib/chef/node/attribute.rb', line 225

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)



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

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

  write(:default, *args)
end

#default_unless(*args) ⇒ Object



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

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)


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

def exist?(*path)
  if path[0].nil?
    true
  else
    self[path[0]] unless path[0].nil? # force deep_merge_cache key construction if necessary
    deep_merge_cache.exist?(*path)
  end
end

#force_default!(*args) ⇒ Object

clears from all default precedence levels and then sets force_default

  • this API autovivifies (and cannot trainwreck)



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

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



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

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)


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

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

#inspectObject



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

def inspect
  "#<#{self.class} " << (COMPONENTS + %i{@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’].



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

def merged_attributes(*path)
  merge_all(path)
end

#normal!(*args) ⇒ Object

sets normal attributes without merging

  • this API autovivifies (and cannot trainwreck)



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

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

  write(:normal, *args)
end

#normal_unless(*args) ⇒ Object



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

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)



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

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

  write(:override, *args)
end

#override_unless(*args) ⇒ Object



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

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 Also known as: dig

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



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

def read(*path)
  if path[0].nil?
    Chef::Log.warn "Calling node.read() without any path argument is very slow, probably a bug, and should be avoided"
    merged_attributes.read(*path) # re-merges everything, slow edge case
  else
    self[path[0]] unless path[0].nil? # force deep_merge_cache key construction if necessary
    deep_merge_cache.read(*path)
  end
end

#read!(*path) ⇒ Object



466
467
468
469
470
471
472
473
474
# File 'lib/chef/node/attribute.rb', line 466

def read!(*path)
  if path[0].nil?
    Chef::Log.warn "Calling node.read!() without any path argument is very slow, probably a bug, and should be avoided"
    merged_attributes.read!(*path) # re-merges everything, slow edge case
  else
    self[path[0]] unless path[0].nil? # force deep_merge_cache key construction if necessary
    deep_merge_cache.read!(*path)
  end
end

#rm(*args) ⇒ Object

clears attributes from all precedence levels



300
301
302
303
304
305
306
# File 'lib/chef/node/attribute.rb', line 300

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



313
314
315
316
317
318
319
320
# File 'lib/chef/node/attribute.rb', line 313

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



327
328
329
# File 'lib/chef/node/attribute.rb', line 327

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



336
337
338
339
340
341
342
343
# File 'lib/chef/node/attribute.rb', line 336

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

#to_sObject



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

def to_s
  merged_attributes.to_s
end


493
494
495
# File 'lib/chef/node/attribute.rb', line 493

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

#unlink!(level, *path) ⇒ Object



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

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

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



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

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

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



489
490
491
# File 'lib/chef/node/attribute.rb', line 489

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