require 'puppet'
Puppet::Network::Handler.report.newreport(:rrdgraph) do
desc "Graph all available data about hosts using the RRD library. You
must have the Ruby RRDtool library installed to use this report, which
you can get from `the RubyRRDTool RubyForge page`_. This package requires
the binary rrdtool2 package to be installed.
.. _the RubyRRDTool RubyForge page: http://rubyforge.org/projects/rubyrrdtool/
This report will create, manage, and graph RRD database files for each
of the metrics generated during transactions, and it will create a
few simple html files to display the reporting host's graphs. At this
point, it will not create a common index file to display links to
all hosts.
All RRD files and graphs get created in the ``rrddir`` directory. If
you want to serve these publicly, you should be able to just alias that
directory in a web server.
If you really know what you're doing, you can tune the ``rrdinterval``,
which defaults to the ``runinterval``."
def hostdir
unless defined? @hostdir
@hostdir = File.join(Puppet[:rrddir], self.host)
end
@hostdir
end
def htmlfile(type, graphs, field)
file = File.join(hostdir, "%s.html" % type)
File.open(file, "w") do |of|
of.puts "
%s graphs for %s" %
[type.capitalize, host]
graphs.each do |graph|
if field == :first
name = graph.sub(/-\w+.png/, '').capitalize
else
name = graph.sub(/\w+-/, '').sub(".png", '').capitalize
end
of.puts "
" % graph
end
of.puts ""
end
return file
end
def mkhtml
images = Dir.entries(hostdir).find_all { |d| d =~ /\.png/ }
periodorder = %w{daily weekly monthly yearly}
periods = {}
types = {}
images.each do |n|
type, period = n.sub(".png", '').split("-")
periods[period] ||= []
types[type] ||= []
periods[period] << n
types[type] << n
end
files = []
# Make the period html files
periodorder.each do |period|
unless ary = periods[period]
raise Puppet::Error, "Could not find graphs for %s" % period
end
files << htmlfile(period, ary, :first)
end
# make the type html files
types.sort { |a,b| a[0] <=> b[0] }.each do |type, ary|
newary = []
periodorder.each do |period|
if graph = ary.find { |g| g.include?("-%s.png" % period) }
newary << graph
else
raise "Could not find %s-%s graph" % [type, period]
end
end
files << htmlfile(type, newary, :second)
end
File.open(File.join(hostdir, "index.html"), "w") do |of|
of.puts "Report graphs for %s" %
host
files.each do |file|
of.puts "%s
" %
File.basename(file).sub(".html",'').capitalize
end
of.puts ""
end
end
def process(time = nil)
time ||= Time.now.to_i
unless File.directory?(hostdir) and FileTest.writable?(hostdir)
# Some hackishness to create the dir with all of the right modes and ownership
config = Puppet::Util::Config.new
config.setdefaults(:reports, :hostdir => {:default => hostdir, :owner => Puppet[:user], :mode => 0755, :group => Puppet[:group], :desc => "eh"})
# This creates the dir.
config.use(:reports)
end
self.metrics.each do |name, metric|
metric.basedir = hostdir
if name == "time"
timeclean(metric)
end
metric.store(time)
metric.graph
end
unless FileTest.exists?(File.join(hostdir, "index.html"))
mkhtml()
end
end
# Unfortunately, RRD does not deal well with changing lists of values,
# so we have to pick a list of values and stick with it. In this case,
# that means we record the total time, the config time, and that's about
# it. We should probably send each type's time as a separate metric.
def timeclean(metric)
metric.values = metric.values.find_all { |name, label, value| [:total, :config_retrieval].include?(name) }
end
end
# $Id$