c5cb4bba565bc5b3079e12de303e7569449e6bac
[packages/precise/mcollective.git] / lib / mcollective / facts / base.rb
1 module MCollective
2   module Facts
3     # A base class for fact providers, to make a new fully functional fact provider
4     # inherit from this and simply provide a self.get_facts method that returns a
5     # hash like:
6     #
7     #  {"foo" => "bar",
8     #   "bar" => "baz"}
9     class Base
10       def initialize
11         @facts = {}
12         @last_good_facts = {}
13         @last_facts_load = 0
14       end
15
16       # Registers new fact sources into the plugin manager
17       def self.inherited(klass)
18         PluginManager << {:type => "facts_plugin", :class => klass.to_s}
19       end
20
21       # Returns the value of a single fact
22       def get_fact(fact=nil)
23         config = Config.instance
24
25         cache_time = config.fact_cache_time || 300
26
27         Thread.exclusive do
28           begin
29             if (Time.now.to_i - @last_facts_load > cache_time.to_i ) || force_reload?
30               Log.debug("Resetting facter cache, now: #{Time.now.to_i} last-known-good: #{@last_facts_load}")
31
32               tfacts = load_facts_from_source
33
34               # Force reset to last known good state on empty facts
35               raise "Got empty facts" if tfacts.empty?
36
37               @facts.clear
38
39               tfacts.each_pair do |key,value|
40                 @facts[key.to_s] = value.to_s
41               end
42
43               @last_good_facts = @facts.clone
44               @last_facts_load = Time.now.to_i
45             else
46               Log.debug("Using cached facts now: #{Time.now.to_i} last-known-good: #{@last_facts_load}")
47             end
48           rescue Exception => e
49             Log.error("Failed to load facts: #{e.class}: #{e}")
50
51             # Avoid loops where failing fact loads cause huge CPU
52             # loops, this way it only retries once every cache_time
53             # seconds
54             @last_facts_load = Time.now.to_i
55
56             # Revert to last known good state
57             @facts = @last_good_facts.clone
58           end
59         end
60
61
62         # If you do not supply a specific fact all facts will be returned
63         if fact.nil?
64           return @facts
65         else
66           @facts.include?(fact) ? @facts[fact] : nil
67         end
68       end
69
70       # Returns all facts
71       def get_facts
72         get_fact(nil)
73       end
74
75       # Returns true if we know about a specific fact, false otherwise
76       def has_fact?(fact)
77         get_fact(nil).include?(fact)
78       end
79
80       # Plugins can override this to provide forced fact invalidation
81       def force_reload?
82         false
83       end
84     end
85   end
86 end