lib/framework/core/cache_manager.rb
# frozen_string_literal: true
module Facter
class CacheManager
def initialize
@groups = {}
@log = Log.new(self)
@fact_groups = Facter::FactGroups.new
@cache_dir = LegacyFacter::Util::Config.facts_cache_dir
end
def resolve_facts(searched_facts)
return searched_facts, [] if !File.directory?(@cache_dir) || !Options[:cache]
facts = []
searched_facts.delete_if do |fact|
res = resolve_fact(fact)
if res
facts << res
true
else
false
end
end
[searched_facts, facts.flatten]
end
def cache_facts(resolved_facts)
return unless Options[:cache]
resolved_facts.each do |fact|
cache_fact(fact)
end
begin
write_cache unless @groups.empty?
rescue Errno::EACCES => e
@log.warn("Could not write cache: #{e.message}")
end
end
def group_cached?(group_name)
cached = @fact_groups.get_group_ttls(group_name) ? true : false
delete_cache(group_name) unless cached
cached
end
private
def resolve_fact(searched_fact)
group_name = if searched_fact.file
searched_fact.name
else
@fact_groups.get_fact_group(searched_fact.name)
end
return unless group_name
return unless group_cached?(group_name)
return unless check_ttls?(group_name)
data = read_group_json(group_name)
return unless data
@log.debug("loading cached values for #{group_name} facts")
create_facts(searched_fact, data)
end
def create_facts(searched_fact, data)
if searched_fact.type == :file
facts = []
data.each do |fact_name, fact_value|
fact = Facter::ResolvedFact.new(fact_name, fact_value, searched_fact.type,
searched_fact.user_query, searched_fact.filter_tokens)
fact.file = searched_fact.file
facts << fact
end
facts
else
[Facter::ResolvedFact.new(searched_fact.name, data[searched_fact.name], searched_fact.type,
searched_fact.user_query, searched_fact.filter_tokens)]
end
end
def cache_fact(fact)
group_name = if fact.file
File.basename(fact.file)
else
@fact_groups.get_fact_group(fact.name)
end
return if !group_name || fact.value.nil?
return unless group_cached?(group_name)
@groups[group_name] ||= {}
@groups[group_name][fact.name] = fact.value
end
def write_cache
unless File.directory?(@cache_dir)
require 'fileutils'
FileUtils.mkdir_p(@cache_dir)
end
@groups.each do |group_name, data|
next unless check_ttls?(group_name)
@log.debug("caching values for #{group_name} facts")
cache_file_name = File.join(@cache_dir, group_name)
File.write(cache_file_name, JSON.pretty_generate(data))
end
end
def read_group_json(group_name)
return @groups[group_name] if @groups.key?(group_name)
cache_file_name = File.join(@cache_dir, group_name)
data = nil
file = Util::FileHelper.safe_read(cache_file_name)
begin
data = JSON.parse(file)
rescue JSON::ParserError
delete_cache(group_name)
end
@groups[group_name] = data
end
def check_ttls?(group_name)
ttls = @fact_groups.get_group_ttls(group_name)
return false unless ttls
cache_file_name = File.join(@cache_dir, group_name)
if File.readable?(cache_file_name)
file_time = File.mtime(cache_file_name)
expire_date = file_time + ttls
return true if expire_date > Time.now
File.delete(cache_file_name)
end
@log.debug("#{group_name} facts cache file expired/missing")
true
end
def delete_cache(group_name)
cache_file_name = File.join(@cache_dir, group_name)
File.delete(cache_file_name) if File.readable?(cache_file_name)
end
end
end