class OctofactsUpdater::FactIndex

Constants

TOP_LEVEL_NODES_KEY

We will create a pseudo-fact that simply lists all of the nodes that were considered in the index. Define the name of that pseudo-fact here.

Attributes

index_data[R]

Public Class Methods

load_file(filename) click to toggle source

Load an index from the YAML file.

filename - A String with the file to be loaded.

Returns a OctofactsUpdater::FactIndex object.

# File lib/octofacts_updater/fact_index.rb, line 33
def self.load_file(filename)
  unless File.file?(filename)
    raise Errno::ENOENT, "load_index cannot load #{filename.inspect}"
  end

  data = YAML.safe_load(File.read(filename))
  new(data, filename: filename)
end
new(data = {}, filename: nil) click to toggle source

Constructor.

data - A Hash of existing index data. filename - Optionally, a String with a file name to write the index to

# File lib/octofacts_updater/fact_index.rb, line 46
def initialize(data = {}, filename: nil)
  @index_data = data
  @filename = filename
end

Public Instance Methods

add(fact_name, fixtures) click to toggle source

Add a fact to the index. If the fact already exists in the index, this will overwrite it.

fact_name - A String with the name of the fact fixtures - An Array with fact fixtures (must respond to .facts and .hostname)

# File lib/octofacts_updater/fact_index.rb, line 55
def add(fact_name, fixtures)
  @index_data[fact_name] ||= {}
  fixtures.each do |fixture|
    fact_value = get_fact(fixture, fact_name)
    next if fact_value.nil?
    @index_data[fact_name][fact_value] ||= []
    @index_data[fact_name][fact_value] << fixture.hostname
  end
end
nodes(quick_mode = true) click to toggle source

Get a list of all of the nodes in the index. This supports a quick mode (default) where the TOP_LEVEL_NODES_KEY key is used, and a more detailed mode where this digs through each indexed fact and value to build a list of nodes.

quick_mode - Boolean whether to use quick mode (default=true)

Returns an Array of nodes whose facts are indexed.

# File lib/octofacts_updater/fact_index.rb, line 72
def nodes(quick_mode = true)
  if quick_mode && @index_data.key?(TOP_LEVEL_NODES_KEY)
    return @index_data[TOP_LEVEL_NODES_KEY]
  end

  seen_hosts = Set.new
  @index_data.each do |fact_name, fact_values|
    next if fact_name == TOP_LEVEL_NODES_KEY
    fact_values.each do |_fact_value, nodes|
      seen_hosts.merge(nodes)
    end
  end
  seen_hosts.to_a.sort
end
recursive_sort(object_in) click to toggle source
# File lib/octofacts_updater/fact_index.rb, line 111
def recursive_sort(object_in)
  if object_in.is_a?(Hash)
    object_out = {}
    object_in.keys.sort.each { |k| object_out[k] = recursive_sort(object_in[k]) }
    object_out
  elsif object_in.is_a?(Array)
    object_in.sort.map { |v| recursive_sort(v) }
  else
    object_in
  end
end
reindex(facts_to_index, fixtures) click to toggle source

Rebuild an index with a specified list of facts. This will remove any indexed facts that are not on the list of facts to use.

facts_to_index - An Array of Strings with facts to index fixtures - An Array with fact fixtures (must respond to .facts and .hostname)

# File lib/octofacts_updater/fact_index.rb, line 92
def reindex(facts_to_index, fixtures)
  @index_data = {}
  facts_to_index.each { |fact| add(fact, fixtures) }
  set_top_level_nodes_fact(fixtures)
end
set_top_level_nodes_fact(fixtures) click to toggle source

Create the top level nodes pseudo-fact.

fixtures - An Array with fact fixtures (must respond to .hostname)

# File lib/octofacts_updater/fact_index.rb, line 101
def set_top_level_nodes_fact(fixtures)
  @index_data[TOP_LEVEL_NODES_KEY] = fixtures.map { |f| f.hostname }.sort
end
to_yaml() click to toggle source

Get YAML representation of the index. This sorts the hash and any arrays without modifying the object.

# File lib/octofacts_updater/fact_index.rb, line 107
def to_yaml
  YAML.dump(recursive_sort(index_data))
end
write_file(filename = nil) click to toggle source

Write the fact index out to a YAML file.

filename - A String with the file to write (defaults to filename from constructor if available)

# File lib/octofacts_updater/fact_index.rb, line 126
def write_file(filename = nil)
  filename ||= @filename
  unless filename.is_a?(String)
    raise ArgumentError, "Called write_file() for fact_index without a filename"
  end
  File.open(filename, "w") { |f| f.write(to_yaml) }
end

Private Instance Methods

get_fact(fixture, fact_name) click to toggle source

Extract a (possibly) structured fact.

fixture - Fact fixture, must respond to .facts fact_name - A String with the name of the fact

Returns the value of the fact, or nil if fact or structure does not exist.

# File lib/octofacts_updater/fact_index.rb, line 142
def get_fact(fixture, fact_name)
  pointer = fixture.facts

  # Get the fact of interest from the fixture, whether structured or not.
  components = fact_name.split(".")
  first_component = components.shift
  return unless pointer.key?(first_component)

  # For simple non-structured facts, just return the value.
  return pointer[first_component].value if components.empty?

  # Structured facts: dig into the structure.
  pointer = pointer[first_component].value
  last_component = components.pop
  components.each do |part|
    return unless pointer.key?(part)
    return unless pointer[part].is_a?(Hash)
    pointer = pointer[part]
  end
  pointer[last_component]
end