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: | ||
| + | ^ 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=" | ||
| + | <code perl> | ||
| + | # | ||
| + | |||
| + | # | ||
| + | #* 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 " | ||
| + | #* 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 < | ||
| + | #* Modified 2008-2010 by David Baldwin < | ||
| + | #* */ | ||
| + | #* 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 => " | ||
| + | ); | ||
| + | |||
| + | # check minimum available memory in host under [free] section | ||
| + | my %memCheckTable = ( esx => { host => " | ||
| + | ); | ||
| + | |||
| + | # CONFIG END | ||
| + | |||
| + | =pod | ||
| + | |||
| + | =head1 NAME | ||
| + | |||
| + | | ||
| + | |||
| + | =head1 SYNOPSIS | ||
| + | |||
| + | Install script in F< | ||
| + | |||
| + | Ensure you also have F< | ||
| + | |||
| + | Add following lines to F</ | ||
| + | |||
| + | | ||
| + | ENVFILE / | ||
| + | NEEDS hobbitd | ||
| + | CMD hobbitd_channel --channel=client --log=$BBSERVERLOGS/ | ||
| + | |||
| + | =head1 DESCRIPTION | ||
| + | |||
| + | Requires: C< | ||
| + | |||
| + | Requires: F< | ||
| + | |||
| + | 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> | ||
| + | |||
| + | | ||
| + | DBG: using clientlog for MYHOST (1.1.1.2) | ||
| + | DBG: clientID linux (linux) | ||
| + | / | ||
| + | |||
| + | & | ||
| + | |||
| + | |||
| + | | ||
| + | " | ||
| + | |||
| + | DBG: netCheck MYHOST (1.1.1.1) GW: 1.1.0.10 SM: 0.0.0.0 | ||
| + | / | ||
| + | |||
| + | & | ||
| + | |||
| + | |||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | " | ||
| + | |||
| + | =cut | ||
| + | |||
| + | my $xymonlib; | ||
| + | BEGIN { $xymonlib = $ENV{BBHOME} && " | ||
| + | |||
| + | 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/ | ||
| + | my $ipre = qr/ | ||
| + | $|=1; | ||
| + | |||
| + | # Get the BB and BBDISP environment settings. | ||
| + | $bb = $ENV{" | ||
| + | $bbdisp = $ENV{" | ||
| + | |||
| + | for(my $i=0; $i< | ||
| + | if($ARGV[$i] =~ / | ||
| + | $debug++; | ||
| + | } elsif($i=$# | ||
| + | $debug ||= 1; | ||
| + | $clientname=$ARGV[$i]; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | |||
| + | if($clientname ne "" | ||
| + | open CL,"bb $bbdisp \' | ||
| + | $hostname = $clientname; | ||
| + | $clientip = XymonExt-> | ||
| + | warn "DBG: using clientlog for $hostname ($clientip)\n" | ||
| + | } else { | ||
| + | open CL,"/ | ||
| + | } | ||
| + | # 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 =~ / | ||
| + | # It's the start of a new client message - the header looks like this: | ||
| + | # @@client# | ||
| + | |||
| + | # Grab the hostname field from the header | ||
| + | my @hdrfields = split(/\|/, $line); | ||
| + | $hostname = $hdrfields[3]; | ||
| + | $hostname =~ s/,/./g; | ||
| + | XymonExt-> | ||
| + | $clientip = XymonExt-> | ||
| + | warn "DBG: processing $hostname ($clientip)\n" | ||
| + | |||
| + | # Clear the variables we use to store the message in | ||
| + | $msgtxt = ""; | ||
| + | %sections = (); | ||
| + | $cursection = ""; | ||
| + | $clientname = ""; | ||
| + | $clientos = ""; | ||
| + | } | ||
| + | elsif ($line =~ /^\@\@/) { | ||
| + | # End of a message. Do something with it. | ||
| + | runTests(); | ||
| + | } | ||
| + | elsif ($line =~ / | ||
| + | # Start of new message section. | ||
| + | |||
| + | $cursection = $1; | ||
| + | $sections{ $cursection } = " | ||
| + | } | ||
| + | elsif ($line =~ / | ||
| + | # client header - used when testing against current client report | ||
| + | # | ||
| + | # | ||
| + | |||
| + | $msgtxt .= $line; | ||
| + | |||
| + | $clientname = $1; | ||
| + | $clientos = $2; | ||
| + | warn "DBG: clientID $clientname ($clientos)\n" | ||
| + | } | ||
| + | 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: | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | # 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, | ||
| + | # Build the command we use to send a status to the Xymon daemon | ||
| + | |||
| + | if($debug) { | ||
| + | print "Would report: | ||
| + | } else { | ||
| + | # And send the message | ||
| + | | ||
| + | } | ||
| + | } | ||
| + | |||
| + | # 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 = " | ||
| + | my $hobbitcolumn = " | ||
| + | |||
| + | # Dont do anything unless we have the " | ||
| + | return unless ( $sections{$sec} ); | ||
| + | |||
| + | # Is there a " | ||
| + | # Note that we must match with /m because there are multiple | ||
| + | # lines in the [who] section. | ||
| + | if ( $sections{$sec} =~ /^root /m ) { | ||
| + | $color = " | ||
| + | $summary = "ROOT login active"; | ||
| + | $statusmsg = "& | ||
| + | } | ||
| + | else { | ||
| + | $color = " | ||
| + | $summary = " | ||
| + | $statusmsg = "& | ||
| + | } | ||
| + | report($hostname, | ||
| + | } | ||
| + | |||
| + | # 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 = " | ||
| + | my $hobbitcolumn = " | ||
| + | |||
| + | # Dont do anything unless we have the " | ||
| + | return unless ( $sections{$sec} ); | ||
| + | |||
| + | # Is there a default gateway somewhere in the " | ||
| + | # Note that we must match with /m because there are multiple | ||
| + | # lines | ||
| + | $color = " | ||
| + | $summary = " | ||
| + | $statusmsg = "& | ||
| + | #darwin form: | ||
| + | # default | ||
| + | # 1.1/ | ||
| + | # 1.1.0.1 | ||
| + | |||
| + | if ( $sections{$sec} =~ / | ||
| + | my $gw = ($clientname eq " | ||
| + | my $sm = ($clientname eq " | ||
| + | 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(! exists $snr{ipre}) { | ||
| + | my $netre = $snr{net}; | ||
| + | $netre =~ s/\./\\./g; | ||
| + | $netre =~ s/\.$//; | ||
| + | $netCheckRoutes{$sn}{ipre} = qr/ | ||
| + | } | ||
| + | if( $clientip =~ $netCheckRoutes{$sn}{ipre} ) { | ||
| + | $found = 1; | ||
| + | $isok = $gw eq $snr{gw}; | ||
| + | $summary = "Found defgw: $gw OK"; | ||
| + | last | ||
| + | } | ||
| + | } | ||
| + | if( !$found && $gw =~ / | ||
| + | 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 = " | ||
| + | $summary = "Bad default route $gw for $clientip found"; | ||
| + | $statusmsg = "& | ||
| + | } | ||
| + | } else { | ||
| + | $color = " | ||
| + | $summary = " | ||
| + | $statusmsg = "& | ||
| + | } | ||
| + | |||
| + | report($hostname, | ||
| + | } | ||
| + | |||
| + | # 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 = " | ||
| + | my $hobbitcolumn = " | ||
| + | my $min; | ||
| + | |||
| + | # Dont do anything unless we have the " | ||
| + | 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(! exists $mhr{hostre}) { | ||
| + | my $hostre = $mhr{host}; | ||
| + | $memCheckTable{$mh}{hostre} = qr/ | ||
| + | } | ||
| + | $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 = " | ||
| + | $summary = " | ||
| + | |||
| + | if ( $sections{$sec} =~ / | ||
| + | my $tot = $1; | ||
| + | $statusmsg = sprintf("& | ||
| + | warn "DBG: memCheck $hostname ($clientip) PhysMEM: $tot\n" | ||
| + | my $isok = $tot > $min; | ||
| + | if(!$isok) { | ||
| + | $color = " | ||
| + | $summary = sprintf(" | ||
| + | $statusmsg = "& | ||
| + | } | ||
| + | } else { | ||
| + | $color = " | ||
| + | $summary = " | ||
| + | $statusmsg = "& | ||
| + | } | ||
| + | |||
| + | report($hostname, | ||
| + | } | ||
| + | |||
| + | </ | ||
| + | </ | ||
| + | |||
| + | ===== Known Bugs and Issues ===== | ||
| + | |||
| + | ===== To Do ===== | ||
| + | |||
| + | ===== Credits ===== | ||
| + | |||
| + | original rootlogin.pl script from Henrik | ||
| + | |||
| + | ===== Changelog ===== | ||
| + | |||
| + | * **2010-07-29** | ||
| + | * Initial release | ||