diff options
Diffstat (limited to 'bin/tSmoke.dist')
-rwxr-xr-x | bin/tSmoke.dist | 543 |
1 files changed, 0 insertions, 543 deletions
diff --git a/bin/tSmoke.dist b/bin/tSmoke.dist deleted file mode 100755 index e389ff2..0000000 --- a/bin/tSmoke.dist +++ /dev/null @@ -1,543 +0,0 @@ -#!/usr/bin/perl -# -#----------------------------------------------- -# tSmoke.pl -# Dan McGinn-Combs, Sep 2003 -# tSmoke.v 0.4 2004/03 McGinn-Combs -#----------------------------------------------- -# -# Modified for Smokeping official distribution since 20050526 -# Original README follows -# -# tSmoke.v04.README -# - added downtime report (--downtime) -# - a few tweaks to the calculations to ensure it's consistent -# -# tSmoke.v03.README -# - Initial Release -# - The script, started through cron, will cull through a config file and -# determine which hosts are down at a point in time (Morning report) and -# send out an smtp message to a mobile phone (for example). -# -# - It will also cull through the same config file and, using an included html -# file (small change to General section of the config file), send an html -# message which shows the availability over the past day, week, month -# and quarter. -# -# - It can also show detail data depending on the setting of -# command line option "detail". -# -# tSmoke.v02.README -# - Local testing version -#----------------------------------------------- -# -# 1) This program is run via CRON or the command line -# 2) It extracts RRD information from a smokeping config file -# 3) It pulls data from RRD files to determine if anything is offline, that is returning 0 PINGs -# 4) tSmoke reports status via an SMTP alert -# 5) tSmoke also generates an SMTP mail showing historical view of availability -# -# Many thanks to the following people for their help and guidance: -# Jim Horwath of Agere Systems Inc. for his examples and pointers to Spreadsheet::WriteExcel -# Frank Harper the author of SLAMon, a tool for tracking Service Level Agreements -# Tobias Oetiker, or course, the author of Smokeping, RRDTool and MRTG -# -use strict; -use warnings; - -# We need to use -# -- Smokeping libraries -# -- RRDTool -# -- Getopt::Long -# -# Point the lib variables to your implementation -use lib qw(lib); -use lib qw(/usr/local/rrdtool-1.0.39/lib/perl); - -use Smokeping 2.004002; -use Net::SMTP; -use Getopt::Long; -use Pod::Usage; -use RRDs; - -# Point to your Smokeping config file -my $cfgfile = "etc/config.dist"; - -# global variables -my $cfg; - -#this is designed to work on IPv4 only -my $havegetaddrinfo = 0; - -# we want opts everywhere -my %opt; - -#Hashes for the data -my (%Daily,%Weekly,%Monthly,%Quarterly); # the entries -my (%DailyC,%WeeklyC,%MonthlyC,%QuarterlyC); # a count of the entries - -###################### -### Moving Average ### -###################### -# Just a reminder of how to do a moving average if you ever want to -# PREV,UN,<DS>,UN,1,<DS>,IF,PREV,IF,<DS>,UN,1,<DS>,IF,-,<WEIGHT>,*,A,UN,1,A,IF,+ - -# Change Log: -# DMC - Added Quarterly Status -# DMC - Added HTML mail reporting and consolidated functions -# DMC = Added an external HTML mail template, tMail -my $RCS_VERSION = '$id: tSmoke.v 0.4 2004/03 McGinn-Combs'; - -sub test_mail($) { - my $cfg = shift; - my $mail = <<"EOF"; -Subject: tSmoke test -To: $cfg->{Alerts}{to} - -This is a test mail with 'tSmoke --testmail'. -EOF - print "Sending a test mail to $cfg->{Alerts}{to} from $cfg->{Alerts}{from}..."; - Smokeping::sendmail($cfg->{Alerts}{from}, $cfg->{Alerts}{to}, $mail); - print "done.\n"; -}; - -sub morning_update($) { - # Send out a morning summary of devices that are down - my $cfg = shift; - my $Body = ""; - my $TmpBody = ""; - my $To = ""; - if ( $opt{to} ) { $To = $opt{to}; } else { $To = $cfg->{Alerts}{to}; } - - # Get a list of the existing RRD Files - my @rrds = split ( /\n/,list_rrds($cfg->{Targets},"","") ); - my $Count = $#rrds + 1; - my $Down = 0; - - foreach my $target (@rrds) { - my $Loss = 0; - my ($start,$step,$names,$data) = RRDs::fetch "$target","AVERAGE","--start","-300"; - my $ERR=RRDs::error; - die "ERROR while reading $_: $ERR\n" if $ERR; - foreach my $line (@$data) { - $Loss += $$line[3]; - } - $Down += 1 if $Loss == 0; - $target =~ s/^([a-zA-Z0-9]*\/)*//; - $target =~ s/.rrd//; - $TmpBody .= "$target\n" if $Loss == 0; - } - $Body = <<MAIL_END; -Subject: Of $Count Hosts, $Down Down -To: $To -Content-Type: text/plain; charset=iso-8859-15 -Content-Transfer-encoding: 8bit -MIME-Version: 1.0 - -Of $Count Hosts, $Down Down: - -$TmpBody -MAIL_END - Smokeping::sendmail($cfg->{Alerts}{from},$To,$Body); -} - -sub weekly_update($) { - # Send out a formatted HTML Table of the - # Previous Day, Week, Month and Quarter Availability - # Get a list of the existing RRD Files - my @rrds = split ( /\n/,list_rrds($cfg->{Targets},"","") ); - - my $To = ""; - if ( $opt{to} ) { $To = $opt{to}; } else { $To = $cfg->{Alerts}{to}; } - - my $Body =''; - -# Calculations Based on the following: -# RRDs::graph "fake.png", -# '--start','-86400', -# '-end','-300', -# "DEF:loss=${rrd}:loss:AVERAGE", -# "CDEF:avail=loss,0,100,IF", or more precisely "CDEF:avail=loss,2,GE,0,100,IF" -# and adding in the check for unknown for systems just coming on line -# "CDEF:avail=loss,UN,0,loss,IF,$pings,GE,0,100,IF" - # Arbitrarily a loss of 10% of Pings means the system was down - my $pings = $cfg->{Database}{pings} * .1; - - foreach my $target (@rrds) { - # Get an average Availability for each RRD file - my $ERR; - - my ($DAverage,$Dxsize,$Dysize) = RRDs::graph "fake.png", - "--start","-86400", - "--end","-600", - "--step","1008", - "DEF:loss=$target:loss:AVERAGE", - "CDEF:avail=loss,UN,0,loss,IF,$pings,GE,0,100,IF", - "PRINT:avail:AVERAGE:%.2lf"; - $ERR=RRDs::error; - die "ERROR while reading $_: $ERR\n" if $ERR; - - my ($WAverage,$Wxsize,$Wysize) = RRDs::graph "fake.png", - "--start","-604800", - "--end","-600", - "--step","4320", - "DEF:loss=$target:loss:AVERAGE", - "CDEF:avail=loss,UN,0,loss,IF,$pings,GE,0,100,IF", - "PRINT:avail:AVERAGE:%.2lf"; - $ERR=RRDs::error; - die "ERROR while reading $_: $ERR\n" if $ERR; - - my ($MAverage,$Mxsize,$Mysize) = RRDs::graph "fake.png", - "--start","-2592000", - "--end","-600", - "--step","4320", - "DEF:loss=$target:loss:AVERAGE", - "CDEF:avail=loss,UN,0,loss,IF,$pings,GE,0,100,IF", - "PRINT:avail:AVERAGE:%.2lf"; - $ERR=RRDs::error; - die "ERROR while reading $_: $ERR\n" if $ERR; - - my ($QAverage,$Qxsize,$Qysize) = RRDs::graph "fake.png", - "--start","-7776000", - "--end","-600", - "--step","4320", - "DEF:loss=$target:loss:AVERAGE", - "CDEF:avail=loss,UN,0,loss,IF,$pings,GE,0,100,IF", - "PRINT:avail:AVERAGE:%.2lf"; - $ERR=RRDs::error; - die "ERROR while reading $_: $ERR\n" if $ERR; - - $target =~ s/$cfg->{General}{datadir}\///; - $target =~ s/.rrd//; - my @Path; - push @Path,split/\//,$target; - update_stats ( \@Path, @$DAverage[0], @$WAverage[0], @$MAverage[0], @$QAverage[0]); - } - - # Prepare the e-mail message - $Body = <<MAIL_END; -Subject: IT System Availability -To: $To -Content-Type: text/html; charset=iso-8859-15 -Content-Transfer-encoding: 8bit -MIME-Version: 1.0 - -MAIL_END - open tSMOKE, $cfg->{General}{tmail} or die "ERROR: can't read $cfg->{General}{tmail}\n"; - while (<tSMOKE>){ - my $Summary = Summary_Sheet(); - s/<##SUMMARY##>/$Summary/ig; - my $Daily = DetailSheet(86400); - s/<##DAYDETAIL##>/$Daily/ig; - my $Weekly = DetailSheet(604800); - s/<##WEEKDETAIL##>/$Weekly/ig; - my $Monthly = DetailSheet(2592000); - s/<##MONTHDETAIL##>/$Monthly/ig; - my $Quarterly = DetailSheet(7776000); - s/<##QUARTERDETAIL##>/$Quarterly/ig; - $Body .= $_; - } - close tSMOKE; - Smokeping::sendmail($cfg->{Alerts}{from}, $To, $Body); -} - -sub update_stats($$$$$); -sub update_stats($$$$$) { - # Update the uptime percentages in the Hash Arrays - my $Path = shift; - my $DAverage = shift; - my $WAverage = shift; - my $MAverage = shift; - my $QAverage = shift; - - #Enter everything once as it exists - #Trim off the rightmost component (hostname) and reenter the code - #If there is only one component, this is the final level - #This is an average of averages - - my $Ticket = join ( ".",@$Path); - $Daily { $Ticket } += $DAverage; - $Weekly { $Ticket } += $WAverage; - $Monthly { $Ticket } += $MAverage; - $Quarterly {$Ticket } += $QAverage; - $DailyC { $Ticket }++; - $WeeklyC { $Ticket }++; - $MonthlyC { $Ticket }++; - $QuarterlyC { $Ticket }++; - my $Length = @$Path; - @$Path = @$Path [ 0 .. $Length - 2 ]; - update_stats(\@$Path,$DAverage,$WAverage,$MAverage,$QAverage) if $Length > 1; -} - -sub Summary_Sheet() { - my $Body = ''; - - $Body .= "<table border='1' bordercolor=#111111>\n"; - $Body .= "<tr>\n"; - $Body .= "<td class ='appHeader' colspan='5'>IT Network Systems Availability Summary</td></tr>\n"; - $Body .= "<tr>\n"; - $Body .= "<td class ='appHeader' colspan='5'>Compiled: ". scalar(localtime) . "</td></tr>\n"; - $Body .= "<tr>\n"; - $Body .= "<td class = 'subhead' width='20%'>Service</td> - <td class = 'subhead' witdh='20%'>Past Quarter</td> - <td class = 'subhead' width='20%'>Past Month</td> - <td class = 'subhead' width='20%'>Past Week</td> - <td class = 'subhead' width='20%'>Past Day</td></tr>\n"; - foreach (sort { $a cmp $b } keys %Monthly) { - next if ( $_ =~ /\./ ); - # this is a major section heading - $Body .= "<tr>\n"; - $Body .= "<td class = 'SubHead'>$_</td>"; - $Body .= "<td class = 'Up99'>" . sprintf('%.2f',$Quarterly{$_}/$QuarterlyC{$_}) . "%</td>" - if $Quarterly{$_}/$QuarterlyC{$_} >= 99 ; - $Body .= "<td class = 'Up95'>" . sprintf('%.2f',$Quarterly{$_}/$QuarterlyC{$_}) . "%</td>" - if $Quarterly{$_}/$QuarterlyC{$_} > 95 and $Quarterly{$_}/$QuarterlyC{$_} < 99 ; - $Body .= "<td class = 'Up90'>" . sprintf('%.2f',$Quarterly{$_}/$QuarterlyC{$_}) . "%</td>" - if $Quarterly{$_}/$QuarterlyC{$_} > 90 and $Quarterly{$_}/$QuarterlyC{$_} < 95 ; - $Body .= "<td class = 'UpNo'>" . sprintf('%.2f',$Quarterly{$_}/$QuarterlyC{$_}) . "%</td>" - if $Quarterly{$_}/$QuarterlyC{$_} < 90 ; - $Body .= "<td class = 'Up99'>" . sprintf('%.2f',$Monthly{$_}/$MonthlyC{$_}) . "%</td>" - if $Monthly{$_}/$MonthlyC{$_} >= 99 ; - $Body .= "<td class = 'Up95'>" . sprintf('%.2f',$Monthly{$_}/$MonthlyC{$_}) . "%</td>" - if $Monthly{$_}/$MonthlyC{$_} > 95 and $Monthly{$_}/$MonthlyC{$_} < 99 ; - $Body .= "<td class = 'Up90'>" . sprintf('%.2f',$Monthly{$_}/$MonthlyC{$_}) . "%</td>" - if $Monthly{$_}/$MonthlyC{$_} > 90 and $Monthly{$_}/$MonthlyC{$_} < 95 ; - $Body .= "<td class = 'UpNo'>" . sprintf('%.2f',$Monthly{$_}/$MonthlyC{$_}) . "%</td>" - if $Monthly{$_}/$MonthlyC{$_} < 90 ; - $Body .= "<td class = 'Up99'>" . sprintf('%.2f',$Weekly{$_}/$WeeklyC{$_}) . "%</td>" - if $Weekly{$_}/$WeeklyC{$_} >= 99; - $Body .= "<td class = 'Up95'>" . sprintf('%.2f',$Weekly{$_}/$WeeklyC{$_}) . "%</td>" - if $Weekly{$_}/$WeeklyC{$_} > 95 and $Weekly{$_}/$WeeklyC{$_} < 99 ; - $Body .= "<td class = 'Up90'>" . sprintf('%.2f',$Weekly{$_}/$WeeklyC{$_}) . "%</td>" - if $Weekly{$_}/$WeeklyC{$_} > 90 and $Weekly{$_}/$WeeklyC{$_} < 95 ; - $Body .= "<td class = 'UpNo'>" . sprintf('%.2f',$Weekly{$_}/$WeeklyC{$_}) . "%</td>" - if $Weekly{$_}/$WeeklyC{$_} < 90 ; - $Body .= "<td class = 'Up99'>" . sprintf('%.2f',$Daily{$_}/$DailyC{$_}) . "%</td>" - if $Daily{$_}/$DailyC{$_} >= 99; - $Body .= "<td class = 'Up95'>" . sprintf('%.2f',$Daily{$_}/$DailyC{$_}) . "%</td>" - if $Daily{$_}/$DailyC{$_} > 95 and $Daily{$_}/$DailyC{$_} < 99 ; - $Body .= "<td class = 'Up90'>" . sprintf('%.2f',$Daily{$_}/$DailyC{$_}) . "%</td>" - if $Daily{$_}/$DailyC{$_} > 90 and $Daily{$_}/$DailyC{$_} < 95 ; - $Body .= "<td class = 'UpNo'>" . sprintf('%.2f',$Daily{$_}/$DailyC{$_}) . "%</td>" - if $Daily{$_}/$DailyC{$_} < 90 ; - $Body .= "</tr>\n"; - } - $Body .= "</table>"; - $Body .= "<P><P><P>\n"; - $Body .= "<table border='1' bordercolor=#111111><tr><td class ='appHeader'>Legend:</td>\n"; - $Body .= "<tr><td class = 'Up99'>if uptime > 99% then GREEN</td></tr>\n"; - $Body .= "<tr><td class = 'Up95'>if uptime > 95% but < 99% then BLUE</td></tr>\n"; - $Body .= "<tr><td class = 'Up90'>if uptime > 90% but < 95% then YELLOW</td></tr>\n"; - $Body .= "<tr><td class = 'UpNo'>if uptime < 90% then RED</td></tr>\n"; - $Body .= "</table>\n"; - return $Body; -} - -sub NumDots($) { - # Count the number of dots in a string - # There's probably a better way to do this - my $DNA = shift; - my $a = 0; - while($DNA =~ /\./ig){$a++} - return $a -} - -sub DetailSheet($) { - # Populate the table with details depending on the value of %opts{detail} - my $Seconds = shift; - my $Body = ''; - - return '' unless $opt{detail}; - - # Monthly/Weekly/Daily - $Body .= "<table border='1' bordercolor=#111111>\n"; - $Body .= "<tr>\n"; - $Body .= "<td class ='appHeader' colspan='3'>IT Network Systems Availability Previous " . $Seconds/86400 . " Day(s)</td></tr>\n"; - $Body .= "<tr>\n"; - $Body .= "<td class ='appHeader' colspan='3'>Compiled: ". scalar(localtime) . "</td></tr>\n"; - $Body .= "<tr>\n"; - $Body .= "<td class = 'SubHead' width='40%'>Service</td> - <td class = 'SubHead' width='30%'>Seconds</td> - <td class = 'SubHead' width='30%'>Percent</td></tr>\n"; - - my %CornBeef; - my %CornBeefC; - - CASE: { - %CornBeef = %Daily, %CornBeefC = %DailyC, print "Doing Daily\n", last CASE if $Seconds == 86400; - %CornBeef = %Weekly, %CornBeefC = %WeeklyC, print "Doing Weekly\n", last CASE if $Seconds == 604800; - %CornBeef = %Monthly, %CornBeefC = %MonthlyC, print "Doing Monthly\n", last CASE if $Seconds == 2592000; - %CornBeef = %Quarterly, %CornBeefC = %QuarterlyC, print "Doing Quarterly\n", last CASE if $Seconds == 7776000; - } # end of CASE block - - foreach (sort { $a cmp $b } keys %CornBeef ) { - next if NumDots ($_) > $opt{detail}; - if ( $_ =~ /\./ ) { - #this is a sub section - $Body .= "<tr>\n"; - $Body .= "<td class = 'SubSubHead'>$_</td>\n"; - $Body .= "<td class = 'SubDetail'>" . sprintf('%.0f',(100 - $CornBeef{$_} / $CornBeefC{$_}) * ($Seconds/100)) . "</td>\n"; - $Body .= "<td class = 'SubDetail'>" . sprintf('%.2f',$CornBeef{$_} / $CornBeefC{$_}) . "%</td>\n"; - $Body .= "</tr>\n"; - } else { - # this is a non-sub section - $Body .= "<tr>\n"; - $Body .= "<td class = 'SubHead'>" . $_ . "</td>\n"; - $Body .= "<td class = 'SubDetail'>" . sprintf('%.0f',(100 - $CornBeef{$_} / $CornBeefC{$_}) * ($Seconds/100)) . "</td>\n"; - $Body .= "<td class = 'SubDetail'>" . sprintf('%.2f',$CornBeef{$_} / $CornBeefC{$_}) . "%</td>\n"; - $Body .= "</tr>"; - } - } - $Body .= "</table>\n"; - return $Body; - } - -sub list_rrds($$$); -sub list_rrds($$$) { - # List the RRD's used by this configuration - my $tree = shift; - my $path = shift; - my $print = shift; - my $prline; - foreach my $rrds (keys %{$tree}) { - if (ref $tree->{$rrds} eq 'HASH'){ - $prline .= list_rrds( $tree->{$rrds}, $path."/$rrds", $print ); - } - if ($rrds eq 'host' and $tree->{$rrds} !~ m|/| ) { - $prline .= "$cfg->{General}{datadir}$path".".rrd\n"; - } - } - return $prline; -} - -sub load_cfg ($) { - my $cfgfile = shift; -# my $parser = get_parser; - my $parser = Smokeping::get_parser; - $cfg = Smokeping::get_config $parser, $cfgfile; -} - -########################################################################### -# The Main Program -########################################################################### - -sub main($); -main($cfgfile); - -sub main ($) { - umask 022; - my $cfgfile = shift; - my $sendto; - GetOptions(\%opt, 'quiet','version','testmail','listrrds','to=s','detail=n','morning','weekly','help','man') or pod2usage(2); - if($opt{version}) { print "$RCS_VERSION\n"; exit(0) }; - if($opt{help}) { pod2usage(-verbose => 1); exit 0 }; - if($opt{man}) { pod2usage(-verbose => 2); exit 0 }; - load_cfg $cfgfile; - print "tSmoke for network managed by $cfg->{General}{owner}\nat $cfg->{General}{contact}\n(c) 2003 Dan McGinn-Combs\n" unless $opt{quiet}; - if($opt{testmail}) { test_mail($cfg) }; - if($opt{listrrds}) { print "List of Round Robin Databases used by this implementation\n"; - my @rrds = split ( /\n/,list_rrds($cfg->{Targets},"","") ); - foreach (@rrds) { - print "RRD: $_\n"; }; - } - if($opt{morning}) { morning_update($cfg) }; - if($opt{weekly}) { weekly_update($cfg) }; - exit 0; -} - -=head1 NAME - -tSmoke - Commandline tool for sending SmokePing information - -=head1 SYNOPSIS - -B<tSmoke> [ B<--testmail> | B<--morning> | B<--weekly> | B<--version> | B<--help> | B<--man>] - - Options: - - --man Show the manpage - --help Help :-) - --version Show SmokePing Version - --testmail Send a test message - --listrrds List the RRDs used by this Smokeping - --morning Send a morning synopsis - --weekly Send a weekly status report - --to E-mail address to send message (i.e. '--to=xyz@company.com.invalid' - --detail How much detail to send in weekly report (i.e. '--detail=1') - --quiet Do not print welcome - -=head1 DESCRIPTION - -The B<tSmoke> tool is a commandline tool which interfaces with the SmokePing system. -Its main function is to send a message indicating the current status of the systems -being monitored by Smokeping or an HTML mail file containing the status over the past day, -past week and past month including an overview. - -Typical crontab used to invoke this are - - # Quick morning alert to see what's down - 0 6 * * * /usr/local/smokeping/bin/tSmoke.pl --q --to=mobilephone@att.net.invalid --morning - # Weekly report on the percent availability of network systems with no detail - 0 8 * * * /usr/local/smokeping/bin/tSmoke.pl --q --to=mailbox@company.com.invalid --weekly --detail=0 - -=head1 SETUP - -When installing tSmoke, some variables must be adjusted to fit your local system. - -We need to use the following B<libraries>: - -=over - -=item Smokeping - -=item RRDTool Perl bindings - -=item Getopt::Long - -=back - -Set up your libraries: - - use lib "/usr/local/smokeping/lib"; - use lib "/usr/local/rrdtool-1.0.39/lib/perl"; - -Point to your Smokeping B<config> file - - my $cfgfile = "/usr/local/smokeping/etc/config"; - -Modify the Smokeping config file to include a path for tmail in the -General section: - - tmail = /usr/local/smokeping/etc/tmail - -=head1 COPYRIGHT - -Copyright (c) 2003 by Dan McGinn-Combs. All right reserved. - -=head1 LICENSE - -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; either -version 2 of the License, or (at your option) any later -version. - -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, write to the Free -Software Foundation, Inc., 675 Mass Ave, Cambridge, MA -02139, USA. - -=head1 AUTHOR - -Dan McGinn-Combs E<lt>d.mcginn-combs@mindspring.comE<gt> - -Modified for Smokeping official distribution by Niko Tyni E<lt>ntyni@iki.fiE<gt> - -=cut - |