Skip to content
Snippets Groups Projects
check_packages2install 7.34 KiB
#!/bin/bash
# ======================================================================
#
# NAGIOS CLIENT CHECK :: check available package updates
# requires no root for yum ... apt I must verify
#
# ----------------------------------------------------------------------
#
# 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
# ======================================================================


. `dirname $0`/inc_pluginfunctions

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


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

function showAutoupdate(){
  ls ${cronfile} >/dev/null 2>&1
  if [ $? -eq 0 ]; then
    echo Autoupdate ON
    grep "\ \-r" ${cronfile} >/dev/null 2>&1
    if [ $? -eq 0 ]; then
      echo Autoreboot ON
    else
      echo Autoreboot OFF
    fi
  else
    echo Autoupdate OFF
  fi
}
# execute a local or a remote command
function _exec(){
    if [ ${MYhost} = "localhost" ]; then
        eval "$1"
    else
        ${MYsshprefix}${MYhost} "$1"
    fi
}

# 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) 
function _filterPkg(){
    local _filter=$( echo $1 | tr " " "|" )

    grep -E "^($_filter)"
}

# autodetect a package manager using which with 
# a list of known pkg managers
function detectPkgManager(){
    local _list="apt yum pamac"
    local out=$( _exec "which $_list 2>/dev/null" )
    for mypkg in $_list
    do
        echo "$out" | grep "/$mypkg" > /dev/null && echo $mypkg
    done
}

# Debian like Linux
# - Debian 11
function pkgApt(){

    local sum=$( _exec "sudo apt-get -u upgrade --assume-no" )

    # detect number of line containing "The following packages will be upgraded:"
    typeset -i local iStart=$( echo "$sum" | grep -n '^The following packages will be upgraded:' | cut -f 1 -d ':' )

    if [ $iStart -eq 0 ]; then
        echo "Nothing to install"
    else
        # show packages = text starting with 2 spaces below start line
        # packages are delimited with space -> replace with new line
        echo "$sum" | sed -n $iStart,\$p | grep "^\ \ " | sed "s#^\ \ ##g" | tr " " "\n"
    fi
}
# Arch Linux, Manjaro
function pkgPamac(){
     _exec "pamac checkupdates | grep -- '->'"
}
# RedHat like Linux
# - Centos 8
function pkgYum(){

    # local sum=$( _exec "sudo dnf check-update" )
    local sum=$( _exec "sudo yum -y check-update" )

    local iStart=3
    # detect number of line containing "Obsoleting Packages"
    typeset -i iEnd=$( echo "$sum" | grep -n '^Obsoleting Packages' | cut -f 1 -d ':' )-1
    local sEnd=$iEnd
    test "$iEnd" = "-1" && sEnd='$'

    echo "$sum" | sed -n ${iStart},${sEnd}p
    # echo "show lines ${iStart} -> ${sEnd}"

}
# check updates with apt and exit script
function checkApt(){
  # bug #2818
  sudo apt-get -v >/dev/null
  if [ $? -ne 0 ]; then
    ph.setStatus "error"
    echo "ERROR: failed to run apt-get"
    echo "OUTPUT is:"
    sudo apt-get -v
  else

    summary=`ph.execIfReady "sudo apt-get -u upgrade --assume-no | grep installed | grep upgraded" `
    # example output:
    # 0 upgraded, 0 newly installed, 0 to remove and 3 not upgraded.
    typeset -i local iPkg2Update=`echo $summary | cut -f 1 -d " "`

    ph.setStatusByLimit ${iPkg2Update} ${iWarnLimit} ${iCriticalLimit}
    ph.perfadd "updates-available" "${iPkg2Update}" ${iWarnLimit} ${iCriticalLimit}

    # --- output
    ph.status "$summary"
    echo "[apt]"
    echo

  fi

}


# check updates with yum and exit script
function checkYum(){
  local _yumout=/tmp/yumoutput.log

  # summary=`ph.execIfReady "/usr/bin/yum --security  check-update 2>&1 | fgrep 'security'" `
  # summary=`ph.execIfReady "/usr/bin/yum --security  check-update 2>&1 | fgrep 'security'" `
  ph.execIfReady "sudo /usr/bin/yum --security  check-update > $_yumout 2>&1"
  local summary=$( cat $_yumout | grep security )
  test -z "$summary" && summary='no data .. no packages to install'


  # example outputs:
  # I   No packages needed for security; 223 packages available
  # II  2 package(s) needed for security, out of 237 available
  typeset -i local iPkgSecurity=` echo $summary | cut -f 1  -d ' ' | sed "s#[^0-9]##g"`
  typeset -i local iPkg2Update=`  echo $summary | cut -f 2- -d ' ' | sed "s#[^0-9]##g"`

  # step I: check limits with packages to update:
  ph.setStatusByLimit ${iPkg2Update} ${iWarnLimit} ${iCriticalLimit}

  # step II: security packages switch to "critical"
  #          remark: a warn level does not exist
  if [ ${iPkgSecurity} -ne 0 ]; then
    ph.setStatus "critical"
  fi

  ph.perfadd "updates-available" "${iPkg2Update}"  ${iWarnLimit} ${iCriticalLimit}
  ph.perfadd "updates-security"  "${iPkgSecurity}" 1             1

  ph.status "$summary"
  echo "[yum]"
  cat $_yumout
  rm -f yumout

  echo
}


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


# set default / override from command line params
typeset -i iWarnLimit=`     ph.getValueWithParam 1   w "$@"`
typeset -i iCriticalLimit=` ph.getValueWithParam 200 c "$@"`

# ----- try package manager apt
pgkman=$( detectPkgManager )
case $pgkman in
    "apt")
        pkgstatus=$( checkApt )
        pkgsum=$( pkgApt )
        ;;
    "pamac")
        pkgstatus=""
        pkgsum=$( pkgPamac )
        ;;
    "yum")
        pkgstatus=$( checkYum )
        pkgsum=$( pkgYum )
        ;;
    *)
      ph.abort "UNKNOWN: package manager [$pgkman] was not detected or is not supported yet."
      ;;
esac

echo "$pkgstatus"
echo
showAutoupdate
echo

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

    # show filtered view
    for filterfile in $( ls -1 $0-data/*txt | sort )
    do
        filtername=$( echo $filterfile | rev | cut -f 1 -d "/" | rev | sed "s#.txt\$##g" | sed "s#^[0-9]*_##g" )
        filterdata=$( cat ${filterfile} | grep "^[a-zA-Z]" )

        out=$( echo "$pkgsum" | _filterPkg "${filterdata}" )
        typeset -i 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 "No package matched a group filter."
    else
        echo "Other packages: $iOther"
    fi

    # total packages
    echo Total packages to install: $iTotal

fi

ph.exit

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