module Facter

Aggregates provide a mechanism for facts to be resolved in multiple steps.

Aggregates are evaluated in two parts: generating individual chunks and then aggregating all chunks together. Each chunk is a block of code that generates a value, and may depend on other chunks when it runs. After all chunks have been evaluated they are passed to the aggregate block as Hash<name, result>. The aggregate block converts the individual chunks into a single value that is returned as the final value of the aggregate.

@api public @since 2.0.0

This class represents a fact. Each fact has a name and multiple {Facter::Util::Resolution resolutions}.

Create facts using {Facter.add}

@api public

This represents a fact resolution. A resolution is a concrete implementation of a fact. A single fact can have many resolutions and the correct resolution will be chosen at runtime. Each time {Facter.add} is called, a new resolution is created and added to the set of resolutions for the fact named in the call. Each resolution has a {#has_weight weight}, which defines its priority over other resolutions, and a set of {#confine confinements}, which defines the conditions under which it will be chosen. All confinements must be satisfied for a fact to be considered suitable.

@api public

CuAt (Customized Attributes) non-default attribute values CuDv (Customized Devices) the devices present on this machine PdAt (Predefined Attributes) default values for all device attributes PdDv (Predefined Devices) the list of all devices supported by this release of AIX

Constants

CYAN
DEFAULT_LOG_LEVEL
GREEN
RED
RESET
VERSION
YELLOW

Public Class Methods

[](name) click to toggle source

Alias method for ::fact @param name [string] fact name

@return [Facter::Util::Fact, nil] The fact object, or nil if no fact

is found.

@api public

# File lib/facter.rb, line 53
def [](name)
  fact(name)
end
add(name, options = {}, &block) click to toggle source

Add custom facts to fact collection @param name [String] Custom fact name @param options = {} [Hash] optional parameters for the fact - attributes

of {Facter::Util::Fact} and {Facter::Util::Resolution} can be
supplied here

@param block [Proc] a block defining a fact resolution

@return [Facter::Util::Fact] the fact object, which includes any previously

defined resolutions

@api public

# File lib/facter.rb, line 68
def add(name, options = {}, &block)
  options[:fact_type] = :custom
  LegacyFacter.add(name, options, &block)
  LegacyFacter.collection.invalidate_custom_facts
end
clear() click to toggle source

Clears all cached values and removes all facts from memory.

@return [nil]

@api public

# File lib/facter.rb, line 79
def clear
  @already_searched = {}
  @debug_once = []
  @warn_once = []
  LegacyFacter.clear
  Options[:custom_dir] = []
  LegacyFacter.collection.invalidate_custom_facts
  LegacyFacter.collection.reload_custom_facts
  SessionCache.invalidate_all_caches
  nil
end
core_value(user_query) click to toggle source

Gets the value for a core fact, external or custom facts are

not returned with this call. Returns `nil` if no such fact exists.

@return [FactCollection] hash with fact names and values

@api private

# File lib/facter.rb, line 97
def core_value(user_query)
  user_query = user_query.to_s
  resolved_facts = Facter::FactManager.instance.resolve_core([user_query])
  fact_collection = FactCollection.new.build_fact_collection!(resolved_facts)
  splitted_user_query = Facter::Utils.split_user_query(user_query)
  fact_collection.dig(*splitted_user_query)
end
debug(message) click to toggle source

Logs debug message when debug option is set to true @param message [Object] Message object to be logged

@return [nil]

@api public

# File lib/facter.rb, line 111
def debug(message)
  return unless debugging?

  logger.debug(message.to_s)
  nil
end
debugging(debug_bool) click to toggle source

Enable or disable debugging @param debug_bool [bool] State which debugging should have

@return [type] [description]

@api public

# File lib/facter.rb, line 175
def debugging(debug_bool)
  Facter::Options[:debug] = debug_bool
end
debugging?() click to toggle source

Check whether debugging is enabled

@return [bool]

@api public

# File lib/facter.rb, line 165
def debugging?
  Options[:debug]
end
debugonce(message) click to toggle source

Logs the same debug message only once when debug option is set to true @param message [Object] Message object to be logged

@return [nil]

@api public

# File lib/facter.rb, line 124
def debugonce(message)
  return unless debugging?

  message_string = message.to_s
  return if @debug_once.include? message_string

  @debug_once << message_string
  logger.debug(message_string)
  nil
end
define_fact(name, options = {}, &block) click to toggle source

Define a new fact or extend an existing fact.

@param name [Symbol] The name of the fact to define @param options [Hash] A hash of options to set on the fact

@return [Facter::Util::Fact] The fact that was defined

@api public

# File lib/facter.rb, line 143
def define_fact(name, options = {}, &block)
  options[:fact_type] = :custom
  LegacyFacter.define_fact(name, options, &block)
end
each() { |name, value| ... } click to toggle source

Iterates over fact names and values

@yieldparam [String] name the fact name @yieldparam [String] value the current value of the fact

@return [Facter]

@api public

# File lib/facter.rb, line 187
def each
  log_blocked_facts
  resolved_facts = Facter::FactManager.instance.resolve_facts

  resolved_facts.each do |fact|
    yield(fact.name, fact.value)
  end

  self
end
fact(user_query) click to toggle source

Returns a fact object by name. If you use this, you still have to call {Facter::Util::Fact#value `value`} on it to retrieve the actual value.

@param user_query [String] the name of the fact

@return [Facter::Util::Fact, nil] The fact object, or nil if no fact

is found.

@api public

# File lib/facter.rb, line 208
def fact(user_query)
  user_query = user_query.to_s
  resolve_fact(user_query)

  @already_searched[user_query]
end
flush() click to toggle source

Flushes cached values for all facts. This does not cause code to be reloaded; it only clears the cached results.

@return [void]

@api public

# File lib/facter.rb, line 235
def flush
  LegacyFacter.flush
  SessionCache.invalidate_all_caches
  nil
end
list() click to toggle source

Returns a list with the names of all solved facts @return [Array] the list with all the fact names

@api public

# File lib/facter.rb, line 402
def list
  to_hash.keys.sort
end
loadfacts() click to toggle source

Loads all facts

@return [nil]

@api public

# File lib/facter.rb, line 246
def loadfacts
  LegacyFacter.loadfacts
  nil
end
log_exception(exception, message = nil) click to toggle source

Logs an exception and an optional message

@return [nil]

@api public

# File lib/facter.rb, line 388
def log_exception(exception, message = nil)
  error_message = []

  error_message << message.to_s unless message.nil? || (message.is_a?(String) && message.empty?)

  parse_exception(exception, error_message)
  logger.error(error_message.flatten.join("\n"))
  nil
end
on_message(&block) click to toggle source

Stores a proc that will be used to output custom messages.

The proc must receive one parameter that will be the message to log.

@param block [Proc] a block defining messages handler

@return [nil]

@api public

# File lib/facter.rb, line 155
def on_message(&block)
  Facter::Log.on_message(&block)
  nil
end
reset() click to toggle source

Reset search paths for custom and external facts If config file is set custom and external facts will be reloaded

@return [nil]

@api public

# File lib/facter.rb, line 221
def reset
  LegacyFacter.reset
  Options[:custom_dir] = []
  Options[:external_dir] = []
  SessionCache.invalidate_all_caches
  nil
end
resolve(args_as_string) click to toggle source

Method used by puppet-agent to retrieve facts @param args_as_string [string] facter cli arguments

@return query result

@api private

# File lib/facter.rb, line 25
def resolve(args_as_string)
  require 'facter/framework/cli/cli_launcher'

  args = args_as_string.split(' ')

  Facter::OptionsValidator.validate(args)
  processed_arguments = CliLauncher.prepare_arguments(args, nil)

  cli = Facter::Cli.new([], processed_arguments)

  if cli.args.include?(:version)
    cli.invoke(:version, [])
  elsif cli.args.include?('--list-cache-groups')
    cli.invoke(:list_cache_groups, [])
  elsif cli.args.include?('--list-block-groups')
    cli.invoke(:list_block_groups, [])
  else
    cli.invoke(:arg_parser)
  end
end
search_external(dirs) click to toggle source

Registers directories to be searched for external facts. @param dirs [Array<String>] An array of searched directories

@return [nil]

@api public

# File lib/facter.rb, line 269
def search_external(dirs)
  Options[:external_dir] += dirs
  nil
end
search_external_path() click to toggle source

Returns the registered search directories.for external facts.

@return [Array<String>] An array of searched directories

@api public

# File lib/facter.rb, line 279
def search_external_path
  Options.external_dir
end
search_path() click to toggle source

Returns the registered search directories for custom facts.

@return [Array<String>] An array of the directories searched

@api public

# File lib/facter.rb, line 288
def search_path
  Options.custom_dir
end
to_hash() click to toggle source

Gets a hash mapping fact names to their values The hash contains core facts, legacy facts, custom facts and external facts (all facts that can be resolved).

@return [FactCollection] hash with fact names and values

@api public

# File lib/facter.rb, line 298
def to_hash
  log_blocked_facts

  resolved_facts = Facter::FactManager.instance.resolve_facts
  Facter::FactCollection.new.build_fact_collection!(resolved_facts)
end
to_user_output(cli_options, *args) click to toggle source

Gets a hash mapping fact names to their values

@return [Array] the hash of fact names and values

@api private

# File lib/facter.rb, line 371
def to_user_output(cli_options, *args)
  init_cli_options(cli_options, args)
  logger.info("executed with command line: #{ARGV.drop(1).join(' ')}")
  log_blocked_facts
  resolved_facts = Facter::FactManager.instance.resolve_facts(args)
  fact_formatter = Facter::FormatterFactory.build(Facter::Options.get)

  status = error_check(resolved_facts)

  [fact_formatter.format(resolved_facts), status || 0]
end
trace(bool) click to toggle source

Enable or disable trace @param bool [bool] Set trace on debug state

@return [bool] Value of trace debug state

@api public

# File lib/facter.rb, line 320
def trace(bool)
  Options[:trace] = bool
end
trace?() click to toggle source

Check whether printing stack trace is enabled

@return [bool]

@api public

# File lib/facter.rb, line 310
def trace?
  Options[:trace]
end
value(user_query) click to toggle source

Gets the value for a fact. Returns `nil` if no such fact exists.

@param user_query [String] the fact name @return [String] the value of the fact, or nil if no fact is found

@api public

# File lib/facter.rb, line 330
def value(user_query)
  user_query = user_query.to_s
  resolve_fact(user_query)
  @already_searched[user_query]&.value
end
values(options, user_queries) click to toggle source

Gets the values for multiple facts.

@param options [Hash] parameters for the fact - attributes

of {Facter::Util::Fact} and {Facter::Util::Resolution} can be
supplied here

@param user_queries [String] the fact names

@return [FactCollection] hash with fact names and values

@api public

# File lib/facter.rb, line 346
def values(options, user_queries)
  init_cli_options(options, user_queries)
  resolved_facts = Facter::FactManager.instance.resolve_facts(user_queries)

  if user_queries.count.zero?
    Facter::FactCollection.new.build_fact_collection!(resolved_facts)
  else
    FormatterHelper.retrieve_facts_to_display_for_user_query(user_queries, resolved_facts)
  end
end
version() click to toggle source

Returns Facter version

@return [String] Current version

@api public

# File lib/facter.rb, line 362
def version
  Facter::VERSION
end
warn(message) click to toggle source

Logs the message parameter as a warning. @param message [Object] the warning object to be displayed

@return [nil]

@api public

# File lib/facter.rb, line 412
def warn(message)
  logger.warn(message.to_s)
  nil
end
warnonce(message) click to toggle source

Logs only once the same warning message. @param message [Object] the warning message object

@return [nil]

@api public

# File lib/facter.rb, line 423
def warnonce(message)
  message_string = message.to_s
  return if @warn_once.include? message_string

  @warn_once << message_string
  logger.warn(message_string)
  nil
end

Private Class Methods

add_fact_to_searched_facts(user_query, value) click to toggle source
# File lib/facter.rb, line 456
def add_fact_to_searched_facts(user_query, value)
  @already_searched[user_query] ||= ResolvedFact.new(user_query, value)
  @already_searched[user_query].value = value
end
error_check(resolved_facts) click to toggle source

Returns exit status when user query contains facts that do

not exist

@param resolved_facts [Array] List of resolved facts

@return [1/nil] Will return status 1 if user query contains

facts that are not found or resolved, otherwise it will return nil

@api private

# File lib/facter.rb, line 491
def error_check(resolved_facts)
  if Options[:strict]
    missing_names = resolved_facts.select { |fact| fact.type == :nil }.map(&:user_query)

    if missing_names.count.positive?
      status = 1
      log_errors(missing_names)
    else
      status = nil
    end
  end

  status
end
init_cli_options(options, args) click to toggle source
# File lib/facter.rb, line 451
def init_cli_options(options, args)
  options = options.map { |(k, v)| [k.to_sym, v] }.to_h
  Facter::Options.init_from_cli(options, args)
end
log_blocked_facts() click to toggle source

Prints out blocked facts before ::to_hash or ::to_user_output is called

@return [nil]

@api private

# File lib/facter.rb, line 511
def log_blocked_facts
  block_list = Options[:block_list]
  return unless block_list.any? && Facter::Options[:block]

  logger.debug("blocking collection of #{block_list.join("\s")} facts")
end
log_errors(missing_names) click to toggle source

Used for printing errors regarding CLI user input validation

@param missing_names [Array] List of facts that were requested

but not found

@return [nil]

@api private

# File lib/facter.rb, line 526
def log_errors(missing_names)
  missing_names.each do |missing_name|
    logger.error("fact \"#{missing_name}\" does not exist.", true)
  end
end
logger() click to toggle source
# File lib/facter.rb, line 447
def logger
  @logger ||= Log.new(self)
end
method_missing(name, *args, &block) click to toggle source

Proxy method that catches not yet implemented method calls

@param name [type] [description] @param *args [type] [description] @param &block [type] [description]

@return [type] [description]

@api private

# File lib/facter.rb, line 541
def method_missing(name, *args, &block)
  logger.error(
    "--#{name}-- not implemented but required \n" \
    'with params: ' \
    "#{args.inspect} \n" \
    'with block: ' \
    "#{block.inspect}  \n" \
    "called by:  \n" \
    "#{caller} \n"
  )
  nil
end
parse_exception(exception, error_message) click to toggle source
# File lib/facter.rb, line 434
def parse_exception(exception, error_message)
  if exception.is_a?(Exception)
    error_message << exception.message if error_message.empty?

    if Options[:trace] && !exception.backtrace.nil?
      error_message << 'backtrace:'
      error_message.concat(exception.backtrace)
    end
  elsif error_message.empty?
    error_message << exception.to_s
  end
end
resolve_fact(user_query) click to toggle source

Returns a ResolvedFact and saves the result in @already_searched array that is used as a global collection. @param user_query [String] Fact that needs resolution

@return [ResolvedFact]

# File lib/facter.rb, line 465
def resolve_fact(user_query)
  user_query = user_query.to_s
  resolved_facts = Facter::FactManager.instance.resolve_facts([user_query])
  # we must make a distinction between custom facts that return nil and nil facts
  # Nil facts should not be packaged as ResolvedFacts! (add_fact_to_searched_facts packages facts)
  resolved_facts = resolved_facts.reject { |fact| fact.type == :nil }
  fact_collection = FactCollection.new.build_fact_collection!(resolved_facts)
  splitted_user_query = Facter::Utils.split_user_query(user_query)

  begin
    value = fact_collection.value(*splitted_user_query)
    add_fact_to_searched_facts(user_query, value)
  rescue KeyError
    nil
  end
end