monitors:rpi-apt

Error loading plugin struct
ParseError: syntax error, unexpected 'fn' (T_STRING), expecting :: (T_PAAMAYIM_NEKUDOTAYIM)
More info is available in the error log.

This is an old revision of the document!


rpi-apt

Author Wim Nelis
Compatibility Xymon 4.2
Requirements Perl
Download None
Last Update 2018-01-20

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 two classes, the security upgrades and the rest. An alert is generated if at least one upgrade is found. Moreover, the package list cache is updated periodically.

Client side

Copy the following script into file /usr/lib/xymon/client/ext/rpi-apt.pl :

Show Code ⇲

Hide Code ⇱

#!/usr/bin/perl -w
#
# Script 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  = '+13h' ;			# 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' ) ;
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
  next			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() {
  @Lines= `$upCmd` ;			# Current list of updatable packages
  foreach ( @Lines ) {
    chomp ;
    if ( m/^Inst (.+?) \[(.+?)] \((.+?) / ) {
      if ( m/securi/i ) {
	$UPL{High}{$1}  = [ $1, $2, $3 ] ;
      } else {
	$UPL{Normal}{$1}= [ $1, $2, $3 ] ;
      }  # of else
      $upCnt++ ;
      
    } elsif ( m/^Conf / ) {
#     next ;				# Do nothing

    } else {
      next			unless $upCnt ;
      print "$Now : $_\n" ;
    }  # of else
  }  # 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.= "<table>\n" ;
  $Result.= " <tr><th>Priority</th><th>Count</th><th>Status</th></tr>\n" ;
  foreach ( sort keys %UPL ) {
    $SubClr= keys %{$UPL{$_}} ? $ColourOf{$Class{$_}} : $ColourOf{'green'} ;
    $Colour= min( $Colour, $SubClr ) ;
    $SubClr= $ColourOf[$SubClr] ;
    $Result.= " <tr><td>&nbsp;$_&nbsp;</td>" .
	      "<td align='right'>" . scalar(keys %{$UPL{$_}}) . "</td>" .
	      "<td>&nbsp;&nbsp;&$SubClr</tr>\n" ;
  }  # of foreach
  $Result.= " <tr><td>&nbsp;</td><td>-----</td><td>&nbsp;</td></tr>\n" ;
  $Result.= " <tr><td>&nbsp;Total&nbsp;</td><td align='right'>$upCnt</td>" .
	    "<td>&nbsp;&nbsp;&$ColourOf[$Colour]</td></tr>\n" ;
  $Result.= "</table>\n" ;

  return			if $upCnt == 0 ;
  
  $Result.= "\nList of upgradable packages\n\n" ;
  $Result.= "<table>\n" ;
  $Result.= " <tr><th>Package</th><th>Priority</th>" .
	    "<th>Current version</th><th>New version</th></tr>\n" ;
  foreach my $class ( sort keys %UPL ) {
    my $hr= $UPL{$class} ;
    foreach my $up ( sort keys %$hr ) {
      $Result.= " <tr><td>&nbsp;$up&nbsp;</td><td>&nbsp;$class&nbsp;</td>" .
		"<td>&nbsp;$$hr{$up}[1]&nbsp;</td><td>&nbsp;$$hr{$up}[2]&nbsp;</td></tr>\n" ;
    }  # of foreach
  }  # of foreach
  $Result.= "</table>\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" .
	   "<b>$_[0]</b>\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 updates' ) ;	# 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.

There are no known issues as per 2018.01.20.

  • 2018-01-20
    • Initial release
  • monitors/rpi-apt.1520762655.txt.gz
  • Last modified: 2018/03/11 10:04
  • by wnelis