On Fri, Aug 13, 2010 at 05:23, Chaitanya Yanamadala
<dr.virus.in...@gmail.com> wrote:
> Hai
> After a lot of frustration i have build this code to check which of the
> server is down and which is up.
snip

Here is a major rewrite.  In order of importance, here is a list of
changes I made:

* Use whitespace properly, when in doubt use [perltidy][0] on your
code and emulate that.
* Use placeholders instead of building SQL with with values, not only
is it more efficient and general, it will also protect you from
injection attacks.
* Don't trust $@ to have a value after an eval, and use Try::Tiny
instead of block eval
* Use the strict and warnings pragmas.
* Check the return value of system calls (e.g. open, print, close, etc.).
* Use the three argument version of open, not the two argument version.
* Move the preparation of SQL out of loops, there is no need to
prepare a statement more than once.
* Use the correct equality and relational operators ( == and the like
for numbers, eq and the like for strings).
* NULL values will be undef in Perl 5, not an empty string
* All user modifiable variables should be defined near the top to make
it easy to find them, but preferably the should be moved to a config
file or passed on the commandline.
* Use lexical filehandles instead of bareword filehandles.
* Use DBI->connect()'s options to make your life easier.
* Use flow control instead of deeply nesting if statements.
* Use constants to give confusing literals meaning to the reader.
* Don't use useless temporary variables.
* Don't use concatenation where you can use interpolation.

I have left several FIXMEs in the code.  They are there because I
don't have enough information to fix them or they are suggesting a
module that will simplify code and I didn't want to force more
dependencies on you (but you really should be using them).

On a separate note, your database table and column names are very bad.
 Misspelling client_name, having a floating _ after status, cryptic
names like etime and and stime, and adding table to every table name
are all confusing or silly.  You might also want to store the IP
address as an integer and use to inet_aton and inet_ntoa to convert it
(this has many benefits including the ability to sort by IP address).

#!/usr/bin/perl

use strict;
use warnings;

use DBI;
use XML::LibXML;

use constant ONLINE  => 0;
use constant OFFLINE => 1;

#FIXME: all of this should be in a config file
#or passed on the commandline, maybe in the XML file?
my $to_email   = 'dr.virus.in...@gmail.com';
my $from_email = 'cha...@server.com';
my $serverxml  = "servers.xml";
my $dsn        = "dbi:mysql:ping:localhost:3306";
my $threshold  = 70;

print "XML NAME    => $serverxml\n";

my $dbh = DBI->connect(
        $dsn,
        "root",
        "",
        {
                ChopBlanks         => 1,         #trim selected fields
                PrintError         => 0,         #don't print errors
                RaiseError         => 1,         #die instead
                ShowErrorStatement => 1,         #and print the SQL too
        }
) or die "Cannot connect to database";

my @servers;
my $parser = XML::LibXML->new();

#FIXME: consider using Try::Tiny instead
#as this construct also has problems
eval {
        my $root = $parser->parse_file($serverxml)->getDocumentElement;
        for my $file ($root->findnodes('/serverdetails/server')) {
                push @servers, $file->findvalue('.');
        }
        1;
} or die "Cannot read XML\n";

my $get_sno = $dbh->prepare("
        SELECT sno
          FROM check_table
         WHERE client_nme = ?
           AND client_ip  = ?
");

my $insert_check_table = $dbh->prepare("
        INSERT INTO check_table (client_nme, client_ip, status_)
                         VALUES (?,          ?,         0)
");

my $get_status = $dbh->prepare("
        SELECT status_
          FROM check_table
         WHERE client_nme = ?
           AND client_ip  = ?
");

my $update_status = $dbh->prepare("
        UPDATE check_table
           SET status_ = ?,
               stime   = now()
         WHERE client_nme = ?
           AND client_ip  = ?
");

my $insert_log = $dbh->prepare("
        INSERT INTO log_table (
                Check_id, client_nme, client_ip, stime, etime, status_
        )
                SELECT sno, client_nme, client_ip, stime, etime, status_
                  FROM check_table
                  WHERE client_nme = ?
                    AND client_ip  = ?
");

for my $server_record (@servers) {
        my ($server_name, $server_ip) = split ',', $server_record;

        $get_sno->execute($server_name, $server_ip);
        my $sno = $get_sno->fetchrow_array();

        unless (defined $sno) {
                $insert_check_table->execute($server_name, $server_ip);
        }

        print
                "Server Name => $server_name\n",
                "Server Ip   => $server_ip\n";

        #FIXME: this should probably be replaced with Net::Ping
        my $pingstats = qx(ping -c 4 $server_ip | grep received);
        my ($Received, $Lost) = (split ',', $pingstats)[1,2];
        #FIXME: $received isn't used, why are we getting it?
        my $received = (split ' ', $Received)[0];
        my $lost     = trim((split '%', $Lost)[0]);

        $get_status->execute($server_name, $server_ip);
        my $status = $get_status->fetchrow_array();

        if ($lost >= $threshold and $status == ONLINE) {
                $update_status->execute(1, $server_name, $server_ip);
                sendEmail(
                        $to_email,
                        $from_email,
                        "SERVER DOWN.",
                        "Server => $server_name is Down. Check it out!!!"
                );
                next;
        }

        if ($lost < $threshold and $status == OFFLINE) {
                $update_status->execute(0, $server_name, $server_ip);
                $insert_log->execute($server_name, $server_ip);
                sendEmail(
                        $to_email,
                        $from_email,
                        "SERVER ONLINE.",
                        "Server => $server_name is Online Now. Check it out!!!"
                );
                next;
        }
}

#FIXME: consider replacing this with Email::Sender
sub sendEmail {
        my ($to, $from, $subject, $message) = @_;
        my $sendmail = '/usr/lib/sendmail';
        open my $mail, "|-", $sendmail, "-oi", "-t"
                or die "could not run sendmail: $!\n";
        print $mail
                "From: $from\n",
                "To: $to\n",
                "Subject: $subject\n\n",
                "$message\n"
                or die "could not talk to sendmail: $!\n";
        close $mail
                or die "could not finish talking to sendmail: $!\n";
}

sub trim {
        my $string = shift;
        $string =~ s/^\s+//;
        $string =~ s/\s+$//;
        return $string;
}

 [0]: http://search.cpan.org/dist/Perl-Tidy/lib/Perl/Tidy.pm

-- 
Chas. Owens
wonkden.net
The most important skill a programmer can have is the ability to read.

-- 
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


Reply via email to