====== rpi-apt ====== ^ Author | [[wim.nelis@nlr.nl| Wim Nelis ]] | ^ Compatibility | Xymon 4.2 | ^ Requirements | Perl | ^ Download | None | ^ Last Update | 2020-01-28 | ===== Description ===== Script rpi-apt.pl is a client-side script, which determines if there are any packages which can be upgraded at a Raspberry Pi running Raspbian. The upgrades are grouped into three classes, the security related upgrades, the normal upgrades and the upgrades which will not be installed. An alert is generated if at least one upgrade in the first two classes is found. The upgrades which are kept back are only reported, as a reminder. Script rpi-apt.pl will update the package list cache periodically. ===== Installation ===== === Client side === Copy the following script into file /usr/lib/xymon/client/ext/rpi-apt.pl : #!/usr/bin/perl -w # # Script rpi-apt.pl is a xymon client-side script. It retrieves the list of # outstanding patches for raspbian. These are divided into two groups, # security-related and the rest. At the same time, this script will reguarly # update the local cache of the package lists. # # Written by W.J.M. Nelis, wim.nelis@ziggo.nl, 201712 # use strict ; use Time::Piece ; use Time::Local ; # # Installation constants. # ----------------------- # my $XyDisp = $ENV{XYMSRV} ; # Name of monitor server my $XySend = $ENV{XYMON} ; # Monitor interface program my $XyLife = '+19h' ; # Status lifetime, default 30m my $FmtDate = "%Y.%m.%d %H:%M:%S" ; # Default date format $FmtDate = $ENV{XYMONDATEFORMAT} if exists $ENV{XYMONDATEFORMAT} ; my $HostName= `hostname` ; # 'Source' of this test chomp( $HostName ) ; # Remove trailing newline my $TestName= 'apt' ; # Name of test my @ColourOf= ( 'red', 'yellow', 'clear', 'green' ) ; my %ColourOf= () ; for ( my $i=0 ; $i<@ColourOf ; $i++ ) { $ColourOf{$ColourOf[$i]}= $i ; } # Package list cache update parameters. my $uplcFileName= '/var/cache/apt/pkgcache.bin' ; my $OneDay= 24*60*60 ; # Length of one day, expressed in [s] my $uplcRefreshAge= 2 * $OneDay ; # Minimum age of cache before refresh my $uplcRefreshCmd= 'sudo apt-get update' ; # Cache refresh command # # Updatable package list parameters. my $upCmd= 'apt-get --just-print upgrade' ; # Command my $upCnt= 0 ; # Total number of upgradable packages # # Global variables. # ----------------- # my $Now= localtime ; # Timestamp of tests $Now= $Now->strftime( $FmtDate ) ; my $Colour= $#ColourOf ; # Test status my $Result= '' ; # Message to sent to Xymon my %Class= ( High => 'red', Normal => 'yellow', Postponed => 'green' ) ; my %UPL = () ; $UPL{$_} = {} foreach ( keys %Class ) ; my @Lines ; sub min($$) { return $_[0] < $_[1] ? $_[0] : $_[1] ; } # # Function UpdatePackageListCache updates the package list cache, if it hasn't # been updated for some time. # sub UpdatePackageListCache() { my (@Time,$Time) ; # Time of last change of cache @Lines= `stat $uplcFileName` ; # Cache file statistics return unless @Lines ; # Ignore error condition foreach ( @Lines ) { next unless @Time= m/^Modify: (\d{4})-(\d+)-(\d+) (\d+):(\d+):(\d+)\./ ; $Time[1]-- ; # Adjust month ordinal $Time= timelocal( reverse @Time ) ; # Compute time stamp return if time - $Time < $uplcRefreshAge ; `$uplcRefreshCmd` ; # Update package list cache last ; # Skip rest of lines } # of foreach } # of UpdatePackageListCache # # Function GetListOfUpdates gets the list of the updatable packages. A typical # line of output, specifying an updatable package, looks like the following # line: # Inst python2.7 [2.7.13-2] (2.7.13-2+deb9u2 Raspbian:stable [armhf]) [] # sub GetListOfUpdates() { my $InPostponed= 0 ; # Flag: in list of kept back packages @Lines= `$upCmd` ; # Current list of updatable packages foreach ( @Lines ) { chomp ; # Handle the list of packages which are not to be upgraded (which are kept # back). The format of such a list is as follows: # The following packages have been kept back: # firmware-brcm80211 # if ( $InPostponed ) { if ( m/^\s\s\S/ ) { foreach my $pn ( split ) { next unless defined $pn; $UPL{Postponed}{$pn}= [ $pn, '?', '?' ] ; $upCnt++ ; } # of foreach next ; # Line is handled } else { $InPostponed= 0 ; # End of section found } # of else } elsif ( m/^The following packages have been kept back/ ) { $InPostponed= 1 ; # Start of section found next ; # Line is handled } # of elsif if ( m/^Inst (.+?) \[(.+?)] \((.+?) / ) { if ( m/securi/i ) { $UPL{High}{$1} = [ $1, $2, $3 ] ; } else { $UPL{Normal}{$1}= [ $1, $2, $3 ] ; } # of else $upCnt++ ; } # of if } # of foreach } # of GetListOfUpdates # # Function BuildMessage creates the message to be sent to Xymon. Any errors # should be recorded in %ErrMsg (too). # sub BuildMessage() { my $SubClr ; # # Build a table showing a summary of the results. # $Result = $upCnt == 0 ? "\n" : "Summary\n\n" ; $Result.= "\n" ; $Result.= " \n" ; foreach ( sort keys %UPL ) { $SubClr= keys %{$UPL{$_}} ? $ColourOf{$Class{$_}} : $ColourOf{'green'} ; $Colour= min( $Colour, $SubClr ) ; $SubClr= $ColourOf[$SubClr] ; $Result.= " " . "" . "\n" ; } # of foreach $Result.= " \n" ; $Result.= " " . "\n" ; $Result.= "
PriorityCountStatus
 $_ " . scalar(keys %{$UPL{$_}}) . "  &$SubClr
 ----- 
 Total $upCnt  &$ColourOf[$Colour]
\n" ; return if $upCnt == 0 and keys(%{$UPL{Postponed}}) == 0 ; $Result.= "\nList of upgradeable packages\n\n" ; $Result.= "\n" ; $Result.= " " . "\n" ; foreach my $class ( sort keys %UPL ) { my $hr= $UPL{$class} ; foreach my $up ( sort keys %$hr ) { $Result.= " " . "\n" ; } # of foreach } # of foreach $Result.= "
PackagePriorityCurrent versionNew version
 $up  $class  $$hr{$up}[1]  $$hr{$up}[2] 
\n" ; } # of BuildMessage # # Function InformXymon sends the message, in global variable $Result, to the # Xymon server. Any error messages in %ErrMsg are prepended to the message and # the status (colour) of the message is adapted accordingly. # sub InformXymon($) { $Colour= $ColourOf[$Colour] ; $Result= "\"status$XyLife $HostName.$TestName $Colour $Now\n" . "$_[0]\n\n$Result\"\n" ; `$XySend $XyDisp $Result` ; # Inform Xymon } # of InformXymon # # MAIN PROGRAM. # ============= # UpdatePackageListCache ; # `apt-get update` GetListOfUpdates ; # Retrieve list of outstanding updates BuildMessage ; # Build message for xymon InformXymon( 'Package upgrades' ) ; # Send message to xymon server
Copy the configuration snippet below to file /usr/lib/xymon/client/etc/clientlaunch.d/rpi-apt.cfg: # # Test rpi-apt retrieves the list of upgradeable packages, and warns if there # are any high (security) or low prio upgrades. # [rpi-apt] ENVFILE $XYMONCLIENTHOME/etc/xymonclient.cfg CMD $XYMONCLIENTHOME/ext/rpi-apt.pl LOGFILE $XYMONCLIENTLOGS/rpi-apt.log INTERVAL 6h Restart the (client part of) xymon. === Server side === There is nothing to install or to configure at the server-side, except possibly for the alerting. ===== Known Bugs and Issues ===== There are no known issues as per 2018.01.20. ===== Changelog ===== * **2018-01-20** * Initial release * **2018-03-11** * Report the packages which are kept back too * **2020-01-28** * Improve detection of kept-back-upgrades