Author | Wim Nelis |
---|---|
Compatibility | Xymon 4.2 |
Requirements | Perl |
Download | None |
Last Update | 2017-01-10 |
This client-side script queries the servers in RedHatNetwork (RHN) for outstanding updates. Additionally, the classification (security level) of each of the updates is retrieved. The number of outstanding updates per class is shown in a table. An alert is generated if there are important updates to be installed.
Install script yum.pl in subdirectory ~xymon/client/ext.
Show Code ⇲
Hide Code ⇱
#!/usr/bin/perl -w # # This script determines the number of outstanding updates (patches) for this # RHEL host. The count is reported to the Xymon monitoring server. This script # requires that: # A- the yum-security plug-in is installed, and # B- that sudo is configured to have this script run `yum`. # # Written by W.J.M. Nelis, wim.nelis@nlr.nl # use strict ; use Time::Piece ; # Format time # # Installation constants. # my $XyDisp= exists $ENV{XYMSRV} ? $ENV{XYMSRV} : $ENV{XYMONSERVERHOSTNAME} ; my $XySend= $ENV{XYMON} ; # Monitor interface program my $XyLife= '+13h' ; # Status lifetime, default 30m my $FmtDate= "%Y.%m.%d %H:%M:%S" ; # Default date format $FmtDate= $ENV{XYMONDATEFORMAT} if exists $ENV{XYMONDATEFORMAT} ; my $TestName= 'update' ; # Test name my @ColourOf= ( 'red', 'yellow', 'clear', 'green' ) ; # # Define the names and the status colours for the various classes of updates. # The names are chosen such that the order sorted on name matches an increased # urge to install. # my %Class= ( 'anonymous' => [ 'Anonymous', 2 ], # Catch undefined classes 'bugfix' => [ 'Bugfix', 3 ], 'enhancement' => [ 'Enhancement', 3 ], 'Low/Sec.' => [ 'Low', 3 ], 'Moderate/Sec.' => [ 'Moderate', 1 ], 'Important/Sec.' => [ 'Serious', 1 ], 'Critical/Sec.' => [ 'Vulnerable', 0 ], 'security' => [ 'Vulnerable', 0 ], ) ; $Class{$Class{$_}[0]}= $Class{$_} foreach ( keys %Class ) ; # # Variable $YumCmd defines the shell command to retrieve the list of outstanding # patches. The return codes of this command are: # 0 - no updates # 1 - error # 100 - updates available # Variable $YumClass defines the shell command to retrieve a list of updates, # including the classification of each of the updates. This list contains # duplicates of updates which are NOT listed by check-update! # my $YumCmd = 'sudo yum check-update 2>&1' ; # Retrieve list of patches my $YumClass= 'sudo yum list-security 2>&1' ; # Retrieve list of classifications # # Global variable allocation. # my $Now= localtime ; # Timestamp of tests $Now= $Now->strftime( $FmtDate ) ; my $Colour= 3 ; # Test status my $SubColour ; # Status of one update class my $HostName = `hostname` ; # Host under test chomp $HostName ; my $Result ; # Status message for xymon my $Count ; # Number of updates my %Update= () ; # List of updates my $Update ; # Full name of an update my %ClassLst= () ; # List of updates per class my %ClassCnt= () ; # Updates per class my $Class ; # Classification of an update my @Lines ; # Output of $YumCmd my $Lines ; # Concatenated output my (@PrvLine,@Fields) ; # Field on a line image sub min($$) { return $_[0] < $_[1] ? $_[0] : $_[1] ; } # # Function InformXymon sends the message, in global variable $Result, to the # xymon server. # sub InformXymon() { $Result= "\"status$XyLife $HostName.$TestName $ColourOf[$Colour] $Now\n" . "$Result\"\n" ; `$XySend $XyDisp $Result` ; # Inform Xymon $Result= '' ; # Reset message parameters $Colour= 3 ; } # of InformXymon ## ## M A I N P R O G R A M ## ----------------------- ## @Lines = `$YumCmd` ; # Retrieve list of updates $Lines = join( '', @Lines ) ; # Single string for error checks $Result= undef ; # Preset message for Xymon # # Check the output of the command for some error conditions. # if ( @Lines == 0 ) { $Colour= 2 ; # Measurement failed $Result= 'No update status received' ; } elsif ( $Lines[0] !~ m/^Loaded plugins/ ) { $Colour= 2 ; # Measurement failed $Result= "Unexpected update status received:\n" ; foreach ( @Lines ) { chomp ; $Result.= " $_\n" ; } # of foreach } elsif ( $Lines =~ m/run this command as root/ ) { $Colour= 2 ; $Result= 'No update status received, insufficient privileges' ; } elsif ( $Lines=~ m/There was an error communicating with RHN/ ) { $Colour= 2 ; $Result= 'Communication with RHN failed' ; } else { $ClassCnt{$Class{$_}[0]}= 0 foreach ( keys %Class ) ; $Count= 0 ; # # Check the output for the number of outstanding updates. # unless ( defined $Result ) { foreach ( @Lines ) { chomp ; last if m/^Obsoleting Packages/ ; @Fields= split ; # Handle an incomplete line. If the name or the version number are long # strings, the fields may be presented on two lines in stead of one. if ( @Fields < 3 ) { if ( @PrvLine ) { unshift @Fields, @PrvLine ; } else { @PrvLine= @Fields ; next ; } # of else } # of if @PrvLine= () ; next unless @Fields == 3 ; next unless $Fields[1] =~ m/^\d/ ; $Count++ ; $Update= $Fields[0] ; # Short name of update $Update= "$1-$Fields[1].$2" if $Update =~ m/^(.+)\.(.+?)$/ ; # print STDERR "$Update\n" ; # Log... $Update{$Update}= 'Anonymous' ; # Set classification } # of foreach # # Go retrieve the classification of each update and count the number of # available updates in each class. # @Lines= `$YumClass` ; foreach ( @Lines ) { chomp ; @Fields= split ; next unless @Fields == 3 ; next unless exists $Update{$Fields[2]} ; $Class= $Fields[1] ; # Classification unless ( exists $Class{$Class} ) { print "$Now Unknown class '$Class'\n" ; } # of unless $Class= exists $Class{$Class} ? $Class{$Class}[0] : 'Anonymous' ; $Update{$Fields[2]}= $Class ; # Save classification push @{$ClassLst{$Class}}, "$Fields[0] $Fields[2]" unless $Class eq 'Anonymous' ; } # of foreach $ClassCnt{$Update{$_}}++ foreach ( keys %Update ) ; # # The list of updates in class "Anonymous" must be build seperately. # if ( $ClassCnt{Anonymous} ) { foreach ( sort keys %Update ) { next unless $Update{$_} eq 'Anonymous' ; push @{$ClassLst{Anonymous}}, "RHNA-0000:0000 $_" ; } # of foreach } # of if # # Build a table showing the results. # $Result = "<table>\n" ; $Result.= " <tr><th align='left'>Category</th><th>Count</th><th>Status</th></tr>\n" ; foreach $Class ( sort keys %ClassCnt ) { $SubColour= $ClassCnt{$Class} == 0 ? 3 : $Class{$Class}[1] ; $Colour = min( $Colour, $SubColour ) ; $SubColour= $ColourOf[$SubColour] ; $ClassLst{$Class}= [ 'None' ] unless exists $ClassLst{$Class} ; $Result.= " <tr><td><span title='" ; $Result.= join( "\n", @{$ClassLst{$Class}} ) ; $Result.= "'>$Class</span></td>" . "<td align='right'>$ClassCnt{$Class}</td>" . "<td> &$SubColour</tr>\n" ; } # of foreach $Result.= " <tr><td> </td><td>-----</td><td> </td></tr>\n" ; $Result.= " <tr><td>Total</td><td align='right'>$Count</td><td> &$ColourOf[$Colour]</td></tr>\n" ; $Result.= "</table>\n" ; } # of unless } # of else $Result= "<b>Yum update status</b>\n" . "\n\n" . $Result . "\n" ; InformXymon ;
Extend file ~xymon/client/etc/clientlaunch.cfg with the following snippet:
[yum] ENVFILE $XYMONCLIENTHOME/etc/xymonclient.cfg CMD $XYMONCLIENTHOME/ext/yum.pl LOGFILE $XYMONCLIENTLOGS/yum.log CRONDATE 0 0-23/6 * * *