#!/usr/bin/perl -w if ((@ARGV != 1) && (@ARGV != 2)) { print STDERR "Syntax: ${0} configfile [uid]\n"; exit(1); } use Net::SNMP; use IO::Socket::INET; use RRDs; use Data::Dumper; $UPSGRAPH::outdir = ""; $UPSGRAPH::step = 60; $UPSGRAPH::keep = (370*24*60*60)/$UPSGRAPH::step; $UPSGRAPH::hosts = (); do $ARGV[0] or die "can't read config: $!"; my $outdir = $UPSGRAPH::outdir; my $step = $UPSGRAPH::step; my $keep = $UPSGRAPH::keep; my $hosts = $UPSGRAPH::hosts; sub rrdcreate(@) { my $newrrd = shift; my $field = shift; my $vars = 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; } } sub fetch_snmp(@) { my $address = shift; my $community = shift; my $oid = shift; (my $session, my $error) = Net::SNMP->session(Hostname => $address, Community => $community); if (!$session) { print STDERR "session error: $error"; } $session->translate(0); my $result = $session->get_request($oid); $session->close; return undef if (!defined($result)); $result->{$oid}; } sub fetch_tcp(@) { my $address = shift; my $port = shift; my $sock = IO::Socket::INET->new(PeerAddr => $address, PeerPort => $port, Proto => 'tcp', Timeout => 1); return undef if (!$sock); chomp(my $value = <$sock>); close($sock); if (!$value) { return undef; } $value=~ s/\s//g; $value; } 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]; } foreach my $host (@$hosts) { my $rrdfile = $host->{'rrdfile'}; foreach my $var (keys(%{$host->{'vars'}})) { $host->{'vars'}->{$var}->{'min'} = 'U' if (!defined($host->{'vars'}->{$var}->{'min'})); $host->{'vars'}->{$var}->{'max'} = 'U' if (!defined($host->{'vars'}->{$var}->{'max'})); } 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}", $host->{'vars'}, (${start}-${ostep})); } } my $pos = $start; foreach my $line (@$data) { foreach my $field (@$names) { my $val = shift (@$line); $val = 'U' 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 (@{$host->{'fields'}}) { if (! -e "${rrdfile}.${field}") { print "Creating ${rrdfile}.${field}...\n"; rrdcreate("${rrdfile}.${field}", "${field}", $host->{'vars'}); } my $rrdinfo = RRDs::info("${rrdfile}.${field}"); if (RRDs::error) { print "Error while getting info: " . RRDs::error . "\n"; exit 1; } if (defined($rrdinfo->{"ds[${field}].min"})) { if ($rrdinfo->{"ds[${field}].min"} ne $host->{'vars'}->{$field}->{'min'}) { RRDs::tune("${rrdfile}.${field}","-i",$field.":".$host->{'vars'}->{$field}->{'min'}); } } else { if ($host->{'vars'}->{$field}->{'min'} ne 'U') { RRDs::tune("${rrdfile}.${field}","-i",$field.":".$host->{'vars'}->{$field}->{'min'}); } } if (RRDs::error) { print "Error while setting min: " . RRDs::error . "\n"; exit 1; } if (defined($rrdinfo->{"ds[${field}].max"})) { if ($rrdinfo->{"ds[${field}].max"} ne $host->{'vars'}->{$field}->{'max'}) { RRDs::tune("${rrdfile}.${field}","-a",$field.":".$host->{'vars'}->{$field}->{'max'}); } } else { if ($host->{'vars'}->{$field}->{'max'} ne 'U') { RRDs::tune("${rrdfile}.${field}","-a",$field.":".$host->{'vars'}->{$field}->{'max'}); } } if (RRDs::error) { print "Error while setting max: " . 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}", $host->{'vars'}, (${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) { open(HTML, ">${outdir}/index.html.new"); print HTML '