Skip to content
Snippets Groups Projects
check_packages2install 8.69 KiB
#!/bin/bash
# ======================================================================
#
# NAGIOS CLIENT CHECK :: check available package updates
# for centos/debian/manjaro/ubuntu
#
# ----------------------------------------------------------------------
#
# ah=axel.hahn@iml.unibe.ch
# ds=daniel.schueler@iml.unibe.ch
#
# 2016-12-23  v0.3  ah,ds
# 2018-12-18  v1.0  ah     added check for auto update (IML specific)
# 2019-03-26  v1.1  ah     fix apt-get (not all constellations worked)
# 2019-04-29  v1.2  ah     yum: supress error channel output (task #2959)
# 2020-03-05  v1.3  <axel.hahn@iml.unibe.ch> switch to ph.* helper functions
# 2020-03-11  v1.4  <axel.hahn@iml.unibe.ch> add -c -w limits; added perfdata (yum)
# 2021-05-11  v1.4  <axel.hahn@iml.unibe.ch> added centos8 support
# 2021-08-20  v1.5  <martin.gasser@iml.unibe.ch> bug fixing - missing sudo in yum command
# 2021-12-16  v1.6  <axel.hahn@iml.unibe.ch> show filtered overview
# 2021-12-17  v1.7  <axel.hahn@iml.unibe.ch> show non matching packages in section "other"
# 2021-12-20  v1.8  <axel.hahn@iml.unibe.ch> show all packages if no filter matched
# 2022-06-03  v1.9  <axel.hahn@iml.unibe.ch> call yum with path; shellcheck updates; plugin like package managers
# 2022-06-07  v1.10 <axel.hahn@iml.unibe.ch> fix iPkg2Update on empty package list
#                                            rename package manager functions
# 2022-10-21  v1.11 <axel.hahn@unibe.ch>     remove grep: warning: stray \ before white space
# 2023-08-24  v1.12 <axel.hahn@unibe.ch>     update help; rename to getSecurityCount
# ======================================================================


. $(dirname $0)/inc_pluginfunctions
self_APPVERSION=1.12

readonly iWarnDefault=1
readonly iCriticalDefault=200

typeset -i iCount=0
cronfile=/etc/cron.d/system-updater
MYhost="localhost"

dir_pkg="$( dirname $0 )/check_packages2install-pkgmanager"
dir_filter="$( dirname $0 )/check_packages2install-data"

# ----------------------------------------------------------------------
# functions
# ----------------------------------------------------------------------

# show if auto update ist enabled here by searching for a cronjob
# see global var cronfile
# global  string  cronfile  filename of the cronjob to detect
function _showAutoupdate(){
  if ls ${cronfile} >/dev/null 2>&1
  then
    echo Autoupdate ON
    if grep -- " -r" ${cronfile} >/dev/null 2>&1
    then
      echo Autoreboot ON
    else
      echo Autoreboot OFF
    fi
  else
    echo Autoupdate OFF
  fi
}

# execute a local or a remote command
# param  string  commandline with command and its params
function _exec(){
    if [ ${MYhost} = "localhost" ]; then
        eval "$1"
    else
        ${MYsshprefix}${MYhost} "$1"
    fi
}

# check if a given function name exists
# param  string  name of a function
function _functionExists(){
  [[ $(type -t $1) == function ]]
}

# show help
function showHelp(){
    local _self
    _self=$(basename $0)
cat <<EOF
$( ph.showImlHelpHeader )

Get packages that must be updated on this system and show found 
packages in groups.

RELATED FILES:
1) For groups and their search filters see files in subdir 
   check_packages2install-data.
2) In the subdir check_packages2install-pkgmanager are scripts
   for supported package managers (with aded ".sh").

OUTPUT:
It returns UNKNOWN if package manager is not supported.

It returns OK if the system is up to date.
It returns WARNING or ERROR if count of found pakackes is greater than
given warn level.

On CentOS it switches to ERROR if a critcal update was found.

The check supports performance data.

Tested operating systems:
- Centos
- Debian
- Manjaro
- Ubuntu

SYNTAX:
$_self [options]

OPTIONS:

    -w   custom warning level; default: $iWarnDefault
    -c   custom critical level; default: $iCriticalDefault

PARAMETERS:

    -h   show this help

EOF
}

# apply filter on incoming piped data
# filter is a param with spaced keywords that will be transformed
# to a regex 
# param1 text if filter keywords (seperated by space) 
# param2 text additional grep params; "-v" to invert filtering
function _filterPkg(){
    local _filter
    _filter=$( echo $1 | tr " " "|" )
    local _moreparams="$2"

    grep $_moreparams -E "^($_filter)"
}

# autodetect a package manager using which with 
# a list of known pkg managers
function _detectPkgManager(){
    find $dir_pkg -name "*.sh" | while read incfile
    do
      pkgmanager=$( basename $incfile | sed "s#.sh##" )
      which "$pkgmanager" > /dev/null 2>&1 && echo "$pkgmanager"
    done
}

# ----------------------------------------------------------------------

# show grouped packages by category
# global  string  dir_filter     directory where to find filters
# global  string  packagemanOut  output of update lister command
function showFilteredPackages(){

  # filtered package view
  if [ -n "$packages2install" ]; then
      typeset -i iTotal
      iTotal=$( echo "$packages2install" | wc -l )
      typeset -i iFound=0
      filterAll=""

      # show filtered view
      for filterfile in $( find "$dir_filter" -name "*txt" | sort )
      do
          # get group name from filename
          filtername=$( echo "$filterfile" | rev | cut -f 1 -d "/" | rev | sed "s#.txt\$##g" | sed "s#^[0-9]*_##g" )

          # get filter for this group
          filterdata=$( cat "${filterfile}" | grep "^[a-zA-Z]" )

          # build a "total filter" with all group filters - used to grep -v later
          filterAll="$filterAll $filterdata"

          out=$( echo "$packages2install" | _filterPkg "${filterdata}" )
          typeset -i iCount
          iCount=$( echo "$out" | grep "." | wc -l )

          test $iCount -ne 0 && ( 
              echo --- $( echo "$filtername" | sed "s#MYfilter##g" ): $iCount
              echo "$out" | nl; echo 
          )
          iFound=$iFound+$iCount
      done

      # show count of non matching packages
      typeset -i iOther=$iTotal-$iFound
      if [ $iFound -eq 0 ]; then
          echo "--- All packages (No package matched a group filter):"
      else
          echo "--- Other packages: $iOther"
      fi
      echo "$packages2install" | _filterPkg "${filterAll}" "-v" | nl
      echo

      # total packages
      echo Total packages to install: $iTotal

  fi

}

# ----------------------------------------------------------------------
# main
# ----------------------------------------------------------------------

# ----- help wanted?
if [ "$1" = "-h" ]; then
  showHelp; exit 0
fi

# ----- set default / override from command line params
typeset -i iWarnLimit
typeset -i iCriticalLimit
iWarnLimit=$(     ph.getValueWithParam $iWarnDefault     w "$@")
iCriticalLimit=$( ph.getValueWithParam $iCriticalDefault c "$@")

# ----- handle output of different package managers
pkgmanager=$( _detectPkgManager )
if [ -z "$pkgmanager" ]; then
  ph.abort "UNKNOWN: the package manager was not detected/ is not supported."
fi

# load functions for the detected package manager
. "${dir_pkg}/${pkgmanager}.sh" || exit 2

packagemanOut=$( ${pkgmanager}.getUpdates )

if [ -z "$packagemanOut" ]; then
  ph.setStatus "critical"
  ph.status "[$pkgmanager] ERROR: failed to get output from package manager."
else

  # generated function names - package manager is prefix
  function2install="${pkgmanager}.getPackageList"
  _functionExists "${pkgmanager}.getStatusLine"    && functionStatus="${pkgmanager}.getStatusLine"
  _functionExists "${pkgmanager}.getSecurityCount"  && functionSecuritycount="${pkgmanager}.getSecurityCount"

  # count of packages ... to install ... critical (centos only)
  typeset -i iPkg2Update=0
  typeset -i iPkgCritical=0

  # get list of packages 2 install
  packages2install=$( $function2install )
  iPkg2Update=$( test -n "$packages2install" && echo "$packages2install" | wc -l )

  # custom: status text
  test -n "$functionStatus" && statusLabel="[$pkgmanager] $( $functionStatus )"
  
  # custom: get count of critical packages
  if [ -n "$functionSecuritycount" ]; then
    iPkgCritical=$( $functionSecuritycount "$statusLabel" )
    ph.perfadd "updates-security"  "${iPkgCritical}" 1 1
  fi

  # set statuscode by found updates
  if [ $iPkgCritical -gt 0 ]; then
    ph.setStatus "critical"
  else
    ph.setStatusByLimit ${iPkg2Update} ${iWarnLimit} ${iCriticalLimit}
  fi
  ph.perfadd "updates-available" "${iPkg2Update}" "${iWarnLimit}" "${iCriticalLimit}"

  # set label for status line
  if [ -z "$statusLabel" ]; then
    test $iPkgCritical -gt 0 && statusLabel="[$pkgmanager] $iPkg2Update updates; $iPkgCritical critcal detected"
    test $iPkgCritical -gt 0 || statusLabel="[$pkgmanager] $iPkg2Update updates"
  fi
  ph.status "$statusLabel"

  # ----- show auto update info and found packages
  echo
  _showAutoupdate
  echo
  showFilteredPackages

fi

ph.exit

# ----------------------------------------------------------------------