%PDF- %PDF-
| Direktori : /proc/self/root/data/old/usr/share/munin/ |
| Current File : //proc/self/root/data/old/usr/share/munin/munin-graph |
#!/usr/bin/perl
# -*- cperl -*-
=encoding utf8
=head1 NAME
munin-graph - generate graphs from RRD files
=begin comment
Copyright (C) 2004-2010 Jimmy Olsen, Steve Schnepp
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 dated June,
1991.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
=end comment
=cut
use strict;
use warnings;
use IO::Handle;
BEGIN {
# This is needed because Date::Manip has deprecated the functional
# interface in >= 6.x. So, we force the use of the 5.x API.
$Date::Manip::Backend = 'DM5';
# Double line here to avoid spurious warnings about D::M::Backend being
# used only once.
$Date::Manip::Backend = 'DM5';
}
use Date::Manip;
use POSIX qw(strftime);
use Time::HiRes qw(gettimeofday tv_interval);
use IO::File;
use Munin::Master::GraphOld;
use Munin::Master::Utils;
use Munin::Master::Logger;
use Log::Log4perl qw( :easy );
my $GRAPHER = "$Munin::Common::Defaults::MUNIN_LIBDIR/munin-graph";
my $conffile = "$Munin::Common::Defaults::MUNIN_CONFDIR/munin.conf";
my %period = ( "day" => 300,
"week" => 1800,
"month" => 7200,
"year" => 86400,
"week-sum" => 1800,
"year-sum" => 86400
);
my $logfile;
my $scale = "day";
my @params = @ARGV;
push @params, "--no-fork"; # We do *not* want to fork. Perf -> FastCGI
push @params, "--log-file", $logfile;
my $config = graph_startup(\@params);
logger_open($config->{'logdir'});
logger_debug() if $config->{debug} or defined($ENV{CGI_DEBUG});
if (! graph_check_cron() ) {
# Should not be launched from cron.
INFO "[INFO] graphing is cgi, do nothing";
exit 0;
}
INFO "Starting munin-graph";
my $graph_time = Time::HiRes::time;
# BEGIN FAST-CGI LOOP:
my $nb_request = 0;
my $nb_request_max = 0;
my $graph_fh = new IO::File($config->{dbdir} . "/graphs");
while (my $path = <$graph_fh>) {
my $pinpoint = undef;
DEBUG "Request path is $path";
# The full URL looks like this:
# Case 1:
# http://localhost:8080/munin-cgi/munin-cgi-graph/client/\
# Backend/dafnes.client.example.com/diskstats_iops-week.png
# $path should be
# client/Backend/dafnes.client.example.com/diskstats_iops-week.png
#
# Interesting bits about that url: Nested groups!
#
# Case 2:
# http://localhost:8080/munin-cgi/munin-cgi-graph/client/\
# Backend/dafnes.client.example.com/diskstats_iops/sda-week.png
# path should be
# client/Backend/dafnes.client.example.com/diskstats_iops/\
# sda-week.png
#
# Interesting bit that url: Nested groups at the start and multigraph
# nesting bits at the end.
#
# Case 3:
# http://localhost:8080/munin-cgi/munin-cgi-graph/client/\
# dafnes.client.example.com/if_err_bond0-day.png
# path:
# client/dafnes.client.example.com/if_err_bond0-day.png
#
# Simplest (old munin 1.2): No nesting at any end, fixed number of /es
#
# Despite the slippery structure of the $path this expression works with
# the rest of the code. To make a more scientific try we would need to
# split on / and traverse the $config to determine what kind of part
# (domain, nested domain, host, service/plugin, or nested service)
# we're looking at.
#
# Scale will in any case work out since - is only used before the
# day/week/month/year/pinpoint part, and the next part is always .png.
#
my ($dom, $host, $serv, $scale) =
$path =~ m#^/(.*)/([^/]+)/(\w+)-([\w=,]+)\.png#; ## avoid bug in vim
DEBUG "asked for ($dom, $host, $serv, $scale)";
if ($scale =~ /pinpoint=(\d+),(\d+)/) {
$pinpoint = [ $1, $2, ];
}
if (! &verify_parameters ($dom, $host, $serv, $scale)) {
ERROR "Invalid parameters!";
next;
}
my $filename = get_picture_filename ($config, $dom, $host, $serv, $scale, $ENV{QUERY_STRING});
my $time = time;
my $no_cache = 0;
# Compute the cache values
my $graph_ttl = $period{$scale} || 1;
my $graph_last_expires = $time - ($time % $graph_ttl);
if ($pinpoint || ! -f $filename || (stat(_))[9] < $graph_last_expires) {
# Should generate it
my $scale_options;
if ($pinpoint) {
$scale_options = "--pinpoint=" . $pinpoint->[0] . "," . $pinpoint->[1];
} else {
$scale_options = "--$scale";
}
next unless
draw_graph_or_complain($dom, $host, $serv, $scale_options, $filename);
}
# Now send it: headers
DEBUG "X-Munin-Request: $nb_request/$nb_request_max";
} continue {
$nb_request++;
if ($nb_request_max && $nb_request > $nb_request_max) {
# Cycle
last;
}
}
# END FAST-CGI LOOP - Time to die. Nicely.
$graph_time = sprintf("%.2f", (Time::HiRes::time - $graph_time));
INFO "Munin-graph finished ($graph_time sec)";
exit 0;
sub get_w3c_date_from_epoch {
my($epoch) = @_;
return strftime("%a, %d %b %Y %H:%M:%S GMT", gmtime($epoch));
}
sub send_graph_data {
# Serve the graph contents.
my($filename) = @_;
my $buffer;
if (! open (GRAPH_PNG_FILE, '<', $filename) ) {
ERROR "[FATAL] Could not open image file \"$filename\" for reading: $!\n";
die "[FATAL] Could not open image file \"$filename\" for reading: $!\n";
}
# No buffering wanted when sending the file
local $| = 1;
while (sysread(GRAPH_PNG_FILE,$buffer,40960)) {
print $buffer;
}
close (GRAPH_PNG_FILE);
}
sub get_picture_filename {
my $config = shift;
my $domain = shift;
my $name = shift;
my $service = shift;
my $scale = shift;
my $params = shift;
my $cgi_tmp_dir = $config->{htmldir};
$params = $params ? "?$params" : "";
$params =~ tr/\//_/; # / are forbidden in a filename
$params = $1 if $params =~ m/(.*)/; # XXX - Q&D untaint
return "$cgi_tmp_dir/$domain/$name/$service-$scale.png" . $params;
}
sub verify_parameters {
my $dom = shift;
my $host = shift;
my $serv = shift;
my $scale = shift;
if (!$dom) {
WARN '[WARNING] Request for graph without specifying domain. Bailing out.';
return 0;
}
if (!$host) {
WARN '[WARNING] Request for graph without specifying host. Bailing out.';
return 0;
}
if (!$serv) {
WARN '[WARNING] Request for graph without specifying service. Bailing out.';
return 0;
}
if (!$scale) {
WARN '[WARNING] Request for graph without specifying scale. Bailing out.';
return 0;
} else {
if (!defined $period{$scale} && $scale !~ /pinpoint=\d+,\d+/) {
WARN '[WARNING] Weird pinpoint setting "'.$scale.'". Bailing out.';
return 0;
}
}
return 1;
}
sub file_newer_than {
my $filename = shift;
my $time = shift;
if (-f $filename) {
my @stats = stat (_);
# $stats[9] holds the "last update" time and this needs
# to be in the last update period
my $last_update = $stats[9];
if ($last_update > $time) {
return $last_update;
} else {
return 0;
}
}
# No file found
return 0;
}
sub draw_graph {
my $dom = shift;
my $host = shift;
my $serv = shift;
my $scale = shift;
my $filename = shift;
# remove old file if present
if (-f $filename and !unlink($filename)) {
ERROR "[FATAL] Could not remove \"$filename\": $!";
die("[FATAL] cannot remove old graph file \"$filename\": $!");
}
$serv =~ s{[^\w_\/"'\[\]\(\)+=-]}{_}g; $serv =~ /^(.+)$/; $serv = $1; #"
# . needs to be legal in host names
$host =~ s{[^\w_\/"'\[\]\(\)\.+=-]}{_}g; $host =~ /^(.+)$/; $host = $1; #"
# FIXME: Make "root" implied!
my @params = ( '--host', $host,
'--only-fqn', "root/$dom/$host/$serv",
$scale,
'--output-file', $filename );
graph_main(\@params);
return $filename;
}
sub draw_graph_or_complain {
my $t0 = [ gettimeofday ];
# Actuall work done here.
my $ret = draw_graph(@_);
my $graph_duration = tv_interval($t0);
if (! -f $ret) {
my ($dom, $host, $serv, $scale, $filename ) = @_;
WARN "[WARNING] Could not draw graph \"$filename\": $ret";
return 0;
} else {
return $ret;
}
}
sub rfctime_newer_than {
# See if the file has been modified since "the last time".
# Format of since_string If-Modified-Since: Wed, 23 Jun 2004 16:11:06 GMT
my $since_string = shift;
my $created = shift;
my $ifmodsec = &UnixDate (&ParseDateString ($since_string), "%s");
return 1 if ($ifmodsec < $created);
return 0;
}
# vim: syntax=perl ts=8