monitors:check-client

no way to compare when less than two revisions

Differences

This shows you the differences between two versions of the page.


monitors:check-client [2010/08/23 22:23] (current) – created - external edit 127.0.0.1
Line 1: Line 1:
 +====== client-check.pl ======
 +
 +^ Author | [[ dbaldwin@users.sf.net | David Baldwin ]] |
 +^ Compatibility | Xymon 4.2 |
 +^ Requirements | Perl, [[monitors:XymonExt.pm]] |
 +^ Download | client-check.pl |
 +^ Last Update | 2010-07-29 |
 +
 +===== Description =====
 +
 +===== Installation =====
 +=== Client side ===
 +
 +=== Server side ===
 +
 +client-check.pl and XymonExt.pm in $BBHOME/ext
 +
 +===== Source =====
 +==== client-check.pl ====
 +
 +<hidden onHidden="Show Code ⇲" onVisible="Hide Code ⇱">
 +<code perl>
 +#!/usr/bin/perl -w
 + 
 +#*---------------------------------------------------------------------------*/
 +#* client-check.pl : Xymon client message processor.                         */
 +#*                                                                           */
 +#* This perl program is a server-side module using the                       */
 +#* data sent by the Xymon clients. This program is fed data from the         */
 +#* Xymon "client" channel via the hobbitd_channel program; each client       */
 +#* message is processed by looking at various sections and generates         */
 +#* a test status report when various conditions are met                      */
 +#*                                                                           */
 +#* Original 2007-Jan-28 by Henrik Storner <henrik@hswn.dk>                   */
 +#* Modified 2008-2010 by David Baldwin <david.baldwin@ausport.gov.au>        */
 +#*                                                                           */
 +#* This program is in the public domain, and may be used freely for          */
 +#* creating your own Xymon server-side modules.                              */
 +#*                                                                           */
 +#*---------------------------------------------------------------------------*/
 +#
 +# CONFIG START
 +
 +# default route where other than .1 address on subnet
 +my %netCheckRoutes = ( prod => { net => "1.1", mask => "/16", gw => "1.1.0.10"},
 +      );
 +
 +# check minimum available memory in host under [free] section
 +my %memCheckTable = ( esx => { host => "esx.*",  min => 799000},
 +      );
 +
 +# CONFIG END
 +
 +=pod
 +
 +=head1 NAME
 +
 + client-check.pl - Perl script to check client messages on xymon/hobbit server
 +
 +=head1 SYNOPSIS
 +
 +Install script in F<$BBHOME/ext/client-check.pl>
 +
 +Ensure you also have F<$BBHOME/ext/XymonExt.pm> installed
 +
 +Add following lines to F</etc/hobbit/hobbitlaunch.cfg>
 +
 + [client-check]
 + ENVFILE /usr/lib/hobbit/server/etc/hobbitserver.cfg
 + NEEDS hobbitd
 + CMD hobbitd_channel --channel=client --log=$BBSERVERLOGS/client-check.log $BBHOME/ext/client-check.pl
 +
 +=head1 DESCRIPTION
 +
 +Requires: C<$BBHOME> environment variable to be set
 +
 +Requires: F<XymonExt.pm> module
 +
 +See CONFIG section at top of script
 +
 +=head1 TESTING
 +
 +If you wish to add your own tests, this script can be run against current client report for that host
 +
 +C<bbcmd client-check.pl -d MYHOST>
 +
 + 2010-07-29 14:04:25 Using default environment file /usr/lib/hobbit/server/etc/hobbitserver.cfg
 + DBG: using clientlog for MYHOST (1.1.1.2)
 + DBG: clientID linux (linux)
 + /usr/lib/hobbit/server/bin/bb 1.1.1.1 "status MYHOST.who green OK
 +
 + &green No root login active
 +
 +
 + someuser pts/1        Jul 26 12:29 (1.1.1.3)
 + "
 +
 + DBG: netCheck MYHOST (1.1.1.1) GW: 1.1.0.10 SM: 0.0.0.0
 + /usr/lib/hobbit/server/bin/bb 1.1.1.1 "status MYHOST green OK
 +
 + &green Default route OK
 +
 +
 + Kernel IP routing table
 + Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
 + 1.1.0.0         0.0.0.0         255.255.0.0             0 0          0 eth0
 + 0.0.0.0         1.1.0.10        0.0.0.0         UG        0 0          0 eth0
 + "
 +
 +=cut
 + 
 +my $xymonlib;
 +BEGIN { $xymonlib = $ENV{BBHOME} && "$ENV{BBHOME}/ext" || "/usr/lib/hobbit/server/ext"; }
 + 
 +use strict;
 +use lib $xymonlib;
 +use XymonExt;
 +
 + 
 +my $bb;
 +my $bbdisp;
 + 
 +my $hostname = "";
 +my $clientip = "";
 +my $clientname = "";
 +my $clientos = "";
 +my $msgtxt = "";
 +my %sections = ();
 +my $cursection = "";
 + 
 +my $debug=0;
 +my $ipsubre = qr/\d|\d\d|1\d\d|2[0-4]\d|25[0-5]/;
 +my $ipre = qr/$ipsubre\.$ipsubre\.$ipsubre\.$ipsubre/;
 +$|=1;
 + 
 +# Get the BB and BBDISP environment settings.
 +$bb = $ENV{"BB"} || die "BB not defined";
 +$bbdisp = $ENV{"BBDISP"} || die "BBDISP not defined";
 +
 +for(my $i=0; $i<=$#ARGV; $i++) {
 +  if($ARGV[$i] =~ /^-(d|-debug)$/) {
 +    $debug++;
 +  } elsif($i=$#ARGV) {
 +    $debug ||= 1;
 +    $clientname=$ARGV[$i];
 +  }
 +}
 + 
 + 
 +if($clientname ne "") {
 +  open CL,"bb $bbdisp \'clientlog $clientname\'|";
 +  $hostname = $clientname;
 +  $clientip = XymonExt->HostIP($hostname);
 +  warn "DBG: using clientlog for $hostname ($clientip)\n" if $debug;
 +} else {
 +  open CL,"/dev/stdin";
 +}
 +# Main routine. 
 +#
 +# This reads client messages from <CL>, looking for the
 +# delimiters that separate each message, and also looking for the
 +# section markers that delimit each part of the client message.
 +# When a message is complete, the processmessage() subroutine
 +# is invoked. $msgtxt contains the complete message, and the
 +# %sections hash contains the individual sections of the client 
 +# message.
 + 
 +while (my $line = <CL>) {
 + if ($line =~ /^\@\@client\#/) {
 + # It's the start of a new client message - the header looks like this:
 + # @@client#830759/HOSTNAME|1169985951.340108|10.60.65.152|HOSTNAME|sunos|sunos
 + 
 + # Grab the hostname field from the header
 + my @hdrfields = split(/\|/, $line);
 + $hostname = $hdrfields[3];
 + $hostname =~ s/,/./g;
 + XymonExt->import; # if don't do this, won't see changes to bb-hosts
 + $clientip = XymonExt->HostIP($hostname);
 + warn "DBG: processing $hostname ($clientip)\n" if $debug;
 + 
 + # Clear the variables we use to store the message in
 + $msgtxt = "";
 + %sections = ();
 + $cursection = ""; # none found yet!
 +                $clientname = "";
 +                $clientos = "";
 + }
 + elsif ($line =~ /^\@\@/) {
 + # End of a message. Do something with it.
 + runTests();
 + }
 + elsif ($line =~ /^\[(.+)\]/) {
 + # Start of new message section.
 + 
 + $cursection = $1;
 + $sections{ $cursection } = "\n";
 + }
 + elsif ($line =~ /^client\s+\S+\.([^.]+)\s+(\w+)/) {
 + # client header - used when testing against current client report
 + #   client esxsv01,ausport,gov,au.linux linux
 + #   client sa01sv1.ausport.gov.au.bbwin win32
 +
 + $msgtxt .= $line;
 + 
 +                $clientname = $1;
 +                $clientos = $2;
 + warn "DBG: clientID $clientname ($clientos)\n" if $debug;
 + }
 + else {
 + # Add another line to the entire message text variable,
 + # and the the current section.
 + $msgtxt .= $line;
 + if($cursection) {
 + $sections{ $cursection } .= $line;
 + } else {
 + my $time = scalar localtime;
 + warn "$time client-check: no current section for client $hostname\n$line";
 + }
 + }
 +}
 +# End of a message. Do something with it. Will only get here using clientlog (we hope)
 +runTests();
 +
 +sub runTests {
 +
 +    whoCheck();
 +    netCheck();
 +    memCheck();
 +}
 + 
 +sub report {
 + 
 + my($hostname, $hobbitcolumn, $color, $summary, $statusmsg) = @_;
 + # Build the command we use to send a status to the Xymon daemon
 + 
 + if($debug) {
 +   print "Would report:\n\"status " . $hostname . "." . $hobbitcolumn . " " . $color . " " . $summary . "\n" . $statusmsg . "\"\n";
 + } else {
 + # And send the message
 +    XymonExt->Report($hostname, $hobbitcolumn, $color,  "$summary\n$statusmsg");
 + }
 +}
 +
 +# This subroutine processes the client message. In this case,
 +# we watch the [who] section of the client message and alert
 +# if there is a root login active.
 + 
 +sub whoCheck {
 + my $color;
 + my $summary;
 + my $statusmsg;
 + my $sec = "who";
 + my $hobbitcolumn = "who";
 + 
 + # Dont do anything unless we have the "who" section
 + return unless ( $sections{$sec} );
 + 
 + # Is there a "root" login somewhere in the "who" section?
 + # Note that we must match with /m because there are multiple
 + # lines in the [who] section.
 + if ( $sections{$sec} =~ /^root /m ) {
 + $color = "yellow";
 + $summary = "ROOT login active";
 + $statusmsg = "&yellow ROOT login detected!\n\n" . $sections{$sec};
 + }
 + else {
 + $color = "green";
 + $summary = "OK";
 + $statusmsg = "&green No root login active\n\n" . $sections{$sec};
 + }
 + report($hostname, $hobbitcolumn, $color, $summary, $statusmsg);
 +}
 +
 +# This subroutine processes the client message. In this case,
 +# we watch the [route] section of the client message and alert
 +# if the default route is incorrect
 + 
 +sub netCheck {
 + my $color;
 + my $summary;
 + my $statusmsg;
 + my $sec = "route";
 + my $hobbitcolumn = "route";
 + 
 + # Dont do anything unless we have the "route" section
 + return unless ( $sections{$sec} );
 + 
 + # Is there a default gateway somewhere in the "route" section?
 + # Note that we must match with /m because there are multiple
 + # lines
 + $color = "green";
 + $summary = "OK";
 + $statusmsg = "&green Default route OK\n\n" . $sections{$sec};
 + #darwin form:
 + # default            1.1.0.1            UGSc        6       91    en0
 + # 1.1/16             link#            UCS        40        0    en0
 + # 1.1.0.1            0:11:11:11:11:87   UHLW        0        0    en0   1196
 +
 + if ( $sections{$sec} =~ /^(?:0\.0\.0\.0|default)\s+($ipre)\s+($ipre|\w+)\s+(\S+)\s/m ) {
 + my $gw = ($clientname eq "bbwin") ? $2 : $1;
 + my $sm = ($clientname eq "bbwin") ? $1 : $2;
 + warn "DBG: netCheck $hostname ($clientip) GW: $gw SM: $sm\n" if $debug;
 + my $isok = 1;
 + my $found = 0;
 + foreach my $sn (keys %netCheckRoutes) {
 +     my %snr = %{$netCheckRoutes{$sn}};
 +     warn "DBG: NET: $sn IP: $snr{net} GW: $snr{gw} SM: $snr{mask}\n" if $debug;
 +     if(! exists $snr{ipre}) {
 + my $netre = $snr{net};
 + $netre =~ s/\./\\./g;
 + $netre =~ s/\.$//;
 +         $netCheckRoutes{$sn}{ipre} = qr/^$netre\./;
 +     }
 +     if( $clientip =~ $netCheckRoutes{$sn}{ipre} ) {
 +         $found = 1;
 + $isok = $gw eq $snr{gw};
 + $summary = "Found defgw: $gw OK";
 + last
 +     }
 + }
 + if( !$found && $gw =~ /^(.*)\.1$/) {
 +         my $net = $1;
 +         warn "DBG: DEFAULT IP: $net GW: $gw SM: /24\n" if $debug;
 + $net =~ s/\./\\./g;
 + $isok = 0 unless $clientip =~ /^$net/;
 + $summary = "Found defgw: $gw OK" if $isok;
 + }
 + if(!$isok) {
 + $color = "red";
 + $summary = "Bad default route $gw for $clientip found";
 + $statusmsg = "&red Bad default route $gw for $clientip found\n\n" . $sections{$sec};
 + }
 + } else {
 + $color = "red";
 + $summary = "Error";
 + $statusmsg = "&red No default route found\n\n" . $sections{$sec};
 + }
 + 
 + report($hostname, $hobbitcolumn, $color, $summary, $statusmsg);
 +}
 +
 +# This subroutine processes the client message. In this case,
 +# we watch the [free] section of the client message and alert
 +# if the machine is an ESX server and the physical memory size is not 800MB
 + 
 +sub memCheck {
 + my $color;
 + my $summary;
 + my $statusmsg;
 + my $sec = "free";
 + my $hobbitcolumn = "pmem";
 + my $min;
 + 
 + # Dont do anything unless we have the "free" section in host starting with "esx"
 + return unless ( $sections{$sec} );
 + my $found = 0;
 + foreach my $mh (keys %memCheckTable) {
 +     my %mhr = %{$memCheckTable{$mh}};
 +     warn "DBG: HOST: $mh MIN: $mhr{min}\n" if $debug;
 +     if(! exists $mhr{hostre}) {
 + my $hostre = $mhr{host};
 + $memCheckTable{$mh}{hostre} = qr/^$hostre\./;
 +     }
 +     $found = $hostname =~ $memCheckTable{$mh}{hostre};
 +     $min = $mhr{min};
 +     last if $found;
 + }
 + return unless ( $found );
 + 
 + # Get the Mem: line
 + # Note that we must match with /m because there are multiple
 + # lines
 + $color = "green";
 + $summary = "OK";
 +
 + if ( $sections{$sec} =~ /^Mem:\s+(\d+)\s+(\d+)\s+(\d+)\s/m ) {
 + my $tot = $1;
 +         $statusmsg = sprintf("&green memory allocation %dMB OK (at least %dMB)\n\n",$tot/1024,$min/1024) . $sections{$sec};
 + warn "DBG: memCheck $hostname ($clientip) PhysMEM: $tot\n" if $debug;
 + my $isok = $tot > $min;
 + if(!$isok) {
 + $color = "red";
 + $summary = sprintf("Bad memory allocation %dMB for %s found (require at least %dMB)",$tot/1024,$hostname,$min/1024);
 + $statusmsg = "&red ". sprintf("Bad memory allocation %dMB for %s found (require at least %dMB)\n\n",$tot/1024,$hostname,$min/1024) . $sections{$sec};
 + }
 + } else {
 + $color = "red";
 + $summary = "Error";
 + $statusmsg = "&red No Mem: line found\n\n" . $sections{$sec};
 + }
 + 
 + report($hostname, $hobbitcolumn, $color, $summary, $statusmsg);
 +}
 +
 +</code>
 +</hidden>
 +
 +===== Known  Bugs and Issues =====
 +
 +===== To Do =====
 +
 +===== Credits =====
 +
 +original rootlogin.pl script from Henrik
 +
 +===== Changelog =====
 +
 +  * **2010-07-29**
 +    * Initial release
  
  • monitors/check-client.txt
  • Last modified: 2010/08/23 22:23
  • by 127.0.0.1