Last active
July 7, 2017 02:41
-
-
Save ttshivers/748e8e5762b0f3c7e9f108165a90cbc2 to your computer and use it in GitHub Desktop.
Xymon Yum Script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 | |
'newpackage' => [ 'New Package', 3 ], # 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 = $ENV{CLIENTHOSTNAME}; # Host under test | |
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 %ShortClassLst = () ; | |
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' ; | |
push @{$ShortClassLst{$Class}}, "$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 $_" ; | |
push @{$ShortClassLst{Anonymous}}, "$_" ; | |
} # 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" ; | |
$Result.= "<table>\n" ; | |
$Result.= " <tr><th align='left'>Category</th><th align='left'>Update</th><th>Status</th></tr>\n" ; | |
foreach $Class ( reverse sort keys %ClassCnt ) { | |
$SubColour= $ClassCnt{$Class} == 0 ? 3 : $Class{$Class}[1] ; | |
$Colour = min( $Colour, $SubColour ) ; | |
$SubColour= $ColourOf[$SubColour] ; | |
foreach my $update (@{$ShortClassLst{$Class}}) { | |
$Result.= "<tr style='color:$SubColour'><td>$Class</td><td>$update</td><td> &$SubColour</td></tr>"; | |
} | |
} | |
$Result.= "</table>\n" ; | |
} # of unless | |
} # of else | |
$Result= "<b>Yum update status</b>\n" . | |
"\n\n" . $Result . "\n" ; | |
InformXymon ; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment