source: other-projects/hathitrust/vagrant-solr-cluster/trunk/modules/stdlib/lib/facter/facter_dot_d.rb@ 30960

Last change on this file since 30960 was 30960, checked in by davidb, 7 years ago

Switch to using Puppet to provision machine. Strongly based on files developed for spark-hdfs cluster

File size: 4.6 KB
Line 
1# A Facter plugin that loads facts from /etc/facter/facts.d
2# and /etc/puppetlabs/facter/facts.d.
3#
4# Facts can be in the form of JSON, YAML or Text files
5# and any executable that returns key=value pairs.
6#
7# In the case of scripts you can also create a file that
8# contains a cache TTL. For foo.sh store the ttl as just
9# a number in foo.sh.ttl
10#
11# The cache is stored in $libdir/facts_dot_d.cache as a mode
12# 600 file and will have the end result of not calling your
13# fact scripts more often than is needed
14
15class Facter::Util::DotD
16 require 'yaml'
17
18 def initialize(dir="/etc/facts.d", cache_file=File.join(Puppet[:libdir], "facts_dot_d.cache"))
19 @dir = dir
20 @cache_file = cache_file
21 @cache = nil
22 @types = {".txt" => :txt, ".json" => :json, ".yaml" => :yaml}
23 end
24
25 def entries
26 Dir.entries(@dir).reject { |f| f =~ /^\.|\.ttl$/ }.sort.map { |f| File.join(@dir, f) }
27 rescue
28 []
29 end
30
31 def fact_type(file)
32 extension = File.extname(file)
33
34 type = @types[extension] || :unknown
35
36 type = :script if type == :unknown && File.executable?(file)
37
38 return type
39 end
40
41 def txt_parser(file)
42 File.readlines(file).each do |line|
43 if line =~ /^([^=]+)=(.+)$/
44 var = $1; val = $2
45
46 Facter.add(var) do
47 setcode { val }
48 end
49 end
50 end
51 rescue StandardError => e
52 Facter.warn("Failed to handle #{file} as text facts: #{e.class}: #{e}")
53 end
54
55 def json_parser(file)
56 begin
57 require 'json'
58 rescue LoadError
59 retry if require 'rubygems'
60 raise
61 end
62
63 JSON.load(File.read(file)).each_pair do |f, v|
64 Facter.add(f) do
65 setcode { v }
66 end
67 end
68 rescue StandardError => e
69 Facter.warn("Failed to handle #{file} as json facts: #{e.class}: #{e}")
70 end
71
72 def yaml_parser(file)
73 require 'yaml'
74
75 YAML.load_file(file).each_pair do |f, v|
76 Facter.add(f) do
77 setcode { v }
78 end
79 end
80 rescue StandardError => e
81 Facter.warn("Failed to handle #{file} as yaml facts: #{e.class}: #{e}")
82 end
83
84 def script_parser(file)
85 result = cache_lookup(file)
86 ttl = cache_time(file)
87
88 unless result
89 result = Facter::Util::Resolution.exec(file)
90
91 if ttl > 0
92 Facter.debug("Updating cache for #{file}")
93 cache_store(file, result)
94 cache_save!
95 end
96 else
97 Facter.debug("Using cached data for #{file}")
98 end
99
100 result.split("\n").each do |line|
101 if line =~ /^(.+)=(.+)$/
102 var = $1; val = $2
103
104 Facter.add(var) do
105 setcode { val }
106 end
107 end
108 end
109 rescue StandardError => e
110 Facter.warn("Failed to handle #{file} as script facts: #{e.class}: #{e}")
111 Facter.debug(e.backtrace.join("\n\t"))
112 end
113
114 def cache_save!
115 cache = load_cache
116 File.open(@cache_file, "w", 0600) { |f| f.write(YAML.dump(cache)) }
117 rescue
118 end
119
120 def cache_store(file, data)
121 load_cache
122
123 @cache[file] = {:data => data, :stored => Time.now.to_i}
124 rescue
125 end
126
127 def cache_lookup(file)
128 cache = load_cache
129
130 return nil if cache.empty?
131
132 ttl = cache_time(file)
133
134 if cache[file]
135 now = Time.now.to_i
136
137 return cache[file][:data] if ttl == -1
138 return cache[file][:data] if (now - cache[file][:stored]) <= ttl
139 return nil
140 else
141 return nil
142 end
143 rescue
144 return nil
145 end
146
147 def cache_time(file)
148 meta = file + ".ttl"
149
150 return File.read(meta).chomp.to_i
151 rescue
152 return 0
153 end
154
155 def load_cache
156 unless @cache
157 if File.exist?(@cache_file)
158 @cache = YAML.load_file(@cache_file)
159 else
160 @cache = {}
161 end
162 end
163
164 return @cache
165 rescue
166 @cache = {}
167 return @cache
168 end
169
170 def create
171 entries.each do |fact|
172 type = fact_type(fact)
173 parser = "#{type}_parser"
174
175 if respond_to?("#{type}_parser")
176 Facter.debug("Parsing #{fact} using #{parser}")
177
178 send(parser, fact)
179 end
180 end
181 end
182end
183
184
185mdata = Facter.version.match(/(\d+)\.(\d+)\.(\d+)/)
186if mdata
187 (major, minor, patch) = mdata.captures.map { |v| v.to_i }
188 if major < 2
189 # Facter 1.7 introduced external facts support directly
190 unless major == 1 and minor > 6
191 Facter::Util::DotD.new("/etc/facter/facts.d").create
192 Facter::Util::DotD.new("/etc/puppetlabs/facter/facts.d").create
193
194 # Windows has a different configuration directory that defaults to a vendor
195 # specific sub directory of the %COMMON_APPDATA% directory.
196 if Dir.const_defined? 'COMMON_APPDATA' then
197 windows_facts_dot_d = File.join(Dir::COMMON_APPDATA, 'PuppetLabs', 'facter', 'facts.d')
198 Facter::Util::DotD.new(windows_facts_dot_d).create
199 end
200 end
201 end
202end
Note: See TracBrowser for help on using the repository browser.