Class: Facter::Util::DotD

Inherits:
Object show all
Defined in:
puppet/modules/stdlib/lib/facter/facter_dot_d.rb

Overview

A Facter plugin that loads facts from /etc/facter/facts.d and /etc/puppetlabs/facter/facts.d.

Facts can be in the form of JSON, YAML or Text files and any executable that returns key=value pairs.

In the case of scripts you can also create a file that contains a cache TTL. For foo.sh store the ttl as just a number in foo.sh.ttl

The cache is stored in $libdir/facts_dot_d.cache as a mode 600 file and will have the end result of not calling your fact scripts more often than is needed

Instance Method Summary collapse

Constructor Details

#initialize(dir = "/etc/facts.d", cache_file = File.join(Puppet[:libdir], "facts_dot_d.cache")) ⇒ DotD

Returns a new instance of DotD



18
19
20
21
22
23
# File 'puppet/modules/stdlib/lib/facter/facter_dot_d.rb', line 18

def initialize(dir="/etc/facts.d", cache_file=File.join(Puppet[:libdir], "facts_dot_d.cache"))
  @dir = dir
  @cache_file = cache_file
  @cache = nil
  @types = {".txt" => :txt, ".json" => :json, ".yaml" => :yaml}
end

Instance Method Details

#cache_lookup(file) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'puppet/modules/stdlib/lib/facter/facter_dot_d.rb', line 127

def cache_lookup(file)
  cache = load_cache

  return nil if cache.empty?

  ttl = cache_time(file)

  if cache[file]
    now = Time.now.to_i

    return cache[file][:data] if ttl == -1
    return cache[file][:data] if (now - cache[file][:stored]) <= ttl
    return nil
  else
    return nil
  end
rescue
  return nil
end

#cache_save!Object



114
115
116
117
118
# File 'puppet/modules/stdlib/lib/facter/facter_dot_d.rb', line 114

def cache_save!
  cache = load_cache
  File.open(@cache_file, "w", 0600) { |f| f.write(YAML.dump(cache)) }
rescue
end

#cache_store(file, data) ⇒ Object



120
121
122
123
124
125
# File 'puppet/modules/stdlib/lib/facter/facter_dot_d.rb', line 120

def cache_store(file, data)
  load_cache

  @cache[file] = {:data => data, :stored => Time.now.to_i}
rescue
end

#cache_time(file) ⇒ Object



147
148
149
150
151
152
153
# File 'puppet/modules/stdlib/lib/facter/facter_dot_d.rb', line 147

def cache_time(file)
  meta = file + ".ttl"

  return File.read(meta).chomp.to_i
rescue
  return 0
end

#createObject



170
171
172
173
174
175
176
177
178
179
180
181
# File 'puppet/modules/stdlib/lib/facter/facter_dot_d.rb', line 170

def create
  entries.each do |fact|
    type = fact_type(fact)
    parser = "#{type}_parser"

    if respond_to?("#{type}_parser")
      Facter.debug("Parsing #{fact} using #{parser}")

      send(parser, fact)
    end
  end
end

#entriesObject



25
26
27
28
29
# File 'puppet/modules/stdlib/lib/facter/facter_dot_d.rb', line 25

def entries
  Dir.entries(@dir).reject { |f| f =~ /^\.|\.ttl$/ }.sort.map { |f| File.join(@dir, f) }
rescue
  []
end

#fact_type(file) ⇒ Object



31
32
33
34
35
36
37
38
39
# File 'puppet/modules/stdlib/lib/facter/facter_dot_d.rb', line 31

def fact_type(file)
  extension = File.extname(file)

  type = @types[extension] || :unknown

  type = :script if type == :unknown && File.executable?(file)

  return type
end

#json_parser(file) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'puppet/modules/stdlib/lib/facter/facter_dot_d.rb', line 55

def json_parser(file)
  begin
    require 'json'
  rescue LoadError
    retry if require 'rubygems'
    raise
  end

  JSON.load(File.read(file)).each_pair do |f, v|
    Facter.add(f) do
      setcode { v }
    end
  end
rescue StandardError => e
  Facter.warn("Failed to handle #{file} as json facts: #{e.class}: #{e}")
end

#load_cacheObject



155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'puppet/modules/stdlib/lib/facter/facter_dot_d.rb', line 155

def load_cache
  unless @cache
    if File.exist?(@cache_file)
      @cache = YAML.load_file(@cache_file)
    else
      @cache = {}
    end
  end

  return @cache
rescue
  @cache = {}
  return @cache
end

#script_parser(file) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'puppet/modules/stdlib/lib/facter/facter_dot_d.rb', line 84

def script_parser(file)
  result = cache_lookup(file)
  ttl = cache_time(file)

  unless result
    result = Facter::Util::Resolution.exec(file)

    if ttl > 0
      Facter.debug("Updating cache for #{file}")
      cache_store(file, result)
      cache_save!
    end
  else
    Facter.debug("Using cached data for #{file}")
  end

  result.split("\n").each do |line|
    if line =~ /^(.+)=(.+)$/
      var = $1; val = $2

      Facter.add(var) do
        setcode { val }
      end
    end
  end
rescue StandardError => e
  Facter.warn("Failed to handle #{file} as script facts: #{e.class}: #{e}")
  Facter.debug(e.backtrace.join("\n\t"))
end

#txt_parser(file) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'puppet/modules/stdlib/lib/facter/facter_dot_d.rb', line 41

def txt_parser(file)
  File.readlines(file).each do |line|
    if line =~ /^([^=]+)=(.+)$/
      var = $1; val = $2

      Facter.add(var) do
        setcode { val }
      end
    end
  end
rescue StandardError => e
  Facter.warn("Failed to handle #{file} as text facts: #{e.class}: #{e}")
end

#yaml_parser(file) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
# File 'puppet/modules/stdlib/lib/facter/facter_dot_d.rb', line 72

def yaml_parser(file)
  require 'yaml'

  YAML.load_file(file).each_pair do |f, v|
    Facter.add(f) do
      setcode { v }
    end
  end
rescue StandardError => e
  Facter.warn("Failed to handle #{file} as yaml facts: #{e.class}: #{e}")
end