summaryrefslogtreecommitdiff
path: root/files/master/lastcheck.rb
blob: f83ccde91aa98c4af638e94e754068585c367470 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
require 'rubygems'
require 'active_support'
require 'puppet/application'

module Puppet::Lastcheck
  module Puppet::Lastcheck::Tests
    def self.included(klass)
      klass.extend ClassMethods
    end
    def self.tests
      @tests ||= {}
    end
    module ClassMethods
      def add_test(name, options={})
        include "Puppet::Lastcheck::Tests::#{name.to_s.classify}".constantize
        Puppet::Lastcheck::Tests.tests[name] = options
        attr_accessor "ignore_#{name}".to_sym
        option("--ignore-#{name.to_s.gsub(/_/,'-')}") do
          self.send("ignore_#{name}=", true)
        end
      end
    end
    module Util
      def facts_hosts
        return @facts_hosts if @facts_hosts
        require 'puppet/indirector/facts/yaml'
        @facts_hopsts = Puppet::Node::Facts.search("*").collect do |node|
          { :hostname => node.name, :expired => node.expired?, :timestamp => node.values[:_timestamp], :expiration => node.expiration }
        end
      end
    end
  end
end

module Puppet::Lastcheck::Tests::NoFact
  def analyze_no_facts
    signed_hosts.each{|host| add_failed_host(host,"No facts available") unless facts_hosts.any?{|fhost| fhost[:hostname] == host } }
  end
  def setup_no_facts
    Puppet::SSL::Host.ca_location = :only
  end

  private
  def signed_hosts
    ca.list
  end

  def ca
    @ca ||= Puppet::SSL::CertificateAuthority.new
  end
end

module Puppet::Lastcheck::Tests::ExpiredFact
  include Puppet::Lastcheck::Tests::Util
  def analyze_expired_facts
      facts_hosts.each{|host| add_failed_host(host[:hostname],"Expired at #{host[:expiration]}") if host[:expired] }
  end
end
module Puppet::Lastcheck::Tests::TimedOutFact
  include Puppet::Lastcheck::Tests::Util
  def analyze_timed_out_facts
    require 'time'
    facts_hosts.each{|host| add_failed_host(host[:hostname], "Last facts save at #{host[:timestamp]}") if Time.parse(host[:timestamp]) < (Time.now - @timeout) }
  end

  def setup_timed_out_facts
    if @timeout
      ignore_expired_facts ||= true
    end
  end
end
module Puppet::Lastcheck::Tests::Storedconfig
  def analyze_storedconfigs
    storedconfigs_hosts.each do |host|
      if !facts_hosts.any?{|fact_host| fact_host[:hostname] == host.name }
        add_failed_host(host.name, "In storedconfigs but no facts available!")
      elsif host.updated_at < (Time.now - @timeout)
        add_failed_host(host.name, "Last update in storedconfigs at #{host.updated_at}")
      end
    end
  end

  private
  def storedconfigs_hosts
    return @storedconfigs_hosts if @storedconfigs_hosts
    Puppet::Rails.connect
    @storedconfigs_hosts = Puppet::Rails::Host.all
  end
end
class Puppet::Application::Lastcheck < Puppet::Application

  should_parse_config
  run_mode :master

  include Puppet::Lastcheck::Tests
  add_test :no_facts
  add_test :expired_facts, :ignore_by_default => true
  add_test :timed_out_facts
  add_test :storedconfigs

  option("--timeout TIMEOUT") do |v|
    @timeout = v.to_i
  end

  def main
    Puppet::Lastcheck::Tests.tests.keys.each do |test|
        self.send("analyze_#{test}") unless self.send("ignore_#{test}")
    end
    print unless @failing_hosts.empty?
  end

  def setup
    exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?

    Puppet::Util::Log.newdestination :console
    Puppet::Node::Facts.terminus_class = :yaml

    Puppet::Lastcheck::Tests.tests.keys.each do |test|
      self.send("ignore_#{test}=", Puppet::Lastcheck::Tests.tests[test][:ignore_by_default]||false) unless self.send("ignore_#{test}")
      self.send("setup_#{test}") if self.respond_to?("setup_#{test}")
    end

    @failing_hosts = {}
    unless @timeout 
      @timeout = Puppet[:runinterval]
    end
  end

  private
  def print
    puts 'The following hosts are out of date:'
    puts '------------------------------------'
    @failing_hosts.keys.each{ |host| puts "#{host} - Reason: #{@failing_hosts[host][:reason]}" }
  end

  def add_failed_host(hostname,reason)
    @failing_hosts[hostname] = { :reason => reason } unless @failing_hosts[hostname]
  end

end