diff --git a/check_packages2install b/check_packages2install index 584b6c378ce931d0794a2bc4cb598fed060289eb..5ac996561bb2f5f6a02936298c59bdc836973aed 100755 --- a/check_packages2install +++ b/check_packages2install @@ -2,7 +2,7 @@ # ====================================================================== # # NAGIOS CLIENT CHECK :: check available package updates -# requires no root for yum ... apt I must verify +# for centos/debian/manjaro/ubuntu # # ---------------------------------------------------------------------- # @@ -20,27 +20,35 @@ # 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 # ====================================================================== -. `dirname $0`/inc_pluginfunctions +. $( dirname "$0" )/inc_pluginfunctions + +readonly iWarnDefault=1 +readonly iCriticalDefault=200 typeset -i iCount=0 -tmpfile=/tmp/packages2install.log cronfile=/etc/cron.d/system-updater MYhost="localhost" +dir_pkg="$( dirname $0 )/check_packages2install-pkgmanager" +dir_filter="$( dirname $0 )/check_packages2install-data" # ---------------------------------------------------------------------- # functions # ---------------------------------------------------------------------- -function showAutoupdate(){ - ls ${cronfile} >/dev/null 2>&1 - if [ $? -eq 0 ]; then +# 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 - grep "\ \-r" ${cronfile} >/dev/null 2>&1 - if [ $? -eq 0 ]; then + if grep "\ \-r" ${cronfile} >/dev/null 2>&1 + then echo Autoreboot ON else echo Autoreboot OFF @@ -49,7 +57,9 @@ function showAutoupdate(){ 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" @@ -58,141 +68,83 @@ function _exec(){ 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) -# param2 text additional grep params; "-v" to invert filtering -function _filterPkg(){ - local _filter=$( echo $1 | tr " " "|" ) - local _moreparams=$2 - - grep $_moreparams -E "^($_filter)" +# check if a given function name exists +# param string name of a function +function _functionExists(){ + [[ $(type -t $1) == function ]] } -# 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 -} +# show help +function showHelp(){ + local _self + _self=$(basename $0) +cat <<EOF +______________________________________________________________________ -# Debian like Linux -# - Debian 10 -# - Debian 11 -# - Ubuntu -function pkgApt(){ +CHECK PACKAGES TO INSTALL +Get packages that must be updated on this system - local sum=$( _exec "sudo apt-get -u upgrade --assume-no" ) +(c) Institute for Medical Education - University of Bern +Licence: GNU GPL 3 +______________________________________________________________________ - # 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 ':' ) +Get packages that must be updated on this system ans show found +packages in groups. - 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(){ +For groups and their search filters see files in subdir +check_packages2install-data. - # local sum=$( _exec "sudo dnf check-update" ) - local sum=$( _exec "sudo yum -y check-update" ) +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. - 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='$' +On CentOS it switches to ERROR if a critcal update was found. - echo "$sum" | sed -n ${iStart},${sEnd}p - # echo "show lines ${iStart} -> ${sEnd}" +Tested operating systems: +- Centos +- Debian +- Manjaro +- Ubuntu -} -# 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 +SYNTAX: +$_self [options] - 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 " "` +OPTIONS: - ph.setStatusByLimit ${iPkg2Update} ${iWarnLimit} ${iCriticalLimit} - ph.perfadd "updates-available" "${iPkg2Update}" ${iWarnLimit} ${iCriticalLimit} + -h show this help + -w custom warning level; default: $iWarnDefault + -c custom critical level; default: $iCriticalDefault - # --- output - ph.status "$summary" - echo "[apt]" - echo +PARAMETERS: - fi + None. +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" -# 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 ) - local summary=$( /usr/bin/yum --bugfix check-update 2>&1 | 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 - # III No security updates needed, but 61 updates available << centos 8 stream - typeset -i local iPkgSecurity - iPkgSecurity=$( echo "$summary" | cut -f 1 -d ' ' | sed "s#[^0-9]##g") - typeset -i local iPkg2Update - 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 + grep $_moreparams -E "^($_filter)" +} - echo +# 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 @@ -200,42 +152,49 @@ function checkYum(){ function showFilteredPackages(){ # filtered package view - if [ ! -z "$pkgsum" ]; then - typeset -i iTotal=$( echo "$pkgsum" | wc -l ) + if [ ! -z "$packages2install" ]; then + typeset -i iTotal + iTotal=$( echo "$packages2install" | wc -l ) typeset -i iFound=0 filterAll="" # show filtered view - for filterfile in $( ls -1 $0-data/*txt | sort ) + local _selfdir=$( dirname "$0" ) + for filterfile in $( find $dir_filter -name "*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]" ) + # 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 "$pkgsum" | _filterPkg "${filterdata}" ) - typeset -i iCount=$( echo "$out" | grep "." | wc -l ) + 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 "Remark: No package matched a group filter." - echo "--- All packages:" + echo "--- All packages (No package matched a group filter):" else echo "--- Other packages: $iOther" fi - echo "$pkgsum" | _filterPkg "${filterAll}" "-v" | nl + echo "$packages2install" | _filterPkg "${filterAll}" "-v" | nl echo # total packages echo Total packages to install: $iTotal + ph.perfadd "updates-available" "$iTotal" ${iWarnLimit} ${iCriticalLimit} fi @@ -245,36 +204,75 @@ function showFilteredPackages(){ # 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 + +. "${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}Packages" + _functionExists "${pkgmanager}Status" && functionStatus="${pkgmanager}Status" + _functionExists "${pkgmanager}Critical" && functionCritical="${pkgmanager}Critical" + + # 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=$( echo "$packages2install" | wc -l ) + + # custom: status text + test -n "$functionStatus" && statusLabel="[$pkgmanager] $( $functionStatus )" + + # custom: get count of critical packages + if [ -n "$functionCritical" ]; then + iPkgCritical=$( $functionCritical "$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 + + # 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 -# 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") - checkApt - pkgsum=$( pkgApt ) - ;; - "pamac") - # pkgstatus="" - pkgsum=$( pkgPamac ) - ;; - "yum") - checkYum - pkgsum=$( pkgYum ) - ;; - *) - ph.abort "UNKNOWN: package manager [$pgkman] was not detected or is not supported yet." - ;; -esac - -# echo "$pkgstatus" -echo -showAutoupdate -echo -showFilteredPackages +fi ph.exit diff --git a/check_packages2install-pkgmanager/apt.sh b/check_packages2install-pkgmanager/apt.sh new file mode 100644 index 0000000000000000000000000000000000000000..b650f3802c33ce4c427b48ebfbf0183852a81a0e --- /dev/null +++ b/check_packages2install-pkgmanager/apt.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# =============================================================== +# +# PACKAGE MANAGER: APT +# Debian, Ubuntu +# +# included by ../check_packages2install +# +# --------------------------------------------------------------- +# ah <axel.hahn@iml.unibe.ch> +# 2022-06-03 v1.0 ah first version +# =============================================================== + + +# --------------------------------------------------------------- +# command to list of updates +function aptGetUpdates(){ + sudo apt-get -u upgrade --assume-no +} + +# --------------------------------------------------------------- +# extract list of packages 2 install +# global string packagemanOut output of update lister command +function aptPackages(){ + + # detect number of line containing "The following packages will be upgraded:" + typeset -i local iStart + iStart=$( echo "$packagemanOut" | 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 "$packagemanOut" | sed -n $iStart,\$p | grep "^\ \ " | sed "s#^\ \ ##g" | tr " " "\n" + fi +} + +# --------------------------------------------------------------- +# get status line on apt based systems (debian, ubuntu) +# global string packagemanOut output of update lister command +function aptStatus(){ + echo "$packagemanOut" | grep "upgraded.*installed" +} + +# --------------------------------------------------------------- diff --git a/check_packages2install-pkgmanager/pamac.sh b/check_packages2install-pkgmanager/pamac.sh new file mode 100644 index 0000000000000000000000000000000000000000..2dfe81d9f74c16c99c8ee9b8ef7b63d6c02081c9 --- /dev/null +++ b/check_packages2install-pkgmanager/pamac.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# =============================================================== +# +# PACKAGE MANAGER: PAMAC +# Manjaro +# +# included by ../check_packages2install +# +# --------------------------------------------------------------- +# ah <axel.hahn@iml.unibe.ch> +# 2022-06-03 v1.0 ah first version +# =============================================================== + +# --------------------------------------------------------------- +# command to list of updates +function pamacGetUpdates(){ + pamac checkupdates +} + +# --------------------------------------------------------------- +# extract list of packages 2 install +function pamacPackages(){ + echo "$packagemanOut" | grep -- '->' +} + +# --------------------------------------------------------------- diff --git a/check_packages2install-pkgmanager/yum.sh b/check_packages2install-pkgmanager/yum.sh new file mode 100644 index 0000000000000000000000000000000000000000..faeb94c2fa98d0ce313a831da033c02a62631bd9 --- /dev/null +++ b/check_packages2install-pkgmanager/yum.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# =============================================================== +# +# PACKAGE MANAGER: YUM +# CentOS +# +# included by ../check_packages2install +# +# --------------------------------------------------------------- +# ah <axel.hahn@iml.unibe.ch> +# 2022-06-03 v1.0 ah first version +# =============================================================== + + +# --------------------------------------------------------------- +# command to list of updates +function yumGetUpdates(){ + sudo /usr/bin/yum -y check-update +} + +# --------------------------------------------------------------- +# extract list of packages 2 install +# global string packagemanOut output of update lister command +function yumPackages(){ + local iStart=3 + # detect number of line containing "Obsoleting Packages" + typeset -i iEnd=$( echo "$packagemanOut" | grep -n '^Obsoleting Packages' | cut -f 1 -d ':' )-1 + + local sEnd=$iEnd + test "$iEnd" = "-1" && sEnd='$' + + echo "$packagemanOut" | sed -n ${iStart},${sEnd}p +} + +# --------------------------------------------------------------- +# get custom status +function yumStatus(){ + if ! /usr/bin/yum --bugfix check-update 2>&1 | grep security; then + echo "Ooops - no output from [/usr/bin/yum --bugfix check-update]" + fi +} + +# --------------------------------------------------------------- +# extract count of critical +# param string text to extract critical counter from +function yumCritical(){ + local summary="$1" + # example outputs: + # I No packages needed for security; 223 packages available + # II 2 package(s) needed for security, out of 237 available + # III No security updates needed, but 61 updates available << centos 8 stream + echo "$summary" | cut -f 1 -d ' ' | sed "s#[^0-9]##g" +} + +# ---------------------------------------------------------------