diff options
Diffstat (limited to 'lib/puppet')
-rw-r--r-- | lib/puppet/reports/rrdgraph.rb | 46 | ||||
-rw-r--r-- | lib/puppet/reports/store.rb | 67 | ||||
-rw-r--r-- | lib/puppet/reports/tagmail.rb | 185 | ||||
-rw-r--r-- | lib/puppet/server.rb | 4 | ||||
-rwxr-xr-x | lib/puppet/server/report.rb | 134 | ||||
-rw-r--r-- | lib/puppet/util/classgen.rb | 9 |
6 files changed, 248 insertions, 197 deletions
diff --git a/lib/puppet/reports/rrdgraph.rb b/lib/puppet/reports/rrdgraph.rb index 0fb7e2ea7..2c405c051 100644 --- a/lib/puppet/reports/rrdgraph.rb +++ b/lib/puppet/reports/rrdgraph.rb @@ -1,34 +1,38 @@ require 'puppet' -Puppet::Server::Report.newreport(:rrdgraph) do |report| - time = Time.now.to_i +Puppet::Server::Report.newreport(:rrdgraph) do + desc "Graph some data about hosts." - host = report.host + def process + time = Time.now.to_i - hostdir = File.join(Puppet[:rrddir], host) + host = self.host - unless File.directory?(hostdir) - # Some hackishness to create the dir - config = Puppet::Config.new - config.setdefaults(:reports, :hostdir => [hostdir, "eh"]) + hostdir = File.join(Puppet[:rrddir], host) - # This creates the dir. - config.use(:reports) - end + unless File.directory?(hostdir) + # Some hackishness to create the dir + config = Puppet::Config.new + config.setdefaults(:reports, :hostdir => [hostdir, "eh"]) - File.open(File.join(hostdir, "index.html"),"w") { |of| - of.puts "<html><body>" - report.metrics.each do |name, metric| - metric.basedir = hostdir - metric.store(time) + # This creates the dir. + config.use(:reports) + end - metric.graph + File.open(File.join(hostdir, "index.html"),"w") { |of| + of.puts "<html><body>" + self.metrics.each do |name, metric| + metric.basedir = hostdir + metric.store(time) - of.puts "<img src=%s.png><br>" % name - end + metric.graph - of.puts "</body></html>" - } + of.puts "<img src=%s.png><br>" % name + end + + of.puts "</body></html>" + } + end end # $Id$ diff --git a/lib/puppet/reports/store.rb b/lib/puppet/reports/store.rb new file mode 100644 index 000000000..82eebff39 --- /dev/null +++ b/lib/puppet/reports/store.rb @@ -0,0 +1,67 @@ +require 'puppet' + +Puppet::Server::Report.newreport(:store, :useyaml => true) do + Puppet.setdefaults(:reporting, + :reportdir => {:default => "$vardir/reports", + :mode => 0750, + :owner => "$user", + :group => "$group", + :desc => "The directory in which to store reports received from the + client. Each client gets a separate subdirectory."} + ) + + Puppet.config.use(:reporting) + + desc "Store the yaml report on disk" + + def mkclientdir(client, dir) + config = Puppet::Config.new + config.setdefaults("reportclient-#{client}", + "clientdir-#{client}" => { :default => dir, + :mode => 0750, + :owner => "$user", + :group => "$group" + } + ) + + config.use("reportclient-#{client}") + end + + def process(yaml) + # We don't want any tracking back in the fs. Unlikely, but there + # you go. + client = self.host.gsub("..",".") + + dir = File.join(Puppet[:reportdir], client) + + unless FileTest.exists?(dir) + mkclientdir(client, dir) + end + + # Now store the report. + now = Time.now.gmtime + name = %w{year month day hour min}.collect do |method| + # Make sure we're at least two digits everywhere + "%02d" % now.send(method).to_s + end.join("") + ".yaml" + + file = File.join(dir, name) + + begin + File.open(file, "w", 0640) do |f| + f.puts yaml + end + rescue => detail + if Puppet[:trace] + puts detail.backtrace + end + Puppet.warning "Could not write report for %s at %s: %s" % + [client, file, detail] + end + + # Only testing cares about the return value + return file + end +end + +# $Id$ diff --git a/lib/puppet/reports/tagmail.rb b/lib/puppet/reports/tagmail.rb index b7025802d..e842b17ac 100644 --- a/lib/puppet/reports/tagmail.rb +++ b/lib/puppet/reports/tagmail.rb @@ -14,116 +14,119 @@ Puppet.config.setdefaults(:reporting, require 'net/smtp' -Puppet::Server::Report.newreport(:tagmail) do |report| - unless FileTest.exists?(Puppet[:tagmap]) - Puppet.notice "Cannot send tagmail report; no tagmap file %s" % - Puppet[:tagmap] - return - end - - # Load the config file - taglists = {} - File.readlines(Puppet[:tagmap]).each do |line| - taglist = emails = nil - case line.chomp - when /^\s*#/: next - when /^\s*$/: next - when /^\s*(.+)\s*:\s*(.+)\s*$/: - taglist = $1 - emails = $2 - else - raise ArgumentError, "Invalid tagmail config file" +Puppet::Server::Report.newreport(:tagmail) do + desc "Send email reports." + def process + unless FileTest.exists?(Puppet[:tagmap]) + Puppet.notice "Cannot send tagmail report; no tagmap file %s" % + Puppet[:tagmap] + return end - pos = [] - neg = [] - taglist.split(/\s*,\s*/).each do |tag| - case tag - when /^\w+/: pos << tag - when /^!\w+/: neg << tag.sub("!", '') + # Load the config file + taglists = {} + File.readlines(Puppet[:tagmap]).each do |line| + taglist = emails = nil + case line.chomp + when /^\s*#/: next + when /^\s*$/: next + when /^\s*(.+)\s*:\s*(.+)\s*$/: + taglist = $1 + emails = $2 else - raise Puppet::Error, "Invalid tag '%s'" % tag + raise ArgumentError, "Invalid tagmail config file" end - end - # Now split the emails - emails = emails.split(/\s*,\s*/) - taglists[emails] = [pos, neg] - end + pos = [] + neg = [] + taglist.split(/\s*,\s*/).each do |tag| + case tag + when /^\w+/: pos << tag + when /^!\w+/: neg << tag.sub("!", '') + else + raise Puppet::Error, "Invalid tag '%s'" % tag + end + end - # Now find any appropriately tagged messages. - reports = {} - taglists.each do |emails, tags| - pos, neg = tags + # Now split the emails + emails = emails.split(/\s*,\s*/) + taglists[emails] = [pos, neg] + end - # First find all of the messages matched by our positive tags - messages = nil - if pos.include?("all") - messages = report.logs - else - # Find all of the messages that are tagged with any of our - # tags. - messages = report.logs.find_all do |log| - pos.detect { |tag| log.tagged?(tag) } + # Now find any appropriately tagged messages. + reports = {} + taglists.each do |emails, tags| + pos, neg = tags + + # First find all of the messages matched by our positive tags + messages = nil + if pos.include?("all") + messages = self.logs + else + # Find all of the messages that are tagged with any of our + # tags. + messages = self.logs.find_all do |log| + pos.detect { |tag| log.tagged?(tag) } + end end - end - # Now go through and remove any messages that match our negative tags - messages.reject! do |log| - if neg.detect do |tag| log.tagged?(tag) end - true + # Now go through and remove any messages that match our negative tags + messages.reject! do |log| + if neg.detect do |tag| log.tagged?(tag) end + true + end end - end - if messages.empty? - Puppet.info "No messages to report to %s" % emails.join(",") - next - else - reports[emails] = messages.collect { |m| m.to_report }.join("\n") + if messages.empty? + Puppet.info "No messages to report to %s" % emails.join(",") + next + else + reports[emails] = messages.collect { |m| m.to_report }.join("\n") + end end - end - # Let's fork for the sending of the email, since you never know what might - # happen. - fork do - if Puppet[:smtpserver] != "none" - begin - Net::SMTP.start(Puppet[:smtpserver]) do |smtp| - reports.each do |emails, messages| - Puppet.info "Sending report to %s" % emails.join(", ") - smtp.send_message(messages, Puppet[:reportfrom], *emails) + # Let's fork for the sending of the email, since you never know what might + # happen. + fork do + if Puppet[:smtpserver] != "none" + begin + Net::SMTP.start(Puppet[:smtpserver]) do |smtp| + reports.each do |emails, messages| + Puppet.info "Sending report to %s" % emails.join(", ") + smtp.send_message(messages, Puppet[:reportfrom], *emails) + end end + rescue => detail + if Puppet[:debug] + puts detail.backtrace + end + raise Puppet::Error, + "Could not send report emails through smtp: %s" % detail end - rescue => detail - if Puppet[:debug] - puts detail.backtrace - end - raise Puppet::Error, - "Could not send report emails through smtp: %s" % detail - end - elsif Puppet[:sendmail] != "" - begin - reports.each do |emails, messages| - Puppet.info "Sending report to %s" % emails.join(", ") - # We need to open a separate process for every set of email addresses - IO.popen(Puppet[:sendmail] + " " + emails.join(" "), "w") do |p| - p.puts "From: #{Puppet[:reportfrom]}" - p.puts "To: %s" % emails.join(', ') - p.puts "Subject: Puppet Report for %s" % report.host - p.puts "To: " + emails.join(", ") + elsif Puppet[:sendmail] != "" + begin + reports.each do |emails, messages| + Puppet.info "Sending report to %s" % emails.join(", ") + # We need to open a separate process for every set of email addresses + IO.popen(Puppet[:sendmail] + " " + emails.join(" "), "w") do |p| + p.puts "From: #{Puppet[:reportfrom]}" + p.puts "To: %s" % emails.join(', ') + p.puts "Subject: Puppet Report for %s" % self.host + p.puts "To: " + emails.join(", ") - p.puts messages + p.puts messages + end end + rescue => detail + if Puppet[:debug] + puts detail.backtrace + end + raise Puppet::Error, + "Could not send report emails via sendmail: %s" % detail end - rescue => detail - if Puppet[:debug] - puts detail.backtrace - end - raise Puppet::Error, - "Could not send report emails via sendmail: %s" % detail + else + raise Puppet::Error, "SMTP server is unset and could not find sendmail" end - else - raise Puppet::Error, "SMTP server is unset and could not find sendmail" end end end diff --git a/lib/puppet/server.rb b/lib/puppet/server.rb index 84d2940c3..6809c7c36 100644 --- a/lib/puppet/server.rb +++ b/lib/puppet/server.rb @@ -143,6 +143,10 @@ module Puppet # the base class for the different handlers class Handler attr_accessor :server + class << self + include Puppet::Util + end + @subclasses = [] def self.each diff --git a/lib/puppet/server/report.rb b/lib/puppet/server/report.rb index 027c78f9d..6253f6a0e 100755 --- a/lib/puppet/server/report.rb +++ b/lib/puppet/server/report.rb @@ -2,18 +2,29 @@ module Puppet class Server # A simple server for triggering a new run on a Puppet client. class Report < Handler + class << self + include Puppet::Util::ClassGen + end + + module ReportBase + include Puppet::Util::Docs + attr_writer :useyaml + + def useyaml? + if defined? @useyaml + @useyaml + else + false + end + end + end + @interface = XMLRPC::Service::Interface.new("puppetreports") { |iface| iface.add_method("string report(array)") } Puppet.setdefaults(:reporting, - :reportdirectory => {:default => "$vardir/reports", - :mode => 0750, - :owner => "$user", - :group => "$group", - :desc => "The directory in which to store reports received from the - client. Each client gets a separate subdirectory."}, - :reports => ["none", + :reports => ["store", "The list of reports to generate. All reports are looked for in puppet/reports/<name>.rb, and multiple report names should be comma-separated (whitespace is okay)." @@ -27,19 +38,19 @@ class Server attr_reader :hooks end - def self.reportmethod(report) - "report_" + report.to_s - end + # Add a new report type. + def self.newreport(name, options = {}, &block) + name = symbolize(name) - # Add a hook for processing reports. - def self.newreport(name, &block) - name = name.intern if name.is_a? String - method = reportmethod(name) + mod = genmodule(name, :extend => ReportBase, :hash => @reports, :block => block) - # We want to define a method so that reports can use 'return'. - define_method(method, &block) + if options[:useyaml] + mod.useyaml = true + end - @reports[name] = method + mod.send(:define_method, :report_name) do + name + end end # Load a report. @@ -58,8 +69,12 @@ class Server return nil end end + @reports[symbolize(name)] + end - @reports[name] + def self.reports + @reportloader.loadall + @reports.keys end def initialize(*args) @@ -68,24 +83,8 @@ class Server Puppet.config.use(:metrics) end - # Dynamically create the report methods as necessary. - def method_missing(name, *args) - if name.to_s =~ /^report_(.+)$/ - if self.class.report($1) - send(name, *args) - else - super - end - else - super - end - end - # Accept a report from a client. def report(report, client = nil, clientip = nil) - # We need the client name for storing files. - client ||= Facter["hostname"].value - # Unescape the report unless @local report = CGI.unescape(report) @@ -99,74 +98,39 @@ class Server puts detail.backtrace end end - - # We don't want any tracking back in the fs. Unlikely, but there - # you go. - client.gsub("..",".") - - dir = File.join(Puppet[:reportdirectory], client) - - unless FileTest.exists?(dir) - mkclientdir(client, dir) - end - - # Now store the report. - now = Time.now.gmtime - name = %w{year month day hour min}.collect do |method| - # Make sure we're at least two digits everywhere - "%02d" % now.send(method).to_s - end.join("") + ".yaml" - - file = File.join(dir, name) - - begin - File.open(file, "w", 0640) do |f| - f.puts report - end - rescue => detail - if Puppet[:trace] - puts detail.backtrace - end - Puppet.warning "Could not write report for %s at %s: %s" % - [client, file, detail] - end - - - # Our report is in YAML - return file end private - def mkclientdir(client, dir) - Puppet.config.setdefaults("reportclient-#{client}", - "clientdir-#{client}" => { :default => dir, - :mode => 0750, - :owner => "$user", - :group => "$group" - } - ) - - Puppet.config.use("reportclient-#{client}") - end - # Process the report using all of the existing hooks. - def process(report) + def process(yaml) return if Puppet[:reports] == "none" # First convert the report to real objects begin - report = YAML.load(report) + report = YAML.load(yaml) rescue => detail Puppet.warning "Could not load report: %s" % detail return end + # Used for those reports that accept yaml + client = report.host + reports().each do |name| - if method = self.class.report(name) and respond_to? method + if mod = self.class.report(name) Puppet.info "Processing report %s" % name + + # We have to use a dup because we're including a module in the + # report. + newrep = report.dup begin - send(method, report) + newrep.extend(mod) + if mod.useyaml? + newrep.process(yaml) + else + newrep.process + end rescue => detail if Puppet[:trace] puts detail.backtrace diff --git a/lib/puppet/util/classgen.rb b/lib/puppet/util/classgen.rb index dabbda3d1..8fa2a34cf 100644 --- a/lib/puppet/util/classgen.rb +++ b/lib/puppet/util/classgen.rb @@ -154,6 +154,15 @@ module Puppet::Util::ClassGen end end + [:include, :extend].each do |method| + if set = options[method] + set = [set] unless set.is_a?(Array) + set.each do |mod| + klass.send(method, mod) + end + end + end + if klass.respond_to? :preinit klass.preinit end |