sunnyfedora99 has asked for the wisdom of the Perl Monks concerning the following question:

Hi there, I have a small issue. I've written this script which will detect if any interfaces are down on my device. If it's down, give it a WARNING flag, check 4 times again, and if it's still down give it an CRITICAL flag. Could someone please look at my code and give me a heads up of how I can achieve this?

sub check_interfaces { my $crit = 0; my $stat=""; my $count=0; my $allInts_OID = ".1.3.6.1.4.1.3375.2.1.2.4.1.2.1.1"; my $ltm_InBytes_Index = "1.3.6.1.4.1.3375.2.1.2.4.4.3.1.3."; my $ltm_OutBytes_Index = "1.3.6.1.4.1.3375.2.1.2.4.4.3.1.5."; #If $ARGV[2] = 0, then check all interfaces through $allInts_OID. if ($int eq 0) { my $allInts = $session->get_table ( -baseoid => $allInts_OID ) +; my %int_table = %{$allInts}; #print "\n\n"; OUT: foreach my $key (sort keys %int_table){ #Convert interface name to OID string my @chars = unpack("C" x length($int_table{$key}),$int_tab +le{$key}); my $int_length = length( $int_table{$key} ); unshift(@chars, $int_length); my $int_oid = join('.' , @chars); #Build OID from index & interface my $ltm_intBytesIn = $ltm_InBytes_Index . $int_oid; my $ltm_intBytesOut = $ltm_OutBytes_Index . $int_oid; #Get first instance my $oids_1 = $session->get_request( -varbindlist => [$ltm_intBytesIn, $ltm_intBytesOut] ); # Wait for second poll {Keep it 10 seconds} #Change after testing sleep 5; #Get second instance my $oids_2 = $session->get_request( -varbindlist => [$ltm_intBytesIn, $ltm_intBytesOut] ); #Calculate Rates my $rate_in = ($oids_2->{$ltm_intBytesIn} - $oids_1->{$ltm +_intBytesIn})*8 / (10*1000000); my $rate_out = ($oids_2->{$ltm_intBytesOut} - $oids_1->{$l +tm_intBytesOut})*8 / (10*1000000); my $rate_total = $rate_in + $rate_out; #Trim to 4 decimal places $rate_in =~s/(^\d{1,}\.\d{4})(.*$)/$1/; $rate_out =~s/(^\d{1,}\.\d{4})(.*$)/$1/; $rate_total =~s/(^\d{1,}\.\d{4})(.*$)/$1/; #Print Results #print "Interface $int_table{$key} rate (Mbits/sec)"; #print "\n\n\t$rate_in (IN)\n"; #print "\t$rate_out (OUT)\n"; #print "\t$rate_total (TOTAL)\n"; my $querystr="select * from device_iface_cache where inter +face_name='$int_table{$key}' and hostname='$host'"; my ($f5_ifacerow); my $query=$dbh->prepare($querystr); $query->execute; if(!($f5_ifacerow=$query->fetchrow_hashref())) { # no row found... insert into f5_selfip append_log ("IFace Stats: No result. Creating a blank + record\n"); my $updatestr="INSERT INTO device_iface_cache (interfa +ce_name, interface_status, lastcheck, hostname) VALUES ('$int_table{$ +key}', '$stat', '$date', '$host');"; append_log ("IFace Stats: SQL\n"); my $update=$dbh->prepare($updatestr); $update->execute; } if($rate_total == $crit){ #Add in flap detection, also, if an interface is down +check x4 #before alarming. $stat = "DOWN"; append_log ("CRITICAL: Interface $int_table{$key} is D +OWN.\n"); append_status("CRITICAL: Interface $int_table{$key} is + DOWN.\n"); my $current_status = $dbh->prepare("SELECT interface_s +tatus FROM device_iface_cache WHERE interface_name='$int_table{$key}' + and hostname='$host';"); $current_status->execute; my ($f5_iface_status); $f5_iface_status=$current_status->fetchrow_hashref(); if($f5_iface_status->{interface_status} ne $stat) { my $iface_result = $dbh->prepare("UPDATE device_if +ace_cache SET interface_status='$stat', lastcheck='$date', hostname=' +$host' WHERE hostname='$host' AND interface_name='$int_table{$key}';" +); $iface_result->execute(); append_log ("STATUS CHANGED: Interface $int_table{ +$key} Was: $f5_iface_status->{interface_status} ------- Now: $stat\n" +); } my $result = $dbh->prepare("UPDATE device_iface_cache +SET interface_status='$stat', lastcheck='$date', hostname='$host' WHE +RE hostname='$host' AND interface_name='$int_table{$key}';"); $result->execute(); } #If Status is OK if($rate_total > $crit) { $stat = "UP"; append_log ("OK: Interface $int_table{$key} is UP.\n") +; append_status("OK: Interface $int_table{$key} is UP.\n +"); my $current_status = $dbh->prepare("SELECT interface_s +tatus FROM device_iface_cache WHERE interface_name='$int_table{$key}' + and hostname='$host';"); $current_status->execute; my ($f5_iface_status); $f5_iface_status=$current_status->fetchrow_hashref(); if($f5_iface_status->{interface_status} ne $stat) { my $iface_result = $dbh->prepare("UPDATE device_if +ace_cache SET interface_status='$stat', lastcheck='$date', hostname=' +$host' WHERE hostname='$host' AND interface_name='$int_table{$key}';" +); $iface_result->execute(); append_log ("STATUS CHANGED: Interface $int_table{ +$key} Was: $f5_iface_status->{interface_status} ------- Now: $stat\n" +); } my $result = $dbh->prepare("UPDATE device_iface_cache +SET interface_status='$stat', lastcheck='$date', hostname='$host' WHE +RE hostname='$host' AND interface_name='$int_table{$key}';"); $result->execute(); } }

If the interface is down, it will need to run the check again 4 times, which starts from - LABELLED BLOCK: OUT. Thanks, Sunny

Replies are listed 'Best First'.
Re: Interface flap detection in Perl
by bart (Canon) on Apr 13, 2011 at 12:46 UTC
    It would be a very sane idea to make sure you're using placeholders in all database commands that use parameters. For example, replace
    my $iface_result = $dbh->prepare("UPDATE device_iface_cache SET interf +ace_status='$stat', lastcheck='$date', hostname='$host' WHERE hostnam +e='$host' AND interface_name='$int_table{$key}';"); $iface_result->execute();
    with
    my $iface_result = $dbh->prepare("UPDATE device_iface_cache SET interf +ace_status=?, lastcheck=? WHERE hostname=? AND interface_name=?"); $iface_result->execute($stat, $date, $host, $int_table{$key});
    (no need to set hostname again where you select on it) or even easier, using DBIx::Simple with SQL::Abstract:
    $db->update('device_iface_cache', { interface_status => $stat, lastcheck => $date }, { hostname => $host, interface_name => $int_table{$key} } );
    (DBIx::Simple uses a database handle that replaces DBI's $dbh, but is not exactly the same thing. Hence the different name $db. You get it by connecting through DBIx::Simple->connect instead of DBI->connect.)

      When I do that on a select statement, i get the following error messages. Use of uninitialized value in string ne at intstatDB.pl line 452. Use of uninitialized value in concatenation (.) or string at intstatDB.pl line 456.

      if($rate_total == $crit){ #Add in flap detection, also, if an interface is down +check x4 #before alarming. $stat = "DOWN"; append_log ("CRITICAL: Interface $int_table{$key} is D +OWN.\n"); append_status("CRITICAL: Interface $int_table{$key} is + DOWN.\n"); my $sth = $dbh->prepare("SELECT interface_status FROM +device_iface_cache WHERE interface_name=? and hostname=?"); $sth->execute($int_table{key}, $host); #my $current_status = $dbh->prepare("SELECT interface_ +status FROM device_iface_cache WHERE interface_name='$int_table{$key} +' and hostname='$host';"); #$current_status->execute; my ($f5_iface_status); $f5_iface_status=$sth->fetchrow_hashref(); #print "$f5_iface_status->{interface_status}\n"; if($f5_iface_status->{interface_status} ne $stat) { #my $iface_result = $dbh->prepare("UPDATE device_i +face_cache SET interface_status='$stat', lastcheck='$date', hostname= +'$host' WHERE hostname='$host' AND interface_name='$int_table{$key}'; +"); #$iface_result->execute(); my $iface_result = $dbh->prepare("UPDATE device_if +ace_cache SET interface_status=?, lastcheck=? WHERE hostname=? AND in +terface_name=?"); $iface_result->execute($stat, $date, $host, $int_t +able{$key}); append_log ("STATUS CHANGED: Interface $int_table{ +$key} Was: $f5_iface_status->{interface_status} ------- Now: $stat\n" +); } my $result = $dbh->prepare("UPDATE device_iface_cache +SET interface_status=?, lastcheck=? WHERE hostname=? AND interface_na +me=?"); $result->execute($stat, $date, $host, $int_table{$key} +); }

      I've used placeholders before as test, and worked fine. Do you know what's going on here.