#!/usr/bin/perl -w
-if (@ARGV != 3) {
- print STDERR "Syntax: ${0} host /path/to/file.rrd /output/directory/\n";
+if ((@ARGV != 1) && (@ARGV != 2)) {
+ print STDERR "Syntax: ${0} configfile [uid]\n";
exit(1);
}
-my $host=$ARGV[0];
-my $rrdfile=$ARGV[1];
-my $outdir=$ARGV[2];
-my $community="public";
-my $step=60;
-
-my @fields = ( 'inputV', 'outputV', 'inputHZ', 'outputHZ', 'battT', 'battC', 'load', 'ambT', 'ambH', 'timeR', 'timeO' );
-
-my $vars = {
- 'inputV' => {
- 'name' => 'Input Voltage',
- 'oidtext' => 'PowerNet-MIB::upsAdvInputLineVoltage.0',
- 'oid' => '1.3.6.1.4.1.318.1.1.1.3.2.1.0',
- 'min' => '180',
- 'max' => '280',
- },
- 'outputV' => {
- 'name' => 'Output Voltage',
- 'oidtext' => 'PowerNet-MIB::upsAdvOutputVoltage.0',
- 'oid' => '1.3.6.1.4.1.318.1.1.1.4.2.1.0',
- 'min' => '180',
- 'max' => '280',
- },
- 'inputHZ' => {
- 'name' => 'Input Frequency',
- 'oidtext' => 'PowerNet-MIB::upsAdvInputFrequency.0',
- 'oid' => '1.3.6.1.4.1.318.1.1.1.3.2.4.0',
- 'min' => '40',
- 'max' => '60',
- },
- 'outputHZ' => {
- 'name' => 'Output Frequency',
- 'oidtext' => 'PowerNet-MIB::upsAdvOutputFrequency.0',
- 'oid' => '1.3.6.1.4.1.318.1.1.1.4.2.2.0',
- 'min' => '40',
- 'max' => '60',
- },
- 'battT' => {
- 'name' => 'Battery Temperature',
- 'oidtext' => 'PowerNet-MIB::upsAdvBatteryTemperature.0',
- 'oid' => '1.3.6.1.4.1.318.1.1.1.2.2.2.0',
- 'min' => '0',
- 'max' => '100',
- },
- 'battC' => {
- 'name' => 'Battery Capacity',
- 'oidtext' => 'PowerNet-MIB::upsAdvBatteryCapacity.0',
- 'oid' => '1.3.6.1.4.1.318.1.1.1.2.2.1.0',
- 'min' => '0',
- 'max' => '110',
- },
- 'load' => {
- 'name' => 'UPS Load',
- 'oidtext' => 'PowerNet-MIB::upsAdvOutputLoad.0',
- 'oid' => '1.3.6.1.4.1.318.1.1.1.4.2.3.0',
- 'min' => '0',
- 'max' => '110',
- },
- 'ambT' => {
- 'name' => 'Ambient Temperature',
- 'oidtext' => 'PowerNet-MIB::mUpsEnvironAmbientTemperature.0',
- 'oid' => '1.3.6.1.4.1.318.1.1.2.1.1.0',
- 'min' => '0',
- 'max' => '60',
- },
- 'ambH' => {
- 'name' => 'Ambient Humidity',
- 'oidtext' => 'PowerNet-MIB::mUpsEnvironRelativeHumidity.0',
- 'oid' => '1.3.6.1.4.1.318.1.1.2.1.2.0',
- 'min' => '0',
- 'max' => '100',
- },
- 'timeR' => {
- 'name' => 'Time Remaining',
- 'oidtext' => 'PowerNet-MIB::upsAdvBatteryRunTimeRemaining.0',
- 'oid' => '1.3.6.1.4.1.318.1.1.1.2.2.3.0',
- 'factor' => 1/6000,
- 'min' => '0',
- 'max' => '360',
- },
- 'timeO' => {
- 'name' => 'Time On Battery',
- 'oidtext' => 'PowerNet-MIB::upsBasicBatteryTimeOnBattery.0',
- 'oid' => '1.3.6.1.4.1.318.1.1.1.2.1.2.0',
- 'factor' => 1/6000,
- 'min' => '0',
- 'max' => '360',
- },
-};
-
use Net::SNMP;
+use RRDs;
+use Data::Dumper;
-if (! -e "${rrdfile}") {
- my $cmd = "rrdtool create \"${rrdfile}\" ";
- foreach my $var (@fields) {
- $cmd .= "DS:${var}:GAUGE:600:" .
- $vars->{$var}->{'min'} . ":" .
- $vars->{$var}->{'max'} . " ";
+$UPSGRAPH::host = "";
+$UPSGRAPH::rrdfile = "";
+$UPSGRAPH::outdir = "";
+$UPSGRAPH::community = "public";
+$UPSGRAPH::step = 60;
+$UPSGRAPH::keep = (370*24*60*60)/$UPSGRAPH::step;
+@UPSGRAPH::fields = ();
+$UPSGRAPH::vars = {};
+
+do $ARGV[0] or die "can't read config: $!";
+
+my $host = $UPSGRAPH::host;
+my $rrdfile = $UPSGRAPH::rrdfile;
+my $outdir = $UPSGRAPH::outdir;
+my $community = $UPSGRAPH::community;
+my $step = $UPSGRAPH::step;
+my $keep = $UPSGRAPH::keep;
+my @fields = @UPSGRAPH::fields;
+my $vars = $UPSGRAPH::vars;
+
+sub rrdcreate(@) {
+ my $newrrd = shift;
+ my $field = shift;
+ my $start = shift;
+
+ my @cmd = ("${newrrd}", "--step=${step}");
+
+ if (defined($start)) {
+ push @cmd, "--start=${start}";
+ }
+
+ push @cmd, "DS:${field}:GAUGE:600:" .
+ $vars->{$field}->{'min'} . ":" .
+ $vars->{$field}->{'max'} . " ";
+
+ push @cmd, "RRA:AVERAGE:0.5:1:${keep}";
+
+ RRDs::create(@cmd);
+ if (RRDs::error) {
+ print "Error while creating: " . RRDs::error . "\n";
+ exit 1;
+ }
+}
+
+if ($> == 0) {
+ if (@ARGV != 2) {
+ print STDERR "Running as root, please provide UID as 2th argument!\n";
+ exit(1);
+ }
+
+ print "Running as root, switching to ".$ARGV[1]."\n";
+ $< = $> = $ARGV[1];
+}
+
+if (-e "${rrdfile}") {
+ print "Reading old ${rrdfile} to preserve data...\n";
+
+ my $rrdinfo = RRDs::info("${rrdfile}");
+ if (RRDs::error) {
+ print "Error while getting info: " . RRDs::error . "\n";
+ exit 1;
+ }
+
+ (my $start, my $ostep, my $names, my $data) =
+ RRDs::fetch("${rrdfile}",
+ "-s " . (time() - ($rrdinfo->{'rra[0].rows'} * $rrdinfo->{'step'})),
+ "AVERAGE");
+
+ if (RRDs::error) {
+ print "Error while fetching data: " . RRDs::error . "\n";
+ exit 1;
+ }
+
+ foreach my $field (@$names) {
+ if (! -e "${rrdfile}.${field}") {
+ rrdcreate("${rrdfile}.${field}","${field}",(${start}-${ostep}));
+ }
+ }
+
+ my $pos = $start;
+ foreach my $line (@$data) {
+ foreach my $field (@$names) {
+ my $val = shift (@$line);
+ next if (!defined($val));
+
+ RRDs::update("${rrdfile}.${field}", "${pos}:${val}");
+ if (RRDs::error) {
+ print "Can't insert data: " . RRDs::error . "\n";
+ exit 1;
+ }
+
+ }
+
+ $pos += $ostep;
+
+ if ((($pos-$start)/$ostep) == $#$data) {
+ last;
+ }
+ }
+
+ rename("${rrdfile}", "${rrdfile}.old") or die "Can't rename old file: $!\n";
+}
+
+foreach my $field (@fields) {
+ if (! -e "${rrdfile}.${field}") {
+ print "Creating ${rrdfile}.${field}...\n";
+ rrdcreate("${rrdfile}.${field}","${field}");
}
- $cmd .= "RRA:AVERAGE:0.5:1:10080 --step ${step}";
- print "Creating ${rrdfile}...\n";
- print `${cmd}`;
+ my $rrdinfo = RRDs::info("${rrdfile}.${field}");
+ if (RRDs::error) {
+ print "Error while getting info: " . RRDs::error . "\n";
+ exit 1;
+ }
+
+ if ($rrdinfo->{'rra[0].rows'} != $keep) {
+ print "Resizing ${rrdfile}.${field} from " . $rrdinfo->{'rra[0].rows'} .
+ " to ${keep} samples.\n";
+
+ (my $start, my $ostep, my $names, my $data) =
+ RRDs::fetch("${rrdfile}.${field}",
+ "-s " . (time() - ($rrdinfo->{'rra[0].rows'} * $rrdinfo->{'step'})),
+ "AVERAGE");
+
+ if (RRDs::error) {
+ print "Error while fetching data: " . RRDs::error . "\n";
+ exit 1;
+ }
+
+ rrdcreate("${rrdfile}.${field}.new", "${field}", (${start}-${ostep}));
+
+ print "Preserving data since " . localtime($start) . "\n";
+
+ my $pos = $start;
+ foreach my $line (@$data) {
+ my $vline = "${pos}";
+
+ foreach my $val (@$line) {
+ $val = 'U' if (!defined($val));
+ $vline .= ":${val}";
+ }
+ RRDs::update("${rrdfile}.${field}.new", $vline) or die "Can't insert data\n";
+
+ if (RRDs::error) {
+ print "Error while updating: " . RRDs::error . "\n";
+ exit 1;
+ }
+ $pos += $ostep;
+
+ if ((($pos-$start)/$ostep) == $#$data) {
+ last;
+ }
+ }
+
+ rename("${rrdfile}.${field}", "${rrdfile}.${field}.old") or die "Can't rename old file: $!\n";
+ rename("${rrdfile}.${field}.new", "${rrdfile}.${field}") or die "Can't rename new file: $!\n";
+
+ $rrdinfo = RRDs::info("${rrdfile}.${field}");
+ if (RRDs::error) {
+ print "Error while getting info: " . RRDs::error . "\n";
+ exit 1;
+ }
+
+ if ($rrdinfo->{'rra[0].rows'} != $keep) {
+ print "Failed!\n";
+ exit 1;
+ }
+ }
}
+my $child = fork();
+
+die "fork failed!" if (!defined($child));
+
+exit 0 if ($child != 0);
+
while(1) {
($session,$error) = Net::SNMP->session(Hostname => $host,
Community => $community);
$session->close;
- my $cmd = "rrdtool update \"${rrdfile}\" \"N";
foreach my $var (@fields) {
if (!(defined($vars->{$var}->{'value'}))) {
$vars->{$var}->{'value'} = 'U';
}
- print $vars->{$var}->{'name'}.": ".$vars->{$var}->{'value'}."\n";
- $cmd .= ":" . $vars->{$var}->{'value'};
+ RRDs::update("${rrdfile}.${var}", "N:" . $vars->{$var}->{'value'});
+ }
+ if (RRDs::error) {
+ print "Error while updating: " . RRDs::error . "\n";
}
- $cmd .= "\"";
- print `${cmd}`;
open(HTML, ">${outdir}/index.html.new");
print HTML '<body bgcolor="#ffffff">';
foreach my $var (@fields) {
- my $graphdef = "-t \"" . $vars->{$var}->{'name'} . "\" \"DEF:${var}=${rrdfile}:${var}:AVERAGE\" \"LINE1:${var}#FF0000\"";
- my $cmd = "rrdtool graph \"${outdir}/${var}.png.new\" -w 720 ${graphdef}";
- my $size = `$cmd`;
- rename("${outdir}/${var}.png.new", "${outdir}/${var}.png");
- (my $width, my $height) = split(/x/,$size);
+ my @graphdef = ("-t", $vars->{$var}->{'name'}, "DEF:${var}=${rrdfile}.${var}:${var}:AVERAGE", "LINE1:${var}#FF0000");
+ (my $averages, my $width, my $height) =
+ RRDs::graph("${outdir}/${var}.png.new",
+ "-w", "720", @graphdef);
+
+ if (RRDs::error) {
+ print "Error while graphing: " . RRDs::error . "\n";
+ } else {
+ rename("${outdir}/${var}.png.new", "${outdir}/${var}.png");
+ }
+
+ print HTML "<a href=\"${var}.html\"><img src=\"${var}.png\" width=\"${width}\" height=\"${height}\" border=\"0\"></a>";
+
+ open (HTML2, ">${outdir}/${var}.html.new");
+ print HTML2 "<html><head><title>" . $vars->{$var}->{'name'} . "</title></head>";
+ print HTML2 '<body bgcolor="#ffffff">';
+
+ ($averages, $width, $height) =
+ RRDs::graph("${outdir}/${var}.long.png.new",
+ "-w", "1008", @graphdef);
+
+ if (RRDs::error) {
+ print "Error while graphing: " . RRDs::error . "\n";
+ } else {
+ rename("${outdir}/${var}.long.png.new", "${outdir}/${var}.long.png");
+ }
+
+ print HTML2 "<img src=\"${var}.long.png\" width=\"${width}\" height=\"${height}\"><br>";
+
+ ($averages, $width, $height) =
+ RRDs::graph("${outdir}/${var}.week.png.new",
+ "-w", "1008", "-e", "now", "-s", "end-1w", @graphdef);
+
+ if (RRDs::error) {
+ print "Error while graphing: " . RRDs::error . "\n";
+ } else {
+ rename("${outdir}/${var}.week.png.new", "${outdir}/${var}.week.png");
+ }
+
+ print HTML2 "<img src=\"${var}.week.png\" width=\"${width}\" height=\"${height}\"><br>";
+
+ ($averages, $width, $height) =
+ RRDs::graph("${outdir}/${var}.year.png.new",
+ "-w", "1008", "-e", "now", "-s", "end-1y", @graphdef);
+
+ if (RRDs::error) {
+ print "Error while graphing: " . RRDs::error . "\n";
+ } else {
+ rename("${outdir}/${var}.year.png.new", "${outdir}/${var}.year.png");
+ }
- my $cmd2 = "rrdtool graph \"${outdir}/${var}.long.png.new\" -w 1008 -e now -s end-1w ${graphdef}";
- my $size2 = `$cmd2`;
- rename("${outdir}/${var}.long.png.new", "${outdir}/${var}.long.png");
+ print HTML2 "<img src=\"${var}.year.png\" width=\"${width}\" height=\"${height}\"><br>";
- print HTML "<a href=\"${var}.long.png\"><img src=\"${var}.png\" width=\"${width}\" height=\"${height}\" border=\"0\"></a>";
+ print HTML2 "</body></html>\n";
+ close(HTML2);
+ rename("${outdir}/${var}.html.new", "${outdir}/${var}.html");
}
print HTML "</body></html>\n";
print HTML "<br>Generated on: " . localtime(time());
+ print HTML ' by <a href="http://git.zerfleddert.de/cgi-bin/gitweb.cgi/upsgraph">upsgraph</a>.';
close(HTML);