From e069b8c5f76fd0b0031ab3db249ba16f6d010178 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Tue, 29 Oct 2019 23:03:21 +1300 Subject: [PATCH 01/29] Rebase for upstream changes --- agents/check_mk_agent.merged | 2774 ++++++++++++++++++++++++++++++++++ 1 file changed, 2774 insertions(+) create mode 100644 agents/check_mk_agent.merged diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged new file mode 100644 index 00000000000..f5d0ba5ef3c --- /dev/null +++ b/agents/check_mk_agent.merged @@ -0,0 +1,2774 @@ +#!/bin/sh +# vim: noai:ts=4:sw=4:expandtab +# Check_MK Agent for UNIX/Linux systems +# +------------------------------------------------------------------+ +# | ____ _ _ __ __ _ __ | +# | / ___| |__ ___ ___| | __ | \/ | |/ / | +# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / | +# | | |___| | | | __/ (__| < | | | | . \ | +# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ | +# | | +# | Copyright Mathias Kettner 2014 mk@mathias-kettner.de | +# +------------------------------------------------------------------+ +# +# This file is part of Check_MK. +# The official homepage is at https://checkmk.com/. +# +# check_mk is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation in version 2. check_mk is distributed +# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with- +# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU General Public License for more de- +# tails. You should have received a copy of the GNU General Public +# License along with GNU Make; see the file COPYING. If not, write +# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301 USA. + +# Remove locale settings to eliminate localized outputs where possible +LC_ALL=C +export LC_ALL +unset LANG + +# Close standard input (for security reasons) and stderr when not explicitly in debug mode. +# When the nodes agent is executed by a e.g. docker node in a container, +# then don't close stdin, because the agent is piped through it in this case. +if [ "${1}" = -d ]; then + set -xv +# TO-DO: Review the validity/use of MK_FROM_NODE, it seems to be superseded now +elif [ -z "${MK_FROM_NODE}" ]; then + exec /dev/null +fi + +#################################################################################################### +# Dynamically build PATH to ensure that locally installed binaries are found +# Blank a variable for the following dynamic PATH task +newPath= + +# Itirate through a list of potential PATH members and add any paths that are found +# to the 'newPath' variable. This way, we dynamically build PATH, and bias Solaris towards XPG4 +for dir in /usr/gnu/bin /usr/xpg6/bin /usr/xpg4/bin /usr/kerberos/bin /usr/kerberos/sbin /bin \ + /sbin /usr/bin /usr/sbin /usr/contrib/bin/usr/local/bin /usr/local/sbin /opt/csw/bin \ + /opt/csw/sbin /opt/sfw/bin /opt/sfw/sbin /usr/pkg/bin /usr/sfw/bin /usr/sfw/sbin /snap/bin; do + + [ -d "${dir}" ] && newPath="${newPath}:${dir}" +done + +# Now assign our freshly built newPath variable, removing any leading colon +PATH="${newPath#:}" + +# Finally, export the PATH and unset newPath +export PATH +unset -v newPath + +# 'mkecho()' abstracts the portability of 'printf' and solves the major +# portability headaches caused by various implementations of 'echo' +# This is called 'mkecho()' rather than an 'echo()' override because +# some shells protect their builtins, denying us the override cleanliness +# Fun exercise: look at Oracle's man page for 'echo', specifically the USAGE section. +# This also adds the '-j' option to output in json keypair format +mkecho() { + case "${1}" in + (-e) + case "${2}" in + (-n) shift 2; printf -- '%b' "${*}" ;; + (*) shift; printf -- '%b\n' "${*}" ;; + esac + ;; + (-E) + case "${2}" in + (-n) shift 2; printf -- '%s' "${*}" ;; + (*) shift; printf -- '%s\n' "${*}" ;; + esac + ;; + (-j) shift; printf -- '{"%s": "%s"}\n' "${1}" "${2}" ;; + (-n) + case "${2}" in + (-e) shift 2; printf -- '%b' "${*}" ;; + (-E) shift 2; printf -- '%s' "${*}" ;; + (*) shift; printf -- '%s' "${*}" ;; + esac + ;; + (-en|-ne) shift; printf -- '%b' "${*}" ;; + (-En|-nE) shift; printf -- '%s' "${*}" ;; + (*) printf -- '%s\n' "${*}" ;; + esac +} + +# Functionalise and standardise 'quiet grep' based tests. +# This gives us 'grep -q' cleanliness where '>/dev/null 2>&1' +# would otherwise be required e.g. Solaris, older versions of grep etc +if mkecho "word" | grep -q "word" >/dev/null 2>&1; then + grepq() { grep -q "$@" 2>/dev/null; } +else + grepq() { grep "$@" >/dev/null 2>&1; } +fi + +# Function to replace "if type [somecmd]" idiom +# 'command -v' tends to be more robust vs 'which' and 'type' based tests +# We set this function early so that it's available for the rest of the agent +inpath() { + command -v "${1:?No command to test}" >/dev/null 2>&1 +} + +#################################################################################################### +# If EUID isn't set, then set it +# Note that 'id -u' is now mostly portable here due to the alignment of xpg4 above +# '[ -w / ]' may be an alternative test for proving root privileges... +if [ ! "${EUID}" ]; then + EUID=$(id -u); readonly EUID; export EUID +fi + +# If HOSTNAME isn't set, then set it +if [ ! "${HOSTNAME}" ]; then + HOSTNAME=$(hostname); readonly HOSTNAME; export HOSTNAME +fi + +# If HOME isn't set, then set it +if [ ! "${HOME}" ]; then + HOME=$(getent passwd | awk -F':' -v EUID="${EUID}" '$3 == EUID{print $6}') + readonly HOME; export HOME +fi + +# date +%s is not portable, so we provide this function +# To do this in pure shell is... fun... however 'perl' is assumed +# elsewhere in this agent, so we may as well depend on that for our failover option +if date +%s 2>/dev/null | grepq '%s'; then + get_epoch() { perl -e 'print time."\n";'; } +else + get_epoch() { date +%s; } +fi + +# Newer shells like zsh and bash5.x have EPOCHSECONDS. If it's not available, we set it +# Note that if this is set here, it will not update each time it's used +# Use get_epoch() if you need that kind of accuracy +if [ ! "${EPOCHSECONDS}" ]; then + EPOCHSECONDS=$(get_epoch); readonly EPOCHSECONDS; export EPOCHSECONDS +fi + +# Because $SHELL is an unreliable thing to test against (e.g. SHLVL > 1), we provide this function +# It tries multiple methods to discover and name the invoking shell +# This won't work for 'fish', which needs 'ps -p %self' or similar non-bourne-esque syntax. +get_shell() { + if [ -r "/proc/$$/cmdline" ]; then + # We use 'tr' because 'cmdline' files have NUL terminated lines + # TO-DO: Possibly handle multi-word output e.g. 'busybox ash' + printf -- '%s\n' "$(tr '\0' ' ' /dev/null 2>&1; then + # This double-awk caters for situations where CMD/COMMAND + # might be a full path e.g. /usr/bin/zsh + ps -p "$$" | tail -n 1 | awk '{print $NF}' | awk -F '/' '{print $NF}' + # This one works well except for busybox + elif ps -o comm= -p "$$" >/dev/null 2>&1; then + ps -o comm= -p "$$" + elif ps -o pid,comm= >/dev/null 2>&1; then + ps -o pid,comm= | awk -v ppid="$$" '$1==ppid {print $2}' + else + case "${BASH_VERSION}" in (*.*) printf -- '%s\n' "bash";; esac; return 0 + case "${KSH_VERSION}" in (*.*) printf -- '%s\n' "ksh";; esac; return 0 + case "${ZSH_VERSION}" in (*.*) printf -- '%s\n' "zsh";; esac; return 0 + # If we get to this point, fail out: + return 1 + fi +} + +# If SHELL isn't set, then set it. +if [ ! "${SHELL}" ]; then + if get_shell >/dev/null 2>&1; then + SHELL=$(command -v "$(get_shell)"); readonly SHELL; export SHELL + fi +fi + +#################################################################################################### +# Define the version of Check_MK +MK_VERSION=TESTING + +# Manually define these variables here if you want to override the defaults +# This is where these would be templated in something like an Ansible role too e.g. +#MK_LIBDIR="{{ mk_libdir | d('/opt/check_mk/lib') }}" +#MK_CONFDIR="{{ mk_confdir | d('/opt/check_mk/etc') }}" +#MK_VARDIR="{{ mk_vardir | d('/opt/check_mk/var') }}" +#MK_TMPDIR="{{ mk_tmpdir | d('/opt/check_mk/tmp') }}" + +# Ensure that the MK_OSSTR environment variable is set. +# This imitates the 'OSTYPE' variable from bash +# We use this variable later on for OS specific behaviour +case $(uname -s) in + ("AIX") + MK_OSSTR=aix + MK_LIBDIR="${MK_LIBDIR:-/usr/check_mk/lib}" + MK_CONFDIR="${MK_CONFDIR:-/usr/check_mk/conf}" + MK_VARDIR="${MK_VARDIR:-/tmp/check_mk}" + ;; + ("Darwin") + MK_OSSTR=mac + #MK_LIBDIR="${MK_LIBDIR:-/to/be/changed}" + #MK_CONFDIR="${MK_CONFDIR:-/to/be/changed}" + #MK_VARDIR="${MK_VARDIR:-/set/this}" + ;; + ("FreeBSD") + MK_OSSTR=freebsd + MK_LIBDIR="${MK_LIBDIR:-/usr/local/lib/check_mk_agent}" + MK_CONFDIR="${MK_CONFDIR:-/etc/check_mk}" + #MK_VARDIR="${MK_VARDIR:-/set/this}" + MK_TMPDIR="${MK_TMPDIR:-/var/run/check_mk}" + ;; + ("HPUX") + MK_OSSTR=hpux + MK_LIBDIR="${MK_LIBDIR:-/usr/lib/check_mk_agent}" + MK_CONFDIR="${MK_CONFDIR:-/etc/check_mk}" + #MK_VARDIR="${MK_VARDIR:-/set/this}"" + ;; + ("Linux"|"linux-gnu"|"GNU"*) + MK_OSSTR=linux + MK_LIBDIR="${MK_LIBDIR:-/usr/lib/check_mk_agent}" + MK_CONFDIR="${MK_CONFDIR:-/etc/check_mk}" + MK_VARDIR="${MK_VARDIR:-/var/lib/check_mk_agent}" + ;; + ("NetBSD") + MK_OSSTR=netbsd + #MK_LIBDIR="${MK_LIBDIR:-/change/me/}" + #MK_CONFDIR="${MK_CONFDIR:-/change/me}" + #MK_VARDIR="${MK_VARDIR:-/set/this}" + ;; + ("OpenBSD") + MK_OSSTR=openbsd + MK_LIBDIR="${MK_LIBDIR:-/usr/lib/check_mk_agent}" + MK_CONFDIR="${MK_CONFDIR:-/etc}" + #MK_VARDIR="${MK_VARDIR:-/set/this}" + ;; + ("SunOS"|"solaris") + MK_OSSTR=solaris + MK_LIBDIR="${MK_LIBDIR:-/usr/lib/check_mk_agent}" + MK_CONFDIR="${MK_CONFDIR:-/etc/check_mk}" + MK_VARDIR="${MK_VARDIR:-/var/lib/check_mk_agent}" + ;; + (*"BSD"|*"bsd"|"DragonFly"|"Bitrig") + MK_OSSTR=bsd + #MK_LIBDIR="${MK_LIBDIR:-/change/me/}" + #MK_CONFDIR="${MK_CONFDIR:-/change/me}" + #MK_VARDIR="${MK_VARDIR:-/set/this}" + ;; + (*) + MK_OSSTR=$(uname -s) + #MK_LIBDIR="${MK_LIBDIR:-/to/be/changed}" + #MK_CONFDIR="${MK_CONFDIR:-/to/be/changed}" + #MK_VARDIR="${MK_VARDIR:-/set/this}" + ;; +esac + +# All executables in MK_PLUGINSDIR will simply be executed and their +# ouput appended to the output of the agent. Plugins define their own +# sections and must output headers with '<<<' and '>>>' +MK_PLUGINSDIR="${MK_LIBDIR:?}"/plugins + +# All executables in MK_LOCALDIR will be executed and their +# output inserted into the section <<>>. Please +# refer to online documentation for details about local checks. +MK_LOCALDIR="${MK_LIBDIR}"/local + +# All files in MK_SPOOLDIR will simply appended to the agent +# output if they are not outdated (see below) +MK_SPOOLDIR="${MK_VARDIR:?}"/spool + +# Protect all our MK variables +readonly MK_OSSTR MK_LIBDIR MK_CONFDIR MK_VARDIR MK_VERSION +readonly MK_PLUGINSDIR MK_LOCALDIR MK_SPOOLDIR MK_TMPDIR + +# Export all our MK variables +export MK_OSSTR MK_LIBDIR MK_CONFDIR MK_VARDIR MK_VERSION +export MK_PLUGINSDIR MK_LOCALDIR MK_SPOOLDIR MK_TMPDIR + +# Now that we have all of that figured out, we work through some OS specific setup tasks +case "${MK_OSSTR}" in + (aix) + # For AIX, force load of environment. + # shellcheck source=/dev/null + [ -e "${HOME}"/.profile ] && . "${HOME}"/.profile >/dev/null 2>&1 + # Avoid problems with wrong decimal separators in other language verions of aix + LC_NUMERIC="en_US" + export LC_NUMERIC + ;; + (freebsd) + osver="$(uname -r)" + is_jailed="$(sysctl -n security.jail.jailed)" + ;; + (solaris) + # Find out what zone we are running in + # Treat all pre-Solaris 10 systems as "global" + if inpath zonename; then + zonename=$(zonename) + pszone="-z $zonename" + else + zonename="global" + pszone="-A" + fi + ;; +esac + +#################################################################################################### +# The package name gets patched for baked agents to either +# "check-mk-agent" or the name set by the "name of agent packages" rule +XINETD_SERVICE_NAME=check_mk + +# Detect whether or not the agent is being executed in a container +# environment. +if [ -f /.dockerenv ]; then + MK_IS_DOCKERIZED=1 +elif grepq container=lxc /proc/1/environ; then + # Works in lxc environment e.g. on Ubuntu bionic, but does not + # seem to work in proxmox (see CMK-1561) + MK_IS_LXC_CONTAINER=1 +elif grepq 'lxcfs /proc/cpuinfo fuse.lxcfs' /proc/mounts; then + # Seems to work in proxmox + MK_IS_LXC_CONTAINER=1 +else + unset -v MK_IS_DOCKERIZED + unset -v MK_IS_LXC_CONTAINER +fi + +# Load our variables for encrypted data. See protect_output() +if [ -r "${MK_CONFDIR}/encryption.cfg" ]; then + # We ensure that this file is secure + chmod 640 "${MK_CONFDIR}/encryption.cfg" 2>/dev/null + + # shellcheck source=/dev/null + . "${MK_CONFDIR}/encryption.cfg" +fi + +# Load our variables for realtime data +RTC_PLUGINS="" +# Load our config file. This provides RTC_TIMEOUT, RTC_PORT, RTC_SECRET and RTC_SECTIONS +if [ -r "${MK_CONFDIR}/real_time_checks.cfg" ]; then + # We ensure that this file is secure + chmod 640 "${MK_CONFDIR}/real_time_checks.cfg" 2>/dev/null + + # shellcheck source=/dev/null + . "${MK_CONFDIR}/real_time_checks.cfg" +fi + +# Provide information about the remote host. That helps when data +# is being sent only once to each remote host. +if [ "${REMOTE_HOST}" ]; then + MK_RTC_HOST="${REMOTE_HOST}" + export MK_RTC_HOST +elif [ "${SSH_CLIENT}" ]; then + MK_RTC_HOST="${SSH_CLIENT%% *}" + export MK_RTC_HOST +fi + +# If we are called via xinetd, try to find only_from configuration +if [ -n "${REMOTE_HOST}" ]; then + # shellcheck disable=SC2039 + mkecho -n 'OnlyFrom: ' + sed -n '/^service[[:space:]]*'$XINETD_SERVICE_NAME'/,/}/s/^[[:space:]]*only_from[[:space:]]*=[[:space:]]*\(.*\)/\1/p' /etc/xinetd.d/* | head -n1 + mkecho +fi + +# 'coreutils' 5.3.0 broke how 'stat' handled its output. This was reverted +# in STABLE in 5.9.4. Just in case we happen across this version +# we catch it and build a workaround to correct its behaviour +# See: https://lists.gnu.org/archive/html/bug-coreutils/2005-12/msg00157.html +if stat --version 2>&1 | head -n 1 | grepq "5.3.0"; then + stat() { + printf -- '%s\n' "$(command stat "${@}")" + } +fi + +# Function to list CIFS mounts for use by section_nfs +get_cifs_mounts() { + if [ -r /proc/mounts ]; then + sed -n '/ cifs\? /s/[^ ]* \([^ ]*\) .*/\1/p' < /proc/mounts | sed 's/\\040/ /g' + else + mount | awk '/ cifs/{print $3;}' + fi +} + +# Function to list NFS mounts for use by section_nfs +get_nfs_mounts() { + if [ -r /proc/mounts ]; then + sed -n '/ nfs4\? /s/[^ ]* \([^ ]*\) .*/\1/p' < /proc/mounts | sed 's/\\040/ /g' + else + mount | awk '/ nfs/{print $3;}' + fi +} + +# In theory, this is how these functions should work: +# If the GNU stat approach fails, its failure will be silenced +# and the BSD stat approach will be tried. Failing that, it's perl to the rescue. +get_file_atime() { + stat -c %X "${1}" 2>/dev/null || + stat -f %a "${1}" 2>/dev/null || + perl -e 'if (! -f $ARGV[0]){die "0000000"};$atime=(stat($ARGV[0]))[8];print $atime."\n";' "${1}" +} + +# Note: ctime is the least portable of these metrics! +get_file_ctime() { + stat -c %Z "${1}" 2>/dev/null || + stat -f %c "${1}" 2>/dev/null || + perl -e 'if (! -f $ARGV[0]){die "0000000"};$ctime=(stat($ARGV[0]))[10];print $ctime."\n";' "${1}" +} + +get_file_mtime() { + stat -c %Y "${1}" 2>/dev/null || + stat -f %m "${1}" 2>/dev/null || + perl -e 'if (! -f $ARGV[0]){die "0000000"};$mtime=(stat($ARGV[0]))[9];print $mtime."\n";' "${1}" +} + +# This function ensures that a file is executable and +# does not have certain patterns within its name +is_valid_plugin() { + case "${1:?No plugin defined}" in + (*dpkg-new|*dpkg-old|*dpkg-temp) + return 1 + ;; + (*) + if [ -x "${1}" ]; then + return 0 + else + return 1 + fi + ;; + esac +} + +# Setup a function to encrypt the output using openssl +protect_output() { + if ! inpath openssl; then + mkecho "ERROR: protect_output(): 'openssl' not found in PATH" >&2 + return + fi + + # If this function has an arg "-rt", then we're being used for realtime data + if [ "${1}" = "-rt" ]; then + # Let's see if RTC_SECRET is defined + if [ ! -r "${MK_CONFDIR}/real_time_checks.cfg" ]; then + mkecho "ERROR: protect_output(): Unable to read real_time_checks.cfg" + return + fi + # If we have a defined RTC_SECRET, then we prioritise that. + # This is a reversal of the previous behaviour, because we may want a setup + # where realtime checks go to hostA secured with pwdA, and normal check + # output goes to hostB secured with pwdB. This approach makes that clear. + if grepq "^RTC_SECRET=.*" "${MK_CONFDIR}/real_time_checks.cfg"; then + PASSPHRASE=$(awk -F '=' '/^RTC_SECRET/{print $2' "${MK_CONFDIR}/real_time_checks.cfg") + fi + fi + + # Convert the openssl version to an integer e.g. 1.0.2k-fips -> 10002 + _opensslVer=$(openssl version | awk '{print $2}' | awk -F . '{print (($1 * 100) + $2) * 100+ $3}') + # shellcheck disable=SC2039 + if [ "${_opensslVer}" -ge 10000 ]; then + _encCode="02" + _encMode=sha256 + else + _encCode="00" + _encMode=md5 + fi + + # Print our protocol and/or epoch information + if [ "${1}" = "-rt" ]; then + mkecho -n "${_encCode}$(get_epoch)" + else + mkecho -n "${_encCode}" + fi + + # Call openssl with our required digest and auth + openssl enc -aes-256-cbc -md "${_encMode}" -k "${PASSPHRASE}" -nosalt + + unset _opensslVer _encMode _encCode +} + +read_ipmi_sensors() { + for _class in Temperature Power_Unit Fan; do + ipmi-sensors "${1:?No format given}" \ + --sdr-cache-directory /var/cache "${2:?No group opt given}" "${_class}" | + sed -e 's/ /_/g' -e 's/:_\\?/ /g' -e 's@ \\([^(]*\\)_(\\([^)]*\\))@ \\2_\\1@' + # In case of a timeout immediately leave loop. + [ $? = 255 ] && break + done + unset -v _class +} + +# Function to format the output of 'ipmitool' +read_ipmitool() { + if ! inpath ipmitool; then + return 1 + fi + case "${MK_OSSTR}" in + (linux) + ipmitool sensor list | + grep -v 'command failed' | + grep -E -v '^[^ ]+ na ' | + grep -v ' discrete ' + ;; + (*bsd) + # IPMI-Data (Fans, CPU, temperature, etc) + # needs the sysutils/ipmitool and kldload ipmi.ko + ipmitool sensor list | + grep -v 'command failed' | + sed -e 's/ *| */|/g' -e "s/ /_/g" -e 's/_*$//' -e 's/|/ /g' | + grep -Ev '^[^ ]+ na ' | + grep -v ' discrete ' + ;; + esac +} + +# We prefer the 'timeout' command shipped with 'coreutils' v7.0 and newer +# Our shipped 'waitmax' is statically linked and crashes on recent Ubuntu releases +if inpath timeout; then + waitmax() { + # The busybox version of 'timeout' requires '-t' to define the duration + # So if we're in busybox, we need to insert '-t' into '$*' + # This means that 'waitmax' invocations MUST follow a standard pattern + case "$(get_shell)" in + (*busybox*) + # This translates calls like 'waitmax -s 9 5 somecommand' + # to instead read like 'waitmax -s 9 -t 5 somecommand' + # Likewise, calls like 'waitmax 5 somecommand' + # are translated to look like 'waitmax -t 5 somecommand' + # Nb: busybox 'timeout' defaults to SIGTERM, GNU's to SIGALRM + case "${1}" in + (-s) + _signal="${2}" + shift 2 + set -- "-s ${_signal} -t ${*}" + ;; + (*) set -- "-t ${*}" ;; + esac + ;; + esac + timeout "${@}" + unset -v _signal + } + # TO-DO: Check if this export is still required + export -f waitmax +fi + +#################################################################################################### + +# Runs a command asynchronous by use of a cache file. Usage: +# run_cached [-m|-a] NAME MAXAGE COMMAND +# -m mrpe-mode: stores exit code with the cache +# -ma mrpe-mode with age: stores exit code with the cache and adds the cache age +# NAME is the name of the section (also used as cache file name) +# MAXAGE is the maximum cache livetime in seconds +# A section header is automatically generated based on NAME and MAXAGE +run_cached() { + # Use _var notation to denote local scope + _cached_section= + _cached_mrpe=0 + _cached_append_age=0 + + while getopts ":ma" _cached_arg; do + case "${_cached_arg}" in + (m) _cached_mrpe=1 ;; + (a) _cached_append_age=1 ;; + (*) : ;; + esac + done + shift "$((OPTIND-1))" + + _cached_name="${1}" + _cached_maxage="${2}" + _cached_section="mkecho '<<<${_cached_name}:cached($(get_epoch),${_cached_maxage})>>>' ; " + shift 2 + _cached_cmd="${_cached_section}${*}" + + # If the cache directory does not exist, create it + [ ! -d "${MK_VARDIR}/cache" ]; mkdir -p "${MK_VARDIR}/cache" + + if [ "${_cached_mrpe}" = 1 ]; then + _cached_file="${MK_VARDIR}/cache/_mrpe_${_cached_name}.cache" + else + _cached_file="${MK_VARDIR}/cache/${_cached_name}.cache" + fi + + # Check if the creation of the cache takes suspiciously long and kill the + # process if the age (access time) of $_cached_file.new is twice the _cached_maxage. + # Output the evantually already cached section anyways and start the cache + # update again. + if [ -e "${_cached_file}".new ]; then + _cf_atime=$(get_file_atime "${_cached_file}".new) + if [ $(( $(get_epoch) - _cf_atime )) -ge $(( _cached_maxage * 2)) ]; then + # Kill the process still accessing that file in case + # it is still running. This avoids overlapping processes! + fuser -k -9 "${_cached_file}".new >/dev/null 2>&1 + rm -f "${_cached_file}".new + fi + fi + + # Check if cache file exists and is recent enough + if [ -s "${_cached_file}" ]; then + _cf_mtime=$(get_file_mtime "${_cached_file}") + _cf_age=$(( $(get_epoch) - _cf_mtime )) + [ "${_cf_age}" -le "${_cached_maxage}" ] && _use_cachefile=1 + # Output the file in any case, even if it is + # outdated. The new file will not yet be available + if [ "${_cached_append_age}" -eq 1 ]; then + # insert the cached-string before the pipe (first -e) + # or, if no pipe found (-e t) append it (third -e), + # but only once and on the second line (2!b) (first line is section header, + # all further lines are long output) + sed -e "2s/|/ (Cached: ${_cf_age}\\/${_cached_maxage}s)|/" \ + -e t \ + -e "2s/$/ (Cached: ${_cf_age}\\/${_cached_maxage}s)/" <"${_cached_file}" + else + _cached_info="cached(${_cf_mtime},${_cached_maxage})" + case "${_cached_name}" in + (local_*) + sed -e "s/^/$_cached_info /" "${_cached_file}" + ;; + (*) + # insert the cache info in the section header (^= after '!'), + # if none is present (^= before '!') + sed -e '/^<<<.*\(:cached(\).*>>>/!s/^<<<\([^>]*\)>>>$/<<<\1:'"${_cached_info}"'>>>/' "${_cached_file}" + ;; + esac + fi + fi + + # Cache file outdated and new job not yet running? Start it + if [ -z "${_use_cachefile}" ] && [ ! -e "${_cached_file}".new ]; then + # When the command fails, the output is throws away ignored + if [ "${_cached_mrpe}" -eq 1 ]; then + mkecho "set -o noclobber ; exec > \"$_cached_file.new\" || exit 1 ; run_mrpe $_cached_name \"$_cached_cmd\" && mv \"$_cached_file.new\" \"$_cached_file\" || rm -f \"$_cached_file\" \"$_cached_file.new\"" | nohup /bin/bash >/dev/null 2>&1 & + else + mkecho "set -o noclobber ; exec > \"$_cached_file.new\" || exit 1 ; $_cached_cmd && mv \"$_cached_file.new\" \"$_cached_file\" || rm -f \"$_cached_file\" \"$_cached_file.new\"" | nohup /bin/bash >/dev/null 2>&1 & + fi + fi + unset -v _cached_section _cached_mrpe _cached_append_age _cached_name _cached_maxage _cached_cmd + unset -v _cached_file _cached_info _cf_atime _cf_mtime _cf_age _use_cachefile +} + +# Make run_cached available for subshells (plugins, local checks, etc.) +# TO-DO: Check if this export is still required +export -f run_cached + +#################################################################################################### +# Define a helper function to send real time check data +# If we're using ksh93 or bash, then we should have /dev/tcp and /dev/udp capability built in +# This isn't always the case, however, as these shells can be compiled without it +# So we test directly for this capability and if it's not working, we use 'netcat' +case $(waitmax 1 bash -c ": &1") in + (""|*"Connection refused"*) + send_rtc() { + # RTC_PORT is defined in "${MK_CONFDIR}/real_time_checks.cfg + waitmax 4 "/dev/udp/${1:?No Host Defined}/${2:?No Port Defined}" < /dev/stdin + } + ;; + (*) + # Otherwise, we try netcat under either its 'nc' or its 'netcat' monikers + # TO-DO: Add alternatives like socat? + if inpath nc netcat; then + send_rtc() { + _bin_nc=$(command -v nc netcat 2>/dev/null | head -n 1) + "${_bin_nc}" "${1:?No Host Defined}" "${2:?No Port Defined}" + unset -v _bin_nc + } + else + mkecho "send_rtc(): Unable to determine communication method" >&2 + fi + ;; +esac + +# Implements Real-Time Check feature of the Check_MK agent which can send +# some section data in 1 second resolution. Useful for fast notifications and +# detailed graphing (if you configure your RRDs to this resolution). +run_real_time_checks() { + _rt_pid=${MK_VARDIR:?}/real_time_checks.pid + mkecho "$$" >"${_rt_pid}" + + while true; do + # terminate when pidfile is gone or other Real-Time Check process started or configured timeout + if [ ! -e "${_rt_pid}" ] || [ "$(cat "${_rt_pid}")" -ne $$ ] || [ "${RTC_TIMEOUT}" -eq 0 ]; then + exit 1 + fi + + for _rt_section in ${RTC_SECTIONS}; do + # Be aware of maximum packet size. Maybe we need to check the size of the section + # output and do some kind of nicer error handling. + # 2 bytes: protocol version, 10 bytes: timestamp, rest: encrypted data + # dd is used to concatenate the output of all commands to a single write/block => udp packet + # TO-DO: See if this use of dd can be made portable. 'iflag' is a gnuism. + { + if [ "${ENCRYPTED_RT}" != "no" ]; then + # protect_output() takes care of printing our protocol and epoch info + section_"${_rt_section}" | protect_output -rt + else + mkecho -n "99$(get_epoch)" + section_"${_rt_section}" + fi + } | dd bs=9999 iflag=fullblock 2>/dev/null | send_rtc "${MK_RTC_HOST}" "${RTC_PORT}" + done + + # Plugins + if cd "${MK_PLUGINSDIR}"; then + for _rt_plugin in ${RTC_PLUGINS}; do + # If the plugin doesn't exist, skip to the next one in the list + [ ! -f "${_rt_plugin}" ] && continue + # Same comment as per section handling above applies here + { + if [ "${ENCRYPTED_RT}" != "no" ]; then + ./"${_rt_plugin}" | protect_output -rt + else + mkecho -n "99$(get_epoch)" + ./"${_rt_plugin}" + fi + } | dd bs=9999 iflag=fullblock 2>/dev/null | send_rtc "${MK_RTC_HOST}" "${RTC_PORT}" + done + fi + + sleep 1 + RTC_TIMEOUT=$((RTC_TIMEOUT - 1)) + done + + unset -v _rt_pid _rt_section _rt_plugin +} + +#################################################################################################### +# CHECK SECTIONS + +# TO-DO: Determine if any of these can be merged into other functions +section_aix() { + if inpath lparstat; then + mkecho '<<>>' + lparstat 1 1 + fi + + # powerHA + if inpath lslpp; then + _cluster_cmd_output=$(lslpp -l cluster.es.server.rte) + if ! mkecho "${_cluster_cmd_output}" | grepq "not installed"; then + # now the following commands should be available + _nodes=$(cllsnode | grep "NODE" | sed -e s/NODE//g -e s/://g) + _list_active_nodes="" + for _node in ${_nodes}; do + _active_nodes=$(clgetactivenodes -n "${_node}") + if mkecho "${_active_nodes}" | grepq "${_node}"; then + _list_active_nodes=${_list_active_nodes}"\\n${_node}" + fi + done + + if [ "${_list_active_nodes}" ]; then + mkecho '<<>>' + # shellcheck disable=SC2039 + mkecho -e "${_list_active_nodes}" + cllsnode + fi + + mkecho '<<>>' + if inpath clshowsrv ; then + waitmax 5 clshowsrv -v + else # fallback, hardcoded base installation path + waitmax 5 /usr/es/sbin/cluster/utilities/clshowsrv -v + fi + + mkecho '<<>>' + waitmax 5 clRGinfo -s + + unset -v _cluster_cmd_output _nodes _list_active_nodes _node _active_nodes + fi + fi + + mkecho '<<>>' + mpstat -a | tail -n1 + + mkecho '<<>>' + # -L disables LVM lock for the query. Avoids blocking while LVM is + # doing changes. For rootvg that is fine. + lsvg -L -l rootvg +} + +section_cpu() { + case "${MK_OSSTR}" in + (aix) + # CPU output of Linux agent simulated (thanks to Cameron Pierce) + mkecho '<<>>' + _load=$(uptime|sed -e 's;.*average: \([[:digit:]]\{1,\}\.[[:digit:]]\{1,\}\), \([[:digit:]]\{1,\}\.[[:digit:]]\{1,\}\), \([[:digit:]]\{1,\}\.[[:digit:]]\{1,\}\);\1 \2 \3;') + _ps=$(ps -eo thcount | awk '{SUM+=$1} END {print SUM}') + _procs=$(vmstat|grep lcpu|sed -e 's;.*lcpu=\([[:digit:]]\{1,4\}\).*;\1;') + mkecho "${_load} 1/${_ps} $$ ${_procs}" + unset -v _load _ps _procs + ;; + (freebsd) + mkecho '<<>>' + sysctl -n vm.loadavg | tr -d '{}' + top -b -n 1 | grep -E '^[0-9]+ processes' | awk '{print $3"/"$1}' + sysctl -n kern.lastpid + sysctl -n hw.ncpu + ;; + (hpux) + mkecho '<<>>' + uptime + # machinfo is unsupported addon thus not in $PATH + /usr/contrib/bin/machinfo | grep -E 'logical proc|core' | tail -1 + ;; + (linux) + if [ "$(uname -m)" = "armv7l" ]; then + _cpu_regex='^processor' + else + _cpu_regex='^CPU|^processor' + fi + _num_cpus=$(grep -c -E ${_cpu_regex} >>' + mkecho "$(cat /proc/loadavg) $_num_cpus" + if [ -f "/proc/sys/kernel/threads-max" ]; then + cat /proc/sys/kernel/threads-max + fi + else + if [ -n "${MK_IS_DOCKERIZED}" ]; then + mkecho '<<>>' + else + mkecho '<<>>' + fi + grep "^cpu " /proc/stat + mkecho "num_cpus ${_num_cpus}" + cat /sys/fs/cgroup/cpuacct/cpuacct.stat + fi + unset -v _cpu_regex _num_cpu + ;; + (mac) + mkecho '<<>>' + sysctl -n vm.loadavg | tr -d '{}' + top -l 1 -n 1 | grep -E '^Processes:' | awk '{$4"/"$2;}' + mkecho 'mkecho $$' | bash + sysctl -n hw.ncpu + ;; + (netbsd|openbsd) + mkecho '<<>>' + sysctl -n vm.loadavg | tr -d '{}' + top -b -n 1 | grep -E '^[0-9]+ processes' | awk '{print $3"/"$1}' + sysctl -n hw.ncpu + ;; + (solaris) + # Simulated Output of Linux /proc/cpu + mkecho '<<>>' + _load=$(uptime|sed -e 's;.*average: \([0-9]\{1,\}\.[0-9]\{1,\}\), \([0-9]\{1,\}\.[0-9]\{1,\}\), \([0-9]\{1,\}\.[0-9]\{1,\}\).*;\1 \2 \3;') + _nthreads=$(($(ps -AL | wc -l))) + _procs=$(($(psrinfo | wc -l))) + mkecho "${_load} 1/${_nthreads} $$ ${_procs}" + unset -v _load _nthreads _procs + ;; + esac +} + +# Print out Partitions / Filesystems. (-P gives non-wrapped POSIXed output) +# Heads up: NFS-mounts are generally supressed to avoid agent hangs. +# If hard NFS mounts are configured or you have too large nfs retry/timeout +# settings, accessing those mounts from the agent would leave you with +# thousands of agent processes and, ultimately, a dead monitored system. +# These should generally be monitored on the NFS server, not on the clients. +section_df() { + case "${MK_OSSTR}" in + (aix) + if [ -x /usr/opt/freeware/bin/df ] ; then + _df_excludefs="-x smbfs -x cifs -x iso9660 -x udf -x nfsv4 -x nfs -x mvfs -x zfs -x cdrfs" + # All instances of _df_excludefs in this function + # are uncommented because we want word-splitting + # shellcheck disable=SC2086 + /usr/opt/freeware/bin/df -PTlk ${_df_excludefs} | sed 1d + + # df inodes information + mkecho '<<>>' + mkecho '[df_inodes_start]' + # shellcheck disable=SC2086 + /usr/opt/freeware/bin/df -PTli ${_df_excludefs} | sed 1d + mkecho '[df_inodes_end]' + else + df -kP | sed 's/ / - /' | grep -v ^/proc | grep -v ^Filesystem | grep -v : + fi + unset -v _df_excludefs + ;; + (freebsd) + mkecho '<<>>' + # no special zfs handling so far, the ZFS.pools plugin has been tested to + # work on FreeBSD + if df -T > /dev/null ; then + df -kTP -t ufs | + grep -Ev '(Filesystem|devfs|procfs|fdescfs|basejail)' + else + df -kP -t ufs | + grep -Ev '(Filesystem|devfs|procfs|fdescfs|basejail)' | + awk '{ print $1,"ufs",$2,$3,$4,$5,$6 }' + fi + ;; + (hpux) + # Filesystems. HP-UX does not provide a filesystem type. We assume + # modern systems with vxfs only here. The filesystem type is currently + # not used by the check anyway. + mkecho '<<>>' + df -kP | + sed 's/ / - /' | + awk '/^(.*-.*)$/ { print $0 } /^([^-]+)$/ { printf $0 }' | + grep -Ev "^/proc|^Filesystem|^/aha|:" + ;; + (linux) + if [ -n "${MK_IS_DOCKERIZED}" ]; then + return + fi + + # The exclusion list is getting a bit of a problem. + # -l should hide any remote FS but seems to be all but working. + _df_excludefs="-x smbfs -x cifs -x iso9660 -x udf -x nfsv4 -x nfs -x mvfs -x prl_fs -x squashfs -x devtmpfs" + if [ -z "${MK_IS_LXC_CONTAINER}" ]; then + _df_excludefs="${_df_excludefs} -x zfs" + fi + + mkecho '<<>>' + # shellcheck disable=SC2086 + df -PTlk ${_df_excludefs} | sed 1d + + # df inodes information + mkecho '<<>>' + mkecho '[df_inodes_start]' + # shellcheck disable=SC2086 + df -PTli ${_df_excludefs} | sed 1d + mkecho '[df_inodes_end]' + + unset -v _df_excludefs + ;; + (mac) + mkecho '<<>>' + df -kPT hfs,apfs | sed 1d | \ + while read -r _df_dev _df_rest; do + _df_type=$(diskutil info "${_df_dev}" | grep '^\s*Type' | cut -d: -f2 | tr -d '[:space:]') + mkecho "${_df_dev} ${_df_type} ${_df_rest}" + done + unset -v df_dev df_type df_rest + ;; + (netbsd|openbsd) + mkecho '<<>>' + df -kPt ffs | sed -e 's/^\([^ ][^ ]*\) \(.*\)$/\1 ffs \2/' | sed 1d + ;; + (solaris) + # Filesystem usage for UFS and VXFS + mkecho '<<>>' + for _fs in ufs vxfs samfs lofs tmpfs; do + df -l -k -F ${_fs} 2>/dev/null | sed 1d | grep -v "^[^ ]*/lib/[^ ]*\\.so\\.1 " | \ + while read -r _Filesystem _kbytes _used _avail _capacity _Mountedon; do + _kbytes=$((_used + _avail)) + mkecho "${_Filesystem} ${_fs} ${_kbytes} ${_used} ${_avail} ${_capacity} ${_Mountedon}" + done + done + unset -v _fs _Filesystem _kbytes _used _avail _capacity _Mountedon + ;; + + esac +} + +section_diskstat() { + # Performancecounter Platten + if [ -z "${MK_IS_DOCKERIZED}" ]&&[ -r "/proc/diskstats" ]; then + mkecho '<<>>' + get_epoch + _grepFilter=" (x?[shv]d[a-z]*[0-9]*|cciss/c[0-9]+d[0-9]+|emcpower[a-z]+|dm-[0-9]+" + _grepFilter="${_grepFilter}|VxVM.*|mmcblk.*|dasd[a-z]*|bcache[0-9]+|nvme[0-9]+n[0-9]+) " + grep -E "${_grepFilter}" >>' + mkecho "[time]" + get_epoch + for _ioFile in io_service_bytes io_serviced; do + mkecho "[${_ioFile}]" + cat "/sys/fs/cgroup/blkio/blkio.throttle.${_ioFile}" + done + mkecho "[names]" + for _ioFile in /sys/block/*; do + # shellcheck disable=SC2039 + mkecho "${_ioFile##*/} $(cat "${_ioFile}/dev")" + done + unset -v _ioFile + fi +} + +section_drbd() { + if [ -z "${MK_IS_DOCKERIZED}" ] && [ -z "${MK_IS_LXC_CONTAINER}" ] && [ -r /proc/drbd ]; then + mkecho '<<>>' + cat /proc/drbd + fi +} + +section_fileinfo() { + # Fileinfo-Check: put patterns for files into /etc/check_mk/fileinfo.cfg + perl -e ' + my @patterns = (); + foreach (bsd_glob("$ARGV[0]/fileinfo.cfg"), bsd_glob("$ARGV[0]/fileinfo.d/*")) { + open my $handle, "<", $_ or next; + while (<$handle>) { + chomp; + next if /^\s*(#|$)/; + my $pattern = $_; + $pattern =~ s/\$DATE:(.*?)\$/substr(`date +"$1"`, 0, -1)/eg; + push @patterns, $pattern; + } + warn "error while reading $_: $!\n" if $!; + close $handle; + } + exit if ! @patterns; + + print "<<>>\n", time, "\n[[[header]]]\nname|status|size|time\n[[[content]]]\n"; + + foreach (@patterns) { + foreach (bsd_glob("$_")) { + if (! -f) { + print "$_|missing\n" if ! -d; + } elsif (my @infos = stat) { + print "$_|ok|$infos[7]|$infos[9]\n"; + } else { + print "$_|stat failed: $!\n"; + } + } + } + ' -- "${MK_CONFDIR}" +} + +section_haproxy() { + for HAPROXY_SOCK in /run/haproxy/admin.sock /var/lib/haproxy/stats; do + if [ -r "$HAPROXY_SOCK" ] && inpath socat; then + mkecho "<<>>" + mkecho "show stat" | socat - "UNIX-CONNECT:$HAPROXY_SOCK" + fi + done +} + +# Function to output the basic details of the check_mk agent's operating conditions +section_head() { +cat << EOF +"<<>>" +"Version: ${MK_VERSION}" +"AgentOS: ${MK_OSSTR}" +"Hostname: ${HOSTNAME}" +"AgentDirectory: ${MK_CONFDIR}" +"DataDirectory: ${MK_VARDIR}" +"SpoolDirectory: ${MK_SPOOLDIR}" +"PluginsDirectory: ${MK_PLUGINSDIR}" +"LocalDirectory: ${MK_LOCALDIR}" +EOF +} + +section_heartbeat() { + # Heartbeat monitoring + # Different handling for heartbeat clusters with and without CRM + # for the resource state + if [ -S /var/run/heartbeat/crm/cib_ro ] || [ -S /var/run/crm/cib_ro ] || pgrep crmd >/dev/null 2>&1; then + mkecho '<<>>' + TZ=UTC crm_mon -1 -r | grep -v ^$ | sed 's/^ //; /^\sResource Group:/,$ s/^\s//; s/^\s/_/g' + fi + if inpath cl_status; then + mkecho '<<>>' + cl_status rscstatus + + mkecho '<<>>' + for _node in $(cl_status listnodes); do + if [ "${_node}" != "$(mkecho "${HOSTNAME}" | tr '[:upper:]' '[:lower:]')" ]; then + _status=$(cl_status nodestatus "${_node}") + # shellcheck disable=SC2039 + mkecho -n "${_node} ${_status}" + for _link in $(cl_status listhblinks "${_node}" 2>/dev/null); do + # shellcheck disable=SC2039 + mkecho -n " ${_link} $(cl_status hblinkstatus "${_node}" "${_link}")" + done + mkecho + fi + done + unset -v _node _status _link + fi +} + +section_hpux() { + # Logical Volume Manager + mkecho '<<>>' + /sbin/vgdisplay -v -F + + mkecho '<<>>' + if inpath cmviewcl; then + cmviewcl -v -f line | grep summary + fi + + # Kernel tunnables + if inpath kcusage; then + mkecho '<<>>' + kcusage -l + fi + + # State of FC HBAs + mkecho '<<>>' + for _hba in /dev/fcd*; do + mkecho "${_hba}" + /opt/fcms/bin/fcdutil "${_hba}" | + grep -e "Driver state" \ + -e "Topology" \ + -e "Dump Available" \ + -e "Code version" \ + -e "Hardware Path" \ + -e "Port World" + done + unset -v _hba +} + +section_iostat() { + # Skip if 'section_diskstat()' has this already covered + if [ -r /proc/diskstats ] || [ "${MK_IS_DOCKERIZED}" ]; then + return 0 + fi + # Skip if 'iostat' isn't present + if ! inpath iostat; then + return 0 + fi + + _grepFilter="^(x?[shv]d[a-z]*[0-9]*|cciss/c[0-9]+d[0-9]+|emcpower[a-z]+|dm-[0-9]+|VxVM.*" + _grepFilter="${_grepFilter}|mmcblk.*|dasd[a-z]*|bcache[0-9]+|nvme[0-9]+n[0-9]+|hdisk) " + + mkecho "<<<${MK_OSSTR}_iostat>>>" + + # AIX was formerly under the header '<<>>' + # TO-DO: Update checkman/aix_diskiod, checks/aix_diskiod etc + # OpenBSD has a different output format, so we ringfence it for now + # FreeBSD - we might like to consider 'gstat' and/or 'dtrace' as well + case "${MK_OSSTR}" in + (openbsd) + iostat "${_iostatOpts:--d}" 2 1 + ;; + (*) + iostat "${_iostatOpts:--d}" 2 1 | tr -s ' ' | grep -E "${_grepFilter}" + ;; + esac + + unset -v _iostatOpts _grepFilter +} + +# This function pairs with read_ipmitool() +# TO-DO: merge them somehow? +section_ipmi() { + # Hardware sensors via IPMI (need ipmitool) + if inpath ipmitool; then + # We denote our delimiter 'i.e. separator' as being at column 124 + run_cached "ipmi:sep(124)" 300 "waitmax 300 read_ipmitool" + # readable discrete sensor states + run_cached "ipmi_discrete:sep(124)" 300 "waitmax 300 ipmitool sdr elist compact" + fi + # IPMI data via ipmi-sensors (of freeipmi). Please make sure, that if you + # have installed freeipmi that IPMI is really support by your hardware. + if (inpath ipmi-sensors && ls /dev/ipmi*) >/dev/null 2>&1; then + mkecho '<<>>' + # Newer ipmi-sensors version have new output format; Legacy format can be used + if ipmi-sensors --help | grepq legacy-output; then + _ipmi_format="--legacy-output" + else + _ipmi_format="" + fi + if ipmi-sensors --help | grepq " \\-\\-groups"; then + _ipmi_group_opt="-g" + else + _ipmi_group_opt="-t" + fi + + # At least with ipmi-sensors 0.7.16 this group is Power_Unit instead of "Power Unit" + run_cached ipmi_sensors 300 "read_ipmi_sensors ${_ipmi_format} ${_ipmi_group_opt}" + unset -v _ipmi_format _ipmi_group_opt + fi +} + +section_jobs() { + # Get statistics about monitored jobs. Below the job directory there + # is a sub directory per user that ran a job. That directory must be + # owned by the user so that a symlink or hardlink attack for reading + # arbitrary files can be avoided. + if [ "${MK_OSSTR}" = "linux" ]; then + ( + cd "${MK_VARDIR}/job" || return + mkecho '<<>>' + for _username in *; do + if [ -d "${_username}" ] && cd "${_username}"; then + if [ "${EUID}" -eq 0 ]; then + su -s "${SHELL}" "${_username}" -c "head -n -0 -v *" + else + head -n -0 -v ./* + fi + cd .. + fi + done + ) + elif [ "${MK_OSSTR}" = "solaris" ]; then + ( + cd "${MK_VARDIR}/job" || return + mkecho '<<>>' + for _username in *; do + if [ -d "${_username}" ] && cd "${_username}" ; then + _count=$(su -s "${SHELL}" "${_username}" -c "ls -1 * | wc -l") + + if [ "${_count}" -eq "1" ]; then + _filename=$(su -s "${SHELL}" "${_username}" -c "ls -1 *") + mkecho "==> ${_filename} <==" + fi + + su -s "${SHELL}" "${_username}" -c "head -n1000 *" + cd .. + fi + done + ) + fi + unset -v _username _filename _count +} + +section_kernel() { + case "${MK_OSSTR}" in + (freebsd) + # Performancecounter Kernel + mkecho "<<>>" + get_epoch + _forks=$(sysctl -n vm.stats.vm.v_forks) + _vforks=$(sysctl -n vm.stats.vm.v_vforks) + _rforks=$(sysctl -n vm.stats.vm.v_rforks) + _kthreads=$(sysctl -n vm.stats.vm.v_kthreads) + mkecho "cpu" "$(sysctl -n kern.cp_time | awk ' { print $1" "$2" "$3" "$5" "$4 } ')" + mkecho "ctxt" "$(sysctl -n vm.stats.sys.v_swtch)" + # TO-DO: confirm that these are all ints and if so, convert to $(()) + # shellcheck disable=SC2003 + mkecho "processes" "$(expr "${_forks}" + "${_vforks}" + "${_rforks}" + "${_kthreads}")" + unset -v _forks _vforks _rforks _kthreads + ;; + (linux) + # Performancecounter Kernel + if [ -z "${MK_IS_DOCKERIZED}" ] && [ -z "${MK_IS_LXC_CONTAINER}" ]; then + mkecho '<<>>' + get_epoch + cat /proc/vmstat /proc/stat + fi + ;; + esac +} + +section_local() { + # Local checks + mkecho '<<>>' + # Contain the 'cd' within a subshell so that we return + # where we came from once the subshell closes + ( + if cd "${MK_LOCALDIR}" 2>/dev/null; then + for _skript in ./*; do + if is_valid_plugin "${_skript}"; then + ./"${_skript}" + fi + done + # Call some plugins only every X'th second + for _skript in [1-9]*/*; do + if is_valid_plugin "${_skript}"; then + _skript_cache=$(mkecho "${_skript}" | sed 's/\//\\/') + run_cached "local_${_skript_cache}" "${_skript%/*}" "${_skript}" + fi + done + unset -v _skript _skript_cache + fi + ) +} + +section_mac() { + # OSX Timemachine + if inpath tmutil; then + mkecho '<<>>' + tmutil latestbackup 2>&1 + fi +} + +#TO-DO: De-duplicate this mess +section_mail() { + # Postfix mailqueue monitoring + # Determine the number of mails and their size in several postfix mail queues + read_postfix_queue_dirs() { + _postfix_queue_dir="${1}" + if [ -n "${_postfix_queue_dir}" ]; then + mkecho '<<>>' + if [ -n "${2}" ]; then + mkecho "[[[${2}]]]" + fi + for _queue in deferred active; do + _count=$(find "${_postfix_queue_dir}/${_queue}" -type f | wc -l) + _size=$(du -s "${_postfix_queue_dir}/${_queue}" | awk '{print $1 }') + if [ -z "${_count}" ]; then + mkecho "Mail queue is empty" + else + mkecho "QUEUE_${_queue} ${_size:-0} ${_count}" + fi + done + fi + unset -v _postfix_queue_dir _queue _count _size + } + + # Postfix mailqueue monitoring + # Determine the number of mails and their size in several postfix mail queues + if inpath postconf; then + case "${MK_OSSTR}" in + (freebsd) + # Only handle mailq when postfix user is present. The mailq command is also + # available when postfix is not installed. But it produces different outputs + # which are not handled by the check at the moment. So try to filter out the + # systems not using postfix by searching for the postfix user. + # + # Cannot take the whole outout. This could produce several MB of agent output + # on blocking queues. + # Only handle the last 6 lines (includes the summary line at the bottom and + # the last message in the queue. The last message is not used at the moment + # but it could be used to get the timestamp of the last message. + mkecho '<<>>' + postfix_queue_dir=$(postconf -h queue_directory) + postfix_count=$(find "$postfix_queue_dir"/deferred -type f | wc -l) + postfix_size=$(du -ks "$postfix_queue_dir"/deferred | awk '{print $1 }') + if [ "$postfix_count" -gt 0 ]; then + mkecho "$postfix_size" Kbytes in "$postfix_count" Requests. + else + mkecho Mail queue is empty + fi + ;; + (linux) + # Check if multi_instance_directories exists in main.cf and is not empty + # always takes the last entry, multiple entries possible + multi_instances_dirs=$(postconf -c /etc/postfix 2>/dev/null | grep ^multi_instance_directories | sed 's/.*=[[:space:]]*//g') + if [ -n "$multi_instances_dirs" ]; then + for queue_dir in $multi_instances_dirs; do + if [ -n "$queue_dir" ]; then + postfix_queue_dir=$(postconf -c "$queue_dir" 2>/dev/null | grep ^queue_directory | sed 's/.*=[[:space:]]*//g') + read_postfix_queue_dirs "$postfix_queue_dir" "$queue_dir" + fi + done + + else + postfix_queue_dir=$(postconf -h queue_directory 2>/dev/null) + read_postfix_queue_dirs "$postfix_queue_dir" + fi + ;; + esac + + elif [ -x /usr/sbin/ssmtp ]; then + mkecho '<<>>' + mailq 2>&1 | sed 's/^[^:]*: \(.*\)/\1/' | tail -n 6 + + # *bsd but should be a reasonable generic fallback + elif inpath mailq && getent passwd postfix >/dev/null 2>&1; then + mkecho '<<>>' + mailq | tail -n 6 + fi + + # From AIX, seems generic enough + if [ -x /usr/sbin/sendmail ] ; then + mkecho '<<>>'; + mailq 2>&1 | tail -n 6 + fi + + # Postfix status monitoring. Can handle multiple instances. + if inpath postfix; then + mkecho "<<>>" + for i in /var/spool/postfix*/; do + if [ -e "$i/pid/master.pid" ]; then + if [ -r "$i/pid/master.pid" ]; then + postfix_pid=$(sed 's/ //g' <"$i/pid/master.pid") # handle possible spaces in output + if readlink -- "/proc/${postfix_pid}/exe" | grepq ".*postfix/\\(s\\?bin/\\)\\?master.*"; then + mkecho "$i:the Postfix mail system is running:PID:$postfix_pid" | sed 's/\/var\/spool\///g' + else + mkecho "$i:PID file exists but instance is not running!" | sed 's/\/var\/spool\///g' + fi + else + mkecho "$i:PID file exists but is not readable" + fi + else + mkecho "$i:the Postfix mail system is not running" | sed 's/\/var\/spool\///g' + fi + done + fi + + # Check status of qmail mailqueue + if inpath qmail-qstat; then + mkecho "<<>>" + qmail-qstat + fi + + # Nullmailer queue monitoring + if inpath nullmailer-send && [ -d /var/spool/nullmailer/queue ]; then + mkecho '<<>>' + COUNT=$(find /var/spool/nullmailer/queue -type f | wc -l) + SIZE=$(du -s /var/spool/nullmailer/queue | awk '{print $1 }') + mkecho "$SIZE $COUNT" + fi +} + +# TO-DO: Standardise section headers +# We ignore the shellcheck alerts for 'mkecho -n' as our 'mkecho()' solves this +# shellcheck disable=SC2039 +section_mem() { + case "${MK_OSSTR}" in + (aix) + mkecho '<<>>' + vmstat -v | tr -s ' ' + swap -s + # TO-DO: Possible candidates? + # lsattr -El sys0 -a realmem + # lsps -s + # lsps -a + ;; + (hpux) + mkecho '<<>>' + machinfo | grep ^Memory + vmstat | sed -n 3p + + ;; + (linux) + if [ -z "${MK_IS_DOCKERIZED}" ]; then + mkecho '<<>>' + grep -E -v '^Swap:|^Mem:|total:' >>' + cat /sys/fs/cgroup/memory/memory.stat + mkecho "usage_in_bytes $(cat /sys/fs/cgroup/memory/memory.usage_in_bytes)" + mkecho "limit_in_bytes $(cat /sys/fs/cgroup/memory/memory.limit_in_bytes)" + grep -F 'MemTotal:' /proc/meminfo + fi + ;; + (mac) + _memFreeSpec=$(vm_stat | grep speculative: | awk '{print $3}') + _memFreeInactive=$(vm_stat | grep inactive: | awk '{print $3}') + _memFree=$(vm_stat | grep free: | awk '{print $3}') + _memFreeMach=$(vm_stat | grep Mach | awk '{print $8}') + mkecho '<<>>' + mkecho "MemTotal: $(mkecho "$(sysctl -n hw.memsize)/1024" | bc) kB" + mkecho "MemFree: $(mkecho "( ${_memFreeSpec} + ${_memFreeInactive} + ${_memFree} ) * ${_memFreeMach} / 1024" | bc) kB" + mkecho "SwapTotal: 0 kB" + mkecho "SwapFree: 0 kB" + # FIXME: Just call vm_stat here, write a check plugin that uses that + # native output of vm_stat + ;; + (openbsd) + mkecho "<<>>" + MEM_FREE=$(vmstat | tail -n1 | awk '{ print $5 }') + MEM_TOTAL=$(sysctl hw.usermem | cut -d= -f2) + MEM_TOTAL=$(mkecho "$MEM_TOTAL/1024" | bc) + + SWAPCTL_OUTPUT=$(swapctl -k -s) + SWAP_FREE=$(mkecho "$SWAPCTL_OUTPUT" | awk '{ print $7 }') + SWAP_TOTAL=$(mkecho "$SWAPCTL_OUTPUT" | awk '{ print $2 }') + + # if there is no swap space swap values are 0 + if [ -z "$SWAPCTL_OUTPUT" ]; then + SWAP_FREE=0 + SWAP_TOTAL=0 + fi + + mkecho -e "MemTotal:\\t$MEM_TOTAL kB" + mkecho -e "MemFree:\\t$MEM_FREE kB" + mkecho -e "SwapTotal:\\t$SWAP_TOTAL kB" + mkecho -e "SwapFree:\\t$SWAP_FREE kB" + ;; + (solaris) + # We prefer to use 'statgrab' if it's available. See section_statgrab() + # If 'statgrab' isn't available, we offer this workaround + if ! inpath statgrab; then + if [ -x /usr/bin/top ] || [ -x /usr/local/bin/top ]; then + mkecho "<<>>" + if [ -x /usr/bin/top ]; then /usr/bin/top | grep '^Memory:'; fi + if [ -x /usr/local/bin/top ]; then /usr/local/bin/top | grep '^Memory:'; fi + fi + fi + ;; + esac +} + +section_mkbackup() { + # Collect states of configured Check_MK site backup jobs + if ls /omd/sites/*/var/check_mk/backup/*.state >/dev/null 2>&1; then + mkecho "<<>>" + for _state_file in /omd/sites/*/var/check_mk/backup/*.state; do + _omd_site=${_state_file#/*/*/*} + _omd_site=${_omd_site%%/*} + + _job_ident=${F%.state} + _job_ident=${_job_ident##*/} + + if [ "${_job_ident}" != "restore" ]; then + mkecho "[[[site:${_omd_site}:${_job_ident}]]]" + cat "${_state_file}" + mkecho + fi + done + unset -v _state_file _omd_site _job_ident + fi + + # Collect states of configured CMA backup jobs + if inpath mkbackup && ls /var/lib/mkbackup/*.state >/dev/null 2>&1; then + mkecho "<<>>" + for _state_file in /var/lib/mkbackup/*.state; do + _job_ident=${_state_file%.state} + _job_ident=${_job_ident##*/} + + if [ "${_job_ident}" != "restore" ]; then + mkecho "[[[system:${_job_ident}]]]" + cat "$F" + mkecho + fi + done + unset -v _state_file _job_ident + fi +} + +section_mounts() { + case "${MK_OSSTR}" in + (freebsd) + # Check mount options. + # FreeBSD doesn't do remount-ro on errors, but the users might consider + # security related mount options more important. + mkecho '<<>>' + mount -p -t ufs + ;; + (linux) + # Check mount options. Filesystems may switch to 'ro' in case + # of a read error. + mkecho '<<>>' + grep ^/dev >>' + + _mrpe_plugin=${_mrpe_cmdline%% *} + _mrpe_output=$(eval "${_mrpe_cmdline}") + + # We ignore the shellcheck alerts for 'mkecho -n' as our 'mkecho()' solves this + # shellcheck disable=SC2039 + mkecho -n "(${_mrpe_plugin##*/}) ${_mrpe_descr} ${?} ${_mrpe_output}" | tr \\n \\1 + mkecho + + # Unset the function variables + unset -v _mrpe_descr _mrpe_cmdline _mrpe_plugin _mrpe_output +} + +section_mrpe() { + + # MK's Remote Plugin Executor + # We handle mrpe.cfg format that looks like this for synchronous running: + # SERVICE_NAME /path/to/the/plugin/script -warn 10 -crit 20 + # Or this for asynchronous running: + # SERVICE_NAME (interval=360:appendage=1) /path/to/the/plugin/script -warn 10 -crit 20 + if [ -r "${MK_CONFDIR}/mrpe.cfg" ]; then + grep -Ev '^[[:space:]]*($|#)' "${MK_CONFDIR}/mrpe.cfg" | + while read -r _mrpe_descr _mrpe_cmdline; do + # Detect if _mrpe_cmdline starts with '(' i.e. async mode + case "${_mrpe_cmdline}" in + (\(*) + # If we do start with '(', then split 'params' out of '_mrpe_cmdline' + # We strip the brackets from 'params' and rewrite '_mrpe_cmdline' without the params + _mrpe_params=$(mkecho "${_mrpe_cmdline% *}" | tr -d '()') + _mrpe_cmdline="${_mrpe_cmdline##* }" + + # split multiple parameter assignments + for _par in $(mkecho "${_mrpe_params}" | tr ":" "\\n"); do + # split each assignment + _key="${_par%=*}" + _value="${_par#*=}" + # Setting 'args' here upsets shellcheck because we're within a while pipeline + # This should be fine: if we use it, it's immediately so + # shellcheck disable=SC2030 + case "${_key}" in + (interval) _interval="${_value}" ;; + (appendage) _args="-ma" ;; + esac + done + run_cached "${_args:--m}" "${_mrpe_descr}" "${_interval:-}" "${_mrpe_cmdline}" + ;; + (*) + run_mrpe "${_mrpe_descr}" "${_mrpe_cmdline}" + ;; + esac + done + unset -v _mrpe_descr _mrpe_cmdline _mrpe_params _par _key _value _interval _args + fi +} + +section_multipathing() { + case "${MK_OSSTR}" in + (aix) + # TO-DO: Consider merging in mpio_get_config, lsmpio, sanlun, + # dlnkmgr, powermt and pcmpath handling + mkecho '<<>>' + lspath -F"name parent status" + ;; + (freebsd) + # Multipathing is supported in FreeBSD by now + # http://www.mywushublog.com/2010/06/freebsd-and-multipath/ + if kldstat -v | grep g_multipath > /dev/null ; then + mkecho '<<>>' + gmultipath status | grep -v ^Name + fi + ;; + (hpux) + # Multipathing + mkecho '<<>>' + scsimgr lun_map | grep -E '^[[:space:]]*(LUN PATH|State|World Wide Identifier)' + ;; + (linux) + if inpath multipath; then + if [ -f /etc/multipath.conf ]; then + mkecho '<<>>' + multipath -l + fi + fi + ;; + (solaris) + if inpath mpathadm; then + if [ "$zonename" = "global" ]; then + mkecho '<<>>' + mpathadm list LU | + nawk '{if(NR%3==1){dev=$1} + if(NR%3==2){tc=$NF} + if(NR%3==0){printf "%s %s %s\n",dev,tc,$NF}}' + fi + fi + ;; + esac +} + +section_net() { + case "${MK_OSSTR}" in + (aix) + mkecho "<<>>" + for ent in $(ifconfig -a | grep '^en' | cut -d ":" -f 1); do + mkecho "[$ent]" + entstat "$ent" | + grep -E "(^Hardware|^Bytes:|^Packets:|^Transmit|^Broadcast:|^Multicast:)" + entstat "$ent" | grep -p "Driver Flags:" + done + ;; + (hpux) + mkecho '<<>>' + for nic in $(nwmgr -g | sed -n '/^lan/s/\(^[^ ]* \).*/\1/p'); do + nwmgr -g --st mib -c "$nic" + done + ;; + (linux) + # New variant: Information about speed and state in one section + if inpath ip; then + mkecho '<<>>' + mkecho "[start_iplink]" + ip address + mkecho "[end_iplink]" + fi + + mkecho '<<>>' + sed 1,2d /proc/net/dev + if inpath ethtool; then + sed -e 1,2d /proc/net/dev | cut -d':' -f1 | sort | while read -r eth; do + mkecho "[$eth]" + ethtool "$eth" | grep -E '(Speed|Duplex|Link detected|Auto-negotiation):' + # shellcheck disable=SC2039 + mkecho -e "\\tAddress: $(cat "/sys/class/net/$eth/address")\\n" + done + fi + + # Current state of bonding interfaces + if [ -e /proc/net/bonding ]; then + mkecho '<<>>' + ( + cd /proc/net/bonding || return + head -v -n 1000 ./* + ) + fi + + # Same for Open vSwitch bonding + if inpath ovs-appctl; then + BONDS=$(ovs-appctl bond/list) + COL=$(mkecho "$BONDS" | awk '{for(i=1;i<=NF;i++) {if($i = "bond") printf("%d", i)} exit 0}') + mkecho '<<>>' + for bond in $(mkecho "$BONDS" | sed -e 1d | cut -f"${COL}"); do + mkecho "[$bond]" + ovs-appctl bond/show "$bond" + done + fi + ;; + (openbsd) + mkecho '<<>>' + # Example line: + # em0 1500 08:00:27:e6:c4:70 16358 0 254 0 0 + netstat -in | grep '' | grep -E -v "\\*|lo|pfsync|enc" | + while read -r _ifName _ _ _ _pktsIn _errsIn _pktsOut _errsOut _collisions; do + # Make another 'netstat' call to get our extra metrics + # Example line: + # em0 1500 08:00:27:e6:c4:70 1815571 37701 + netstat -inb | grep "${_ifName}.*" | + while read -r _ _ _ _ _bytesIn _bytesOut; do + _ifData="${_ifName}:${_bytesIn} ${_pktsIn} ${_errsIn} 0 0 0 0 0 ${_bytesOut}" + _ifData="${_ifData} ${_pktsOut} ${_errsOut} 0 0 ${_collisions} 0 0" + mkecho "${_ifData}" + done + done + + unset -v _ifName _pktsIn _errsIn _pktsOut _errsOut _collisions _ifData + + for _ifName in $(netstat -in | awk '//{print $1}' | grep -E -v "\\*|lo|pfsync|enc"); do + mkecho "[${_ifName}]" + + _macAddr=$(ifconfig "${_ifName}" | awk '/lladdr/{print $NF}') + + # Example line: + # media: Ethernet autoselect (1000baseT full-duplex) + _ifData=$(ifconfig "${_ifName}" | grep "media:") + + # Speed + _ifSpeed=$(mkecho "${_ifData}" | cut -d\( -f2 | cut -db -f1) + # shellcheck disable=SC2039 + [ "${_ifSpeed}" ] && mkecho -e "\\tSpeed: ${_ifSpeed}Mb/s" + + # Detect duplexity - in reality only available for physical devices but + # virtual ones like CARP devices will get at least a half duplex + # shellcheck disable=SC2039 + case "${_ifData}" in + (*full-duplex*) mkecho -e "\\tDuplex: Full" ;; + (*half-duplex*) mkecho -e "\\tDuplex: Half" ;; + (*) mkecho -e "\\tDuplex: Unknown" ;; + esac + + # Auto-negotiation + # shellcheck disable=SC2039 + case "${_ifData}" in + (*autoselect*) mkecho -e "\\tAuto-negotiation: on" ;; + (*) mkecho -e "\\tAuto-negotiation: off" ;; + esac + + # Detect detected link + if ifconfig "${_ifName}" | grep "status:" | grepq -E "active|backup|master"; then + # shellcheck disable=SC2039 + mkecho -e "\\tLink detected: yes" + fi + # shellcheck disable=SC2039 + mkecho -e "\\tAddress: ${_macAddr}" + done + + unset -v _ifName _ifData _ifSpeed _macAddr + ;; + esac +} + +section_netctr() { + case "${MK_OSSTR}" in + (freebsd) + # Network device statistics (Packets, Collisions, etc) + # only the "Link/Num" interface has all counters. + mkecho '<<>>' + get_epoch + if [ "$(mkecho "${osver}" | cut -f1 -d\. )" -gt "8" ]; then + netstat -inb | + grep -Ev '(^Name|lo|plip)' | + grep Link | + awk '{print $1" "$8" "$5" "$6" "$7" 0 0 0 0 "$11" "$9" "$10" 0 0 0 0 0"}' + else + # pad output for freebsd 7 and before + netstat -inb | + grep -Ev '(^Name|lo|plip)' | + grep Link | + awk '{print $1" "$7" "$5" "$6" 0 0 0 0 0 "$10" "$8" "$9" 0 0 "$11" 0 0"}' + fi + ;; + (mac) + mkecho '<<>>'; + get_epoch + netstat -inb | + grep -Ev '(^Name|lo|plip)' | + grep Link | + awk '{ print $1,$7,$5,$6,"0","0","0","0","0",$10,$8,$9,"0","0",$11,"0","0"; }' + ;; + (netbsd) + mkecho '<<>>' + # BI= Bytes in + # PI= Packets in + # EI= Errors in + # EO= Errors out + # BO= Bytes out + # PO= Packets out + # CO= Colls + + Z1=1 + Z2=p + + get_epoch + while [ $Z1 -lt 15 ]; do + BI=$( netstat -inb | grep -Ev Name | grep Link | awk '{print $1" "$5}' | sed -ne $Z1$Z2 ) + PI=$( netstat -in | grep -Ev Name | grep Link | awk '{print $5}' | sed -ne $Z1$Z2 ) + EI=$( netstat -in | grep -Ev Name | grep Link | awk '{print $6}' | sed -ne $Z1$Z2 ) + FF1="0 0 0 0 0" + BO=$( netstat -inb | grep -Ev Name | grep Link | awk '{print $6}' | sed -ne $Z1$Z2 ) + PO=$( netstat -in | grep -Ev Name | grep Link | awk '{print $7}' | sed -ne $Z1$Z2 ) + EO=$( netstat -in | grep -Ev Name | grep Link | awk '{print $8}' | sed -ne $Z1$Z2 ) + CO=$( netstat -in | grep -Ev Name | grep Link | awk '{print $9}' | sed -ne $Z1$Z2 ) + FF2="0 0" + if [ "$PI" -gt "0" ]; then + mkecho "$BI $PI $EI $FF1 $BO $PO $EO $FF2 $CO $FF2" + fi + Z1=$((Z1+1)) + done + esac +} + +section_nfs() { + # Check NFS mounts by accessing them with stat -f (System call statfs()). + # If this lasts more then 2 seconds we consider it as hanging. We need waitmax. + if inpath waitmax; then + case "${MK_OSSTR}" in + (aix) statFmt="ok - - - -" ;; + (linux) statFmt="ok %b %f %a %s" ;; + esac + mkecho '<<>>' + get_nfs_mounts | while read -r mountPoint; do + waitmax -s 9 5 stat -f -c "${mountPoint} ${statFmt}" "${mountPoint}" \ + || mkecho "${mountPoint} hanging 0 0 0 0" + done + + mkecho '<<>>' + get_cifs_mounts | while read -r mountPoint; do + if [ ! -r "${mountPoint}" ]; then + mkecho "${mountPoint} Permission denied" + else + waitmax -s 9 2 stat -f -c "${mountPoint} ${statFmt}" "${mountPoint}" \ + || mkecho "${mountPoint} hanging 0 0 0 0" + fi + done + fi + + # Clean up our function variables + unset mountPoint statFmt +} + +section_ntp() { + # Time synchronization with NTP + if inpath ntpq; then + if [ "${MK_OSSTR}" = "aix" ]; then + if [ "$(lssrc -s xntpd|grep -c active)" -gt 0 ] ; then + mkecho '<<>>' + ntpq -np | sed -e 1,2d -e 's/^\(.\)/\1 /' -e 's/^ /%/' + fi + elif [ "${MK_OSSTR}" = "solaris" ]; then + # 'psgrep' does not work well in this case + # shellcheck disable=SC2009 + if ps -o comm $pszone | grep -w ".*ntpd" >/dev/null 2>&1; then + mkecho '<<>>' + ntpq -np | sed -e 1,2d -e 's/^\(.\)/\1 /' -e 's/^ /%/' + fi + # The following should cover everything else + else + # remove heading, make first column space separated + run_cached ntp 30 "waitmax 5 ntpq -np | sed -e 1,2d -e 's/^\\(.\\)/\\1 /' -e 's/^ /%/' || true" + fi + fi + + # Time synchronization with Chrony + if inpath chronyc; then + # Force successful exit code. Otherwise section will be missing if daemon not running + # + # The "| cat" has been added for some kind of regression in RedHat 7.5. The + # SELinux rules shipped with that release were denying the chronyc call + # without cat. + run_cached chrony 30 "waitmax 5 chronyc -n tracking | cat || true" + fi + + # Time synchronization with systemd timesyncd + if inpath timedatectl; then + _systemd_version=$(systemctl --version | awk '{if(NR==1) print $2}') + if [ "${_systemd_version}" -ge 239 ]; then + mkecho "<<>>" + timedatectl timesync-status + get_file_mtime /var/lib/systemd/timesync/clock | awk '{print "[[["$1"]]]"}' + fi + unset -v _systemd_version + fi +} + +section_nvidia() { + if inpath nvidia-settings && [ -S /tmp/.X11-unix/X0 ]; then + mkecho '<<>>' + for _var in GPUErrors GPUCoreTemp; do + DISPLAY=:0 waitmax 2 nvidia-settings -t -q "${_var}" | sed "s/^/${_var}: /" + done + unset -v _var + fi +} + +section_omd() { + # Check status of OMD sites and Check_MK Notification spooler + if inpath omd; then + mkecho '<<>>' + # mkecho '{"cmk/check_mk_server": "yes"}' + mkecho -j "cmk/check_mk_server" "yes" + + run_cached omd_status 60 "omd status --bare --auto || true" + mkecho '<<>>' + get_epoch + for statefile in /omd/sites/*/var/log/mknotifyd.state; do + if [ -e "$statefile" ]; then + site=${statefile%/var/log*} + site=${site#/omd/sites/} + mkecho "[$site]" + grep -v '^#' <"$statefile" + fi + done + + mkecho '<<>>' + for statsfile in /omd/sites/*/var/log/apache/stats; do + if [ -e "$statsfile" ]; then + site=${statsfile%/var/log*} + site=${site#/omd/sites/} + mkecho "[$site]" + cat "$statsfile" + : >"$statsfile" + # prevent next section to fail caused by a missing newline at the end of the statsfile + mkecho + fi + done + fi + + # Get stats about OMD monitoring cores running on this machine. + # Since cd is a shell builtin the check does not affect the performance + # on non-OMD machines. + if cd /omd/sites; then + mkecho '<<>>' + for site in *; do + if [ -S "/omd/sites/$site/tmp/run/live" ]; then + mkecho "[$site]" + # shellcheck disable=SC2039 + mkecho -e "GET status" | + waitmax 3 "/omd/sites/$site/bin/unixcat" "/omd/sites/$site/tmp/run/live" + fi + done + + mkecho '<<>>' + for site in *; do + mkecho "[$site]" + for PEM_PATH in "/omd/sites/$site/etc/ssl/ca.pem" "/omd/sites/$site/etc/ssl/sites/$site.pem"; do + if [ -f "$PEM_PATH" ]; then + CERT_DATE=$(openssl x509 -enddate -noout -in "$PEM_PATH") + # TO-DO: Confirm that this works + CERT_DATE=$(mkecho "${CERT_DATE}" | sed 's/notAfter=//g') + mkecho "$PEM_PATH|$(date --date="$CERT_DATE" --utc +%s)" + fi + done + done + + mkecho '<<>>' + for site in *; do + if [ -S "/omd/sites/$site/tmp/run/mkeventd/status" ]; then + mkecho "[\"$site\"]" + # shellcheck disable=SC2039 + mkecho -e "GET status\\nOutputFormat: json" | + waitmax 3 "/omd/sites/$site/bin/unixcat" "/omd/sites/$site/tmp/run/mkeventd/status" + fi + done + fi +} + +section_openvpn() { + # OpenVPN Clients. These are our two known log locations. + # The 'sed' invocation may need to be tested on non-linux + if [ -e /etc/openvpn/openvpn-status.log ]; then + _openvpn_logfile='/etc/openvpn/openvpn-status.log' + elif [ -e /var/log/openvpn/openvpn-status.log ]; then + _openvpn_logfile='/var/log/openvpn/openvpn-status.log' + else + return 0 + fi + + mkecho '<<>>' + sed -n -e '/CLIENT LIST/,/ROUTING TABLE/p' < "${_openvpn_logfile}" | + sed -e 1,3d -e '$d' + + unset -v _openvpn_logfile +} + +# TO-DO: Merge with section_local and deduplicate i.e. DRY approach +section_plugins() { + # Plugins + ( + if cd "${MK_PLUGINSDIR}" 2>/dev/null; then + for _skript in ./*; do + if is_valid_plugin "${_skript}"; then + ./"${_skript}" + fi + done + # Call some plugins only every Xth second + for _skript in [1-9]*/*; do + if is_valid_plugin "${_skript}"; then + _skript_cache=$(mkecho "${_skript}" | sed 's/\//\\/') + run_cached "plugins_${_skript_cache}" "${_skript%/*}" "${_skript}" + fi + done + unset -v _skript _skript_cache + fi + ) +} + +section_proxmox() { + # Proxmox Cluster + if inpath pvecm; then + mkecho "<<>>" + pvecm status + mkecho "<<>>" + pvecm nodes + fi +} + +section_ps() { + case "${MK_OSSTR}" in + (aix) + mkecho '<<>>' + ps -ef -F user,vszsize,rssize,pcpu,etime,pid,args | + sed -e 1d -e 's/ *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) */(\1,\2,\3,\4\/\5,\6) /' + ;; + (freebsd) + # processes including username, without kernel processes + mkecho '<<>>' + COLUMNS=10000 + if [ "$is_jailed" = "0" ]; then + ps ax -o state,user,vsz,rss,pcpu,command | + sed -e 1d -e '/\([^ ]*J\) */d' -e 's/ *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) */(\2,\3,\4,\5) /' + else + ps ax -o user,vsz,rss,pcpu,command | + sed -e 1d -e 's/ *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) */(\1,\2,\3,\4) /' + fi + ;; + (hpux) + # Process table: HP-UX does not provide a resident size of processes. + # We send a 0 here for RSZ. + mkecho '<<>>' + UNIX95=yes ps -ef -o user,vsz,pcpu,args | + sed -e 1d -e 's/ *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) */(\1,\2,0,\3) /' + ;; + (linux) + if inpath ps; then + # processes including username, without kernel processes + mkecho '<<>>' + mkecho 'dummy section -- refer to section ps_lnx' + mkecho '<<>>' + CGROUP="" + if [ -e /sys/fs/cgroup ]; then + CGROUP="cgroup:512," + fi + # shellcheck disable=SC2039 + mkecho "[header] $(ps ax -o "$CGROUP"user:32,vsz,rss,cputime,etime,pid,command --columns 10000)" + fi + ;; + (mac|netbsd|openbsd) + mkecho '<<>>' + COLUMNS=10000 + ps ax -o user,vsz,rss,pcpu,command | + sed -e 1d -e 's/ *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) */(\1,\2,\3,\4) /' + ;; + (solaris) + mkecho '<<>>' + # The default solaris ps command strips the command lines of the processes. But for good process + # matching on the server we really need to whole command line. On linux there are arguments to + # make ps output the whole command line, but on solaris this seems to be missing. We use the ucb + # ps command to get the full command line instead. What a hack. + if [ -x /usr/ucb/ps ]; then + UCB_PS=$(/usr/ucb/ps -agwwwx) + ps -o user,vsz,rss,pcpu,etime,pid,args $pszone | + sed -e 1d -e 's/ *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) */(\1,\2,\3,\4\/\5,\6) /' | + while read -r LINE; do + STATS=${LINE%) *} + PID=${STATS##*,} + + # Directly use ps output when line is too slow to be stripped + if [ ${#LINE} -lt 100 ]; then + mkecho "$LINE" + continue + fi + + CMD=$(mkecho "$UCB_PS" | grep "^[ ]*$PID " | head -n1 | \ + awk '{ s = ""; for (i = 5; i <= NF; i++) s = s $i " "; print s }') + # Only use the ucb ps line when it's not empty (process might already been gone) + if [ -z "$CMD" ]; then + mkecho "$LINE" + else + mkecho "${STATS}) ${CMD}" + fi + done + else + ps -o user,vsz,rss,pcpu,etime,pidargs "${pszone}" | + sed -e 1d -e 's/ *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) */(\1,\2,\3,\4\/\5,\6) /' + fi + ;; + esac +} + +section_raid() { + case "${MK_OSSTR}" in + (freebsd) + # Soft-RAID + mkecho '<<>>' + gmirror status | grep -v ^Name + ;; + (linux) + # RAID status of Linux software RAID + mkecho '<<>>' + cat /proc/mdstat + + # RAID status of Linux RAID via device mapper + if inpath dmraid && DMSTATUS=$(waitmax 3 dmraid -r); then + mkecho '<<>>' + + # Output name and status + waitmax 20 dmraid -s | grep -e ^name -e ^status + + # Output disk names of the RAID disks + DISKS=$(mkecho "$DMSTATUS" | cut -f1 -d":") + + for disk in $DISKS; do + device=$(cat /sys/block/"$(basename "$disk")"/device/model) + status=$(mkecho "$DMSTATUS" | grep "^${disk}") + mkecho "${status} Model: ${device}" + done + fi + ;; + esac + # RAID status of LSI controllers via cfggen + if inpath cfggen; then + mkecho '<<>>' + cfggen 0 DISPLAY | + grep -E '(Target ID|State|Volume ID|Status of volume)[[:space:]]*:' | + sed -e 's/ *//g' -e 's/:/ /' + fi + + # RAID status of LSI MegaRAID controller via MegaCli. You can download that tool from: + # http://www.lsi.com/downloads/Public/MegaRAID%20Common%20Files/8.02.16_MegaCLI.zip + # From this list, the first that's found in PATH (if any) is mapped to lsicli() + for cliAlt in MegaCli MegaCli64 megacli storcli storcli64; do + if inpath "${cliAlt}"; then + lsicli() { "${cliAlt}"; } + break + fi + unset cliAlt + done + + if inpath lsicli; then + mkecho '<<>>' + for part in $(lsicli -EncInfo -aALL -NoLog >>' + lsicli -LDInfo -Lall -aALL -NoLog >>' + lsicli -AdpBbuCmd -GetBbuStatus -aALL -NoLog >>' + tw_cli "/${_tw_ctl}" show all | grep -E 'Model =|Firmware|Serial' + mkecho '<<<3ware_disks>>>' + tw_cli "/${_tw_ctl}" show drivestatus | grep -E 'p[0-9]' | sed "s/^/${_tw_ctl}\\//" + mkecho '<<<3ware_units>>>' + tw_cli "/${_tw_ctl}" show unitstatus | grep -E 'u[0-9]' | sed "s/^/${_tw_ctl}\\//" + done + unset -v _tw_ctl + fi + + # RAID controllers from areca (Taiwan) + # cli64 can be found at ftp://ftp.areca.com.tw/RaidCards/AP_Drivers/Linux/CLI/ + if inpath cli64; then + run_cached arc_raid_status 300 "cli64 rsf info | tail -n +3 | head -n -2" + fi +} + +# Start new liveupdate process in background on each agent execution. +# Starting a new live update process will terminate the old one +# automatically after a maximum of 1 second. +section_realtime_checks() { + # Validate that we're configured and equipped, otherwise return + if [ -r "${MK_CONFDIR}/real_time_checks.cfg" ]; then + if [ -z "${MK_RTC_HOST}" ]; then + mkecho "ERROR: \${MK_RTC_HOST} not specified. Not starting Real-Time Checks." >&2 + return + elif ! inpath openssl; then + mkecho "ERROR: openssl command is missing. Not starting Real-Time Checks." >&2 + return + fi + else + return + fi + + run_real_time_checks >/dev/null & +} + +section_runas() { + # MK's runas Executor + # runas.cfg syntax is: [Script type] [User context] [File / Directory] + # Script type can be 'mrpe', 'local' or 'plugin' + # User context defines the target user. Use '-' to skip + if [ -r "${MK_CONFDIR}/runas.cfg" ]; then + + # For now, we only define this function for this section. + runas_user() { + _suUser="${1:?No user supplied}" + shift + _suCmd="${*}" + case "${_suUser}" in + ('-'|'_'|null ) "${_suCmd}" ;; + (*) su "${_suUser}" -s "${SHELL}" -c "${_suCmd}" ;; + esac + unset _suUser _suCmd + } + + # Filter out lines startng with unwanted characters, then read what's left + grep -Ev '^[[:space:]]*($|#)' "${MK_CONFDIR}/runas.cfg" | while read -r type user include; do + case "${type}" in + (mrpe) + grep -Ev '^[[:space:]]*($|#)' "$include" | while read -r descr cmdline; do + # Detect if cmdline starts with '(' i.e. async mode + case "${cmdline}" in + (\(*) + # If we do start with '(', then split 'params' out of 'cmdline' + # We strip the brackets from 'params' and rewrite 'cmdline' without the params + params=$(mkecho "${cmdline% *}" | tr -d '()') + cmdline="${cmdline##* }" + # split multiple parameter assignments + for par in $(mkecho "${params}" | tr ":" "\\n"); do + # split each assignment + key="${par%=*}" + value="${par#*=}" + case "${key}" in + (interval) interval="${value}" ;; + (appendage) args="-ma" ;; + esac + done + case "${user}" in + ('-') + run_cached "${args:--m}" "${descr}" "${interval:-}" "${cmdline}" + ;; + (*) + run_cached "${args:--m}" "${descr}" "${interval:-}" runas_user "${user}" "${cmdline}" + ;; + esac + ;; + (*) + case "${user}" in + ('-') + run_mrpe "${descr}" "${cmdline}" + ;; + (*) + run_mrpe "${descr}" runas_user "${user}" "${cmdline}" + ;; + esac + ;; + esac + done + ;; + (local|plugin) + [ "$type" = "local" ] && mkecho "<<>>" + find "$include" -executable -type f | + while read -r filename; do + runas_user "${user}" "${filename}" + done + ;; + esac + done + fi +} + +section_services() { + case "${MK_OSSTR}" in + (linux) + if inpath systemctl; then + mkecho '<<>>' + mkecho "[list-unit-files]" + systemctl list-unit-files --no-pager + mkecho "[all]" + systemctl --all --no-pager | sed '/^$/q' + fi + + # Next we check for 'chkconfig' + if inpath chkconfig; then + mkecho '<<>>' + chkconfig --list 2>&1 + fi + + # Some debian hosts have sysv-rc-conf + if inpath sysv-rc-conf; then + mkecho '<<>>' + sysv-rc-conf + fi + ;; + (solaris) + # Getting Information About Services Running on Solaris + # We can get a list of all service instances, including disabled + # or incomplete ones by 'svcs -a' + if inpath svcs; then + mkecho '<<>>' + svcs -a + fi + ;; + esac +} + +section_solaris() { + if inpath prtdiag; then + # prtdiag does not work in local zones + if [ "${zonename}" = "global" ]; then + run_cached solaris_prtdiag_status 300 '/usr/sbin/prtdiag 1>/dev/null 2>&1; mkecho $?' + fi + fi + + # Displaying Information About Faults or Defects + # If there are no faults the output of this command will be empty. + if inpath fmadm; then + mkecho '<<>>' + fmadm faulty + fi +} + +section_spooldir() { + # Agent output snippets created by cronjobs, etc. + # See: Werk 0016 + ( + # Output every file in this directory. If the file is prefixed with a number, + # then that number is the maximum age of the file in seconds. + # If the file is older than that, it is ignored. + if cd "${MK_SPOOLDIR}" 2>/dev/null; then + _now=$(get_epoch) + + for _file in *; do + [ "${_file}" = "*" ] && break + + # Split any leading digits from a filename and assign to 'maxage' + # This should ignore further digits e.g. '600file20' will output '600' + _maxage="$(mkecho "${_file}" | sed 's/^[^0-9]*//;s/[^0-9].*$//')" + + # If 'maxage' is set, then we grab the file's mtime, subtract it from + # the epoch time, and compare that to 'maxage' + if [ "${_maxage}" ]; then + _mtime=$(get_file_mtime "${_file}") + if [ $((_now - _mtime)) -gt "${_maxage}" ]; then + continue + fi + fi + + # Output the file + cat "${_file}" + done + unset -v _now _file _maxage _mtime + fi + ) +} + +section_statgrab() { + if inpath statgrab; then + case "${MK_OSSTR}" in + (freebsd) + # To install: pkg install libstatgrab + statgrab_vars="const. disk. general. page. proc. user." + statgrab_vars_mem="mem. swap." + statgrab_sections="proc disk page" + + statgrab "$statgrab_vars" | grep -v md 1> /tmp/statgrab.$$ + statgrab "$statgrab_vars_mem" 1>>/tmp/statgrab.$$ + + for s in $statgrab_sections; do + mkecho "<<>>" + grep "^${s}\\." /tmp/statgrab.$$ | cut -d. -f2-99 | sed 's/ *= */ /' + done + + mkecho '<<>>' + statgrab net. 2>&1 | cut -d. -f2-99 | sed 's/ *= */ /' + + mkecho '<<>>' + grep -E "^(swap|mem)\\." /tmp/statgrab.$$ | sed 's/ *= */ /' + + [ -f /tmp/statgrab.$$ ] && rm -f /tmp/statgrab.$$ + ;; + (solaris) + # source: http://www.i-scream.org/libstatgrab/ + # binary: http://www.opencsw.org/ + statgrab_vars="const. cpu. disk. general. mem. page. swap. user." + statgrab_sections="cpu disk page" + + # Collect net stats in the global zone and in local zones if dlstat is present. + if [ "$zonename" = "global" ] || inpath dlstat >/dev/null 2>&1; then + statgrab_vars="$statgrab_vars net." + statgrab_sections="$statgrab_sections net" + fi + + statgrab "$statgrab_vars" | grep -v md 1> /tmp/statgrab.$$ + for s in $statgrab_sections; do + mkecho "<<>>" + grep "^$s\\." /tmp/statgrab.$$ | cut -d. -f2-99 | sed 's/ *= */ /' + done + + # <<>> info is preferred over <<>> + # since solaris_mem is under suspicion to be buggy. + mkecho '<<>>' + grep -E "^(swap|mem)\\." /tmp/statgrab.$$ | sed 's/ *= */ /' + + [ -f /tmp/statgrab.$$ ] && rm -f /tmp/statgrab.$$ + + ;; + esac + fi +} + +section_tcp_stats() { + # Helper function, we'll keep it tucked away here for now + filter_netstats() { + awk ' /^tcp/ { c[$6]++; } END { for (x in c) { print x, c[x]; } }' + } + mkecho '<<>>' + case "${MK_OSSTR}" in + (aix|mac) _netstat_opts="-ntfinet" ;; + (freebsd) _netstat_opts="-na" ;; + (hpux) _netstat_opts="-f inet -n" ;; + (linux) + if inpath waitmax; then + _tcp_stats=$(waitmax 5 cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | awk ' /:/ { c[$4]++; } END { for (x in c) { print x, c[x]; } }') + # We simply ignore this warning until we can come up with a cleaner way to do this + # shellcheck disable=SC2181 + if [ $? = 0 ]; then + mkecho "${_tcp_stats}" + elif inpath ss; then + ss -ant | + grep -v ^State | + awk ' /:/ { c[$1]++; } END { for (x in c) { print x, c[x]; } }' | + sed -e 's/^ESTAB/01/g;s/^SYN-SENT/02/g;s/^SYN-RECV/03/g;s/^FIN-WAIT-1/04/g;s/^FIN-WAIT-2/05/g;s/^TIME-WAIT/06/g;s/^CLOSED/07/g;s/^CLOSE-WAIT/08/g;s/^LAST-ACK/09/g;s/^LISTEN/0A/g;s/^CLOSING/0B/g;' + else + _netstat_opts="-na" + fi + unset -v _tcp_stats + else + _netstat_opts="-na" + fi + ;; + (solaris) + netstat -n -a -f inet -P tcp | + tail +5 | + nawk '{ c[$7]++; } END { for (x in c) { print x, c[x]; } }' + return + ;; + esac + netstat "${_netstat_opts}" | filter_netstats + unset -v _netstat_opts +} + +section_thermal() { + # Gather thermal information provided e.g. by acpi + # At the moment only supporting thermal sensors + if [ -z "${MK_IS_DOCKERIZED}" ] && [ -z "${MK_IS_LXC_CONTAINER}" ] && ls /sys/class/thermal/thermal_zone* >/dev/null 2>&1; then + mkecho '<<>>' + for _sysPath in /sys/class/thermal/thermal_zone*; do + _line="${_sysPath##*/}" + if [ ! -e "${_sysPath}/mode" ]; then + _line="${_line}|-" + else + _line="${_line}|$(cat "${_sysPath}"/mode)" + fi + _line="${_line}|$(cat "${_sysPath}"/type "${_sysPath}"/temp 2>/dev/null | tr \\n "|")" + for _temp in "${_sysPath}"/trip_point_*_temp; do + _line="${_line}$(tr <"${_temp}" \\n "|")" + done + for _type in "${_sysPath}"/trip_point_*_type; do + _line="${_line}$(tr <"${_type}" \\n "|")" + done + mkecho "${_line%?}" + done + unset _sysPath _line _temp _type + fi +} + +# Libelle Business Shadow +section_trd() { + if inpath trd; then + mkecho "<<>>" + trd -s + fi +} + +section_uptime() { + mkecho '<<>>' + case "${MK_OSSTR}" in + (aix) + # uptime formats + # 12:55pm up 105 days, 21 hrs, 2 users, load average: 0.26, 0.26, 0.26 --> 9147600 + # 1:41pm up 105 days, 21:46, 2 users, load average: 0.28, 0.28, 0.27 --> 9150360 + # 05:26PM up 1:16, 1 user, load average: 0.33, 0.21, 0.20 --> 4560 + # 06:13PM up 2:03, 1 user, load average: 1.16, 1.07, 0.91 --> 7380 + # 08:43AM up 29 mins, 1 user, load average: 0.09, 0.18, 0.21 --> 1740 + # 08:47AM up 66 days, 18:34, 1 user, load average: 2.25, 2.43, 2.61 --> 5769240 + # 08:45AM up 76 days, 34 mins, 1 user, load average: 2.25, 2.43, 2.61 --> 5769240 + + _uptime=$(uptime | sed -e 's/^.*up//g' -e 's/[0-9]* user.*//g') + case ${_uptime} in + ( *day* ) _up_days=$(mkecho "${_uptime}" | sed -e 's/days\{0,1\},.*//g') ;; + ( * ) _up_days="0" ;; + esac + + case ${_uptime} in + ( *:* ) + _up_hours=$(mkecho "${_uptime}" | sed -e 's/.*days\{0,1\},//g' -e 's/:.*//g') + _up_mins=$(mkecho "${_uptime}" | sed -e 's/.*days\{0,1\},//g' -e 's/.*://g' -e 's/,.*//g') + ;; + ( *hr* ) + _up_hours=$(mkecho "${_uptime}" | sed -e 's/hrs\{0,1\},.*//g' -e 's/.*,//g') + _up_mins=0 + ;; + ( *min* ) + _up_hours=0 + _up_mins=$(mkecho "${_uptime}" | sed -e 's/mins\{0,1\},.*//g' -e 's/.*hrs\{0,1\},//g' -e 's/.*days\{0,1\},//g') + ;; + ( * ) + _up_hours="0" + _up_mins=0 + ;; + esac + + mkecho $(((_up_days*86400)+(_up_hours*3600)+(_up_mins*60))) + unset -v _uptime _up_hours _up_mins + ;; + (freebsd) + # Calculate the uptime in seconds since epoch compatible to /proc/uptime in linux + _up_seconds=$(( $(get_epoch) - $(sysctl -n kern.boottime | cut -f1 -d\, | awk '{print $4}') )) + # pgrep is not appropriate (or even available?) here + # shellcheck disable=SC2009 + _idle_seconds=$(ps axw | grep "[i]dle" | awk '/idle/{print $4}' | cut -f1 -d':' ) + mkecho "${_up_seconds} ${_idle_seconds}" + unset -v _up_seconds _idle_seconds + ;; + (linux) + if [ -z "${MK_IS_DOCKERIZED}" ]; then + cat /proc/uptime + else + mkecho "$(($(get_epoch) - $(stat -c %Z /dev/pts)))" + fi + ;; + (mac|netbsd|openbsd) + mkecho "$(get_epoch) - $(sysctl -n kern.boottime | cut -d' ' -f 4,7 | tr ',' '.' | tr -d ' ')" | bc + ;; + (solaris) + # Solaris doesn't always give a consistent output on uptime, thus include side information + # Tested in VM for solaris 10/11 + _ctime=$(nawk 'BEGIN{print srand()}') + _btime=$(kstat '-p' 'unix:::boot_time' 2>&1|grep 'boot_time'|awk '{print $2}') + mkecho $((_ctime - _btime)); + mkecho '[uptime_solaris_start]' + uname -a + zonename + uptime + kstat -p unix:0:system_misc:snaptime + mkecho '[uptime_solaris_end]' + unset -v _ctime _btime + ;; + esac + + # 'who -b' is a mostly portable way to report the boot time + # TO-DO: is this information header the correct format? + if who -b > /dev/null 2>&1; then + mkecho "[who_b_boot_time]" + who -b + fi +} + +# HTTP Accelerator Statistics +section_varnishstat() { + if inpath varnishstat; then + mkecho "<<>>" + varnishstat -1 + fi +} + +section_vbox() { + # VirtualBox Guests. Section must always been output. Otherwise the + # check would not be executed in case no guest additions are installed. + # And that is something the check wants to detect + mkecho '<<>>' + if inpath VBoxControl; then + if lsmod | grepq vboxguest; then + VBoxControl -nologo guestproperty enumerate | cut -d, -f1,2 + fi + else + mkecho "ERROR" + fi +} + +section_vcs() { + # Veritas Cluster Server + # Software is always installed in /opt/VRTSvcs. + # Secure mode must be off to allow root to execute commands + if [ -x /opt/VRTSvcs/bin/haclus ]; then + mkecho "<<>>" + vcshost=$(hostname | cut -d. -f1) + waitmax -s 9 2 /opt/VRTSvcs/bin/haclus -display -localclus | grep -e ClusterName -e ClusState + waitmax -s 9 2 /opt/VRTSvcs/bin/hasys -display -attribute SysState + waitmax -s 9 2 /opt/VRTSvcs/bin/hagrp -display -sys "$vcshost" -attribute State -localclus + waitmax -s 9 2 /opt/VRTSvcs/bin/hares -display -sys "$vcshost" -attribute State -localclus + waitmax -s 9 2 /opt/VRTSvcs/bin/hagrp -display -attribute TFrozen -attribute Frozen + fi +} + +# TO-DO: Standardise headers +section_vmstat() { + case "${MK_OSSTR}" in + (aix) + mkecho '<<>>' + vmstat | tail -n1 + ;; + (hpux) + # Several machine performance counters + mkecho '<<>>' + vmstat -s + ;; + esac +} + +# TO-DO: Can this behaviour be simplified or made portable? +section_zfs() { + if [ "${MK_OSSTR}" = "linux" ]||[ "${MK_OSSTR}" = "solaris" ]; then + # Filesystem usage for ZFS + if inpath zfs; then + mkecho '<<>>' + zfs get -t filesystem,volume -Hp name,quota,used,avail,mountpoint,type || \ + zfs get -Hp name,referenced,avail,mountpoint,type | sed 's/referenced/used/g' + mkecho '<<>>' + mkecho '[df]' + df -PTlk -t zfs | sed 1d + fi + fi + + if [ "${MK_OSSTR}" = "linux" ]; then + # Welcome the ZFS check on Linux + # We do not endorse running ZFS on linux if your vendor doesnt support it ;) + # check zpool status + if inpath zpool; then + mkecho "<<>>" + zpool status -x + mkecho "<<>>" + zpool list + fi + fi + + if [ "${MK_OSSTR}" = "freebsd" ]; then + # Filesystem usage for ZFS + if inpath zfs; then + mkecho '<<>>' + zfs get -t filesystem,volume -Hp name,quota,used,avail,mountpoint,type || \ + zfs get -Hp name,quota,used,avail,mountpoint,type + mkecho '[df]' + df -kP -t zfs | sed 1d + # arc stats for zfs_arc_cache + mkecho '<<>>' + sysctl -q kstat.zfs.misc.arcstats | sed -e 's/kstat.zfs.misc.arcstats.//g' -e 's/: / = /g' + fi + + # check zpool status + if [ -x /sbin/zpool ]; then + mkecho "<<>>" + /sbin/zpool status -x | grep -v "errors: No known data errors" + fi + fi + + if [ "${MK_OSSTR}" = "solaris" ]; then + # ZFS arc cache + # newer Solaris (>=11.3) do not provide hits and misses via mdb -k + mkecho '<<>>' + if inpath kstat; then + kstat -p zfs:0:arcstats | + sed -e 's/.*arcstats://g' | + awk '{printf "%s = %s\n", $1, $2;}' + elif inpath; then + mkecho '::arc' | mdb -k + fi + + # zpool status + if [ -x /sbin/zpool ]; then + run_cached zpool_status 120 "/sbin/zpool status -x" + mkecho '<<>>' + zpool list + fi + fi +} + +######################################################################################################################## +# Output begins here +main() { + section_head + section_cpu + section_mem + section_df + section_zfs + section_nfs + section_mounts + section_multipathing + section_raid + section_diskstat + section_net + section_netctr + section_tcp_stats + section_ntp + section_mail + section_uptime + section_kernel + section_services + section_ps + section_statgrab + section_vmstat + section_ipmi + section_thermal + section_openvpn + section_omd + section_mkbackup + section_jobs + section_vbox + section_nvidia + section_heartbeat + section_vcs + section_proxmox + section_drbd + section_trd + section_varnishstat + section_haproxy + section_realtime_checks + section_fileinfo + section_runas + section_mrpe + section_local + section_plugins + section_spooldir + # Now any OS-specific catch-all functions + # I wonder if this could be called universally/portably with section_${MK_OSSTR} + case "${MK_OSSTR}" in + (aix) section_aix ;; + (hpux) section_hpux ;; + (mac) section_mac ;; + (solaris) section_solaris ;; + esac +} + +# Determine whether we need to send our output via encryption or not +case "${ENCRYPTION}" in + (yY*) main | protect_output ;; + (*) main ;; +esac From 68cb5c8987615678158bb823fa4146e23a387519 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Wed, 20 Nov 2019 07:32:59 +1300 Subject: [PATCH 02/29] Merge in changes from 3bc28c2 --- agents/check_mk_agent.merged | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index f5d0ba5ef3c..dcdf684c9d0 100644 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -1291,9 +1291,8 @@ section_mail() { _postfix_queue_dir="${1}" if [ -n "${_postfix_queue_dir}" ]; then mkecho '<<>>' - if [ -n "${2}" ]; then - mkecho "[[[${2}]]]" - fi + mkecho "[[[${2}]]]" + for _queue in deferred active; do _count=$(find "${_postfix_queue_dir}/${_queue}" -type f | wc -l) _size=$(du -s "${_postfix_queue_dir}/${_queue}" | awk '{print $1 }') @@ -1343,12 +1342,10 @@ section_mail() { read_postfix_queue_dirs "$postfix_queue_dir" "$queue_dir" fi done - - else - postfix_queue_dir=$(postconf -h queue_directory 2>/dev/null) - read_postfix_queue_dirs "$postfix_queue_dir" fi - ;; + # Always check for the default queue. It can exist even if multiple instances are configured + read_postfix_queue_dirs "$(postconf -h queue_directory 2>/dev/null)" + ;; esac elif [ -x /usr/sbin/ssmtp ]; then From eda9e44874863233f635ce3ee6c18785a99c4645 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Wed, 20 Nov 2019 11:55:00 +1300 Subject: [PATCH 03/29] Update get_shell() based on OpenBSD testing --- agents/check_mk_agent.merged | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index dcdf684c9d0..c74ca871a01 100644 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -157,7 +157,7 @@ get_shell() { elif ps -p "$$" >/dev/null 2>&1; then # This double-awk caters for situations where CMD/COMMAND # might be a full path e.g. /usr/bin/zsh - ps -p "$$" | tail -n 1 | awk '{print $NF}' | awk -F '/' '{print $NF}' + ps -p "$$" | tail -n 1 | awk '{print $NF}' | awk -F '/' '{print $NF}' | tr -d '()' # This one works well except for busybox elif ps -o comm= -p "$$" >/dev/null 2>&1; then ps -o comm= -p "$$" From dd8fdd7e2b0536390d100184bebd950a7b72c638 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Wed, 4 Dec 2019 15:32:44 +1300 Subject: [PATCH 04/29] Merged in changes from 7d27349 --- agents/check_mk_agent.merged | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index c74ca871a01..92704037333 100644 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -26,8 +26,13 @@ # Boston, MA 02110-1301 USA. # Remove locale settings to eliminate localized outputs where possible -LC_ALL=C -export LC_ALL +# The locale logic here is used to make the Python encoding detection +# work (see CMK-2778). +MK_LOCALE=$(locale -a |grep -E '^C$|^C.UTF-8$|^c.utf8$' | head -n 1) +if [ -z "${MK_LOCALE}" ]; then + LC_ALL="${MK_LOCALE}" + export LC_ALL +fi unset LANG # Close standard input (for security reasons) and stderr when not explicitly in debug mode. @@ -115,17 +120,17 @@ inpath() { # If EUID isn't set, then set it # Note that 'id -u' is now mostly portable here due to the alignment of xpg4 above # '[ -w / ]' may be an alternative test for proving root privileges... -if [ ! "${EUID}" ]; then +if [ -z "${EUID}" ]; then EUID=$(id -u); readonly EUID; export EUID fi # If HOSTNAME isn't set, then set it -if [ ! "${HOSTNAME}" ]; then +if [ -z "${HOSTNAME}" ]; then HOSTNAME=$(hostname); readonly HOSTNAME; export HOSTNAME fi # If HOME isn't set, then set it -if [ ! "${HOME}" ]; then +if [ -z "${HOME}" ]; then HOME=$(getent passwd | awk -F':' -v EUID="${EUID}" '$3 == EUID{print $6}') readonly HOME; export HOME fi @@ -142,7 +147,7 @@ fi # Newer shells like zsh and bash5.x have EPOCHSECONDS. If it's not available, we set it # Note that if this is set here, it will not update each time it's used # Use get_epoch() if you need that kind of accuracy -if [ ! "${EPOCHSECONDS}" ]; then +if [ -z "${EPOCHSECONDS}" ]; then EPOCHSECONDS=$(get_epoch); readonly EPOCHSECONDS; export EPOCHSECONDS fi @@ -173,7 +178,7 @@ get_shell() { } # If SHELL isn't set, then set it. -if [ ! "${SHELL}" ]; then +if [ -z "${SHELL}" ]; then if get_shell >/dev/null 2>&1; then SHELL=$(command -v "$(get_shell)"); readonly SHELL; export SHELL fi From 6b21677fbb0dc4e5628b3ddf36f3ad72cfb6ac0a Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Fri, 6 Dec 2019 16:20:05 +1300 Subject: [PATCH 05/29] Correct permissions on merged agent --- agents/check_mk_agent.merged | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) mode change 100644 => 100755 agents/check_mk_agent.merged diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged old mode 100644 new mode 100755 index 92704037333..61b0e9545b5 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -428,11 +428,11 @@ is_valid_plugin() { return 1 ;; (*) - if [ -x "${1}" ]; then - return 0 - else - return 1 - fi + if [ -x "${1}" ]; then + return 0 + else + return 1 + fi ;; esac } From dda19080337f167125aac2aa2bc194f09e121702 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Tue, 17 Dec 2019 22:18:58 +1300 Subject: [PATCH 06/29] Merge changes from a7d348e --- agents/check_mk_agent.merged | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index 61b0e9545b5..3cff76a348b 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -1673,14 +1673,18 @@ section_net() { mkecho '<<>>' sed 1,2d /proc/net/dev - if inpath ethtool; then - sed -e 1,2d /proc/net/dev | cut -d':' -f1 | sort | while read -r eth; do - mkecho "[$eth]" + sed -e 1,2d /proc/net/dev | cut -d':' -f1 | sort | while read -r eth; do + mkecho "[$eth]" + if inpath ethtool; then ethtool "$eth" | grep -E '(Speed|Duplex|Link detected|Auto-negotiation):' - # shellcheck disable=SC2039 - mkecho -e "\\tAddress: $(cat "/sys/class/net/$eth/address")\\n" - done - fi + else + # If interface down we get "Invalid argument" + speed=$(cat "/sys/class/net/$eth/speed" 2>/dev/null) + [ -n "$speed" ] && mkecho -e "\tSpeed: ${speed}Mb/s\n" + fi + # shellcheck disable=SC2039 + mkecho -e "\\tAddress: $(cat "/sys/class/net/$eth/address")\\n" + done # Current state of bonding interfaces if [ -e /proc/net/bonding ]; then From b9937725d5f2bb82e1afc5b32a15cae62837d4e5 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Tue, 17 Dec 2019 22:22:35 +1300 Subject: [PATCH 07/29] Merge changes from 182f281 --- agents/check_mk_agent.merged | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index 3cff76a348b..46d6f516d92 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -268,7 +268,7 @@ esac MK_PLUGINSDIR="${MK_LIBDIR:?}"/plugins # All executables in MK_LOCALDIR will be executed and their -# output inserted into the section <<>>. Please +# output inserted into the section <<>>. Please # refer to online documentation for details about local checks. MK_LOCALDIR="${MK_LIBDIR}"/local @@ -1258,7 +1258,7 @@ section_kernel() { section_local() { # Local checks - mkecho '<<>>' + mkecho '<<>>' # Contain the 'cd' within a subshell so that we return # where we came from once the subshell closes ( @@ -2289,7 +2289,7 @@ section_runas() { done ;; (local|plugin) - [ "$type" = "local" ] && mkecho "<<>>" + [ "$type" = "local" ] && mkecho "<<>>" find "$include" -executable -type f | while read -r filename; do runas_user "${user}" "${filename}" From 70f69c1c8ddaad752f0f7752440b330088bc0b74 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Tue, 14 Jan 2020 11:19:25 +1300 Subject: [PATCH 08/29] Updates for ntp handling in response to cc8af1a, merge 5f4a2a5 --- agents/check_mk_agent.merged | 79 +++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index 46d6f516d92..d1cb9a89985 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -303,7 +303,7 @@ case "${MK_OSSTR}" in # Treat all pre-Solaris 10 systems as "global" if inpath zonename; then zonename=$(zonename) - pszone="-z $zonename" + pszone="-z ${zonename}" else zonename="global" pszone="-A" @@ -1680,7 +1680,7 @@ section_net() { else # If interface down we get "Invalid argument" speed=$(cat "/sys/class/net/$eth/speed" 2>/dev/null) - [ -n "$speed" ] && mkecho -e "\tSpeed: ${speed}Mb/s\n" + [ -n "${speed}" ] && [ "${speed}" -ge 0 ] && mkecho -e "\tSpeed: ${speed}Mb/s\n" fi # shellcheck disable=SC2039 mkecho -e "\\tAddress: $(cat "/sys/class/net/$eth/address")\\n" @@ -1812,14 +1812,14 @@ section_netctr() { get_epoch while [ $Z1 -lt 15 ]; do - BI=$( netstat -inb | grep -Ev Name | grep Link | awk '{print $1" "$5}' | sed -ne $Z1$Z2 ) - PI=$( netstat -in | grep -Ev Name | grep Link | awk '{print $5}' | sed -ne $Z1$Z2 ) - EI=$( netstat -in | grep -Ev Name | grep Link | awk '{print $6}' | sed -ne $Z1$Z2 ) + BI=$( netstat -inb | grep -Ev Name | awk '/Link/{print $1" "$5}' | sed -ne $Z1$Z2 ) + PI=$( netstat -in | grep -Ev Name | awk '/Link/{print $5}' | sed -ne $Z1$Z2 ) + EI=$( netstat -in | grep -Ev Name | awk '/Link/{print $6}' | sed -ne $Z1$Z2 ) FF1="0 0 0 0 0" - BO=$( netstat -inb | grep -Ev Name | grep Link | awk '{print $6}' | sed -ne $Z1$Z2 ) - PO=$( netstat -in | grep -Ev Name | grep Link | awk '{print $7}' | sed -ne $Z1$Z2 ) - EO=$( netstat -in | grep -Ev Name | grep Link | awk '{print $8}' | sed -ne $Z1$Z2 ) - CO=$( netstat -in | grep -Ev Name | grep Link | awk '{print $9}' | sed -ne $Z1$Z2 ) + BO=$( netstat -inb | grep -Ev Name | awk '/Link/{print $6}' | sed -ne $Z1$Z2 ) + PO=$( netstat -in | grep -Ev Name | awk '/Link/{print $7}' | sed -ne $Z1$Z2 ) + EO=$( netstat -in | grep -Ev Name | awk '/Link/{print $8}' | sed -ne $Z1$Z2 ) + CO=$( netstat -in | grep -Ev Name | awk '/Link/{print $9}' | sed -ne $Z1$Z2 ) FF2="0 0" if [ "$PI" -gt "0" ]; then mkecho "$BI $PI $EI $FF1 $BO $PO $EO $FF2 $CO $FF2" @@ -1859,25 +1859,48 @@ section_nfs() { } section_ntp() { - # Time synchronization with NTP + # ntpq helper function + get_ntpq() { + inpath ntpq || return 1 + [ "${1}" = "--header" ] && mkecho '<<>>' + ntpq -np | sed -e 1,2d -e 's/^\\(.\\)/\\1 /' -e 's/^ /%/' || true + } + + # Time synchronization with NTP (ntpq required) if inpath ntpq; then - if [ "${MK_OSSTR}" = "aix" ]; then - if [ "$(lssrc -s xntpd|grep -c active)" -gt 0 ] ; then - mkecho '<<>>' - ntpq -np | sed -e 1,2d -e 's/^\(.\)/\1 /' -e 's/^ /%/' - fi - elif [ "${MK_OSSTR}" = "solaris" ]; then - # 'psgrep' does not work well in this case - # shellcheck disable=SC2009 - if ps -o comm $pszone | grep -w ".*ntpd" >/dev/null 2>&1; then - mkecho '<<>>' - ntpq -np | sed -e 1,2d -e 's/^\(.\)/\1 /' -e 's/^ /%/' - fi - # The following should cover everything else - else - # remove heading, make first column space separated - run_cached ntp 30 "waitmax 5 ntpq -np | sed -e 1,2d -e 's/^\\(.\\)/\\1 /' -e 's/^ /%/' || true" - fi + case "${MK_OSSTR}" in + (aix) + [ "$(lssrc -s xntpd|grep -c active)" -gt 0 ] && get_ntpq --header + ;; + (solaris) + # 'pgrep' does not work well in this case + ps -o comm "${pszone}" | grepq -w ".*ntpd" && get_ntpq --header + ;; + (linux|*) + # Check for systemd + if inpath systemctl; then + # Identify whether ntp/ntpd/openntpd is active, if so, run ntpq + # shellcheck disable=SC2016 + if [ "$(systemctl awk '/(^ntp?|^openntpd).service/{print $3; exit}')" = "active" ]; then + # remove heading, make first column space separated + run_cached -s ntp 30 "waitmax 5 get_ntpq" + fi + # Otherwise, we're pre-systemd... try to determine status via /etc/init.d + # This might also be appropriate for AIX, Solaris and others + else + for _ntp_daemon in ntp ntpd openntpd; do + # Check for a service script + if [ -x /etc/init.d/"${_ntp_daemon}" ]; then + # If the status returns 0, we assume we have a running service + if /etc/init.d/"${_ntp_daemon}" status >/dev/null 2>&1; then + run_cached -s ntp 30 "waitmax 5 get_ntpq" + fi + fi + done + unset -v _ntp_daemon + fi + ;; + esac fi # Time synchronization with Chrony @@ -2088,7 +2111,7 @@ section_ps() { # ps command to get the full command line instead. What a hack. if [ -x /usr/ucb/ps ]; then UCB_PS=$(/usr/ucb/ps -agwwwx) - ps -o user,vsz,rss,pcpu,etime,pid,args $pszone | + ps -o user,vsz,rss,pcpu,etime,pid,args "${pszone}" | sed -e 1d -e 's/ *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) */(\1,\2,\3,\4\/\5,\6) /' | while read -r LINE; do STATS=${LINE%) *} From 26f1ccb8457d548906a481c80c63df2c5f5f9fa7 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Tue, 14 Jan 2020 15:33:43 +1300 Subject: [PATCH 09/29] Merge in adjustments from linux_agent_ntp_fixes branch --- agents/check_mk_agent.merged | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index d1cb9a89985..29ef9af3aa0 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -1881,7 +1881,7 @@ section_ntp() { if inpath systemctl; then # Identify whether ntp/ntpd/openntpd is active, if so, run ntpq # shellcheck disable=SC2016 - if [ "$(systemctl awk '/(^ntp?|^openntpd).service/{print $3; exit}')" = "active" ]; then + if [ "$(systemctl | awk '/ntp.service|ntpd.service/{print $3; exit}')" = "active" ]; then # remove heading, make first column space separated run_cached -s ntp 30 "waitmax 5 get_ntpq" fi From 99decf667298f0f596ce1bf93f2593a928f49a1e Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Tue, 21 Jan 2020 22:50:19 +1300 Subject: [PATCH 10/29] Update section_ntp() after feedback on #116 --- agents/check_mk_agent.merged | 90 +++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 42 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index 29ef9af3aa0..bd907070c01 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -1866,7 +1866,44 @@ section_ntp() { ntpq -np | sed -e 1,2d -e 's/^\\(.\\)/\\1 /' -e 's/^ /%/' || true } - # Time synchronization with NTP (ntpq required) + # First we check for systemd, and then attempt the methods that we know about + # Our goal here is to avoid multiple outputs e.g. timedatectl + ntpq + if inpath systemctl; then + # Attempt to check time synchronization with systemd-timesyncd + if inpath timedatectl; then + if timedatectl timesync-status >/dev/null 2>&1; then + mkecho "<<>>" + timedatectl timesync-status + get_file_mtime /var/lib/systemd/timesync/clock | awk '{print "[[["$1"]]]"}' + + # Return to get out of 'section_ntp()' with no further processing + return + fi + fi + + # Next, we try to check time synchronization with Chrony + # Force successful exit code. Otherwise section will be missing if daemon not running + # + # The "| cat" has been added for some kind of regression in RedHat 7.5. The + # SELinux rules shipped with that release were denying the chronyc call without cat. + if inpath chronyc; then + # Identify if the daemon is active... + if [ "$(systemctl | awk '/chronyd.service/{print $3; exit}')" = "active" ]; then + run_cached chrony 30 "waitmax 5 chronyc -n tracking | cat || true" + return + fi + fi + + # Finally, try to identify whether ntp/ntpd/openntpd is active, if so, run ntpq + # shellcheck disable=SC2016 + if [ "$(systemctl | awk '/ntp.service|ntpd.service/{print $3; exit}')" = "active" ]; then + # remove heading, make first column space separated + run_cached -s ntp 30 "waitmax 5 get_ntpq" + return + fi + fi + + # If we get to this point, we attempt via classic ntp daemons (ntpq required) if inpath ntpq; then case "${MK_OSSTR}" in (aix) @@ -1877,52 +1914,21 @@ section_ntp() { ps -o comm "${pszone}" | grepq -w ".*ntpd" && get_ntpq --header ;; (linux|*) - # Check for systemd - if inpath systemctl; then - # Identify whether ntp/ntpd/openntpd is active, if so, run ntpq - # shellcheck disable=SC2016 - if [ "$(systemctl | awk '/ntp.service|ntpd.service/{print $3; exit}')" = "active" ]; then - # remove heading, make first column space separated - run_cached -s ntp 30 "waitmax 5 get_ntpq" - fi - # Otherwise, we're pre-systemd... try to determine status via /etc/init.d + # Try to determine status via /etc/init.d # This might also be appropriate for AIX, Solaris and others - else - for _ntp_daemon in ntp ntpd openntpd; do - # Check for a service script - if [ -x /etc/init.d/"${_ntp_daemon}" ]; then - # If the status returns 0, we assume we have a running service - if /etc/init.d/"${_ntp_daemon}" status >/dev/null 2>&1; then - run_cached -s ntp 30 "waitmax 5 get_ntpq" - fi + for _ntp_daemon in ntp ntpd openntpd; do + # Check for a service script + if [ -x /etc/init.d/"${_ntp_daemon}" ]; then + # If the status returns 0, we assume we have a running service + if /etc/init.d/"${_ntp_daemon}" status >/dev/null 2>&1; then + run_cached -s ntp 30 "waitmax 5 get_ntpq" fi - done - unset -v _ntp_daemon - fi + fi + done + unset -v _ntp_daemon ;; esac fi - - # Time synchronization with Chrony - if inpath chronyc; then - # Force successful exit code. Otherwise section will be missing if daemon not running - # - # The "| cat" has been added for some kind of regression in RedHat 7.5. The - # SELinux rules shipped with that release were denying the chronyc call - # without cat. - run_cached chrony 30 "waitmax 5 chronyc -n tracking | cat || true" - fi - - # Time synchronization with systemd timesyncd - if inpath timedatectl; then - _systemd_version=$(systemctl --version | awk '{if(NR==1) print $2}') - if [ "${_systemd_version}" -ge 239 ]; then - mkecho "<<>>" - timedatectl timesync-status - get_file_mtime /var/lib/systemd/timesync/clock | awk '{print "[[["$1"]]]"}' - fi - unset -v _systemd_version - fi } section_nvidia() { From 326dfaea2a742bb55c1a457a760df31f22e98628 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Wed, 22 Jan 2020 09:55:33 +1300 Subject: [PATCH 11/29] Further adjustments to section_ntp() based on feedback on #116 --- agents/check_mk_agent.merged | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index bd907070c01..aa8f912e038 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -1881,19 +1881,6 @@ section_ntp() { fi fi - # Next, we try to check time synchronization with Chrony - # Force successful exit code. Otherwise section will be missing if daemon not running - # - # The "| cat" has been added for some kind of regression in RedHat 7.5. The - # SELinux rules shipped with that release were denying the chronyc call without cat. - if inpath chronyc; then - # Identify if the daemon is active... - if [ "$(systemctl | awk '/chronyd.service/{print $3; exit}')" = "active" ]; then - run_cached chrony 30 "waitmax 5 chronyc -n tracking | cat || true" - return - fi - fi - # Finally, try to identify whether ntp/ntpd/openntpd is active, if so, run ntpq # shellcheck disable=SC2016 if [ "$(systemctl | awk '/ntp.service|ntpd.service/{print $3; exit}')" = "active" ]; then @@ -1903,6 +1890,18 @@ section_ntp() { fi fi + # Next, we try to check time synchronization with Chrony + # Force successful exit code. Otherwise section will be missing if daemon not running + # + # The "| cat" has been added for some kind of regression in RedHat 7.5. The + # SELinux rules shipped with that release were denying the chronyc call without cat. + if inpath chronyc; then + # Identify if the daemon is active... + if [ "$(systemctl | awk '/chronyd.service/{print $3; exit}')" = "active" ]; then + run_cached chrony 30 "waitmax 5 chronyc -n tracking | cat || true" + fi + fi + # If we get to this point, we attempt via classic ntp daemons (ntpq required) if inpath ntpq; then case "${MK_OSSTR}" in From dfee98099621878c870aa65b1d72ba7df3ccbf1e Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Wed, 22 Jan 2020 10:32:16 +1300 Subject: [PATCH 12/29] Adjust 'section_jobs()' after #119 --- agents/check_mk_agent.merged | 73 +++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index aa8f912e038..cecb55b8dd3 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -1191,40 +1191,51 @@ section_jobs() { # is a sub directory per user that ran a job. That directory must be # owned by the user so that a symlink or hardlink attack for reading # arbitrary files can be avoided. - if [ "${MK_OSSTR}" = "linux" ]; then - ( - cd "${MK_VARDIR}/job" || return - mkecho '<<>>' - for _username in *; do - if [ -d "${_username}" ] && cd "${_username}"; then - if [ "${EUID}" -eq 0 ]; then - su -s "${SHELL}" "${_username}" -c "head -n -0 -v *" - else - head -n -0 -v ./* + ( + cd "${MK_VARDIR}/job" || return + mkecho '<<>>' + case "${MK_OSSTR}" in + (aix) + for _username in *; do + if [ -d "${_username}" ] && cd "${_username}"; then + for _filename in *; do + # Maybe a cursory "if [ -r "${_filename}" ]" could go here? + mkecho "==> ${_filename} <==" + cat "${_filename}" + done + cd .. fi - cd .. - fi - done - ) - elif [ "${MK_OSSTR}" = "solaris" ]; then - ( - cd "${MK_VARDIR}/job" || return - mkecho '<<>>' - for _username in *; do - if [ -d "${_username}" ] && cd "${_username}" ; then - _count=$(su -s "${SHELL}" "${_username}" -c "ls -1 * | wc -l") - - if [ "${_count}" -eq "1" ]; then - _filename=$(su -s "${SHELL}" "${_username}" -c "ls -1 *") - mkecho "==> ${_filename} <==" + done + ;; + (linux) + for _username in *; do + if [ -d "${_username}" ] && cd "${_username}"; then + if [ "${EUID}" -eq 0 ]; then + su -s "${SHELL}" "${_username}" -c "head -n -0 -v *" + else + head -n -0 -v ./* + fi + cd .. fi + done + ;; + (solaris) + for _username in *; do + if [ -d "${_username}" ] && cd "${_username}" ; then + _count=$(su -s "${SHELL}" "${_username}" -c "ls -1 * | wc -l") - su -s "${SHELL}" "${_username}" -c "head -n1000 *" - cd .. - fi - done - ) - fi + if [ "${_count}" -eq "1" ]; then + _filename=$(su -s "${SHELL}" "${_username}" -c "ls -1 *") + mkecho "==> ${_filename} <==" + fi + + su -s "${SHELL}" "${_username}" -c "head -n1000 *" + cd .. + fi + done + ;; + esac + ) unset -v _username _filename _count } From 6138a65825d3a6432a547a1e99ab431bdd083527 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Wed, 22 Jan 2020 11:47:41 +1300 Subject: [PATCH 13/29] Add handling for USER env variable to enable merged mk-job --- agents/check_mk_agent.merged | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index cecb55b8dd3..4450c27e12e 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -135,6 +135,12 @@ if [ -z "${HOME}" ]; then readonly HOME; export HOME fi +# If USER isn't set, then set it +if [ -z "${USER}" ]; then + USER=$(getent passwd | awk -F':' -v EUID="${EUID}" '$3 == EUID{print $1}') + readonly USER; export USER +fi + # date +%s is not portable, so we provide this function # To do this in pure shell is... fun... however 'perl' is assumed # elsewhere in this agent, so we may as well depend on that for our failover option From 1bfbe7241b67e15edacfdfdc6083cb55e5296c6f Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Wed, 22 Jan 2020 14:39:15 +1300 Subject: [PATCH 14/29] Merged mk-job script, taking into account #119 --- agents/mk-job | 106 +++++++++++++++++++++++++++++------------- agents/mk-job.solaris | 57 ----------------------- 2 files changed, 73 insertions(+), 90 deletions(-) delete mode 100755 agents/mk-job.solaris diff --git a/agents/mk-job b/agents/mk-job index 94b0f461c89..34ecbbb60d2 100755 --- a/agents/mk-job +++ b/agents/mk-job @@ -3,57 +3,97 @@ # This file is part of Checkmk (https://checkmk.com). It is subject to the terms and # conditions defined in the file COPYING, which is part of this source code package. -export MK_VARDIR=/var/lib/check_mk_agent - +# Exempt from indentation rules as it's a heredoc help() { - echo "Usage: mk-job IDENT PROGRAM [ARGS...]" - echo "" - echo "Execute PROGRAM as subprocess while measuring performance information" - echo "about the running process and writing it to an output file. This file" - echo "can be monitored using Check_MK. The Check_MK Agent will forward the" - echo "information of all job files to the monitoring server." - echo "" - echo "This file is being distributed with the Check_MK Agent." +cat << EOF >&2 +Usage: mk-job ident PROGRAM [ARGS...] + +Execute PROGRAM as subprocess while measuring performance information +about the running process and writing it to an output file. This file +can be monitored using checkmk. The checkmk Agent will forward the +information of all job files to the monitoring server. + +This file is being distributed with the checkmk Agent. +EOF + +exit "${1:-0}" } -if [ $# -lt 2 ]; then - help >&2 - exit 1 -fi +# If args is less than 2, or 0, call `help()` and exit 1 +[ "${#}" -lt 2 ] && help 1 +[ "${#}" -eq 0 ] && help 1 -MYSELF=$(id -nu) -OUTPUT_PATH=$MK_VARDIR/job/$MYSELF -IDENT=$1 -RUNNING_FILE="$OUTPUT_PATH/$IDENT.$$running" +# If help is requested, deliver it +[ "${1}" = "-h" ] && help 0 +[ "${1}" = "--help" ] && help 0 +# Source the agent, as it has a bunch of functions and variables for us to use +# shellcheck disable=SC1090 +. "$(command -v check_mk_agent)" || exit 1 + +# Set up the variables that are specific to this script +output_path="${MK_VARDIR}/job/${USER}" +ident="${1:?}" +running_file="${output_path}/${ident}.$$running" +tmp_file="${running_file}.tmp" + +# Shift to the rest of the positional parameters shift -if [ ! -d "$OUTPUT_PATH" ]; then - if [ "$MYSELF" = root ] ; then - mkdir -p "$OUTPUT_PATH" +if [ ! -d "${output_path}" ]; then + if [ "${USER}" = root ]; then + mkdir -p "${output_path}" else - echo "ERROR: Missing output directory $OUTPUT_PATH for non-root user '$MYSELF'." >&2 + echo "ERROR: Missing output directory ${output_path} for non-root user '${USER}'." >&2 exit 1 fi fi -if ! type $1 >/dev/null 2>&1; then - echo -e "ERROR: Cannot run $1. Command not found.\n" >&2 - help >&2 - exit 1 +if ! inpath "${1}"; then + echo "ERROR: Cannot run '${1}'. Command not found." >&2 + help 1 fi -date +"start_time %s" > "$RUNNING_FILE" 2>/dev/null +echo "start_time $(get_epoch)" > "${running_file}" 2>/dev/null -if [ ! -w "$RUNNING_FILE" ] ; then +if [ ! -w "${running_file}" ] ; then # Looks like we are lacking the permissions to create this file.. # In this scenario no mk-job status file is created. We simply execute the command exec "$@" fi +case "${MK_OSSTR}" in + (aix) + /usr/bin/time -p "$@" > "${tmp_file}" # execute the command + return_code="${?}" # save return code + echo "exit_code ${return_code}" >> "${running_file}" # then add the return code + # and finally add the output of /usr/bin/time + grep -E '^real |^user |^sys ' "${tmp_file}" | + sed -e 's/,/\./g' \ + -e 's/^real /real_time/g' \ + -e 's/^user /user_time/g' \ + -e 's/^sys /system_time/g' \ + >> "${running_file}" + echo "reads 0\nwrites 0\nmax_res_kbytes 0\navg_mem_kbytes 0\ninvol_context_switches 0\nvol_context_switches 0" >> "${running_file}" + ;; + (linux) + /usr/bin/time -o "${running_file}" --append \ + -f "exit_code %x\nreal_time %E\nuser_time %U\nsystem_time %S\nreads %I\nwrites %O\nmax_res_kbytes %M\navg_mem_kbytes %K\ninvol_context_switches %c\nvol_context_switches %w" "$@" + return_code="${?}" + ;; + (solaris) + info=$( (/usr/bin/time -p sh -c "$* 2>/dev/null 1>&2" 2>&1; echo $?) | sed -e 's/,/\./g') + return_code=$(echo "${info}" | awk '{print $7}') + + (echo "${info}" | + awk '{print "exit_code "$7"\nreal_time "$2"\nuser_time "$4"\nsystem_time "$6""}' + ) >> "${running_file}" + + (echo -e "reads 0\nwrites 0\nmax_res_kbytes 0\navg_mem_kbytes 0\ninvol_context_switches 0\nvol_context_switches 0"; + ) >> "${running_file}" + ;; +esac -/usr/bin/time -o "$RUNNING_FILE" --append \ - -f "exit_code %x\nreal_time %E\nuser_time %U\nsystem_time %S\nreads %I\nwrites %O\nmax_res_kbytes %M\navg_mem_kbytes %K\ninvol_context_switches %c\nvol_context_switches %w" "$@" -RC=$? -mv "$RUNNING_FILE" "$OUTPUT_PATH/$IDENT" -exit $RC +mv "${running_file}" "${output_path}/${ident}" +[ -e "${tmp_file}" ] && rm -f "${tmp_file}" +exit "${return_code}" diff --git a/agents/mk-job.solaris b/agents/mk-job.solaris deleted file mode 100755 index 9e92113f94d..00000000000 --- a/agents/mk-job.solaris +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash -# Copyright (C) 2019 tribe29 GmbH - License: GNU General Public License v2 -# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and -# conditions defined in the file COPYING, which is part of this source code package. - -export MK_VARDIR=/var/lib/check_mk - -help() { - echo "Usage: mk-job IDENT PROGRAM [ARGS...]" - echo "" - echo "Execute PROGRAM as subprocess while measuring performance information" - echo "about the running process and writing it to an output file. This file" - echo "can be monitored using Check_MK. The Check_MK Agent will forward the" - echo "information of all job files to the monitoring server." - echo "" - echo "This file is being distributed with the Check_MK Agent." -} - -if [ $# -lt 2 ]; then - help >&2 - exit 1 -fi - -MYSELF=`id | awk -F')' '{print $1}' | awk -F'(' '{print $2}'` -OUTPUT_PATH=$MK_VARDIR/job/$MYSELF -IDENT=$1 -RUNNING_FILE="$OUTPUT_PATH/$IDENT.$$running" - -shift - -if [ ! -d "$OUTPUT_PATH" ]; then - if [ "$MYSELF" = root ] ; then - mkdir -p "$OUTPUT_PATH" - else - echo "ERROR: Missing output directory $OUTPUT_PATH for non-root user '$MYSELF'." >&2 - exit 1 - fi -fi - -if ! type $1 >/dev/null 2>&1; then - echo -e "ERROR: Cannot run $1. Command not found.\n" >&2 - help >&2 - exit 1 -fi - - -echo "start_time `perl -e 'print time'`" > "$RUNNING_FILE" - -info=`(/usr/bin/time -p sh -c "$@ 2>/dev/null 1>&2" 2>&1; echo $?) | sed -e 's/,/\./g'` -RC=`echo $info | awk '{print $7}'` - -(echo $info | awk '{print "exit_code "$7"\nreal_time "$2"\nuser_time "$4"\nsystem_time "$6""}') >> "$RUNNING_FILE" -(echo -e "reads 0\nwrites 0\nmax_res_kbytes 0\navg_mem_kbytes 0\ninvol_context_switches 0\nvol_context_switches 0";) >> "$RUNNING_FILE" - -mv "$RUNNING_FILE" "$OUTPUT_PATH/$IDENT" -exit $RC - From 7149f4581d62275d51e405dd47f7ab735d347c62 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Thu, 23 Jan 2020 23:42:23 +1300 Subject: [PATCH 15/29] Further updates to ntp handling based on discussion in #116 --- agents/check_mk_agent.merged | 65 ++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index 4450c27e12e..e46ec6baed2 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -791,6 +791,18 @@ section_aix() { lsvg -L -l rootvg } +# Function to pull timesync information from chrony +section_chrony() { + # The "| cat" has been added for some kind of regression in RedHat 7.5. The + # SELinux rules shipped with that release were denying the chronyc call without cat. + if inpath chronyc; then + # Identify if the daemon is active... + if [ "$(systemctl | awk '/chronyd.service/{print $3; exit}')" = "active" ]; then + run_cached chrony 30 "waitmax 5 chronyc -n tracking | cat || true" + fi + fi +} + section_cpu() { case "${MK_OSSTR}" in (aix) @@ -1883,40 +1895,34 @@ section_ntp() { ntpq -np | sed -e 1,2d -e 's/^\\(.\\)/\\1 /' -e 's/^ /%/' || true } + # Function to pull timesync information via timedatectl (if possible) + get_timesyncd() { + inpath timedatectl || return 1 + timedatectl timesync-status >/dev/null 2>&1 || return 1 + mkecho "<<>>" + timedatectl timesync-status + get_file_mtime /var/lib/systemd/timesync/clock | awk '{print "[[["$1"]]]"}' + return 0 + } + # First we check for systemd, and then attempt the methods that we know about # Our goal here is to avoid multiple outputs e.g. timedatectl + ntpq if inpath systemctl; then - # Attempt to check time synchronization with systemd-timesyncd - if inpath timedatectl; then - if timedatectl timesync-status >/dev/null 2>&1; then - mkecho "<<>>" - timedatectl timesync-status - get_file_mtime /var/lib/systemd/timesync/clock | awk '{print "[[["$1"]]]"}' - - # Return to get out of 'section_ntp()' with no further processing - return + # First we try with timedatectl + get_timesyncd + _timesync_rc="${?}" + + # If we don't get a success from get_timesyncd, we try ntpq + if [ "${_timesync_rc}" -gt 0 ]; then + # shellcheck disable=SC2016 + if [ "$(systemctl | awk '/ntp.service|ntpd.service/{print $3; exit}')" = "active" ]; then + # remove heading, make first column space separated + run_cached -s ntp 30 "waitmax 5 get_ntpq" fi fi - - # Finally, try to identify whether ntp/ntpd/openntpd is active, if so, run ntpq - # shellcheck disable=SC2016 - if [ "$(systemctl | awk '/ntp.service|ntpd.service/{print $3; exit}')" = "active" ]; then - # remove heading, make first column space separated - run_cached -s ntp 30 "waitmax 5 get_ntpq" - return - fi - fi - - # Next, we try to check time synchronization with Chrony - # Force successful exit code. Otherwise section will be missing if daemon not running - # - # The "| cat" has been added for some kind of regression in RedHat 7.5. The - # SELinux rules shipped with that release were denying the chronyc call without cat. - if inpath chronyc; then - # Identify if the daemon is active... - if [ "$(systemctl | awk '/chronyd.service/{print $3; exit}')" = "active" ]; then - run_cached chrony 30 "waitmax 5 chronyc -n tracking | cat || true" - fi + unset -v _timesync_rc + # Return to leave the function with no further processing + return fi # If we get to this point, we attempt via classic ntp daemons (ntpq required) @@ -2779,6 +2785,7 @@ main() { section_netctr section_tcp_stats section_ntp + section_chrony section_mail section_uptime section_kernel From c8063cf835017bf4bc94bd2a037b382d8a7d3133 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Fri, 24 Jan 2020 22:26:10 +1300 Subject: [PATCH 16/29] Split ntp and timesyncd into separate functions and plumb them together --- agents/check_mk_agent.merged | 103 ++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 51 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index e46ec6baed2..f6c533f1d58 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -1888,69 +1888,55 @@ section_nfs() { } section_ntp() { - # ntpq helper function + # If '${timesync_rc}' is 0, then 'section_timesyncd()' has returned successfully in + # which case we do not want to proceed with ntpq, so return and skip further processing + [ "${timesync_rc}" -eq 0 ] && return 0 + + # If ntpq isn't in PATH, there's no point going further + inpath ntpq || return 1 + + # If we get to this point, declare our ntpq helper function get_ntpq() { - inpath ntpq || return 1 [ "${1}" = "--header" ] && mkecho '<<>>' ntpq -np | sed -e 1,2d -e 's/^\\(.\\)/\\1 /' -e 's/^ /%/' || true } - # Function to pull timesync information via timedatectl (if possible) - get_timesyncd() { - inpath timedatectl || return 1 - timedatectl timesync-status >/dev/null 2>&1 || return 1 - mkecho "<<>>" - timedatectl timesync-status - get_file_mtime /var/lib/systemd/timesync/clock | awk '{print "[[["$1"]]]"}' - return 0 - } - - # First we check for systemd, and then attempt the methods that we know about - # Our goal here is to avoid multiple outputs e.g. timedatectl + ntpq + # First we try to identify if we're beholden to systemd if inpath systemctl; then - # First we try with timedatectl - get_timesyncd - _timesync_rc="${?}" - - # If we don't get a success from get_timesyncd, we try ntpq - if [ "${_timesync_rc}" -gt 0 ]; then - # shellcheck disable=SC2016 - if [ "$(systemctl | awk '/ntp.service|ntpd.service/{print $3; exit}')" = "active" ]; then - # remove heading, make first column space separated - run_cached -s ntp 30 "waitmax 5 get_ntpq" - fi + # shellcheck disable=SC2016 + if [ "$(systemctl | awk '/ntp.service|ntpd.service/{print $3; exit}')" = "active" ]; then + # remove heading, make first column space separated + run_cached -s ntp 30 "waitmax 5 get_ntpq" fi - unset -v _timesync_rc # Return to leave the function with no further processing return fi - # If we get to this point, we attempt via classic ntp daemons (ntpq required) - if inpath ntpq; then - case "${MK_OSSTR}" in - (aix) - [ "$(lssrc -s xntpd|grep -c active)" -gt 0 ] && get_ntpq --header - ;; - (solaris) - # 'pgrep' does not work well in this case - ps -o comm "${pszone}" | grepq -w ".*ntpd" && get_ntpq --header - ;; - (linux|*) - # Try to determine status via /etc/init.d - # This might also be appropriate for AIX, Solaris and others - for _ntp_daemon in ntp ntpd openntpd; do - # Check for a service script - if [ -x /etc/init.d/"${_ntp_daemon}" ]; then - # If the status returns 0, we assume we have a running service - if /etc/init.d/"${_ntp_daemon}" status >/dev/null 2>&1; then - run_cached -s ntp 30 "waitmax 5 get_ntpq" - fi + # If we get to this point, we attempt to test classic ntp daemons + case "${MK_OSSTR}" in + (aix) + [ "$(lssrc -s xntpd|grep -c active)" -gt 0 ] && get_ntpq --header + ;; + (solaris) + # 'pgrep' does not work well in this case + ps -o comm "${pszone}" | grepq -w ".*ntpd" && get_ntpq --header + ;; + (linux|*) + # Try to determine status via /etc/init.d + # This might also be appropriate for AIX, Solaris and others + for _ntp_daemon in ntp ntpd openntpd; do + # Check for a service script + if [ -x /etc/init.d/"${_ntp_daemon}" ]; then + # If the status returns 0, we assume we have a running service + if /etc/init.d/"${_ntp_daemon}" status >/dev/null 2>&1; then + run_cached -s ntp 30 "waitmax 5 get_ntpq" fi - done - unset -v _ntp_daemon - ;; - esac - fi + fi + done + unset -v _ntp_daemon + ;; + esac + } section_nvidia() { @@ -2557,6 +2543,16 @@ section_thermal() { fi } +# Function to pull timesync information via timedatectl (if possible) +section_timesyncd() { + inpath timedatectl || return 1 + timedatectl timesync-status >/dev/null 2>&1 || return 1 + mkecho "<<>>" + timedatectl timesync-status + get_file_mtime /var/lib/systemd/timesync/clock | awk '{print "[[["$1"]]]"}' + return 0 +} + # Libelle Business Shadow section_trd() { if inpath trd; then @@ -2784,7 +2780,12 @@ main() { section_net section_netctr section_tcp_stats + section_timesyncd + # Grab the exit code from 'section_timesyncd()' as this determines 'section_ntp()'s behaviour + # Our goal here is to avoid multiple outputs e.g. timedatectl + ntpq + timesync_rc="${?}" section_ntp + unset -v timesync_rc section_chrony section_mail section_uptime From e25cde88060bb0d8a1319800fdb74ce352d40828 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Sat, 25 Jan 2020 10:28:36 +1300 Subject: [PATCH 17/29] Promote 'get_ntpq()' to toplevel --- agents/check_mk_agent.merged | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index f6c533f1d58..a6696042728 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -404,6 +404,14 @@ get_nfs_mounts() { fi } +# Helper function for 'section_ntp()' +get_ntpq() { + # If 'ntpq' isn't in PATH, there's no point going further + inpath ntpq || return 1 + [ "${1}" = "--header" ] && mkecho '<<>>' + ntpq -np | sed -e 1,2d -e 's/^\\(.\\)/\\1 /' -e 's/^ /%/' || true +} + # In theory, this is how these functions should work: # If the GNU stat approach fails, its failure will be silenced # and the BSD stat approach will be tried. Failing that, it's perl to the rescue. @@ -1887,20 +1895,15 @@ section_nfs() { unset mountPoint statFmt } +# Requires 'get_ntpq()' section_ntp() { # If '${timesync_rc}' is 0, then 'section_timesyncd()' has returned successfully in - # which case we do not want to proceed with ntpq, so return and skip further processing + # which case we do not want to proceed with 'ntpq', so return and skip further processing [ "${timesync_rc}" -eq 0 ] && return 0 - # If ntpq isn't in PATH, there's no point going further + # If 'ntpq' isn't in PATH, there's no point going further inpath ntpq || return 1 - # If we get to this point, declare our ntpq helper function - get_ntpq() { - [ "${1}" = "--header" ] && mkecho '<<>>' - ntpq -np | sed -e 1,2d -e 's/^\\(.\\)/\\1 /' -e 's/^ /%/' || true - } - # First we try to identify if we're beholden to systemd if inpath systemctl; then # shellcheck disable=SC2016 @@ -1936,7 +1939,6 @@ section_ntp() { unset -v _ntp_daemon ;; esac - } section_nvidia() { From 76ca967e7dd8911f5274392c633090f7cd77c218 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Tue, 3 Mar 2020 22:40:22 +1300 Subject: [PATCH 18/29] Merge in latest tranche of changes to various *nix agents --- agents/check_mk_agent.merged | 143 +++++++++++++++++++++++++++-------- 1 file changed, 113 insertions(+), 30 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index a6696042728..1f041e32a69 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -386,6 +386,47 @@ if stat --version 2>&1 | head -n 1 | grepq "5.3.0"; then } fi +# Expected format example: "Nov 10 2034 21:19:01" +convert_time_to_epoch() { + month day timestamp year hours min sec + + # Read our incoming date/time information into our variables + mkecho "${*:?No date provided}" | read -r month day year timestamp + mkecho "${timestamp}" | IFS=':' read -r hours min sec + + # Convert the month to 0..11 range + case "${month}" in + ([jJ]an*) month=0 ;; + ([fF]eb*) month=1 ;; + ([mM]ar*) month=2 ;; + ([aA]pr*) month=3 ;; + ([mM]ay) month=4 ;; + ([jJ]un*) month=5 ;; + ([jJ]ul*) month=6 ;; + ([aA]ug*) month=7 ;; + ([sS]ep*) month=8 ;; + ([oO]ct*) month=9 ;; + ([nN]ov*) month=10 ;; + ([dD]ec*) month=11 ;; + esac + + # Pass our variables to the mighty 'perl' + perl -e 'use Time::Local; print timegm(@ARGV[0,1,2,3,4], $ARGV[5]-1900)."\n";' "${sec}" "${min}" "${hours}" "${day}" "${month}" "${year}" +} + +# Calculate how many days until the cert expires +# Short circuit versions of 'date' that don't support '-d' (e.g. Solaris) +# In this instance, we want to call 'convert_time_to_epoch()' +if date -d yesterday 2>&1 | grep illegal >/dev/null 2>&1; then + calculate_cert_epoch() { + convert_time_to_epoch "$(read_cert_expiry "${1:?No Cert Defined}")" + } +else + calculate_cert_epoch() { + date -d "$(read_cert_expiry "${1:?No Cert Defined}")" +%s + } +fi + # Function to list CIFS mounts for use by section_nfs get_cifs_mounts() { if [ -r /proc/mounts ]; then @@ -1958,69 +1999,111 @@ section_omd() { # mkecho '{"cmk/check_mk_server": "yes"}' mkecho -j "cmk/check_mk_server" "yes" - run_cached omd_status 60 "omd status --bare --auto || true" + run_cached omd_status 60 "omd status --bare || true" mkecho '<<>>' get_epoch - for statefile in /omd/sites/*/var/log/mknotifyd.state; do - if [ -e "$statefile" ]; then - site=${statefile%/var/log*} - site=${site#/omd/sites/} - mkecho "[$site]" - grep -v '^#' <"$statefile" + for _statefile in /omd/sites/*/var/log/mknotifyd.state; do + if [ -e "${_statefile}" ]; then + _site=${_statefile%/var/log*} + _site=${_site#/omd/sites/} + mkecho "[${_site}]" + grep -v '^#' <"${_statefile}" fi + unset -v _site done mkecho '<<>>' - for statsfile in /omd/sites/*/var/log/apache/stats; do - if [ -e "$statsfile" ]; then - site=${statsfile%/var/log*} - site=${site#/omd/sites/} - mkecho "[$site]" - cat "$statsfile" - : >"$statsfile" + for _statsfile in /omd/sites/*/var/log/apache/stats; do + if [ -e "${_statsfile}" ]; then + _site=${_statsfile%/var/log*} + _site=${_site#/omd/sites/} + mkecho "[${_site}]" + cat "${_statsfile}" + : >"${_statsfile}" # prevent next section to fail caused by a missing newline at the end of the statsfile mkecho fi + unset -v _site done fi + mkecho '<<>>' + mkecho '[versions]' + mkecho 'version;number;edition;demo' + for _versiondir in /omd/versions/*; do + _omd_version=${_versiondir#/omd/versions/} + + # filter out special directory 'default' + [ "${_omd_version}" = "default" ] && continue + + _omd_number="${_omd_version}" + _omd_demo="0" + case "${_omd_version}" in + (*.demo) + _omd_number=${_omd_version%.demo} + _omd_demo="1" + ;; + esac + _omd_edition=${_omd_number##*.} + _omd_number=${_omd_number%.*} + mkecho "${_omd_version};${_omd_number};${_omd_edition};${_omd_demo}" + done + mkecho '[sites]' + mkecho 'site;used_version;autostart' + for _sitedir in /omd/sites/*; do + _site=${_sitedir#/omd/sites/} + _used_version=$(readlink "${_sitedir}"/version) + _used_version=${_used_version##*/} + _autostart="0" + if grepq "CONFIG_AUTOSTART[[:blank:]]*=[[:blank:]]*'on'" "${_sitedir}"/etc/omd/site.conf; then + _autostart="1" + fi + mkecho "${_site};${_used_version};${_autostart}" + done + # Get stats about OMD monitoring cores running on this machine. # Since cd is a shell builtin the check does not affect the performance # on non-OMD machines. if cd /omd/sites; then mkecho '<<>>' - for site in *; do - if [ -S "/omd/sites/$site/tmp/run/live" ]; then - mkecho "[$site]" + for _site in *; do + if [ -S "/omd/sites/${_site}/tmp/run/live" ]; then + mkecho "[${_site}]" # shellcheck disable=SC2039 mkecho -e "GET status" | - waitmax 3 "/omd/sites/$site/bin/unixcat" "/omd/sites/$site/tmp/run/live" + waitmax 3 "/omd/sites/${_site}/bin/unixcat" "/omd/sites/${_site}/tmp/run/live" fi done mkecho '<<>>' - for site in *; do - mkecho "[$site]" - for PEM_PATH in "/omd/sites/$site/etc/ssl/ca.pem" "/omd/sites/$site/etc/ssl/sites/$site.pem"; do - if [ -f "$PEM_PATH" ]; then - CERT_DATE=$(openssl x509 -enddate -noout -in "$PEM_PATH") + for _site in *; do + mkecho "[${_site}]" + for _pem_path in "/omd/sites/${_site}/etc/ssl/ca.pem" "/omd/sites/${_site}/etc/ssl/sites/${_site}.pem"; do + if [ -f "${_pem_path}" ]; then + _cert_date=$( + openssl x509 -enddate -noout -in "${_pem_path}" | + sed -e "s/^notAfter=//" -e "s/GMT//" | + awk '{printf("%s %02d %d %s\n", $1,$2,$4,$3)}' + ) # TO-DO: Confirm that this works - CERT_DATE=$(mkecho "${CERT_DATE}" | sed 's/notAfter=//g') - mkecho "$PEM_PATH|$(date --date="$CERT_DATE" --utc +%s)" + mkecho "${_pem_path}|$(calculate_cert_epoch "${_cert_date}")" fi done done mkecho '<<>>' - for site in *; do - if [ -S "/omd/sites/$site/tmp/run/mkeventd/status" ]; then - mkecho "[\"$site\"]" + for _site in *; do + if [ -S "/omd/sites/${_site}/tmp/run/mkeventd/status" ]; then + mkecho "[\"${_site}\"]" # shellcheck disable=SC2039 mkecho -e "GET status\\nOutputFormat: json" | - waitmax 3 "/omd/sites/$site/bin/unixcat" "/omd/sites/$site/tmp/run/mkeventd/status" + waitmax 3 "/omd/sites/${_site}/bin/unixcat" "/omd/sites/${_site}/tmp/run/mkeventd/status" fi done fi + + unset -v _autostart _site _sitedir _statefile _statsfile _used_version _versiondir + unset -v _omd_demo _omd_edition _omd_number _omd_site _omd_version } section_openvpn() { @@ -2217,7 +2300,7 @@ section_raid() { done mkecho lsicli -PDList -aALL -NoLog >>' lsicli -LDInfo -Lall -aALL -NoLog >>' From 1baf57384b3d27866961970b38ac7d52e245248f Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Tue, 10 Mar 2020 16:20:39 +1300 Subject: [PATCH 19/29] Update license header and correct perl block --- agents/check_mk_agent.merged | 29 +++++------------------------ 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index 1f041e32a69..8c7cf40ad5d 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -1,29 +1,9 @@ #!/bin/sh # vim: noai:ts=4:sw=4:expandtab -# Check_MK Agent for UNIX/Linux systems -# +------------------------------------------------------------------+ -# | ____ _ _ __ __ _ __ | -# | / ___| |__ ___ ___| | __ | \/ | |/ / | -# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / | -# | | |___| | | | __/ (__| < | | | | . \ | -# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ | -# | | -# | Copyright Mathias Kettner 2014 mk@mathias-kettner.de | -# +------------------------------------------------------------------+ -# -# This file is part of Check_MK. -# The official homepage is at https://checkmk.com/. -# -# check_mk is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation in version 2. check_mk is distributed -# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with- -# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. See the GNU General Public License for more de- -# tails. You should have received a copy of the GNU General Public -# License along with GNU Make; see the file COPYING. If not, write -# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -# Boston, MA 02110-1301 USA. + +# Copyright (C) 2019 tribe29 GmbH - License: GNU General Public License v2 +# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and +# conditions defined in the file COPYING, which is part of this source code package. # Remove locale settings to eliminate localized outputs where possible # The locale logic here is used to make the Python encoding detection @@ -1075,6 +1055,7 @@ section_drbd() { section_fileinfo() { # Fileinfo-Check: put patterns for files into /etc/check_mk/fileinfo.cfg perl -e ' + use File::Glob "bsd_glob"; my @patterns = (); foreach (bsd_glob("$ARGV[0]/fileinfo.cfg"), bsd_glob("$ARGV[0]/fileinfo.d/*")) { open my $handle, "<", $_ or next; From 6c191a8e6dc92ea57ec710723756088c092bfb67 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Fri, 15 May 2020 12:01:01 +1200 Subject: [PATCH 20/29] Update merged script, include var_* functions and mac improvements --- agents/check_mk_agent.merged | 1279 +++++++++++++++++++--------------- 1 file changed, 699 insertions(+), 580 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index 8c7cf40ad5d..d8201563dbb 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -6,14 +6,21 @@ # conditions defined in the file COPYING, which is part of this source code package. # Remove locale settings to eliminate localized outputs where possible -# The locale logic here is used to make the Python encoding detection -# work (see CMK-2778). -MK_LOCALE=$(locale -a |grep -E '^C$|^C.UTF-8$|^c.utf8$' | head -n 1) -if [ -z "${MK_LOCALE}" ]; then - LC_ALL="${MK_LOCALE}" - export LC_ALL -fi -unset LANG +# The locale logic here is used to make the Python encoding detection work (see CMK-2778). +unset -v LANG +case "$(locale -a | paste -sd ' ' -)" in + (*'C.UTF-8'*) LC_ALL="C.UTF-8" ;; + (*'c.utf-8'*) LC_ALL="c.utf-8" ;; + (*'C'*|*) LC_ALL="C" ;; +esac +LC_ALL="${LC_ALL:-C}" +export LC_ALL + +# Set these helper functions early so that they can assist with init +var_is_set() { [ "${1+x}" = "x" ] && [ "${#1}" -gt "0" ]; } # set and not null +var_is_unset() { [ -z "${1+x}" ]; } # unset +var_is_empty() { [ "${1+x}" = "x" ] && [ "${#1}" -eq "0" ]; } # set and null +var_is_blank() { var_is_unset "${1}" || var_is_empty "${1}"; } # unset, or set and null # Close standard input (for security reasons) and stderr when not explicitly in debug mode. # When the nodes agent is executed by a e.g. docker node in a container, @@ -46,13 +53,13 @@ PATH="${newPath#:}" export PATH unset -v newPath -# 'mkecho()' abstracts the portability of 'printf' and solves the major +# 'println()' abstracts the portability of 'printf' and solves the major # portability headaches caused by various implementations of 'echo' -# This is called 'mkecho()' rather than an 'echo()' override because +# This is called 'println()' rather than an 'echo()' override because # some shells protect their builtins, denying us the override cleanliness # Fun exercise: look at Oracle's man page for 'echo', specifically the USAGE section. # This also adds the '-j' option to output in json keypair format -mkecho() { +println() { case "${1}" in (-e) case "${2}" in @@ -83,7 +90,7 @@ mkecho() { # Functionalise and standardise 'quiet grep' based tests. # This gives us 'grep -q' cleanliness where '>/dev/null 2>&1' # would otherwise be required e.g. Solaris, older versions of grep etc -if mkecho "word" | grep -q "word" >/dev/null 2>&1; then +if println "word" | grep -q "word" >/dev/null 2>&1; then grepq() { grep -q "$@" 2>/dev/null; } else grepq() { grep "$@" >/dev/null 2>&1; } @@ -100,23 +107,23 @@ inpath() { # If EUID isn't set, then set it # Note that 'id -u' is now mostly portable here due to the alignment of xpg4 above # '[ -w / ]' may be an alternative test for proving root privileges... -if [ -z "${EUID}" ]; then +if var_is_unset "${EUID}"; then EUID=$(id -u); readonly EUID; export EUID fi # If HOSTNAME isn't set, then set it -if [ -z "${HOSTNAME}" ]; then +if var_is_unset "${HOSTNAME}"; then HOSTNAME=$(hostname); readonly HOSTNAME; export HOSTNAME fi # If HOME isn't set, then set it -if [ -z "${HOME}" ]; then +if var_is_unset "${HOME}"; then HOME=$(getent passwd | awk -F':' -v EUID="${EUID}" '$3 == EUID{print $6}') readonly HOME; export HOME fi # If USER isn't set, then set it -if [ -z "${USER}" ]; then +if var_is_unset "${USER}"; then USER=$(getent passwd | awk -F':' -v EUID="${EUID}" '$3 == EUID{print $1}') readonly USER; export USER fi @@ -133,7 +140,7 @@ fi # Newer shells like zsh and bash5.x have EPOCHSECONDS. If it's not available, we set it # Note that if this is set here, it will not update each time it's used # Use get_epoch() if you need that kind of accuracy -if [ -z "${EPOCHSECONDS}" ]; then +if var_is_unset "${EPOCHSECONDS}"; then EPOCHSECONDS=$(get_epoch); readonly EPOCHSECONDS; export EPOCHSECONDS fi @@ -164,7 +171,7 @@ get_shell() { } # If SHELL isn't set, then set it. -if [ -z "${SHELL}" ]; then +if var_is_unset "${SHELL}"; then if get_shell >/dev/null 2>&1; then SHELL=$(command -v "$(get_shell)"); readonly SHELL; export SHELL fi @@ -262,6 +269,18 @@ MK_LOCALDIR="${MK_LIBDIR}"/local # output if they are not outdated (see below) MK_SPOOLDIR="${MK_VARDIR:?}"/spool +# Now we load our configuration files +# shellcheck source=/dev/null +{ + chmod 640 "${MK_CONFDIR}"/* 2>/dev/null + [ -r "${MK_CONFDIR}/agent.cfg" ] && . "${MK_CONFDIR}/agent.cfg" + [ -r "${MK_CONFDIR}/encryption.cfg" ] && . "${MK_CONFDIR}/encryption.cfg" + [ -r "${MK_CONFDIR}/exclude_sections.cfg" ] && . "${MK_CONFDIR}/exclude_sections.cfg" + RTC_PLUGINS="" # Is this still necessary? + # This provides RTC_TIMEOUT, RTC_PORT, RTC_SECRET and RTC_SECTIONS + [ -r "${MK_CONFDIR}/real_time_checks.cfg" ] && . "${MK_CONFDIR}/real_time_checks.cfg" +} + # Protect all our MK variables readonly MK_OSSTR MK_LIBDIR MK_CONFDIR MK_VARDIR MK_VERSION readonly MK_PLUGINSDIR MK_LOCALDIR MK_SPOOLDIR MK_TMPDIR @@ -302,20 +321,21 @@ esac # "check-mk-agent" or the name set by the "name of agent packages" rule XINETD_SERVICE_NAME=check_mk -# Detect whether or not the agent is being executed in a container -# environment. -if [ -f /.dockerenv ]; then - MK_IS_DOCKERIZED=1 -elif grepq container=lxc /proc/1/environ; then - # Works in lxc environment e.g. on Ubuntu bionic, but does not - # seem to work in proxmox (see CMK-1561) - MK_IS_LXC_CONTAINER=1 -elif grepq 'lxcfs /proc/cpuinfo fuse.lxcfs' /proc/mounts; then - # Seems to work in proxmox - MK_IS_LXC_CONTAINER=1 -else - unset -v MK_IS_DOCKERIZED - unset -v MK_IS_LXC_CONTAINER +# Detect whether or not the agent is being executed in a container environment. +if var_is_blank "${MK_IS_DOCKERIZED}" || var_is_blank "${MK_IS_LXC_CONTAINER}"; then + if [ -f /.dockerenv ]; then + MK_IS_DOCKERIZED=1 + elif grepq container=lxc /proc/1/environ; then + # Works in lxc environment e.g. on Ubuntu bionic, but does not + # seem to work in proxmox (see CMK-1561) + MK_IS_LXC_CONTAINER=1 + elif grepq 'lxcfs /proc/cpuinfo fuse.lxcfs' /proc/mounts; then + # Seems to work in proxmox + MK_IS_LXC_CONTAINER=1 + else + unset -v MK_IS_DOCKERIZED + unset -v MK_IS_LXC_CONTAINER + fi fi # Load our variables for encrypted data. See protect_output() @@ -340,27 +360,64 @@ fi # Provide information about the remote host. That helps when data # is being sent only once to each remote host. -if [ "${REMOTE_HOST}" ]; then +if var_is_set "${REMOTE_HOST}"; then MK_RTC_HOST="${REMOTE_HOST}" export MK_RTC_HOST -elif [ "${SSH_CLIENT}" ]; then +elif var_is_set "${SSH_CLIENT}"; then MK_RTC_HOST="${SSH_CLIENT%% *}" export MK_RTC_HOST fi # If we are called via xinetd, try to find only_from configuration -if [ -n "${REMOTE_HOST}" ]; then +if var_is_set "${REMOTE_HOST}"; then # shellcheck disable=SC2039 - mkecho -n 'OnlyFrom: ' + println -n 'OnlyFrom: ' sed -n '/^service[[:space:]]*'$XINETD_SERVICE_NAME'/,/}/s/^[[:space:]]*only_from[[:space:]]*=[[:space:]]*\(.*\)/\1/p' /etc/xinetd.d/* | head -n1 - mkecho + println fi -# 'coreutils' 5.3.0 broke how 'stat' handled its output. This was reverted -# in STABLE in 5.9.4. Just in case we happen across this version -# we catch it and build a workaround to correct its behaviour +# Convert a three number style semantic version number to an integer for version comparisons +# This zero pads, to double digits, the second and third numbers and removes any non-numerical chars +# e.g. 'openssl 1.0.2k-fips' -> '10002' +semver_to_int() { + _sem_ver="${1:?No version number supplied}" + + # Strip the variable of any non-numerics or dots + _sem_ver="$(println "${_sem_ver}" | sed 's/[^0-9.]//g')" + + # Swap the dots for spaces and assign the outcome to the positional param array + # We want word splitting here, so we disable shellcheck's complaints + # shellcheck disable=SC2046 + set -- $(println "${_sem_ver}" | tr '.' ' ') + + # Assemble and print our integer + printf -- '%d%02d%02d' "${1}" "${2:-0}" "${3:-0}" + + unset -v _sem_ver +} + +# GNU 'coreutils' 5.3.0 broke how 'stat' handled line endings in its output. +# This was corrected somewhere around 5.92 - 5.94 STABLE. +# If we detect a version of GNU stat 5.x, we investigate and set MK_STAT_BUG # See: https://lists.gnu.org/archive/html/bug-coreutils/2005-12/msg00157.html -if stat --version 2>&1 | head -n 1 | grepq "5.3.0"; then +if var_is_blank "${MK_STAT_BUG}"; then + # We only care about versions in the range [ 5.3.0 .. 5.94 ] (yes different numbering schemes) + if stat --version 2>&1 | grepq "GNU.*5.[3-9]"; then + # Convert the version information from semantic versioning to an integer + stat_version=$(semver_to_int "$(stat --version 2>&1 | head -n 1)") + if [ "${stat_version}" -ge 50300 ] && [ "${stat_version}" -lt 59400 ]; then + MK_STAT_BUG="true" + else + MK_STAT_BUG="false" + fi + readonly MK_STAT_BUG + export MK_STAT_BUG + fi + +fi + +# If MK_STAT_BUG is true, we correct 'stat's behaviour globally +if [ "${MK_STAT_BUG}" = "true" ]; then stat() { printf -- '%s\n' "$(command stat "${@}")" } @@ -368,30 +425,30 @@ fi # Expected format example: "Nov 10 2034 21:19:01" convert_time_to_epoch() { - month day timestamp year hours min sec - - # Read our incoming date/time information into our variables - mkecho "${*:?No date provided}" | read -r month day year timestamp - mkecho "${timestamp}" | IFS=':' read -r hours min sec - - # Convert the month to 0..11 range - case "${month}" in - ([jJ]an*) month=0 ;; - ([fF]eb*) month=1 ;; - ([mM]ar*) month=2 ;; - ([aA]pr*) month=3 ;; - ([mM]ay) month=4 ;; - ([jJ]un*) month=5 ;; - ([jJ]ul*) month=6 ;; - ([aA]ug*) month=7 ;; - ([sS]ep*) month=8 ;; - ([oO]ct*) month=9 ;; - ([nN]ov*) month=10 ;; - ([dD]ec*) month=11 ;; - esac - - # Pass our variables to the mighty 'perl' - perl -e 'use Time::Local; print timegm(@ARGV[0,1,2,3,4], $ARGV[5]-1900)."\n";' "${sec}" "${min}" "${hours}" "${day}" "${month}" "${year}" + # Read our incoming date/time information into our variables + _month="${1:?No date provided}"; _day="${2}"; _year="${3}"; _timestamp="${4}" + println "${_timestamp}" | while IFS=':' read -r _hours _min _sec; do + # Convert the month to 0..11 range + case "${_month}" in + ([jJ]an*) _month=0 ;; + ([fF]eb*) _month=1 ;; + ([mM]ar*) _month=2 ;; + ([aA]pr*) _month=3 ;; + ([mM]ay) _month=4 ;; + ([jJ]un*) _month=5 ;; + ([jJ]ul*) _month=6 ;; + ([aA]ug*) _month=7 ;; + ([sS]ep*) _month=8 ;; + ([oO]ct*) _month=9 ;; + ([nN]ov*) _month=10 ;; + ([dD]ec*) _month=11 ;; + esac + + # Pass our variables to the mighty 'perl' + perl -e 'use Time::Local; print timegm(@ARGV[0,1,2,3,4], $ARGV[5]-1900)."\n";' \ + "${_sec}" "${_min}" "${_hours}" "${_day}" "${_month}" "${_year}" + done + unset -v _sec _min _hours _day _month _year _timestamp } # Calculate how many days until the cert expires @@ -429,7 +486,7 @@ get_nfs_mounts() { get_ntpq() { # If 'ntpq' isn't in PATH, there's no point going further inpath ntpq || return 1 - [ "${1}" = "--header" ] && mkecho '<<>>' + [ "${1}" = "--header" ] && println '<<>>' ntpq -np | sed -e 1,2d -e 's/^\\(.\\)/\\1 /' -e 's/^ /%/' || true } @@ -459,23 +516,17 @@ get_file_mtime() { # does not have certain patterns within its name is_valid_plugin() { case "${1:?No plugin defined}" in - (*dpkg-new|*dpkg-old|*dpkg-temp) - return 1 - ;; - (*) - if [ -x "${1}" ]; then - return 0 - else - return 1 - fi - ;; + (*dpkg-new) return 1 ;; + (*dpkg-old) return 1 ;; + (*dpkg-temp) return 1 ;; + (*) [ -x "${1}" ] && return "${?}" ;; esac } # Setup a function to encrypt the output using openssl protect_output() { if ! inpath openssl; then - mkecho "ERROR: protect_output(): 'openssl' not found in PATH" >&2 + println "ERROR: protect_output(): 'openssl' not found in PATH" >&2 return fi @@ -483,7 +534,7 @@ protect_output() { if [ "${1}" = "-rt" ]; then # Let's see if RTC_SECRET is defined if [ ! -r "${MK_CONFDIR}/real_time_checks.cfg" ]; then - mkecho "ERROR: protect_output(): Unable to read real_time_checks.cfg" + println "ERROR: protect_output(): Unable to read real_time_checks.cfg" return fi # If we have a defined RTC_SECRET, then we prioritise that. @@ -496,7 +547,7 @@ protect_output() { fi # Convert the openssl version to an integer e.g. 1.0.2k-fips -> 10002 - _opensslVer=$(openssl version | awk '{print $2}' | awk -F . '{print (($1 * 100) + $2) * 100+ $3}') + _opensslVer=$(semver_to_int "$(openssl version | awk '{print $2}')") # shellcheck disable=SC2039 if [ "${_opensslVer}" -ge 10000 ]; then _encCode="02" @@ -508,9 +559,9 @@ protect_output() { # Print our protocol and/or epoch information if [ "${1}" = "-rt" ]; then - mkecho -n "${_encCode}$(get_epoch)" + println -n "${_encCode}$(get_epoch)" else - mkecho -n "${_encCode}" + println -n "${_encCode}" fi # Call openssl with our required digest and auth @@ -532,9 +583,7 @@ read_ipmi_sensors() { # Function to format the output of 'ipmitool' read_ipmitool() { - if ! inpath ipmitool; then - return 1 - fi + inpath ipmitool || return 1 case "${MK_OSSTR}" in (linux) ipmitool sensor list | @@ -611,7 +660,7 @@ run_cached() { _cached_name="${1}" _cached_maxage="${2}" - _cached_section="mkecho '<<<${_cached_name}:cached($(get_epoch),${_cached_maxage})>>>' ; " + _cached_section="println '<<<${_cached_name}:cached($(get_epoch),${_cached_maxage})>>>' ; " shift 2 _cached_cmd="${_cached_section}${*}" @@ -669,12 +718,12 @@ run_cached() { fi # Cache file outdated and new job not yet running? Start it - if [ -z "${_use_cachefile}" ] && [ ! -e "${_cached_file}".new ]; then + if var_is_unset "${_use_cachefile}" && [ ! -e "${_cached_file}".new ]; then # When the command fails, the output is throws away ignored if [ "${_cached_mrpe}" -eq 1 ]; then - mkecho "set -o noclobber ; exec > \"$_cached_file.new\" || exit 1 ; run_mrpe $_cached_name \"$_cached_cmd\" && mv \"$_cached_file.new\" \"$_cached_file\" || rm -f \"$_cached_file\" \"$_cached_file.new\"" | nohup /bin/bash >/dev/null 2>&1 & + println "set -o noclobber ; exec > \"$_cached_file.new\" || exit 1 ; run_mrpe $_cached_name \"$_cached_cmd\" && mv \"$_cached_file.new\" \"$_cached_file\" || rm -f \"$_cached_file\" \"$_cached_file.new\"" | nohup /bin/bash >/dev/null 2>&1 & else - mkecho "set -o noclobber ; exec > \"$_cached_file.new\" || exit 1 ; $_cached_cmd && mv \"$_cached_file.new\" \"$_cached_file\" || rm -f \"$_cached_file\" \"$_cached_file.new\"" | nohup /bin/bash >/dev/null 2>&1 & + println "set -o noclobber ; exec > \"$_cached_file.new\" || exit 1 ; $_cached_cmd && mv \"$_cached_file.new\" \"$_cached_file\" || rm -f \"$_cached_file\" \"$_cached_file.new\"" | nohup /bin/bash >/dev/null 2>&1 & fi fi unset -v _cached_section _cached_mrpe _cached_append_age _cached_name _cached_maxage _cached_cmd @@ -707,7 +756,7 @@ case $(waitmax 1 bash -c ": &1") in unset -v _bin_nc } else - mkecho "send_rtc(): Unable to determine communication method" >&2 + println "send_rtc(): Unable to determine communication method" >&2 fi ;; esac @@ -717,7 +766,7 @@ esac # detailed graphing (if you configure your RRDs to this resolution). run_real_time_checks() { _rt_pid=${MK_VARDIR:?}/real_time_checks.pid - mkecho "$$" >"${_rt_pid}" + println "$$" >"${_rt_pid}" while true; do # terminate when pidfile is gone or other Real-Time Check process started or configured timeout @@ -736,7 +785,7 @@ run_real_time_checks() { # protect_output() takes care of printing our protocol and epoch info section_"${_rt_section}" | protect_output -rt else - mkecho -n "99$(get_epoch)" + println -n "99$(get_epoch)" section_"${_rt_section}" fi } | dd bs=9999 iflag=fullblock 2>/dev/null | send_rtc "${MK_RTC_HOST}" "${RTC_PORT}" @@ -752,7 +801,7 @@ run_real_time_checks() { if [ "${ENCRYPTED_RT}" != "no" ]; then ./"${_rt_plugin}" | protect_output -rt else - mkecho -n "99$(get_epoch)" + println -n "99$(get_epoch)" ./"${_rt_plugin}" fi } | dd bs=9999 iflag=fullblock 2>/dev/null | send_rtc "${MK_RTC_HOST}" "${RTC_PORT}" @@ -769,57 +818,90 @@ run_real_time_checks() { #################################################################################################### # CHECK SECTIONS +# RAID status of 3WARE disk controller (by Radoslaw Bak) +section_3ware_raid() { + if inpath tw_cli; then + for _tw_ctl in $(tw_cli show | awk 'NR < 4 { next } { print $1 }'); do + println '<<<3ware_info>>>' + tw_cli "/${_tw_ctl}" show all | grep -E 'Model =|Firmware|Serial' + println '<<<3ware_disks>>>' + tw_cli "/${_tw_ctl}" show drivestatus | grep -E 'p[0-9]' | sed "s/^/${_tw_ctl}\\//" + println '<<<3ware_units>>>' + tw_cli "/${_tw_ctl}" show unitstatus | grep -E 'u[0-9]' | sed "s/^/${_tw_ctl}\\//" + done + unset -v _tw_ctl + fi +} + # TO-DO: Determine if any of these can be merged into other functions section_aix() { if inpath lparstat; then - mkecho '<<>>' + println '<<>>' lparstat 1 1 fi # powerHA if inpath lslpp; then _cluster_cmd_output=$(lslpp -l cluster.es.server.rte) - if ! mkecho "${_cluster_cmd_output}" | grepq "not installed"; then + if ! println "${_cluster_cmd_output}" | grepq "not installed"; then # now the following commands should be available _nodes=$(cllsnode | grep "NODE" | sed -e s/NODE//g -e s/://g) _list_active_nodes="" for _node in ${_nodes}; do _active_nodes=$(clgetactivenodes -n "${_node}") - if mkecho "${_active_nodes}" | grepq "${_node}"; then + if println "${_active_nodes}" | grepq "${_node}"; then _list_active_nodes=${_list_active_nodes}"\\n${_node}" fi done if [ "${_list_active_nodes}" ]; then - mkecho '<<>>' + println '<<>>' # shellcheck disable=SC2039 - mkecho -e "${_list_active_nodes}" + println -e "${_list_active_nodes}" cllsnode fi - mkecho '<<>>' + println '<<>>' if inpath clshowsrv ; then waitmax 5 clshowsrv -v else # fallback, hardcoded base installation path waitmax 5 /usr/es/sbin/cluster/utilities/clshowsrv -v fi - mkecho '<<>>' + println '<<>>' waitmax 5 clRGinfo -s unset -v _cluster_cmd_output _nodes _list_active_nodes _node _active_nodes fi fi - mkecho '<<>>' + println '<<>>' mpstat -a | tail -n1 - mkecho '<<>>' + println '<<>>' # -L disables LVM lock for the query. Avoids blocking while LVM is # doing changes. For rootvg that is fine. lsvg -L -l rootvg } +# RAID controllers from areca (Taiwan) +# cli64 can be found at ftp://ftp.areca.com.tw/RaidCards/AP_Drivers/Linux/CLI/ +section_areca_raid() { + if inpath cli64; then + run_cached arc_raid_status 300 "cli64 rsf info | tail -n +3 | head -n -2" + fi +} + +# RAID status of LSI controllers via cfggen +section_cfggen() { + if inpath cfggen; then + println '<<>>' + cfggen 0 DISPLAY | + grep -E '(Target ID|State|Volume ID|Status of volume)[[:space:]]*:' | + sed -e 's/ *//g' -e 's/:/ /' + fi +} + # Function to pull timesync information from chrony section_chrony() { # The "| cat" has been added for some kind of regression in RedHat 7.5. The @@ -836,22 +918,22 @@ section_cpu() { case "${MK_OSSTR}" in (aix) # CPU output of Linux agent simulated (thanks to Cameron Pierce) - mkecho '<<>>' + println '<<>>' _load=$(uptime|sed -e 's;.*average: \([[:digit:]]\{1,\}\.[[:digit:]]\{1,\}\), \([[:digit:]]\{1,\}\.[[:digit:]]\{1,\}\), \([[:digit:]]\{1,\}\.[[:digit:]]\{1,\}\);\1 \2 \3;') _ps=$(ps -eo thcount | awk '{SUM+=$1} END {print SUM}') _procs=$(vmstat|grep lcpu|sed -e 's;.*lcpu=\([[:digit:]]\{1,4\}\).*;\1;') - mkecho "${_load} 1/${_ps} $$ ${_procs}" + println "${_load} 1/${_ps} $$ ${_procs}" unset -v _load _ps _procs ;; (freebsd) - mkecho '<<>>' + println '<<>>' sysctl -n vm.loadavg | tr -d '{}' top -b -n 1 | grep -E '^[0-9]+ processes' | awk '{print $3"/"$1}' sysctl -n kern.lastpid sysctl -n hw.ncpu ;; (hpux) - mkecho '<<>>' + println '<<>>' uptime # machinfo is unsupported addon thus not in $PATH /usr/contrib/bin/machinfo | grep -E 'logical proc|core' | tail -1 @@ -864,44 +946,44 @@ section_cpu() { fi _num_cpus=$(grep -c -E ${_cpu_regex} >>' - mkecho "$(cat /proc/loadavg) $_num_cpus" + if var_is_unset "${MK_IS_DOCKERIZED}" && var_is_unset "${MK_IS_LXC_CONTAINER}"; then + println '<<>>' + println "$(cat /proc/loadavg) $_num_cpus" if [ -f "/proc/sys/kernel/threads-max" ]; then cat /proc/sys/kernel/threads-max fi else - if [ -n "${MK_IS_DOCKERIZED}" ]; then - mkecho '<<>>' + if var_is_set "${MK_IS_DOCKERIZED}"; then + println '<<>>' else - mkecho '<<>>' + println '<<>>' fi grep "^cpu " /proc/stat - mkecho "num_cpus ${_num_cpus}" + println "num_cpus ${_num_cpus}" cat /sys/fs/cgroup/cpuacct/cpuacct.stat fi unset -v _cpu_regex _num_cpu ;; (mac) - mkecho '<<>>' + println '<<>>' sysctl -n vm.loadavg | tr -d '{}' top -l 1 -n 1 | grep -E '^Processes:' | awk '{$4"/"$2;}' - mkecho 'mkecho $$' | bash + println 'println $$' | bash sysctl -n hw.ncpu ;; (netbsd|openbsd) - mkecho '<<>>' + println '<<>>' sysctl -n vm.loadavg | tr -d '{}' top -b -n 1 | grep -E '^[0-9]+ processes' | awk '{print $3"/"$1}' sysctl -n hw.ncpu ;; (solaris) # Simulated Output of Linux /proc/cpu - mkecho '<<>>' + println '<<>>' _load=$(uptime|sed -e 's;.*average: \([0-9]\{1,\}\.[0-9]\{1,\}\), \([0-9]\{1,\}\.[0-9]\{1,\}\), \([0-9]\{1,\}\.[0-9]\{1,\}\).*;\1 \2 \3;') _nthreads=$(($(ps -AL | wc -l))) _procs=$(($(psrinfo | wc -l))) - mkecho "${_load} 1/${_nthreads} $$ ${_procs}" + println "${_load} 1/${_nthreads} $$ ${_procs}" unset -v _load _nthreads _procs ;; esac @@ -924,18 +1006,18 @@ section_df() { /usr/opt/freeware/bin/df -PTlk ${_df_excludefs} | sed 1d # df inodes information - mkecho '<<>>' - mkecho '[df_inodes_start]' + println '<<>>' + println '[df_inodes_start]' # shellcheck disable=SC2086 /usr/opt/freeware/bin/df -PTli ${_df_excludefs} | sed 1d - mkecho '[df_inodes_end]' + println '[df_inodes_end]' else df -kP | sed 's/ / - /' | grep -v ^/proc | grep -v ^Filesystem | grep -v : fi unset -v _df_excludefs ;; (freebsd) - mkecho '<<>>' + println '<<>>' # no special zfs handling so far, the ZFS.pools plugin has been tested to # work on FreeBSD if df -T > /dev/null ; then @@ -951,58 +1033,56 @@ section_df() { # Filesystems. HP-UX does not provide a filesystem type. We assume # modern systems with vxfs only here. The filesystem type is currently # not used by the check anyway. - mkecho '<<>>' + println '<<>>' df -kP | sed 's/ / - /' | awk '/^(.*-.*)$/ { print $0 } /^([^-]+)$/ { printf $0 }' | grep -Ev "^/proc|^Filesystem|^/aha|:" ;; (linux) - if [ -n "${MK_IS_DOCKERIZED}" ]; then - return - fi + var_is_set "${MK_IS_DOCKERIZED}" && return # The exclusion list is getting a bit of a problem. # -l should hide any remote FS but seems to be all but working. _df_excludefs="-x smbfs -x cifs -x iso9660 -x udf -x nfsv4 -x nfs -x mvfs -x prl_fs -x squashfs -x devtmpfs" - if [ -z "${MK_IS_LXC_CONTAINER}" ]; then + if var_is_unset "${MK_IS_LXC_CONTAINER}"; then _df_excludefs="${_df_excludefs} -x zfs" fi - mkecho '<<>>' + println '<<>>' # shellcheck disable=SC2086 df -PTlk ${_df_excludefs} | sed 1d # df inodes information - mkecho '<<>>' - mkecho '[df_inodes_start]' + println '<<>>' + println '[df_inodes_start]' # shellcheck disable=SC2086 df -PTli ${_df_excludefs} | sed 1d - mkecho '[df_inodes_end]' + println '[df_inodes_end]' unset -v _df_excludefs ;; (mac) - mkecho '<<>>' + println '<<>>' df -kPT hfs,apfs | sed 1d | \ while read -r _df_dev _df_rest; do _df_type=$(diskutil info "${_df_dev}" | grep '^\s*Type' | cut -d: -f2 | tr -d '[:space:]') - mkecho "${_df_dev} ${_df_type} ${_df_rest}" + println "${_df_dev} ${_df_type} ${_df_rest}" done unset -v df_dev df_type df_rest ;; (netbsd|openbsd) - mkecho '<<>>' + println '<<>>' df -kPt ffs | sed -e 's/^\([^ ][^ ]*\) \(.*\)$/\1 ffs \2/' | sed 1d ;; (solaris) # Filesystem usage for UFS and VXFS - mkecho '<<>>' + println '<<>>' for _fs in ufs vxfs samfs lofs tmpfs; do df -l -k -F ${_fs} 2>/dev/null | sed 1d | grep -v "^[^ ]*/lib/[^ ]*\\.so\\.1 " | \ while read -r _Filesystem _kbytes _used _avail _capacity _Mountedon; do _kbytes=$((_used + _avail)) - mkecho "${_Filesystem} ${_fs} ${_kbytes} ${_used} ${_avail} ${_capacity} ${_Mountedon}" + println "${_Filesystem} ${_fs} ${_kbytes} ${_used} ${_avail} ${_capacity} ${_Mountedon}" done done unset -v _fs _Filesystem _kbytes _used _avail _capacity _Mountedon @@ -1013,41 +1093,61 @@ section_df() { section_diskstat() { # Performancecounter Platten - if [ -z "${MK_IS_DOCKERIZED}" ]&&[ -r "/proc/diskstats" ]; then - mkecho '<<>>' + if var_is_unset "${MK_IS_DOCKERIZED}" && [ -r "/proc/diskstats" ]; then + println '<<>>' get_epoch _grepFilter=" (x?[shv]d[a-z]*[0-9]*|cciss/c[0-9]+d[0-9]+|emcpower[a-z]+|dm-[0-9]+" _grepFilter="${_grepFilter}|VxVM.*|mmcblk.*|dasd[a-z]*|bcache[0-9]+|nvme[0-9]+n[0-9]+) " grep -E "${_grepFilter}" >>' - mkecho "[time]" + elif var_is_set "${MK_IS_DOCKERIZED}"; then + println '<<>>' + println "[time]" get_epoch for _ioFile in io_service_bytes io_serviced; do - mkecho "[${_ioFile}]" + println "[${_ioFile}]" cat "/sys/fs/cgroup/blkio/blkio.throttle.${_ioFile}" done - mkecho "[names]" + println "[names]" for _ioFile in /sys/block/*; do # shellcheck disable=SC2039 - mkecho "${_ioFile##*/} $(cat "${_ioFile}/dev")" + println "${_ioFile##*/} $(cat "${_ioFile}/dev")" done unset -v _ioFile fi } +section_dm_raid() { + # RAID status of Linux RAID via device mapper + if inpath dmraid && _dmstatus=$(waitmax 3 dmraid -r); then + println '<<>>' + + # Output name and status + waitmax 20 dmraid -s | grep -e ^name -e ^status + + # Output disk names of the RAID disks + _disks=$(println "${_dmstatus}" | cut -f1 -d":") + + for _disk in ${_disks}; do + _device=$(cat /sys/block/"$(basename "${_disk}")"/device/model) + _status=$(println "${_dmstatus}" | grep "^${_disk}") + println "${_status} Model: ${_device}" + done + fi + unset -v _dmstatus _disks _disk _device _status +} + section_drbd() { - if [ -z "${MK_IS_DOCKERIZED}" ] && [ -z "${MK_IS_LXC_CONTAINER}" ] && [ -r /proc/drbd ]; then - mkecho '<<>>' + if var_is_unset "${MK_IS_DOCKERIZED}" && var_is_unset "${MK_IS_LXC_CONTAINER}" && [ -r /proc/drbd ]; then + println '<<>>' cat /proc/drbd fi } @@ -1090,8 +1190,8 @@ section_fileinfo() { section_haproxy() { for HAPROXY_SOCK in /run/haproxy/admin.sock /var/lib/haproxy/stats; do if [ -r "$HAPROXY_SOCK" ] && inpath socat; then - mkecho "<<>>" - mkecho "show stat" | socat - "UNIX-CONNECT:$HAPROXY_SOCK" + println "<<>>" + println "show stat" | socat - "UNIX-CONNECT:$HAPROXY_SOCK" fi done } @@ -1113,27 +1213,32 @@ EOF section_heartbeat() { # Heartbeat monitoring - # Different handling for heartbeat clusters with and without CRM - # for the resource state - if [ -S /var/run/heartbeat/crm/cib_ro ] || [ -S /var/run/crm/cib_ro ] || pgrep crmd >/dev/null 2>&1; then - mkecho '<<>>' + # Different handling for heartbeat clusters with and without CRM for the resource state + # Ref: Werk 11042, commit da543b1 + if { + [ -S /var/run/heartbeat/crm/cib_ro ] || + [ -S /var/run/crm/cib_ro ] || + pgrep crmd >/dev/null 2>&1 || + pgrep -f pacemaker-controld >/dev/null 2>&1 + }; then + println '<<>>' TZ=UTC crm_mon -1 -r | grep -v ^$ | sed 's/^ //; /^\sResource Group:/,$ s/^\s//; s/^\s/_/g' fi if inpath cl_status; then - mkecho '<<>>' + println '<<>>' cl_status rscstatus - mkecho '<<>>' + println '<<>>' for _node in $(cl_status listnodes); do - if [ "${_node}" != "$(mkecho "${HOSTNAME}" | tr '[:upper:]' '[:lower:]')" ]; then + if [ "${_node}" != "$(println "${HOSTNAME}" | tr '[:upper:]' '[:lower:]')" ]; then _status=$(cl_status nodestatus "${_node}") # shellcheck disable=SC2039 - mkecho -n "${_node} ${_status}" + println -n "${_node} ${_status}" for _link in $(cl_status listhblinks "${_node}" 2>/dev/null); do # shellcheck disable=SC2039 - mkecho -n " ${_link} $(cl_status hblinkstatus "${_node}" "${_link}")" + println -n " ${_link} $(cl_status hblinkstatus "${_node}" "${_link}")" done - mkecho + println fi done unset -v _node _status _link @@ -1142,24 +1247,24 @@ section_heartbeat() { section_hpux() { # Logical Volume Manager - mkecho '<<>>' + println '<<>>' /sbin/vgdisplay -v -F - mkecho '<<>>' + println '<<>>' if inpath cmviewcl; then cmviewcl -v -f line | grep summary fi # Kernel tunnables if inpath kcusage; then - mkecho '<<>>' + println '<<>>' kcusage -l fi # State of FC HBAs - mkecho '<<>>' + println '<<>>' for _hba in /dev/fcd*; do - mkecho "${_hba}" + println "${_hba}" /opt/fcms/bin/fcdutil "${_hba}" | grep -e "Driver state" \ -e "Topology" \ @@ -1184,7 +1289,7 @@ section_iostat() { _grepFilter="^(x?[shv]d[a-z]*[0-9]*|cciss/c[0-9]+d[0-9]+|emcpower[a-z]+|dm-[0-9]+|VxVM.*" _grepFilter="${_grepFilter}|mmcblk.*|dasd[a-z]*|bcache[0-9]+|nvme[0-9]+n[0-9]+|hdisk) " - mkecho "<<<${MK_OSSTR}_iostat>>>" + println "<<<${MK_OSSTR}_iostat>>>" # AIX was formerly under the header '<<>>' # TO-DO: Update checkman/aix_diskiod, checks/aix_diskiod etc @@ -1204,7 +1309,7 @@ section_iostat() { # This function pairs with read_ipmitool() # TO-DO: merge them somehow? -section_ipmi() { +section_ipmitool() { # Hardware sensors via IPMI (need ipmitool) if inpath ipmitool; then # We denote our delimiter 'i.e. separator' as being at column 124 @@ -1212,10 +1317,13 @@ section_ipmi() { # readable discrete sensor states run_cached "ipmi_discrete:sep(124)" 300 "waitmax 300 ipmitool sdr elist compact" fi +} + +section_ipmisensors() { # IPMI data via ipmi-sensors (of freeipmi). Please make sure, that if you # have installed freeipmi that IPMI is really support by your hardware. if (inpath ipmi-sensors && ls /dev/ipmi*) >/dev/null 2>&1; then - mkecho '<<>>' + println '<<>>' # Newer ipmi-sensors version have new output format; Legacy format can be used if ipmi-sensors --help | grepq legacy-output; then _ipmi_format="--legacy-output" @@ -1241,14 +1349,14 @@ section_jobs() { # arbitrary files can be avoided. ( cd "${MK_VARDIR}/job" || return - mkecho '<<>>' + println '<<>>' case "${MK_OSSTR}" in (aix) for _username in *; do if [ -d "${_username}" ] && cd "${_username}"; then for _filename in *; do # Maybe a cursory "if [ -r "${_filename}" ]" could go here? - mkecho "==> ${_filename} <==" + println "==> ${_filename} <==" cat "${_filename}" done cd .. @@ -1269,12 +1377,12 @@ section_jobs() { ;; (solaris) for _username in *; do - if [ -d "${_username}" ] && cd "${_username}" ; then + if [ -d "${_username}" ] && cd "${_username}"; then _count=$(su -s "${SHELL}" "${_username}" -c "ls -1 * | wc -l") if [ "${_count}" -eq "1" ]; then _filename=$(su -s "${SHELL}" "${_username}" -c "ls -1 *") - mkecho "==> ${_filename} <==" + println "==> ${_filename} <==" fi su -s "${SHELL}" "${_username}" -c "head -n1000 *" @@ -1291,23 +1399,23 @@ section_kernel() { case "${MK_OSSTR}" in (freebsd) # Performancecounter Kernel - mkecho "<<>>" + println "<<>>" get_epoch _forks=$(sysctl -n vm.stats.vm.v_forks) _vforks=$(sysctl -n vm.stats.vm.v_vforks) _rforks=$(sysctl -n vm.stats.vm.v_rforks) _kthreads=$(sysctl -n vm.stats.vm.v_kthreads) - mkecho "cpu" "$(sysctl -n kern.cp_time | awk ' { print $1" "$2" "$3" "$5" "$4 } ')" - mkecho "ctxt" "$(sysctl -n vm.stats.sys.v_swtch)" + println "cpu" "$(sysctl -n kern.cp_time | awk ' { print $1" "$2" "$3" "$5" "$4 } ')" + println "ctxt" "$(sysctl -n vm.stats.sys.v_swtch)" # TO-DO: confirm that these are all ints and if so, convert to $(()) # shellcheck disable=SC2003 - mkecho "processes" "$(expr "${_forks}" + "${_vforks}" + "${_rforks}" + "${_kthreads}")" + println "processes" "$(expr "${_forks}" + "${_vforks}" + "${_rforks}" + "${_kthreads}")" unset -v _forks _vforks _rforks _kthreads ;; (linux) # Performancecounter Kernel - if [ -z "${MK_IS_DOCKERIZED}" ] && [ -z "${MK_IS_LXC_CONTAINER}" ]; then - mkecho '<<>>' + if var_is_unset "${MK_IS_DOCKERIZED}" && var_is_unset "${MK_IS_LXC_CONTAINER}"; then + println '<<>>' get_epoch cat /proc/vmstat /proc/stat fi @@ -1317,7 +1425,7 @@ section_kernel() { section_local() { # Local checks - mkecho '<<>>' + println '<<>>' # Contain the 'cd' within a subshell so that we return # where we came from once the subshell closes ( @@ -1330,7 +1438,7 @@ section_local() { # Call some plugins only every X'th second for _skript in [1-9]*/*; do if is_valid_plugin "${_skript}"; then - _skript_cache=$(mkecho "${_skript}" | sed 's/\//\\/') + _skript_cache=$(println "${_skript}" | sed 's/\//\\/') run_cached "local_${_skript_cache}" "${_skript%/*}" "${_skript}" fi done @@ -1342,28 +1450,28 @@ section_local() { section_mac() { # OSX Timemachine if inpath tmutil; then - mkecho '<<>>' + println '<<>>' tmutil latestbackup 2>&1 fi } #TO-DO: De-duplicate this mess -section_mail() { +section_mailqueue() { # Postfix mailqueue monitoring # Determine the number of mails and their size in several postfix mail queues read_postfix_queue_dirs() { _postfix_queue_dir="${1}" - if [ -n "${_postfix_queue_dir}" ]; then - mkecho '<<>>' - mkecho "[[[${2}]]]" + if var_is_set "${_postfix_queue_dir}" ]; then + println '<<>>' + println "[[[${2}]]]" for _queue in deferred active; do _count=$(find "${_postfix_queue_dir}/${_queue}" -type f | wc -l) _size=$(du -s "${_postfix_queue_dir}/${_queue}" | awk '{print $1 }') - if [ -z "${_count}" ]; then - mkecho "Mail queue is empty" + if var_is_empty "${_count}"; then + println "Mail queue is empty" else - mkecho "QUEUE_${_queue} ${_size:-0} ${_count}" + println "QUEUE_${_queue} ${_size:-0} ${_count}" fi done fi @@ -1385,23 +1493,23 @@ section_mail() { # Only handle the last 6 lines (includes the summary line at the bottom and # the last message in the queue. The last message is not used at the moment # but it could be used to get the timestamp of the last message. - mkecho '<<>>' + println '<<>>' postfix_queue_dir=$(postconf -h queue_directory) postfix_count=$(find "$postfix_queue_dir"/deferred -type f | wc -l) postfix_size=$(du -ks "$postfix_queue_dir"/deferred | awk '{print $1 }') if [ "$postfix_count" -gt 0 ]; then - mkecho "$postfix_size" Kbytes in "$postfix_count" Requests. + println "$postfix_size" Kbytes in "$postfix_count" Requests. else - mkecho Mail queue is empty + println Mail queue is empty fi ;; (linux) # Check if multi_instance_directories exists in main.cf and is not empty # always takes the last entry, multiple entries possible multi_instances_dirs=$(postconf -c /etc/postfix 2>/dev/null | grep ^multi_instance_directories | sed 's/.*=[[:space:]]*//g') - if [ -n "$multi_instances_dirs" ]; then + if var_is_set "$multi_instances_dirs"; then for queue_dir in $multi_instances_dirs; do - if [ -n "$queue_dir" ]; then + if var_is_set "$queue_dir"; then postfix_queue_dir=$(postconf -c "$queue_dir" 2>/dev/null | grep ^queue_directory | sed 's/.*=[[:space:]]*//g') read_postfix_queue_dirs "$postfix_queue_dir" "$queue_dir" fi @@ -1413,64 +1521,96 @@ section_mail() { esac elif [ -x /usr/sbin/ssmtp ]; then - mkecho '<<>>' + println '<<>>' mailq 2>&1 | sed 's/^[^:]*: \(.*\)/\1/' | tail -n 6 # *bsd but should be a reasonable generic fallback elif inpath mailq && getent passwd postfix >/dev/null 2>&1; then - mkecho '<<>>' + println '<<>>' mailq | tail -n 6 fi # From AIX, seems generic enough if [ -x /usr/sbin/sendmail ] ; then - mkecho '<<>>'; + println '<<>>'; mailq 2>&1 | tail -n 6 fi # Postfix status monitoring. Can handle multiple instances. if inpath postfix; then - mkecho "<<>>" + println "<<>>" for i in /var/spool/postfix*/; do if [ -e "$i/pid/master.pid" ]; then if [ -r "$i/pid/master.pid" ]; then postfix_pid=$(sed 's/ //g' <"$i/pid/master.pid") # handle possible spaces in output if readlink -- "/proc/${postfix_pid}/exe" | grepq ".*postfix/\\(s\\?bin/\\)\\?master.*"; then - mkecho "$i:the Postfix mail system is running:PID:$postfix_pid" | sed 's/\/var\/spool\///g' + println "$i:the Postfix mail system is running:PID:$postfix_pid" | sed 's/\/var\/spool\///g' else - mkecho "$i:PID file exists but instance is not running!" | sed 's/\/var\/spool\///g' + println "$i:PID file exists but instance is not running!" | sed 's/\/var\/spool\///g' fi else - mkecho "$i:PID file exists but is not readable" + println "$i:PID file exists but is not readable" fi else - mkecho "$i:the Postfix mail system is not running" | sed 's/\/var\/spool\///g' + println "$i:the Postfix mail system is not running" | sed 's/\/var\/spool\///g' fi done fi # Check status of qmail mailqueue if inpath qmail-qstat; then - mkecho "<<>>" + println "<<>>" qmail-qstat fi # Nullmailer queue monitoring if inpath nullmailer-send && [ -d /var/spool/nullmailer/queue ]; then - mkecho '<<>>' + println '<<>>' COUNT=$(find /var/spool/nullmailer/queue -type f | wc -l) SIZE=$(du -s /var/spool/nullmailer/queue | awk '{print $1 }') - mkecho "$SIZE $COUNT" + println "$SIZE $COUNT" + fi +} + +section_megaraid() { + # RAID status of LSI MegaRAID controller via MegaCli. You can download that tool from: + # http://www.lsi.com/downloads/Public/MegaRAID%20Common%20Files/8.02.16_MegaCLI.zip + # From this list, the first that's found in PATH (if any) is mapped to lsicli() + for cliAlt in MegaCli MegaCli64 megacli storcli storcli64; do + if inpath "${cliAlt}"; then + lsicli() { "${cliAlt}"; } + break + fi + unset cliAlt + done + + if inpath lsicli; then + println '<<>>' + for part in $(lsicli -EncInfo -aALL -NoLog >>' + lsicli -LDInfo -Lall -aALL -NoLog >>' + lsicli -AdpBbuCmd -GetBbuStatus -aALL -NoLog >>' + println '<<>>' vmstat -v | tr -s ' ' swap -s # TO-DO: Possible candidates? @@ -1479,20 +1619,19 @@ section_mem() { # lsps -a ;; (hpux) - mkecho '<<>>' + println '<<>>' machinfo | grep ^Memory vmstat | sed -n 3p - ;; (linux) - if [ -z "${MK_IS_DOCKERIZED}" ]; then - mkecho '<<>>' + if var_is_unset "${MK_IS_DOCKERIZED}"; then + println '<<>>' grep -E -v '^Swap:|^Mem:|total:' >>' + println '<<>>' cat /sys/fs/cgroup/memory/memory.stat - mkecho "usage_in_bytes $(cat /sys/fs/cgroup/memory/memory.usage_in_bytes)" - mkecho "limit_in_bytes $(cat /sys/fs/cgroup/memory/memory.limit_in_bytes)" + println "usage_in_bytes $(cat /sys/fs/cgroup/memory/memory.usage_in_bytes)" + println "limit_in_bytes $(cat /sys/fs/cgroup/memory/memory.limit_in_bytes)" grep -F 'MemTotal:' /proc/meminfo fi ;; @@ -1501,41 +1640,42 @@ section_mem() { _memFreeInactive=$(vm_stat | grep inactive: | awk '{print $3}') _memFree=$(vm_stat | grep free: | awk '{print $3}') _memFreeMach=$(vm_stat | grep Mach | awk '{print $8}') - mkecho '<<>>' - mkecho "MemTotal: $(mkecho "$(sysctl -n hw.memsize)/1024" | bc) kB" - mkecho "MemFree: $(mkecho "( ${_memFreeSpec} + ${_memFreeInactive} + ${_memFree} ) * ${_memFreeMach} / 1024" | bc) kB" - mkecho "SwapTotal: 0 kB" - mkecho "SwapFree: 0 kB" + println '<<>>' + println "MemTotal: $(println "$(sysctl -n hw.memsize)/1024" | bc) kB" + println "MemFree: $(println "( ${_memFreeSpec} + ${_memFreeInactive} + ${_memFree} ) * ${_memFreeMach} / 1024" | bc) kB" + println "SwapTotal: 0 kB" + println "SwapFree: 0 kB" # FIXME: Just call vm_stat here, write a check plugin that uses that # native output of vm_stat + unset -v _memFreeSpec _memFreeInactive _memFree _memFreeMach ;; (openbsd) - mkecho "<<>>" + println "<<>>" MEM_FREE=$(vmstat | tail -n1 | awk '{ print $5 }') MEM_TOTAL=$(sysctl hw.usermem | cut -d= -f2) - MEM_TOTAL=$(mkecho "$MEM_TOTAL/1024" | bc) + MEM_TOTAL=$(println "$MEM_TOTAL/1024" | bc) SWAPCTL_OUTPUT=$(swapctl -k -s) - SWAP_FREE=$(mkecho "$SWAPCTL_OUTPUT" | awk '{ print $7 }') - SWAP_TOTAL=$(mkecho "$SWAPCTL_OUTPUT" | awk '{ print $2 }') + SWAP_FREE=$(println "$SWAPCTL_OUTPUT" | awk '{ print $7 }') + SWAP_TOTAL=$(println "$SWAPCTL_OUTPUT" | awk '{ print $2 }') # if there is no swap space swap values are 0 - if [ -z "$SWAPCTL_OUTPUT" ]; then + if var_is_unset "$SWAPCTL_OUTPUT"; then SWAP_FREE=0 SWAP_TOTAL=0 fi - mkecho -e "MemTotal:\\t$MEM_TOTAL kB" - mkecho -e "MemFree:\\t$MEM_FREE kB" - mkecho -e "SwapTotal:\\t$SWAP_TOTAL kB" - mkecho -e "SwapFree:\\t$SWAP_FREE kB" + println -e "MemTotal:\\t$MEM_TOTAL kB" + println -e "MemFree:\\t$MEM_FREE kB" + println -e "SwapTotal:\\t$SWAP_TOTAL kB" + println -e "SwapFree:\\t$SWAP_FREE kB" ;; (solaris) # We prefer to use 'statgrab' if it's available. See section_statgrab() # If 'statgrab' isn't available, we offer this workaround if ! inpath statgrab; then if [ -x /usr/bin/top ] || [ -x /usr/local/bin/top ]; then - mkecho "<<>>" + println "<<>>" if [ -x /usr/bin/top ]; then /usr/bin/top | grep '^Memory:'; fi if [ -x /usr/local/bin/top ]; then /usr/local/bin/top | grep '^Memory:'; fi fi @@ -1547,7 +1687,7 @@ section_mem() { section_mkbackup() { # Collect states of configured Check_MK site backup jobs if ls /omd/sites/*/var/check_mk/backup/*.state >/dev/null 2>&1; then - mkecho "<<>>" + println "<<>>" for _state_file in /omd/sites/*/var/check_mk/backup/*.state; do _omd_site=${_state_file#/*/*/*} _omd_site=${_omd_site%%/*} @@ -1556,9 +1696,9 @@ section_mkbackup() { _job_ident=${_job_ident##*/} if [ "${_job_ident}" != "restore" ]; then - mkecho "[[[site:${_omd_site}:${_job_ident}]]]" + println "[[[site:${_omd_site}:${_job_ident}]]]" cat "${_state_file}" - mkecho + println fi done unset -v _state_file _omd_site _job_ident @@ -1566,15 +1706,15 @@ section_mkbackup() { # Collect states of configured CMA backup jobs if inpath mkbackup && ls /var/lib/mkbackup/*.state >/dev/null 2>&1; then - mkecho "<<>>" + println "<<>>" for _state_file in /var/lib/mkbackup/*.state; do _job_ident=${_state_file%.state} _job_ident=${_job_ident##*/} if [ "${_job_ident}" != "restore" ]; then - mkecho "[[[system:${_job_ident}]]]" + println "[[[system:${_job_ident}]]]" cat "$F" - mkecho + println fi done unset -v _state_file _job_ident @@ -1587,13 +1727,13 @@ section_mounts() { # Check mount options. # FreeBSD doesn't do remount-ro on errors, but the users might consider # security related mount options more important. - mkecho '<<>>' + println '<<>>' mount -p -t ufs ;; (linux) # Check mount options. Filesystems may switch to 'ro' in case # of a read error. - mkecho '<<>>' + println '<<>>' grep ^/dev >>' + println '<<>>' _mrpe_plugin=${_mrpe_cmdline%% *} _mrpe_output=$(eval "${_mrpe_cmdline}") - # We ignore the shellcheck alerts for 'mkecho -n' as our 'mkecho()' solves this + # We ignore the shellcheck alerts for 'println -n' as our 'println()' solves this # shellcheck disable=SC2039 - mkecho -n "(${_mrpe_plugin##*/}) ${_mrpe_descr} ${?} ${_mrpe_output}" | tr \\n \\1 - mkecho + println -n "(${_mrpe_plugin##*/}) ${_mrpe_descr} ${?} ${_mrpe_output}" | tr \\n \\1 + println # Unset the function variables unset -v _mrpe_descr _mrpe_cmdline _mrpe_plugin _mrpe_output @@ -1634,11 +1774,11 @@ section_mrpe() { (\(*) # If we do start with '(', then split 'params' out of '_mrpe_cmdline' # We strip the brackets from 'params' and rewrite '_mrpe_cmdline' without the params - _mrpe_params=$(mkecho "${_mrpe_cmdline% *}" | tr -d '()') + _mrpe_params=$(println "${_mrpe_cmdline% *}" | tr -d '()') _mrpe_cmdline="${_mrpe_cmdline##* }" # split multiple parameter assignments - for _par in $(mkecho "${_mrpe_params}" | tr ":" "\\n"); do + for _par in $(println "${_mrpe_params}" | tr ":" "\\n"); do # split each assignment _key="${_par%=*}" _value="${_par#*=}" @@ -1666,26 +1806,26 @@ section_multipathing() { (aix) # TO-DO: Consider merging in mpio_get_config, lsmpio, sanlun, # dlnkmgr, powermt and pcmpath handling - mkecho '<<>>' + println '<<>>' lspath -F"name parent status" ;; (freebsd) # Multipathing is supported in FreeBSD by now # http://www.mywushublog.com/2010/06/freebsd-and-multipath/ if kldstat -v | grep g_multipath > /dev/null ; then - mkecho '<<>>' + println '<<>>' gmultipath status | grep -v ^Name fi ;; (hpux) # Multipathing - mkecho '<<>>' + println '<<>>' scsimgr lun_map | grep -E '^[[:space:]]*(LUN PATH|State|World Wide Identifier)' ;; (linux) if inpath multipath; then if [ -f /etc/multipath.conf ]; then - mkecho '<<>>' + println '<<>>' multipath -l fi fi @@ -1693,7 +1833,7 @@ section_multipathing() { (solaris) if inpath mpathadm; then if [ "$zonename" = "global" ]; then - mkecho '<<>>' + println '<<>>' mpathadm list LU | nawk '{if(NR%3==1){dev=$1} if(NR%3==2){tc=$NF} @@ -1707,66 +1847,80 @@ section_multipathing() { section_net() { case "${MK_OSSTR}" in (aix) - mkecho "<<>>" - for ent in $(ifconfig -a | grep '^en' | cut -d ":" -f 1); do - mkecho "[$ent]" - entstat "$ent" | - grep -E "(^Hardware|^Bytes:|^Packets:|^Transmit|^Broadcast:|^Multicast:)" - entstat "$ent" | grep -p "Driver Flags:" + println "<<>>" + for _ent in $(ifconfig -a | grep '^en' | cut -d ":" -f 1); do + println "[${_ent}]" + entstat "${_ent}" | grep -E "(^Hardware|^Bytes:|^Packets:|^Transmit|^Broadcast:|^Multicast:)" + entstat "${_ent}" | grep -p "Driver Flags:" done + unset -v _ent ;; (hpux) - mkecho '<<>>' - for nic in $(nwmgr -g | sed -n '/^lan/s/\(^[^ ]* \).*/\1/p'); do - nwmgr -g --st mib -c "$nic" + println '<<>>' + for _nic in $(nwmgr -g | sed -n '/^lan/s/\(^[^ ]* \).*/\1/p'); do + nwmgr -g --st mib -c "${_nic}" done + unset -v _nic ;; (linux) # New variant: Information about speed and state in one section if inpath ip; then - mkecho '<<>>' - mkecho "[start_iplink]" + println '<<>>' + println "[start_iplink]" ip address - mkecho "[end_iplink]" + println "[end_iplink]" fi - mkecho '<<>>' + println '<<>>' sed 1,2d /proc/net/dev - sed -e 1,2d /proc/net/dev | cut -d':' -f1 | sort | while read -r eth; do - mkecho "[$eth]" + sed -e 1,2d /proc/net/dev | cut -d':' -f1 | sort | while read -r _eth; do + println "[${_eth}]" if inpath ethtool; then - ethtool "$eth" | grep -E '(Speed|Duplex|Link detected|Auto-negotiation):' + ethtool "${_eth}" | grep -E '(Speed|Duplex|Link detected|Auto-negotiation):' else # If interface down we get "Invalid argument" - speed=$(cat "/sys/class/net/$eth/speed" 2>/dev/null) - [ -n "${speed}" ] && [ "${speed}" -ge 0 ] && mkecho -e "\tSpeed: ${speed}Mb/s\n" + _speed=$(cat "/sys/class/net/${_eth}/speed" 2>/dev/null) + var_is_set "${_speed}" && println -e "\tSpeed: ${_speed}Mb/s\n" fi # shellcheck disable=SC2039 - mkecho -e "\\tAddress: $(cat "/sys/class/net/$eth/address")\\n" + println -e "\\tAddress: $(cat "/sys/class/net/${_eth}/address")\\n" + done + unset -v _eth _speed + ;; + (mac) + println '<<>>' + println "[start_iplink]" + _linkNum=1 + for _link in $(netstat -inb | awk '/(^en|^lo).*Link/{print $1}'); do + printf '%s: %s' "${_linkNum}" "$(ifconfig "${_link}")" + _linkNum=$(( _linkNum + 1 )) done + println "[end_iplink]" - # Current state of bonding interfaces - if [ -e /proc/net/bonding ]; then - mkecho '<<>>' - ( - cd /proc/net/bonding || return - head -v -n 1000 ./* - ) - fi + println '<<>>'; - # Same for Open vSwitch bonding - if inpath ovs-appctl; then - BONDS=$(ovs-appctl bond/list) - COL=$(mkecho "$BONDS" | awk '{for(i=1;i<=NF;i++) {if($i = "bond") printf("%d", i)} exit 0}') - mkecho '<<>>' - for bond in $(mkecho "$BONDS" | sed -e 1d | cut -f"${COL}"); do - mkecho "[$bond]" - ovs-appctl bond/show "$bond" - done - fi + netstat -inb | + awk '/(^en|^lo).*Link/{print $1": "$7,$5,$6,"0","0","0","0","0",$10,$8,$9,"0","0",$11,"0","0";}' + + printf '%s\n%s\n' "[lo0]" "Link detected: yes" + for _iface in $(netstat -inb | sed -e 's/[*]//g' | awk '/^en.*Link/{print $1;}'); do + ifconfig "${_iface}" | grepq "media: autoselect" && _ifauto="on" + ifconfig "${_iface}" | grepq "full-duplex" && _ifduplex="Full" + ifconfig "${_iface}" | grepq "status: active" && _iflink="yes" + if ifconfig "${_iface}" | grepq -E '[0-9]+baseT'; then + _ifspeed=$(ifconfig "${_iface}" | grep -Eo '[0-9]+baseT' | sed -e 's@baseT@Mb/s@') + fi + println "[${_iface}]" + println " Speed: ${_ifspeed:-Unknown!}" + println " Duplex: ${_ifduplex:-Half}" + println " Auto-negotiation: ${_ifauto:-off}" + println " Link detected: ${_iflink:-no}" + done + + unset -v _linkNum _link _iface _ifspeed _ifduplex _ifauto _iflink ;; (openbsd) - mkecho '<<>>' + println '<<>>' # Example line: # em0 1500 08:00:27:e6:c4:70 16358 0 254 0 0 netstat -in | grep '' | grep -E -v "\\*|lo|pfsync|enc" | @@ -1778,14 +1932,14 @@ section_net() { while read -r _ _ _ _ _bytesIn _bytesOut; do _ifData="${_ifName}:${_bytesIn} ${_pktsIn} ${_errsIn} 0 0 0 0 0 ${_bytesOut}" _ifData="${_ifData} ${_pktsOut} ${_errsOut} 0 0 ${_collisions} 0 0" - mkecho "${_ifData}" + println "${_ifData}" done done unset -v _ifName _pktsIn _errsIn _pktsOut _errsOut _collisions _ifData for _ifName in $(netstat -in | awk '//{print $1}' | grep -E -v "\\*|lo|pfsync|enc"); do - mkecho "[${_ifName}]" + println "[${_ifName}]" _macAddr=$(ifconfig "${_ifName}" | awk '/lladdr/{print $NF}') @@ -1794,33 +1948,33 @@ section_net() { _ifData=$(ifconfig "${_ifName}" | grep "media:") # Speed - _ifSpeed=$(mkecho "${_ifData}" | cut -d\( -f2 | cut -db -f1) + _ifSpeed=$(println "${_ifData}" | cut -d\( -f2 | cut -db -f1) # shellcheck disable=SC2039 - [ "${_ifSpeed}" ] && mkecho -e "\\tSpeed: ${_ifSpeed}Mb/s" + [ "${_ifSpeed}" ] && println -e "\\tSpeed: ${_ifSpeed}Mb/s" # Detect duplexity - in reality only available for physical devices but # virtual ones like CARP devices will get at least a half duplex # shellcheck disable=SC2039 case "${_ifData}" in - (*full-duplex*) mkecho -e "\\tDuplex: Full" ;; - (*half-duplex*) mkecho -e "\\tDuplex: Half" ;; - (*) mkecho -e "\\tDuplex: Unknown" ;; + (*full-duplex*) println -e "\\tDuplex: Full" ;; + (*half-duplex*) println -e "\\tDuplex: Half" ;; + (*) println -e "\\tDuplex: Unknown" ;; esac # Auto-negotiation # shellcheck disable=SC2039 case "${_ifData}" in - (*autoselect*) mkecho -e "\\tAuto-negotiation: on" ;; - (*) mkecho -e "\\tAuto-negotiation: off" ;; + (*autoselect*) println -e "\\tAuto-negotiation: on" ;; + (*) println -e "\\tAuto-negotiation: off" ;; esac # Detect detected link if ifconfig "${_ifName}" | grep "status:" | grepq -E "active|backup|master"; then # shellcheck disable=SC2039 - mkecho -e "\\tLink detected: yes" + println -e "\\tLink detected: yes" fi # shellcheck disable=SC2039 - mkecho -e "\\tAddress: ${_macAddr}" + println -e "\\tAddress: ${_macAddr}" done unset -v _ifName _ifData _ifSpeed _macAddr @@ -1828,14 +1982,25 @@ section_net() { esac } -section_netctr() { +section_net_bonding() { + # Current state of bonding interfaces + if [ -e /proc/net/bonding ]; then + println '<<>>' + ( + cd /proc/net/bonding || return + head -v -n 1000 ./* + ) + fi +} + +section_net_ctr() { case "${MK_OSSTR}" in (freebsd) # Network device statistics (Packets, Collisions, etc) # only the "Link/Num" interface has all counters. - mkecho '<<>>' + println '<<>>' get_epoch - if [ "$(mkecho "${osver}" | cut -f1 -d\. )" -gt "8" ]; then + if [ "$(println "${osver}" | cut -f1 -d\. )" -gt "8" ]; then netstat -inb | grep -Ev '(^Name|lo|plip)' | grep Link | @@ -1849,7 +2014,7 @@ section_netctr() { fi ;; (mac) - mkecho '<<>>'; + println '<<>>'; get_epoch netstat -inb | grep -Ev '(^Name|lo|plip)' | @@ -1857,7 +2022,7 @@ section_netctr() { awk '{ print $1,$7,$5,$6,"0","0","0","0","0",$10,$8,$9,"0","0",$11,"0","0"; }' ;; (netbsd) - mkecho '<<>>' + println '<<>>' # BI= Bytes in # PI= Packets in # EI= Errors in @@ -1881,13 +2046,27 @@ section_netctr() { CO=$( netstat -in | grep -Ev Name | awk '/Link/{print $9}' | sed -ne $Z1$Z2 ) FF2="0 0" if [ "$PI" -gt "0" ]; then - mkecho "$BI $PI $EI $FF1 $BO $PO $EO $FF2 $CO $FF2" + println "$BI $PI $EI $FF1 $BO $PO $EO $FF2 $CO $FF2" fi Z1=$((Z1+1)) done esac } +section_net_openvswitch_bonding() { + # Same as section_net_bonding(), but for Open vSwitch bonding + if inpath ovs-appctl; then + _bonds=$(ovs-appctl bond/list) + _col=$(println "${_bonds}" | awk '{for(i=1;i<=NF;i++) {if($i = "bond") printf("%d", i)} exit 0}') + println '<<>>' + for _bond in $(println "${_bonds}" | sed -e 1d | cut -f"${_col}"); do + println "[${_bond}]" + ovs-appctl bond/show "${_bond}" + done + fi + unset -v _bonds _col _bond +} + section_nfs() { # Check NFS mounts by accessing them with stat -f (System call statfs()). # If this lasts more then 2 seconds we consider it as hanging. We need waitmax. @@ -1896,19 +2075,19 @@ section_nfs() { (aix) statFmt="ok - - - -" ;; (linux) statFmt="ok %b %f %a %s" ;; esac - mkecho '<<>>' + println '<<>>' get_nfs_mounts | while read -r mountPoint; do waitmax -s 9 5 stat -f -c "${mountPoint} ${statFmt}" "${mountPoint}" \ - || mkecho "${mountPoint} hanging 0 0 0 0" + || println "${mountPoint} hanging 0 0 0 0" done - mkecho '<<>>' + println '<<>>' get_cifs_mounts | while read -r mountPoint; do if [ ! -r "${mountPoint}" ]; then - mkecho "${mountPoint} Permission denied" + println "${mountPoint} Permission denied" else waitmax -s 9 2 stat -f -c "${mountPoint} ${statFmt}" "${mountPoint}" \ - || mkecho "${mountPoint} hanging 0 0 0 0" + || println "${mountPoint} hanging 0 0 0 0" fi done fi @@ -1919,10 +2098,6 @@ section_nfs() { # Requires 'get_ntpq()' section_ntp() { - # If '${timesync_rc}' is 0, then 'section_timesyncd()' has returned successfully in - # which case we do not want to proceed with 'ntpq', so return and skip further processing - [ "${timesync_rc}" -eq 0 ] && return 0 - # If 'ntpq' isn't in PATH, there's no point going further inpath ntpq || return 1 @@ -1965,7 +2140,7 @@ section_ntp() { section_nvidia() { if inpath nvidia-settings && [ -S /tmp/.X11-unix/X0 ]; then - mkecho '<<>>' + println '<<>>' for _var in GPUErrors GPUCoreTemp; do DISPLAY=:0 waitmax 2 nvidia-settings -t -q "${_var}" | sed "s/^/${_var}: /" done @@ -1976,41 +2151,41 @@ section_nvidia() { section_omd() { # Check status of OMD sites and Check_MK Notification spooler if inpath omd; then - mkecho '<<>>' - # mkecho '{"cmk/check_mk_server": "yes"}' - mkecho -j "cmk/check_mk_server" "yes" + println '<<>>' + # println '{"cmk/check_mk_server": "yes"}' + println -j "cmk/check_mk_server" "yes" run_cached omd_status 60 "omd status --bare || true" - mkecho '<<>>' + println '<<>>' get_epoch for _statefile in /omd/sites/*/var/log/mknotifyd.state; do if [ -e "${_statefile}" ]; then _site=${_statefile%/var/log*} _site=${_site#/omd/sites/} - mkecho "[${_site}]" + println "[${_site}]" grep -v '^#' <"${_statefile}" fi unset -v _site done - mkecho '<<>>' + println '<<>>' for _statsfile in /omd/sites/*/var/log/apache/stats; do if [ -e "${_statsfile}" ]; then _site=${_statsfile%/var/log*} _site=${_site#/omd/sites/} - mkecho "[${_site}]" + println "[${_site}]" cat "${_statsfile}" : >"${_statsfile}" # prevent next section to fail caused by a missing newline at the end of the statsfile - mkecho + println fi unset -v _site done fi - mkecho '<<>>' - mkecho '[versions]' - mkecho 'version;number;edition;demo' + println '<<>>' + println '[versions]' + println 'version;number;edition;demo' for _versiondir in /omd/versions/*; do _omd_version=${_versiondir#/omd/versions/} @@ -2027,10 +2202,10 @@ section_omd() { esac _omd_edition=${_omd_number##*.} _omd_number=${_omd_number%.*} - mkecho "${_omd_version};${_omd_number};${_omd_edition};${_omd_demo}" + println "${_omd_version};${_omd_number};${_omd_edition};${_omd_demo}" done - mkecho '[sites]' - mkecho 'site;used_version;autostart' + println '[sites]' + println 'site;used_version;autostart' for _sitedir in /omd/sites/*; do _site=${_sitedir#/omd/sites/} _used_version=$(readlink "${_sitedir}"/version) @@ -2039,26 +2214,31 @@ section_omd() { if grepq "CONFIG_AUTOSTART[[:blank:]]*=[[:blank:]]*'on'" "${_sitedir}"/etc/omd/site.conf; then _autostart="1" fi - mkecho "${_site};${_used_version};${_autostart}" + println "${_site};${_used_version};${_autostart}" done + unset -v _autostart _site _sitedir _statefile _statsfile _used_version _versiondir + unset -v _omd_demo _omd_edition _omd_number _omd_site _omd_version +} + +section_omd_core() ( # Get stats about OMD monitoring cores running on this machine. # Since cd is a shell builtin the check does not affect the performance # on non-OMD machines. if cd /omd/sites; then - mkecho '<<>>' + println '<<>>' for _site in *; do if [ -S "/omd/sites/${_site}/tmp/run/live" ]; then - mkecho "[${_site}]" + println "[${_site}]" # shellcheck disable=SC2039 - mkecho -e "GET status" | + println -e "GET status" | waitmax 3 "/omd/sites/${_site}/bin/unixcat" "/omd/sites/${_site}/tmp/run/live" fi done - mkecho '<<>>' + println '<<>>' for _site in *; do - mkecho "[${_site}]" + println "[${_site}]" for _pem_path in "/omd/sites/${_site}/etc/ssl/ca.pem" "/omd/sites/${_site}/etc/ssl/sites/${_site}.pem"; do if [ -f "${_pem_path}" ]; then _cert_date=$( @@ -2067,25 +2247,23 @@ section_omd() { awk '{printf("%s %02d %d %s\n", $1,$2,$4,$3)}' ) # TO-DO: Confirm that this works - mkecho "${_pem_path}|$(calculate_cert_epoch "${_cert_date}")" + println "${_pem_path}|$(calculate_cert_epoch "${_cert_date}")" fi done done - mkecho '<<>>' + println '<<>>' for _site in *; do if [ -S "/omd/sites/${_site}/tmp/run/mkeventd/status" ]; then - mkecho "[\"${_site}\"]" + println "[\"${_site}\"]" # shellcheck disable=SC2039 - mkecho -e "GET status\\nOutputFormat: json" | + println -e "GET status\\nOutputFormat: json" | waitmax 3 "/omd/sites/${_site}/bin/unixcat" "/omd/sites/${_site}/tmp/run/mkeventd/status" fi done fi - - unset -v _autostart _site _sitedir _statefile _statsfile _used_version _versiondir - unset -v _omd_demo _omd_edition _omd_number _omd_site _omd_version -} + unset -v _site _pem_path _cert_date +) section_openvpn() { # OpenVPN Clients. These are our two known log locations. @@ -2098,7 +2276,7 @@ section_openvpn() { return 0 fi - mkecho '<<>>' + println '<<>>' sed -n -e '/CLIENT LIST/,/ROUTING TABLE/p' < "${_openvpn_logfile}" | sed -e 1,3d -e '$d' @@ -2118,7 +2296,7 @@ section_plugins() { # Call some plugins only every Xth second for _skript in [1-9]*/*; do if is_valid_plugin "${_skript}"; then - _skript_cache=$(mkecho "${_skript}" | sed 's/\//\\/') + _skript_cache=$(println "${_skript}" | sed 's/\//\\/') run_cached "plugins_${_skript_cache}" "${_skript%/*}" "${_skript}" fi done @@ -2130,9 +2308,9 @@ section_plugins() { section_proxmox() { # Proxmox Cluster if inpath pvecm; then - mkecho "<<>>" + println "<<>>" pvecm status - mkecho "<<>>" + println "<<>>" pvecm nodes fi } @@ -2140,13 +2318,13 @@ section_proxmox() { section_ps() { case "${MK_OSSTR}" in (aix) - mkecho '<<>>' + println '<<>>' ps -ef -F user,vszsize,rssize,pcpu,etime,pid,args | sed -e 1d -e 's/ *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) */(\1,\2,\3,\4\/\5,\6) /' ;; (freebsd) # processes including username, without kernel processes - mkecho '<<>>' + println '<<>>' COLUMNS=10000 if [ "$is_jailed" = "0" ]; then ps ax -o state,user,vsz,rss,pcpu,command | @@ -2159,32 +2337,32 @@ section_ps() { (hpux) # Process table: HP-UX does not provide a resident size of processes. # We send a 0 here for RSZ. - mkecho '<<>>' + println '<<>>' UNIX95=yes ps -ef -o user,vsz,pcpu,args | sed -e 1d -e 's/ *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) */(\1,\2,0,\3) /' ;; (linux) if inpath ps; then # processes including username, without kernel processes - mkecho '<<>>' - mkecho 'dummy section -- refer to section ps_lnx' - mkecho '<<>>' + println '<<>>' + println 'dummy section -- refer to section ps_lnx' + println '<<>>' CGROUP="" if [ -e /sys/fs/cgroup ]; then CGROUP="cgroup:512," fi # shellcheck disable=SC2039 - mkecho "[header] $(ps ax -o "$CGROUP"user:32,vsz,rss,cputime,etime,pid,command --columns 10000)" + println "[header] $(ps ax -o "$CGROUP"user:32,vsz,rss,cputime,etime,pid,command --columns 10000)" fi ;; (mac|netbsd|openbsd) - mkecho '<<>>' + println '<<>>' COLUMNS=10000 ps ax -o user,vsz,rss,pcpu,command | sed -e 1d -e 's/ *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) */(\1,\2,\3,\4) /' ;; (solaris) - mkecho '<<>>' + println '<<>>' # The default solaris ps command strips the command lines of the processes. But for good process # matching on the server we really need to whole command line. On linux there are arguments to # make ps output the whole command line, but on solaris this seems to be missing. We use the ucb @@ -2199,17 +2377,17 @@ section_ps() { # Directly use ps output when line is too slow to be stripped if [ ${#LINE} -lt 100 ]; then - mkecho "$LINE" + println "$LINE" continue fi - CMD=$(mkecho "$UCB_PS" | grep "^[ ]*$PID " | head -n1 | \ + CMD=$(println "$UCB_PS" | grep "^[ ]*$PID " | head -n1 | \ awk '{ s = ""; for (i = 5; i <= NF; i++) s = s $i " "; print s }') # Only use the ucb ps line when it's not empty (process might already been gone) - if [ -z "$CMD" ]; then - mkecho "$LINE" + if var_is_unset "$CMD"; then + println "$LINE" else - mkecho "${STATS}) ${CMD}" + println "${STATS}) ${CMD}" fi done else @@ -2220,92 +2398,19 @@ section_ps() { esac } -section_raid() { +section_soft_raid() { case "${MK_OSSTR}" in (freebsd) # Soft-RAID - mkecho '<<>>' + println '<<>>' gmirror status | grep -v ^Name ;; (linux) # RAID status of Linux software RAID - mkecho '<<>>' + println '<<>>' cat /proc/mdstat - - # RAID status of Linux RAID via device mapper - if inpath dmraid && DMSTATUS=$(waitmax 3 dmraid -r); then - mkecho '<<>>' - - # Output name and status - waitmax 20 dmraid -s | grep -e ^name -e ^status - - # Output disk names of the RAID disks - DISKS=$(mkecho "$DMSTATUS" | cut -f1 -d":") - - for disk in $DISKS; do - device=$(cat /sys/block/"$(basename "$disk")"/device/model) - status=$(mkecho "$DMSTATUS" | grep "^${disk}") - mkecho "${status} Model: ${device}" - done - fi ;; esac - # RAID status of LSI controllers via cfggen - if inpath cfggen; then - mkecho '<<>>' - cfggen 0 DISPLAY | - grep -E '(Target ID|State|Volume ID|Status of volume)[[:space:]]*:' | - sed -e 's/ *//g' -e 's/:/ /' - fi - - # RAID status of LSI MegaRAID controller via MegaCli. You can download that tool from: - # http://www.lsi.com/downloads/Public/MegaRAID%20Common%20Files/8.02.16_MegaCLI.zip - # From this list, the first that's found in PATH (if any) is mapped to lsicli() - for cliAlt in MegaCli MegaCli64 megacli storcli storcli64; do - if inpath "${cliAlt}"; then - lsicli() { "${cliAlt}"; } - break - fi - unset cliAlt - done - - if inpath lsicli; then - mkecho '<<>>' - for part in $(lsicli -EncInfo -aALL -NoLog >>' - lsicli -LDInfo -Lall -aALL -NoLog >>' - lsicli -AdpBbuCmd -GetBbuStatus -aALL -NoLog >>' - tw_cli "/${_tw_ctl}" show all | grep -E 'Model =|Firmware|Serial' - mkecho '<<<3ware_disks>>>' - tw_cli "/${_tw_ctl}" show drivestatus | grep -E 'p[0-9]' | sed "s/^/${_tw_ctl}\\//" - mkecho '<<<3ware_units>>>' - tw_cli "/${_tw_ctl}" show unitstatus | grep -E 'u[0-9]' | sed "s/^/${_tw_ctl}\\//" - done - unset -v _tw_ctl - fi - - # RAID controllers from areca (Taiwan) - # cli64 can be found at ftp://ftp.areca.com.tw/RaidCards/AP_Drivers/Linux/CLI/ - if inpath cli64; then - run_cached arc_raid_status 300 "cli64 rsf info | tail -n +3 | head -n -2" - fi } # Start new liveupdate process in background on each agent execution. @@ -2314,11 +2419,11 @@ section_raid() { section_realtime_checks() { # Validate that we're configured and equipped, otherwise return if [ -r "${MK_CONFDIR}/real_time_checks.cfg" ]; then - if [ -z "${MK_RTC_HOST}" ]; then - mkecho "ERROR: \${MK_RTC_HOST} not specified. Not starting Real-Time Checks." >&2 + if var_is_unset "${MK_RTC_HOST}"; then + println "ERROR: \${MK_RTC_HOST} not specified. Not starting Real-Time Checks." >&2 return elif ! inpath openssl; then - mkecho "ERROR: openssl command is missing. Not starting Real-Time Checks." >&2 + println "ERROR: openssl command is missing. Not starting Real-Time Checks." >&2 return fi else @@ -2357,10 +2462,10 @@ section_runas() { (\(*) # If we do start with '(', then split 'params' out of 'cmdline' # We strip the brackets from 'params' and rewrite 'cmdline' without the params - params=$(mkecho "${cmdline% *}" | tr -d '()') + params=$(println "${cmdline% *}" | tr -d '()') cmdline="${cmdline##* }" # split multiple parameter assignments - for par in $(mkecho "${params}" | tr ":" "\\n"); do + for par in $(println "${params}" | tr ":" "\\n"); do # split each assignment key="${par%=*}" value="${par#*=}" @@ -2392,7 +2497,7 @@ section_runas() { done ;; (local|plugin) - [ "$type" = "local" ] && mkecho "<<>>" + [ "$type" = "local" ] && println "<<>>" find "$include" -executable -type f | while read -r filename; do runas_user "${user}" "${filename}" @@ -2407,22 +2512,22 @@ section_services() { case "${MK_OSSTR}" in (linux) if inpath systemctl; then - mkecho '<<>>' - mkecho "[list-unit-files]" + println '<<>>' + println "[list-unit-files]" systemctl list-unit-files --no-pager - mkecho "[all]" + println "[all]" systemctl --all --no-pager | sed '/^$/q' fi # Next we check for 'chkconfig' if inpath chkconfig; then - mkecho '<<>>' + println '<<>>' chkconfig --list 2>&1 fi # Some debian hosts have sysv-rc-conf if inpath sysv-rc-conf; then - mkecho '<<>>' + println '<<>>' sysv-rc-conf fi ;; @@ -2431,7 +2536,7 @@ section_services() { # We can get a list of all service instances, including disabled # or incomplete ones by 'svcs -a' if inpath svcs; then - mkecho '<<>>' + println '<<>>' svcs -a fi ;; @@ -2442,14 +2547,14 @@ section_solaris() { if inpath prtdiag; then # prtdiag does not work in local zones if [ "${zonename}" = "global" ]; then - run_cached solaris_prtdiag_status 300 '/usr/sbin/prtdiag 1>/dev/null 2>&1; mkecho $?' + run_cached solaris_prtdiag_status 300 '/usr/sbin/prtdiag 1>/dev/null 2>&1; println $?' fi fi # Displaying Information About Faults or Defects # If there are no faults the output of this command will be empty. if inpath fmadm; then - mkecho '<<>>' + println '<<>>' fmadm faulty fi } @@ -2469,7 +2574,7 @@ section_spooldir() { # Split any leading digits from a filename and assign to 'maxage' # This should ignore further digits e.g. '600file20' will output '600' - _maxage="$(mkecho "${_file}" | sed 's/^[^0-9]*//;s/[^0-9].*$//')" + _maxage="$(println "${_file}" | sed 's/^[^0-9]*//;s/[^0-9].*$//')" # If 'maxage' is set, then we grab the file's mtime, subtract it from # the epoch time, and compare that to 'maxage' @@ -2501,14 +2606,14 @@ section_statgrab() { statgrab "$statgrab_vars_mem" 1>>/tmp/statgrab.$$ for s in $statgrab_sections; do - mkecho "<<>>" + println "<<>>" grep "^${s}\\." /tmp/statgrab.$$ | cut -d. -f2-99 | sed 's/ *= */ /' done - mkecho '<<>>' + println '<<>>' statgrab net. 2>&1 | cut -d. -f2-99 | sed 's/ *= */ /' - mkecho '<<>>' + println '<<>>' grep -E "^(swap|mem)\\." /tmp/statgrab.$$ | sed 's/ *= */ /' [ -f /tmp/statgrab.$$ ] && rm -f /tmp/statgrab.$$ @@ -2527,13 +2632,13 @@ section_statgrab() { statgrab "$statgrab_vars" | grep -v md 1> /tmp/statgrab.$$ for s in $statgrab_sections; do - mkecho "<<>>" + println "<<>>" grep "^$s\\." /tmp/statgrab.$$ | cut -d. -f2-99 | sed 's/ *= */ /' done # <<>> info is preferred over <<>> # since solaris_mem is under suspicion to be buggy. - mkecho '<<>>' + println '<<>>' grep -E "^(swap|mem)\\." /tmp/statgrab.$$ | sed 's/ *= */ /' [ -f /tmp/statgrab.$$ ] && rm -f /tmp/statgrab.$$ @@ -2548,7 +2653,7 @@ section_tcp_stats() { filter_netstats() { awk ' /^tcp/ { c[$6]++; } END { for (x in c) { print x, c[x]; } }' } - mkecho '<<>>' + println '<<>>' case "${MK_OSSTR}" in (aix|mac) _netstat_opts="-ntfinet" ;; (freebsd) _netstat_opts="-na" ;; @@ -2559,7 +2664,7 @@ section_tcp_stats() { # We simply ignore this warning until we can come up with a cleaner way to do this # shellcheck disable=SC2181 if [ $? = 0 ]; then - mkecho "${_tcp_stats}" + println "${_tcp_stats}" elif inpath ss; then ss -ant | grep -v ^State | @@ -2587,8 +2692,12 @@ section_tcp_stats() { section_thermal() { # Gather thermal information provided e.g. by acpi # At the moment only supporting thermal sensors - if [ -z "${MK_IS_DOCKERIZED}" ] && [ -z "${MK_IS_LXC_CONTAINER}" ] && ls /sys/class/thermal/thermal_zone* >/dev/null 2>&1; then - mkecho '<<>>' + if { + var_is_unset "${MK_IS_DOCKERIZED}" && + var_is_unset "${MK_IS_LXC_CONTAINER}" && + ls /sys/class/thermal/thermal_zone* >/dev/null 2>&1 + }; then + println '<<>>' for _sysPath in /sys/class/thermal/thermal_zone*; do _line="${_sysPath##*/}" if [ ! -e "${_sysPath}/mode" ]; then @@ -2603,7 +2712,7 @@ section_thermal() { for _type in "${_sysPath}"/trip_point_*_type; do _line="${_line}$(tr <"${_type}" \\n "|")" done - mkecho "${_line%?}" + println "${_line%?}" done unset _sysPath _line _temp _type fi @@ -2613,22 +2722,22 @@ section_thermal() { section_timesyncd() { inpath timedatectl || return 1 timedatectl timesync-status >/dev/null 2>&1 || return 1 - mkecho "<<>>" + println "<<>>" timedatectl timesync-status get_file_mtime /var/lib/systemd/timesync/clock | awk '{print "[[["$1"]]]"}' return 0 } # Libelle Business Shadow -section_trd() { +section_libelle() { if inpath trd; then - mkecho "<<>>" + println "<<>>" trd -s fi } section_uptime() { - mkecho '<<>>' + println '<<>>' case "${MK_OSSTR}" in (aix) # uptime formats @@ -2642,22 +2751,22 @@ section_uptime() { _uptime=$(uptime | sed -e 's/^.*up//g' -e 's/[0-9]* user.*//g') case ${_uptime} in - ( *day* ) _up_days=$(mkecho "${_uptime}" | sed -e 's/days\{0,1\},.*//g') ;; + ( *day* ) _up_days=$(println "${_uptime}" | sed -e 's/days\{0,1\},.*//g') ;; ( * ) _up_days="0" ;; esac case ${_uptime} in ( *:* ) - _up_hours=$(mkecho "${_uptime}" | sed -e 's/.*days\{0,1\},//g' -e 's/:.*//g') - _up_mins=$(mkecho "${_uptime}" | sed -e 's/.*days\{0,1\},//g' -e 's/.*://g' -e 's/,.*//g') + _up_hours=$(println "${_uptime}" | sed -e 's/.*days\{0,1\},//g' -e 's/:.*//g') + _up_mins=$(println "${_uptime}" | sed -e 's/.*days\{0,1\},//g' -e 's/.*://g' -e 's/,.*//g') ;; ( *hr* ) - _up_hours=$(mkecho "${_uptime}" | sed -e 's/hrs\{0,1\},.*//g' -e 's/.*,//g') + _up_hours=$(println "${_uptime}" | sed -e 's/hrs\{0,1\},.*//g' -e 's/.*,//g') _up_mins=0 ;; ( *min* ) _up_hours=0 - _up_mins=$(mkecho "${_uptime}" | sed -e 's/mins\{0,1\},.*//g' -e 's/.*hrs\{0,1\},//g' -e 's/.*days\{0,1\},//g') + _up_mins=$(println "${_uptime}" | sed -e 's/mins\{0,1\},.*//g' -e 's/.*hrs\{0,1\},//g' -e 's/.*days\{0,1\},//g') ;; ( * ) _up_hours="0" @@ -2665,7 +2774,7 @@ section_uptime() { ;; esac - mkecho $(((_up_days*86400)+(_up_hours*3600)+(_up_mins*60))) + println $(((_up_days*86400)+(_up_hours*3600)+(_up_mins*60))) unset -v _uptime _up_hours _up_mins ;; (freebsd) @@ -2674,31 +2783,31 @@ section_uptime() { # pgrep is not appropriate (or even available?) here # shellcheck disable=SC2009 _idle_seconds=$(ps axw | grep "[i]dle" | awk '/idle/{print $4}' | cut -f1 -d':' ) - mkecho "${_up_seconds} ${_idle_seconds}" + println "${_up_seconds} ${_idle_seconds}" unset -v _up_seconds _idle_seconds ;; (linux) - if [ -z "${MK_IS_DOCKERIZED}" ]; then + if var_is_unset "${MK_IS_DOCKERIZED}"; then cat /proc/uptime else - mkecho "$(($(get_epoch) - $(stat -c %Z /dev/pts)))" + println "$(($(get_epoch) - $(stat -c %Z /dev/pts)))" fi ;; (mac|netbsd|openbsd) - mkecho "$(get_epoch) - $(sysctl -n kern.boottime | cut -d' ' -f 4,7 | tr ',' '.' | tr -d ' ')" | bc + println "$(get_epoch) - $(sysctl -n kern.boottime | cut -d' ' -f 4,7 | tr ',' '.' | tr -d ' ')" | bc ;; (solaris) # Solaris doesn't always give a consistent output on uptime, thus include side information # Tested in VM for solaris 10/11 _ctime=$(nawk 'BEGIN{print srand()}') _btime=$(kstat '-p' 'unix:::boot_time' 2>&1|grep 'boot_time'|awk '{print $2}') - mkecho $((_ctime - _btime)); - mkecho '[uptime_solaris_start]' + println $((_ctime - _btime)); + println '[uptime_solaris_start]' uname -a zonename uptime kstat -p unix:0:system_misc:snaptime - mkecho '[uptime_solaris_end]' + println '[uptime_solaris_end]' unset -v _ctime _btime ;; esac @@ -2706,39 +2815,39 @@ section_uptime() { # 'who -b' is a mostly portable way to report the boot time # TO-DO: is this information header the correct format? if who -b > /dev/null 2>&1; then - mkecho "[who_b_boot_time]" + println "[who_b_boot_time]" who -b fi } # HTTP Accelerator Statistics -section_varnishstat() { +section_http_accelerator() { if inpath varnishstat; then - mkecho "<<>>" + println "<<>>" varnishstat -1 fi } -section_vbox() { +section_vbox_guest() { # VirtualBox Guests. Section must always been output. Otherwise the # check would not be executed in case no guest additions are installed. # And that is something the check wants to detect - mkecho '<<>>' + println '<<>>' if inpath VBoxControl; then if lsmod | grepq vboxguest; then VBoxControl -nologo guestproperty enumerate | cut -d, -f1,2 fi else - mkecho "ERROR" + println "ERROR" fi } -section_vcs() { +section_veritas_cluster() { # Veritas Cluster Server # Software is always installed in /opt/VRTSvcs. # Secure mode must be off to allow root to execute commands if [ -x /opt/VRTSvcs/bin/haclus ]; then - mkecho "<<>>" + println "<<>>" vcshost=$(hostname | cut -d. -f1) waitmax -s 9 2 /opt/VRTSvcs/bin/haclus -display -localclus | grep -e ClusterName -e ClusState waitmax -s 9 2 /opt/VRTSvcs/bin/hasys -display -attribute SysState @@ -2748,140 +2857,150 @@ section_vcs() { fi } -# TO-DO: Standardise headers +# TO-DO: Standardise headers, identify what these commands are for, merge with section_kernel() ? section_vmstat() { case "${MK_OSSTR}" in (aix) - mkecho '<<>>' + println '<<>>' vmstat | tail -n1 ;; (hpux) # Several machine performance counters - mkecho '<<>>' + println '<<>>' vmstat -s ;; esac } # TO-DO: Can this behaviour be simplified or made portable? +# Filesystem usage for ZFS section_zfs() { - if [ "${MK_OSSTR}" = "linux" ]||[ "${MK_OSSTR}" = "solaris" ]; then - # Filesystem usage for ZFS - if inpath zfs; then - mkecho '<<>>' - zfs get -t filesystem,volume -Hp name,quota,used,avail,mountpoint,type || \ - zfs get -Hp name,referenced,avail,mountpoint,type | sed 's/referenced/used/g' - mkecho '<<>>' - mkecho '[df]' - df -PTlk -t zfs | sed 1d - fi - fi - - if [ "${MK_OSSTR}" = "linux" ]; then - # Welcome the ZFS check on Linux - # We do not endorse running ZFS on linux if your vendor doesnt support it ;) - # check zpool status - if inpath zpool; then - mkecho "<<>>" - zpool status -x - mkecho "<<>>" - zpool list - fi - fi - - if [ "${MK_OSSTR}" = "freebsd" ]; then - # Filesystem usage for ZFS - if inpath zfs; then - mkecho '<<>>' - zfs get -t filesystem,volume -Hp name,quota,used,avail,mountpoint,type || \ - zfs get -Hp name,quota,used,avail,mountpoint,type - mkecho '[df]' - df -kP -t zfs | sed 1d - # arc stats for zfs_arc_cache - mkecho '<<>>' - sysctl -q kstat.zfs.misc.arcstats | sed -e 's/kstat.zfs.misc.arcstats.//g' -e 's/: / = /g' - fi - - # check zpool status - if [ -x /sbin/zpool ]; then - mkecho "<<>>" - /sbin/zpool status -x | grep -v "errors: No known data errors" - fi - fi + case "${MK_OSSTR}" in + (freebsd) + if inpath zfs; then + println '<<>>' + zfs get -t filesystem,volume -Hp name,quota,used,avail,mountpoint,type || + zfs get -Hp name,quota,used,avail,mountpoint,type + println '[df]' + df -kP -t zfs | sed 1d + # arc stats for zfs_arc_cache + println '<<>>' + sysctl -q kstat.zfs.misc.arcstats | + sed -e 's/kstat.zfs.misc.arcstats.//g' -e 's/: / = /g' + fi + ;; + (linux|solaris) + if inpath zfs; then + println '<<>>' + zfs get -t filesystem,volume -Hp name,quota,used,avail,mountpoint,type || + zfs get -Hp name,referenced,avail,mountpoint,type | sed 's/referenced/used/g' + println '<<>>' + println '[df]' + df -PTlk -t zfs | sed 1d + fi + ;; + esac if [ "${MK_OSSTR}" = "solaris" ]; then # ZFS arc cache # newer Solaris (>=11.3) do not provide hits and misses via mdb -k - mkecho '<<>>' + println '<<>>' if inpath kstat; then kstat -p zfs:0:arcstats | sed -e 's/.*arcstats://g' | awk '{printf "%s = %s\n", $1, $2;}' elif inpath; then - mkecho '::arc' | mdb -k - fi - - # zpool status - if [ -x /sbin/zpool ]; then - run_cached zpool_status 120 "/sbin/zpool status -x" - mkecho '<<>>' - zpool list + println '::arc' | mdb -k fi fi } +section_zpool() { + case "${MK_OSSTR}" in + (freebsd) + # check zpool status + if [ -x /sbin/zpool ]; then + println "<<>>" + /sbin/zpool status -x | grep -v "errors: No known data errors" + fi + ;; + (linux) + if inpath zpool; then + println "<<>>" + zpool status -x + println "<<>>" + zpool list + fi + ;; + (solaris) + if [ -x /sbin/zpool ]; then + run_cached zpool_status 120 "/sbin/zpool status -x" + println '<<>>' + zpool list + fi + ;; + esac +} + ######################################################################################################################## # Output begins here main() { section_head - section_cpu - section_mem - section_df - section_zfs - section_nfs - section_mounts - section_multipathing - section_raid - section_diskstat - section_net - section_netctr - section_tcp_stats - section_timesyncd - # Grab the exit code from 'section_timesyncd()' as this determines 'section_ntp()'s behaviour - # Our goal here is to avoid multiple outputs e.g. timedatectl + ntpq - timesync_rc="${?}" - section_ntp - unset -v timesync_rc - section_chrony - section_mail - section_uptime - section_kernel - section_services - section_ps - section_statgrab - section_vmstat - section_ipmi - section_thermal - section_openvpn - section_omd + var_is_unset "${MK_SKIP_CPU}" && section_cpu + var_is_unset "${MK_SKIP_MEM}" && section_mem + var_is_unset "${MK_SKIP_DF}" && section_df + var_is_unset "${MK_SKIP_ZFS}" && section_zfs + var_is_unset "${MK_SKIP_NFS_MOUNTS}" && section_nfs + var_is_unset "${MK_SKIP_MOUNTS}" && section_mounts + var_is_unset "${MK_SKIP_MULTIPATHING}" && section_multipathing + var_is_unset "${MK_SKIP_SOFT_RAID}" && section_soft_raid + var_is_unset "${MK_SKIP_DM_RAID}" && section_dm_raid + var_is_unset "${MK_SKIP_CFGGEN}" && section_cfggen + var_is_unset "${MK_SKIP_MEGARAID}" && section_megaraid + var_is_unset "${MK_SKIP_THREE_WARE_RAID}" && section_3ware_raid + var_is_unset "${MK_SKIP_ARECA}" && section_areca_raid + var_is_unset "${MK_SKIP_ZPOOL}" && section_zpool + var_is_unset "${MK_SKIP_DISKSTAT}" && section_diskstat + var_is_unset "${MK_SKIP_NET}" && section_net + var_is_unset "${MK_SKIP_NET_CTR}" && section_net_ctr + var_is_unset "${MK_SKIP_NET_BONDING}" && section_net_bonding + var_is_unset "${MK_SKIP_NET_VSWITCH_BONDING}" && section_net_openvswitch_bonding + var_is_unset "${MK_SKIP_TCP_STATS}" && section_tcp_stats + if var_is_unset "${MK_SKIP_TIMESYNCHRONISATION}"; then + section_timesyncd || section_ntp + fi + var_is_unset "${MK_SKIP_CHRONY}" && section_chrony + var_is_unset "${MK_SKIP_MAILQUEUE}" && section_mailqueue + var_is_unset "${MK_SKIP_UPTIME}" && section_uptime + var_is_unset "${MK_SKIP_KERNEL}" && section_kernel + var_is_unset "${MK_SKIP_SERVICES}" && section_services + var_is_unset "${MK_SKIP_PS}" && section_ps + var_is_unset "${MK_SKIP_STATGRAB}" && section_statgrab + var_is_unset "${MK_SKIP_VMSTAT}" && section_vmstat + var_is_unset "${MK_SKIP_IPMITOOL}" && section_ipmitool + var_is_unset "${MK_SKIP_IPMISENSORS}" && section_ipmisensors + var_is_unset "${MK_SKIP_THERMAL}" && section_thermal + var_is_unset "${MK_SKIP_OPENVPN}" && section_openvpn + var_is_unset "${MK_SKIP_OMD}" && section_omd + var_is_unset "${MK_SKIP_OMD_CORES}" && section_omd_core section_mkbackup - section_jobs - section_vbox - section_nvidia - section_heartbeat - section_vcs - section_proxmox - section_drbd - section_trd - section_varnishstat - section_haproxy + var_is_unset "${MK_SKIP_JOBS}" && section_jobs + var_is_unset "${MK_SKIP_VBOX_GUEST}" && section_vbox_guest + var_is_unset "${MK_SKIP_NVIDIA}" && section_nvidia + var_is_unset "${MK_SKIP_HEARTBEAT}" && section_heartbeat + var_is_unset "${MK_SKIP_VERITAS}" && section_veritas_cluster + var_is_unset "${MK_SKIP_PROXMOX}" && section_proxmox + var_is_unset "${MK_SKIP_DRBD}" && section_drbd + var_is_unset "${MK_SKIP_LIBELLE}" && section_libelle + var_is_unset "${MK_SKIP_HTTP_ACCELERATOR}" && section_http_accelerator + var_is_unset "${MK_SKIP_HAPROXY}" && section_haproxy section_realtime_checks - section_fileinfo + var_is_unset "${MK_SKIP_FILEINFO}" && section_fileinfo section_runas section_mrpe section_local section_plugins - section_spooldir + var_is_unset "${MK_SKIP_SPOOLDIR}" && section_spooldir # Now any OS-specific catch-all functions # I wonder if this could be called universally/portably with section_${MK_OSSTR} case "${MK_OSSTR}" in From 5f840df5a0d04352a74ca5c7b488041661439eeb Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Sat, 16 May 2020 01:00:35 +1200 Subject: [PATCH 21/29] Merge in some changes from #145 and #179, as well as latest commits to Linux agent e.g. fce2188 --- agents/check_mk_agent.merged | 139 ++++++++++++++++++++++++----------- 1 file changed, 98 insertions(+), 41 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index d8201563dbb..2636f66cd3a 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -200,9 +200,10 @@ case $(uname -s) in ;; ("Darwin") MK_OSSTR=mac - #MK_LIBDIR="${MK_LIBDIR:-/to/be/changed}" - #MK_CONFDIR="${MK_CONFDIR:-/to/be/changed}" - #MK_VARDIR="${MK_VARDIR:-/set/this}" + MK_OSVER="$(sw_vers | sed 1d | paste -sd ' ' - | awk -F" " '{print $2" ("$4")"}')" + MK_LIBDIR="${MK_LIBDIR:-/usr/local/lib/check_mk_agent}" + MK_CONFDIR="${MK_CONFDIR:-/etc/check_mk}" + MK_VARDIR="${MK_VARDIR:-/var/lib/check_mk_agent}" ;; ("FreeBSD") MK_OSSTR=freebsd @@ -1044,7 +1045,8 @@ section_df() { # The exclusion list is getting a bit of a problem. # -l should hide any remote FS but seems to be all but working. - _df_excludefs="-x smbfs -x cifs -x iso9660 -x udf -x nfsv4 -x nfs -x mvfs -x prl_fs -x squashfs -x devtmpfs" + _df_excludefs="-x smbfs -x cifs -x iso9660 -x udf -x nfsv4 -x nfs -x mvfs" + _df_excludefs="${_df_excludefs} -x prl_fs -x squashfs -x devtmpfs -x autofs" if var_is_unset "${MK_IS_LXC_CONTAINER}"; then _df_excludefs="${_df_excludefs} -x zfs" fi @@ -1064,7 +1066,9 @@ section_df() { ;; (mac) println '<<>>' - df -kPT hfs,apfs | sed 1d | \ + df -kPT hfs,apfs | + grep -Ev "Time Machine|com.apple.TimeMachine.localsnapshots|/Volumes/|/private/var/vm" | + sed 1d | while read -r _df_dev _df_rest; do _df_type=$(diskutil info "${_df_dev}" | grep '^\s*Type' | cut -d: -f2 | tr -d '[:space:]') println "${_df_dev} ${_df_type} ${_df_rest}" @@ -1201,7 +1205,7 @@ section_head() { cat << EOF "<<>>" "Version: ${MK_VERSION}" -"AgentOS: ${MK_OSSTR}" +"AgentOS: ${MK_OSSTR} ${MK_OSVER}" "Hostname: ${HOSTNAME}" "AgentDirectory: ${MK_CONFDIR}" "DataDirectory: ${MK_VARDIR}" @@ -1455,13 +1459,41 @@ section_mac() { fi } +# TODO: Flesh this out +# See https://apple.stackexchange.com/questions/117864/how-can-i-tell-if-my-mac-is-keeping-the-clock-updated-properly +section_mac_time() { + # If we're not using network time, there's no point continuing + systemsetup -getusingnetworktime | grepq "Network Time: On" || return 1 + # Figure out our OS version so that we can determine our approach + var_is_blank "${MK_OSVER}" && return 1 + _macver=$(println "${MK_OSVER}" | tr -d '.') + if [ "${_macver}" -ge "1014" ]; then + # If this file is missing, create it + [ -f /var/db/ntp-kod ] || touch /var/db/ntp-kod + chown root:wheel /var/db/ntp-kod >/dev/null 2>&1 + + # Alt: systemsetup -getnetworktimeserver | awk -F ': ' '{print $2; exit}' + _ntp_server=$(awk '/^server/{print $2; exit}' /etc/ntp.conf) + var_is_blank "${_ntp_server}" && return + # Call sntp + sntp -sS pool.ntp.org "${_ntp_server}" + elif [ "${_macver}" -eq "1013" ]; then + defaults read /var/db/timed/com.apple.timed TMLastSystemTime + # TODO: parse /var/db/timed/com.apple.timed.plist and provide compatible output + # defaults read /var/db/timed/com.apple.timed TMSystemSource | grep TMTimeError | head -n1 | awk -F'"' '{print $2}' + elif [ "${_macver}" -le "1012" ]; then + get_ntpq + fi + unset -v _macver _ntp_server +} + #TO-DO: De-duplicate this mess section_mailqueue() { # Postfix mailqueue monitoring # Determine the number of mails and their size in several postfix mail queues read_postfix_queue_dirs() { _postfix_queue_dir="${1}" - if var_is_set "${_postfix_queue_dir}" ]; then + if var_is_set "${_postfix_queue_dir}"; then println '<<>>' println "[[[${2}]]]" @@ -1636,18 +1668,24 @@ section_mem() { fi ;; (mac) - _memFreeSpec=$(vm_stat | grep speculative: | awk '{print $3}') - _memFreeInactive=$(vm_stat | grep inactive: | awk '{print $3}') - _memFree=$(vm_stat | grep free: | awk '{print $3}') - _memFreeMach=$(vm_stat | grep Mach | awk '{print $8}') + # TODO: Validate if 'bc' is required here or if we can use builtin integer arithmetic + _pagesSpeculative=$(vm_stat | awk '/speculative:/{print $3}') + _pagesInactive=$(vm_stat | awk '/inactive:/{print $3}') + _pagesFree=$(vm_stat | awk '/free:/{print $3}') + _pageSize=$(vm_stat | awk '/^Mach/{print $8}') + _compressedPagesStored=$(vm_stat | awk '/stored in compressor:/{print $5}') + _compressedPagesOccupied=$(vm_stat | awk '/occupied by compressor:/{print $5}') + _memFree=$(println "( ${_pagesSpeculative} + ${_pagesInactive} + ${_pagesFree} ) * ${_pageSize} / 1024" | bc) + _swapTotal=$(println "${_compressedPagesStored} * ${_pageSize} / 1024" | bc) + _swapFree=$(println "( ${_compressedPagesStored} - ${_compressedPagesOccupied} ) * ${_pageSize} / 1024" | bc) println '<<>>' println "MemTotal: $(println "$(sysctl -n hw.memsize)/1024" | bc) kB" - println "MemFree: $(println "( ${_memFreeSpec} + ${_memFreeInactive} + ${_memFree} ) * ${_memFreeMach} / 1024" | bc) kB" - println "SwapTotal: 0 kB" - println "SwapFree: 0 kB" - # FIXME: Just call vm_stat here, write a check plugin that uses that - # native output of vm_stat - unset -v _memFreeSpec _memFreeInactive _memFree _memFreeMach + println "MemFree: ${_memFree} kB" + println "SwapTotal: ${_swapTotal} kB" + println "SwapFree: ${_swapFree} kB" + + unset -v _pagesSpeculative _pagesInactive _pagesFree _pageSize _swapTotal _swapFree + unset -v _compressedPagesStored _compressedPagesOccupied _memFree ;; (openbsd) println "<<>>" @@ -1883,7 +1921,7 @@ section_net() { var_is_set "${_speed}" && println -e "\tSpeed: ${_speed}Mb/s\n" fi # shellcheck disable=SC2039 - println -e "\\tAddress: $(cat "/sys/class/net/${_eth}/address")\\n" + println -e "\tAddress: $(cat "/sys/class/net/${_eth}/address")\n" done unset -v _eth _speed ;; @@ -1891,33 +1929,53 @@ section_net() { println '<<>>' println "[start_iplink]" _linkNum=1 - for _link in $(netstat -inb | awk '/(^en|^lo).*Link/{print $1}'); do - printf '%s: %s' "${_linkNum}" "$(ifconfig "${_link}")" - _linkNum=$(( _linkNum + 1 )) - done + if inpath ip; then + _interfaces=$(ip a | awk -F ':' '/^[a-z]/{print $1}' | grep -Ev '^(awdl0|utun|llw)') + var_is_blank "${_interfaces}" && return + for _link in ${_interfaces}; do + println "${_linkNum}: $(ip a show "${_link}")" + _linkNum=$(( _linkNum + 1 )) + done + else + _interfaces=$(netstat -inb | awk '/(^en|^lo).*Link/ && $7>0{print $1}') + var_is_blank "${_interfaces}" && return + for _link in ${_interfaces}; do + println "${_linkNum}: $(ifconfig "${_link}")" + _linkNum=$(( _linkNum + 1 )) + done + fi println "[end_iplink]" println '<<>>'; - - netstat -inb | - awk '/(^en|^lo).*Link/{print $1": "$7,$5,$6,"0","0","0","0","0",$10,$8,$9,"0","0",$11,"0","0";}' - - printf '%s\n%s\n' "[lo0]" "Link detected: yes" - for _iface in $(netstat -inb | sed -e 's/[*]//g' | awk '/^en.*Link/{print $1;}'); do - ifconfig "${_iface}" | grepq "media: autoselect" && _ifauto="on" - ifconfig "${_iface}" | grepq "full-duplex" && _ifduplex="Full" - ifconfig "${_iface}" | grepq "status: active" && _iflink="yes" - if ifconfig "${_iface}" | grepq -E '[0-9]+baseT'; then - _ifspeed=$(ifconfig "${_iface}" | grep -Eo '[0-9]+baseT' | sed -e 's@baseT@Mb/s@') - fi + # Format: + # Name, IBytes, IPckts, IErr, Drop, 0 (fifo), 0 (frame), 0 (compressed), 0 (multicast), + # Coll, Obyts, OPckts, OErrs, 0 (drop), 0 (fifo), 0 (coll), 0 (drop) + # Collisions & drops are not broken out into in/out, so I'm assuming receive for now + netstat -inb | + grep -E "${_interfaces}" | + awk '/Link/{print $1": "$7,$5,$6,$12,"0 0 0 0",$11,$10,$8,$9,"0 0 0 0";}' + + # Convert OSX ifconfig to lnx_if format: + # Note: Wifi interfaces may have variable speeds each call + printf '%s\n\t%s\n' "[lo0]" "Link detected: yes" + for _iface in ${_interfaces}; do + _cur_ifconfig=$(ifconfig -v "${_iface}") + # Alt: grep -E "^\s*(down)?link rate:\s*" | cut -d " " -f3,4 | sed -E 's, (.)bps$,\1b/s,' + _ifspeed=$(println "${_cur_ifconfig}" | grep -Eo '[0-9]+baseT' | sed -e 's@baseT@Mb/s@') + println "${_cur_ifconfig}" | grepq "full-duplex" && _ifduplex="Full" + println "${_cur_ifconfig}" | grepq "media: autoselect" && _ifauto="on" + println "${_cur_ifconfig}" | grepq "status: active" && _iflink="yes" + [ "${_iface}" = "lo0" ] && _iflink="yes" + _ifaddr=$(println "${_cur_ifconfig}" | grep -E '^\s*ether' | cut -d " " -f2) println "[${_iface}]" - println " Speed: ${_ifspeed:-Unknown!}" - println " Duplex: ${_ifduplex:-Half}" - println " Auto-negotiation: ${_ifauto:-off}" - println " Link detected: ${_iflink:-no}" + println -e "\tSpeed: ${_ifspeed:-Unknown!}" + println -e "\tDuplex: ${_ifduplex:-Half}" + println -e "\tAuto-negotiation: ${_ifauto:-off}" + println -e "\tLink detected: ${_iflink:-no}" + println -e "\tAddress: ${_ifaddr:-00:00:00:00:00:00}" done - unset -v _linkNum _link _iface _ifspeed _ifduplex _ifauto _iflink + unset -v _linkNum _link _iface _cur_ifconfig _ifspeed _ifduplex _ifauto _iflink _ifaddr ;; (openbsd) println '<<>>' @@ -2018,8 +2076,7 @@ section_net_ctr() { get_epoch netstat -inb | grep -Ev '(^Name|lo|plip)' | - grep Link | - awk '{ print $1,$7,$5,$6,"0","0","0","0","0",$10,$8,$9,"0","0",$11,"0","0"; }' + awk '/Link/{ print $1,$7,$5,$6,"0","0","0","0","0",$10,$8,$9,"0","0",$11,"0","0"; }' ;; (netbsd) println '<<>>' From 4069dd87bef7a3031018f98b0feee7044edaedc5 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Mon, 18 May 2020 22:58:48 +1200 Subject: [PATCH 22/29] Update mk_job to ndjson-style output. To be tested --- agents/check_mk_agent.merged | 39 +++++++++++++------- agents/mk-job | 69 ++++++++++++++++++++++-------------- 2 files changed, 68 insertions(+), 40 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index 2636f66cd3a..a26edfa3733 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -41,7 +41,8 @@ newPath= # to the 'newPath' variable. This way, we dynamically build PATH, and bias Solaris towards XPG4 for dir in /usr/gnu/bin /usr/xpg6/bin /usr/xpg4/bin /usr/kerberos/bin /usr/kerberos/sbin /bin \ /sbin /usr/bin /usr/sbin /usr/contrib/bin/usr/local/bin /usr/local/sbin /opt/csw/bin \ - /opt/csw/sbin /opt/sfw/bin /opt/sfw/sbin /usr/pkg/bin /usr/sfw/bin /usr/sfw/sbin /snap/bin; do + /opt/csw/sbin /opt/sfw/bin /opt/sfw/sbin /usr/pkg/bin /usr/sfw/bin /usr/sfw/sbin /snap/bin \ + /opt/lsi /opt/MegaRAID/storcli; do [ -d "${dir}" ] && newPath="${newPath}:${dir}" done @@ -53,10 +54,9 @@ PATH="${newPath#:}" export PATH unset -v newPath -# 'println()' abstracts the portability of 'printf' and solves the major -# portability headaches caused by various implementations of 'echo' -# This is called 'println()' rather than an 'echo()' override because -# some shells protect their builtins, denying us the override cleanliness +# 'println()' abstracts the portability of 'printf' and solves the major portability headaches +# caused by various implementations of 'echo'. This is called 'println()' rather than 'echo()' as +# an override function, because some shells protect their builtins and complain. # Fun exercise: look at Oracle's man page for 'echo', specifically the USAGE section. # This also adds the '-j' option to output in json keypair format println() { @@ -1476,7 +1476,7 @@ section_mac_time() { _ntp_server=$(awk '/^server/{print $2; exit}' /etc/ntp.conf) var_is_blank "${_ntp_server}" && return # Call sntp - sntp -sS pool.ntp.org "${_ntp_server}" + sntp -sS "${_ntp_server}" elif [ "${_macver}" -eq "1013" ]; then defaults read /var/db/timed/com.apple.timed TMLastSystemTime # TODO: parse /var/db/timed/com.apple.timed.plist and provide compatible output @@ -1608,12 +1608,12 @@ section_megaraid() { # RAID status of LSI MegaRAID controller via MegaCli. You can download that tool from: # http://www.lsi.com/downloads/Public/MegaRAID%20Common%20Files/8.02.16_MegaCLI.zip # From this list, the first that's found in PATH (if any) is mapped to lsicli() - for cliAlt in MegaCli MegaCli64 megacli storcli storcli64; do - if inpath "${cliAlt}"; then - lsicli() { "${cliAlt}"; } + for _cliAlt in MegaCli MegaCli64 megacli storcli storcli64; do + if inpath "${_cliAlt}"; then + lsicli() { "${_cliAlt}"; } break fi - unset cliAlt + unset -v _cliAlt done if inpath lsicli; then @@ -1633,6 +1633,13 @@ section_megaraid() { lsicli -LDInfo -Lall -aALL -NoLog >>' lsicli -AdpBbuCmd -GetBbuStatus -aALL -NoLog >>" + # lsicli /call/eall/sall show + # println "<<>>" + # /opt/MegaRAID/storcli/storcli64 /call/vall show + # fi fi } @@ -1957,7 +1964,6 @@ section_net() { # Convert OSX ifconfig to lnx_if format: # Note: Wifi interfaces may have variable speeds each call - printf '%s\n\t%s\n' "[lo0]" "Link detected: yes" for _iface in ${_interfaces}; do _cur_ifconfig=$(ifconfig -v "${_iface}") # Alt: grep -E "^\s*(down)?link rate:\s*" | cut -d " " -f3,4 | sed -E 's, (.)bps$,\1b/s,' @@ -2196,13 +2202,20 @@ section_ntp() { } section_nvidia() { + # See PR #129 / f8a96be + if inpath nvidia-smi; then + _nvidia_settings="GPUErrors" + println '<<>>' + waitmax 2 nvidia-smi --query-gpu=temperature.gpu --format=csv,nounits,noheader | sed "s/^/GPUCoreTemp: /" + fi + if inpath nvidia-settings && [ -S /tmp/.X11-unix/X0 ]; then println '<<>>' - for _var in GPUErrors GPUCoreTemp; do + for _var in ${_nvidia_settings:-GPUErrors GPUCoreTemp}; do DISPLAY=:0 waitmax 2 nvidia-settings -t -q "${_var}" | sed "s/^/${_var}: /" done - unset -v _var fi + unset -v _var _nvidia_settings } section_omd() { diff --git a/agents/mk-job b/agents/mk-job index 34ecbbb60d2..af445ca2440 100755 --- a/agents/mk-job +++ b/agents/mk-job @@ -35,10 +35,9 @@ exit "${1:-0}" output_path="${MK_VARDIR}/job/${USER}" ident="${1:?}" running_file="${output_path}/${ident}.$$running" -tmp_file="${running_file}.tmp" # Shift to the rest of the positional parameters -shift +shift 1 if [ ! -d "${output_path}" ]; then if [ "${USER}" = root ]; then @@ -54,46 +53,62 @@ if ! inpath "${1}"; then help 1 fi -echo "start_time $(get_epoch)" > "${running_file}" 2>/dev/null +# Structure GNU's time format into an NDJSON format +gnu_time_fmt="{\"$(get_epoch)\": {\"exit_code\": %x, \"real_time\": \"%E\", \"user_time\": \"%U\"," +gnu_time_fmt="${gnu_time_fmt} \"system_time\": \"%S\", \"reads\": %I, \"writes\": %O," +gnu_time_fmt="${gnu_time_fmt} \"max_res_kbytes\": %M, \"avg_mem_kbytes\": %K," +gnu_time_fmt="${gnu_time_fmt} \"invol_context_switches\": %c, \"vol_context_switches\": %w}" + +# Structure our dummy data for older systems +dummy_data="\"reads\": 0, \"writes\": 0, \"max_res_kbytes\": 0, \"avg_mem_kbytes\": 0," +dummy_data="${dummy_data} \"invol_context_switches\": 0, \"vol_context_switches\": 0}}" if [ ! -w "${running_file}" ] ; then - # Looks like we are lacking the permissions to create this file.. + # Looks like we are lacking the permissions to create this file... # In this scenario no mk-job status file is created. We simply execute the command exec "$@" fi case "${MK_OSSTR}" in (aix) - /usr/bin/time -p "$@" > "${tmp_file}" # execute the command - return_code="${?}" # save return code - echo "exit_code ${return_code}" >> "${running_file}" # then add the return code - # and finally add the output of /usr/bin/time - grep -E '^real |^user |^sys ' "${tmp_file}" | - sed -e 's/,/\./g' \ - -e 's/^real /real_time/g' \ - -e 's/^user /user_time/g' \ - -e 's/^sys /system_time/g' \ - >> "${running_file}" - echo "reads 0\nwrites 0\nmax_res_kbytes 0\navg_mem_kbytes 0\ninvol_context_switches 0\nvol_context_switches 0" >> "${running_file}" + # TO-DO: Test if the AIX approach a) works and b) also works for Solaris, if so, merge them + # We want word splitting here so that our positional params are assigned properly + # shellcheck disable=SC2046 + set -- $( (/usr/bin/time -p "${@}" 2>&1; echo "${?}") | tail -n 4 | paste -sd ' ' -) + + # Start building our output format + classic_fmt="{\"$(get_epoch)\": {\"exit_code\": ${7}, \"real_time\": \"${2}\"," + classic_fmt="${classic_fmt} \"user_time\": \"${4}\", \"system_time\": \"${6}\"," + classic_fmt="${classic_fmt} ${dummy_data}" + return_code="${7}" + + echo "${classic_fmt}" >> "${running_file}" ;; (linux) - /usr/bin/time -o "${running_file}" --append \ - -f "exit_code %x\nreal_time %E\nuser_time %U\nsystem_time %S\nreads %I\nwrites %O\nmax_res_kbytes %M\navg_mem_kbytes %K\ninvol_context_switches %c\nvol_context_switches %w" "$@" + /usr/bin/time -o "${running_file}" --append -f "${gnu_time_fmt}" "${@}" + return_code="${?}" + ;; + (mac) + # For OSX: requires GNU-time installed (`brew install gnu-time`) + inpath gtime || return 1 + /usr/local/bin/gtime -o "${running_file}" --append -f "${gnu_time_fmt}" "${@}" return_code="${?}" ;; (solaris) - info=$( (/usr/bin/time -p sh -c "$* 2>/dev/null 1>&2" 2>&1; echo $?) | sed -e 's/,/\./g') - return_code=$(echo "${info}" | awk '{print $7}') - - (echo "${info}" | - awk '{print "exit_code "$7"\nreal_time "$2"\nuser_time "$4"\nsystem_time "$6""}' - ) >> "${running_file}" - - (echo -e "reads 0\nwrites 0\nmax_res_kbytes 0\navg_mem_kbytes 0\ninvol_context_switches 0\nvol_context_switches 0"; - ) >> "${running_file}" + # TO-DO: Test if the AIX approach a) works and b) also works for Solaris, if so, merge them + # We want word splitting here so that our positional params are assigned properly + # shellcheck disable=SC2046 + set -- $( (/usr/bin/time -p sh -c "$* 2>/dev/null 1>&2" 2>&1; echo $?) | sed -e 's/,/\./g') + + # Start building our output format + classic_fmt="{\"$(get_epoch)\": {\"exit_code\": ${7}, \"real_time\": \"${2}\"," + classic_fmt="${classic_fmt} \"user_time\": \"${4}\", \"system_time\": \"${6}\"," + classic_fmt="${classic_fmt} ${dummy_data}" + return_code="${7}" + + echo "${classic_fmt}" >> "${running_file}" ;; esac mv "${running_file}" "${output_path}/${ident}" -[ -e "${tmp_file}" ] && rm -f "${tmp_file}" exit "${return_code}" From 32e155feb0a0300a6ebce1f908ed01d5b9a4ba10 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Tue, 29 Oct 2019 23:03:21 +1300 Subject: [PATCH 23/29] Rebase for upstream changes --- agents/check_mk_agent.merged | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index a26edfa3733..ab08cee7eb3 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -2022,14 +2022,14 @@ section_net() { case "${_ifData}" in (*full-duplex*) println -e "\\tDuplex: Full" ;; (*half-duplex*) println -e "\\tDuplex: Half" ;; - (*) println -e "\\tDuplex: Unknown" ;; + (*) println -e "\\tDuplex: Unknown" ;; esac # Auto-negotiation # shellcheck disable=SC2039 case "${_ifData}" in (*autoselect*) println -e "\\tAuto-negotiation: on" ;; - (*) println -e "\\tAuto-negotiation: off" ;; + (*) println -e "\\tAuto-negotiation: off" ;; esac # Detect detected link From 155aab299d8d35e30ce3ad0469c50ef661e501f9 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Fri, 24 Jan 2020 22:26:10 +1300 Subject: [PATCH 24/29] Split ntp and timesyncd into separate functions and plumb them together --- agents/check_mk_agent.merged | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index ab08cee7eb3..02264707f3f 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -2199,6 +2199,10 @@ section_ntp() { unset -v _ntp_daemon ;; esac +<<<<<<< HEAD +======= + +>>>>>>> Split ntp and timesyncd into separate functions and plumb them together } section_nvidia() { From 7e4baa18d6dced09bff134ecd2574d6c08587180 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Sat, 25 Jan 2020 10:28:36 +1300 Subject: [PATCH 25/29] Promote 'get_ntpq()' to toplevel --- agents/check_mk_agent.merged | 3 +++ 1 file changed, 3 insertions(+) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index 02264707f3f..5e7dd83da76 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -2200,9 +2200,12 @@ section_ntp() { ;; esac <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> Split ntp and timesyncd into separate functions and plumb them together +======= +>>>>>>> Promote 'get_ntpq()' to toplevel } section_nvidia() { From d66c41450c9d92c653b0967624a251d0701dad25 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Tue, 3 Mar 2020 22:40:22 +1300 Subject: [PATCH 26/29] Merge in latest tranche of changes to various *nix agents --- agents/check_mk_agent.merged | 129 +++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index 5e7dd83da76..2a6e31fa2e7 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -2233,24 +2233,40 @@ section_omd() { println -j "cmk/check_mk_server" "yes" run_cached omd_status 60 "omd status --bare || true" +<<<<<<< HEAD println '<<>>' +======= + mkecho '<<>>' +>>>>>>> Merge in latest tranche of changes to various *nix agents get_epoch for _statefile in /omd/sites/*/var/log/mknotifyd.state; do if [ -e "${_statefile}" ]; then _site=${_statefile%/var/log*} _site=${_site#/omd/sites/} +<<<<<<< HEAD println "[${_site}]" +======= + mkecho "[${_site}]" +>>>>>>> Merge in latest tranche of changes to various *nix agents grep -v '^#' <"${_statefile}" fi unset -v _site done +<<<<<<< HEAD println '<<>>' +======= + mkecho '<<>>' +>>>>>>> Merge in latest tranche of changes to various *nix agents for _statsfile in /omd/sites/*/var/log/apache/stats; do if [ -e "${_statsfile}" ]; then _site=${_statsfile%/var/log*} _site=${_site#/omd/sites/} +<<<<<<< HEAD println "[${_site}]" +======= + mkecho "[${_site}]" +>>>>>>> Merge in latest tranche of changes to various *nix agents cat "${_statsfile}" : >"${_statsfile}" # prevent next section to fail caused by a missing newline at the end of the statsfile @@ -2260,9 +2276,15 @@ section_omd() { done fi +<<<<<<< HEAD println '<<>>' println '[versions]' println 'version;number;edition;demo' +======= + mkecho '<<>>' + mkecho '[versions]' + mkecho 'version;number;edition;demo' +>>>>>>> Merge in latest tranche of changes to various *nix agents for _versiondir in /omd/versions/*; do _omd_version=${_versiondir#/omd/versions/} @@ -2279,10 +2301,17 @@ section_omd() { esac _omd_edition=${_omd_number##*.} _omd_number=${_omd_number%.*} +<<<<<<< HEAD println "${_omd_version};${_omd_number};${_omd_edition};${_omd_demo}" done println '[sites]' println 'site;used_version;autostart' +======= + mkecho "${_omd_version};${_omd_number};${_omd_edition};${_omd_demo}" + done + mkecho '[sites]' + mkecho 'site;used_version;autostart' +>>>>>>> Merge in latest tranche of changes to various *nix agents for _sitedir in /omd/sites/*; do _site=${_sitedir#/omd/sites/} _used_version=$(readlink "${_sitedir}"/version) @@ -2291,6 +2320,7 @@ section_omd() { if grepq "CONFIG_AUTOSTART[[:blank:]]*=[[:blank:]]*'on'" "${_sitedir}"/etc/omd/site.conf; then _autostart="1" fi +<<<<<<< HEAD println "${_site};${_used_version};${_autostart}" done @@ -2299,23 +2329,43 @@ section_omd() { } section_omd_core() ( +======= + mkecho "${_site};${_used_version};${_autostart}" + done + +>>>>>>> Merge in latest tranche of changes to various *nix agents # Get stats about OMD monitoring cores running on this machine. # Since cd is a shell builtin the check does not affect the performance # on non-OMD machines. if cd /omd/sites; then +<<<<<<< HEAD println '<<>>' for _site in *; do if [ -S "/omd/sites/${_site}/tmp/run/live" ]; then println "[${_site}]" # shellcheck disable=SC2039 println -e "GET status" | +======= + mkecho '<<>>' + for _site in *; do + if [ -S "/omd/sites/${_site}/tmp/run/live" ]; then + mkecho "[${_site}]" + # shellcheck disable=SC2039 + mkecho -e "GET status" | +>>>>>>> Merge in latest tranche of changes to various *nix agents waitmax 3 "/omd/sites/${_site}/bin/unixcat" "/omd/sites/${_site}/tmp/run/live" fi done +<<<<<<< HEAD println '<<>>' for _site in *; do println "[${_site}]" +======= + mkecho '<<>>' + for _site in *; do + mkecho "[${_site}]" +>>>>>>> Merge in latest tranche of changes to various *nix agents for _pem_path in "/omd/sites/${_site}/etc/ssl/ca.pem" "/omd/sites/${_site}/etc/ssl/sites/${_site}.pem"; do if [ -f "${_pem_path}" ]; then _cert_date=$( @@ -2324,23 +2374,43 @@ section_omd_core() ( awk '{printf("%s %02d %d %s\n", $1,$2,$4,$3)}' ) # TO-DO: Confirm that this works +<<<<<<< HEAD println "${_pem_path}|$(calculate_cert_epoch "${_cert_date}")" +======= + mkecho "${_pem_path}|$(calculate_cert_epoch "${_cert_date}")" +>>>>>>> Merge in latest tranche of changes to various *nix agents fi done done +<<<<<<< HEAD println '<<>>' for _site in *; do if [ -S "/omd/sites/${_site}/tmp/run/mkeventd/status" ]; then println "[\"${_site}\"]" # shellcheck disable=SC2039 println -e "GET status\\nOutputFormat: json" | +======= + mkecho '<<>>' + for _site in *; do + if [ -S "/omd/sites/${_site}/tmp/run/mkeventd/status" ]; then + mkecho "[\"${_site}\"]" + # shellcheck disable=SC2039 + mkecho -e "GET status\\nOutputFormat: json" | +>>>>>>> Merge in latest tranche of changes to various *nix agents waitmax 3 "/omd/sites/${_site}/bin/unixcat" "/omd/sites/${_site}/tmp/run/mkeventd/status" fi done fi +<<<<<<< HEAD unset -v _site _pem_path _cert_date ) +======= + + unset -v _autostart _site _sitedir _statefile _statsfile _used_version _versiondir + unset -v _omd_demo _omd_edition _omd_number _omd_site _omd_version +} +>>>>>>> Merge in latest tranche of changes to various *nix agents section_openvpn() { # OpenVPN Clients. These are our two known log locations. @@ -2488,6 +2558,65 @@ section_soft_raid() { cat /proc/mdstat ;; esac +<<<<<<< HEAD +======= + # RAID status of LSI controllers via cfggen + if inpath cfggen; then + mkecho '<<>>' + cfggen 0 DISPLAY | + grep -E '(Target ID|State|Volume ID|Status of volume)[[:space:]]*:' | + sed -e 's/ *//g' -e 's/:/ /' + fi + + # RAID status of LSI MegaRAID controller via MegaCli. You can download that tool from: + # http://www.lsi.com/downloads/Public/MegaRAID%20Common%20Files/8.02.16_MegaCLI.zip + # From this list, the first that's found in PATH (if any) is mapped to lsicli() + for cliAlt in MegaCli MegaCli64 megacli storcli storcli64; do + if inpath "${cliAlt}"; then + lsicli() { "${cliAlt}"; } + break + fi + unset cliAlt + done + + if inpath lsicli; then + mkecho '<<>>' + for part in $(lsicli -EncInfo -aALL -NoLog >>' + lsicli -LDInfo -Lall -aALL -NoLog >>' + lsicli -AdpBbuCmd -GetBbuStatus -aALL -NoLog >>' + tw_cli "/${_tw_ctl}" show all | grep -E 'Model =|Firmware|Serial' + mkecho '<<<3ware_disks>>>' + tw_cli "/${_tw_ctl}" show drivestatus | grep -E 'p[0-9]' | sed "s/^/${_tw_ctl}\\//" + mkecho '<<<3ware_units>>>' + tw_cli "/${_tw_ctl}" show unitstatus | grep -E 'u[0-9]' | sed "s/^/${_tw_ctl}\\//" + done + unset -v _tw_ctl + fi + + # RAID controllers from areca (Taiwan) + # cli64 can be found at ftp://ftp.areca.com.tw/RaidCards/AP_Drivers/Linux/CLI/ + if inpath cli64; then + run_cached arc_raid_status 300 "cli64 rsf info | tail -n +3 | head -n -2" + fi +>>>>>>> Merge in latest tranche of changes to various *nix agents } # Start new liveupdate process in background on each agent execution. From c23fe66740871c4a70c03c4ac18f949353f57f42 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Fri, 15 May 2020 12:01:01 +1200 Subject: [PATCH 27/29] Update merged script, include var_* functions and mac improvements --- agents/check_mk_agent.merged | 82 +++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index 2a6e31fa2e7..0f229b2d5bc 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -2218,7 +2218,11 @@ section_nvidia() { if inpath nvidia-settings && [ -S /tmp/.X11-unix/X0 ]; then println '<<>>' +<<<<<<< HEAD for _var in ${_nvidia_settings:-GPUErrors GPUCoreTemp}; do +======= + for _var in GPUErrors GPUCoreTemp; do +>>>>>>> Update merged script, include var_* functions and mac improvements DISPLAY=:0 waitmax 2 nvidia-settings -t -q "${_var}" | sed "s/^/${_var}: /" done fi @@ -2233,40 +2237,56 @@ section_omd() { println -j "cmk/check_mk_server" "yes" run_cached omd_status 60 "omd status --bare || true" +<<<<<<< HEAD <<<<<<< HEAD println '<<>>' ======= mkecho '<<>>' >>>>>>> Merge in latest tranche of changes to various *nix agents +======= + println '<<>>' +>>>>>>> Update merged script, include var_* functions and mac improvements get_epoch for _statefile in /omd/sites/*/var/log/mknotifyd.state; do if [ -e "${_statefile}" ]; then _site=${_statefile%/var/log*} _site=${_site#/omd/sites/} +<<<<<<< HEAD <<<<<<< HEAD println "[${_site}]" ======= mkecho "[${_site}]" >>>>>>> Merge in latest tranche of changes to various *nix agents +======= + println "[${_site}]" +>>>>>>> Update merged script, include var_* functions and mac improvements grep -v '^#' <"${_statefile}" fi unset -v _site done +<<<<<<< HEAD <<<<<<< HEAD println '<<>>' ======= mkecho '<<>>' >>>>>>> Merge in latest tranche of changes to various *nix agents +======= + println '<<>>' +>>>>>>> Update merged script, include var_* functions and mac improvements for _statsfile in /omd/sites/*/var/log/apache/stats; do if [ -e "${_statsfile}" ]; then _site=${_statsfile%/var/log*} _site=${_site#/omd/sites/} +<<<<<<< HEAD <<<<<<< HEAD println "[${_site}]" ======= mkecho "[${_site}]" >>>>>>> Merge in latest tranche of changes to various *nix agents +======= + println "[${_site}]" +>>>>>>> Update merged script, include var_* functions and mac improvements cat "${_statsfile}" : >"${_statsfile}" # prevent next section to fail caused by a missing newline at the end of the statsfile @@ -2276,6 +2296,7 @@ section_omd() { done fi +<<<<<<< HEAD <<<<<<< HEAD println '<<>>' println '[versions]' @@ -2285,6 +2306,11 @@ section_omd() { mkecho '[versions]' mkecho 'version;number;edition;demo' >>>>>>> Merge in latest tranche of changes to various *nix agents +======= + println '<<>>' + println '[versions]' + println 'version;number;edition;demo' +>>>>>>> Update merged script, include var_* functions and mac improvements for _versiondir in /omd/versions/*; do _omd_version=${_versiondir#/omd/versions/} @@ -2301,6 +2327,7 @@ section_omd() { esac _omd_edition=${_omd_number##*.} _omd_number=${_omd_number%.*} +<<<<<<< HEAD <<<<<<< HEAD println "${_omd_version};${_omd_number};${_omd_edition};${_omd_demo}" done @@ -2312,6 +2339,12 @@ section_omd() { mkecho '[sites]' mkecho 'site;used_version;autostart' >>>>>>> Merge in latest tranche of changes to various *nix agents +======= + println "${_omd_version};${_omd_number};${_omd_edition};${_omd_demo}" + done + println '[sites]' + println 'site;used_version;autostart' +>>>>>>> Update merged script, include var_* functions and mac improvements for _sitedir in /omd/sites/*; do _site=${_sitedir#/omd/sites/} _used_version=$(readlink "${_sitedir}"/version) @@ -2320,6 +2353,7 @@ section_omd() { if grepq "CONFIG_AUTOSTART[[:blank:]]*=[[:blank:]]*'on'" "${_sitedir}"/etc/omd/site.conf; then _autostart="1" fi +<<<<<<< HEAD <<<<<<< HEAD println "${_site};${_used_version};${_autostart}" done @@ -2334,10 +2368,21 @@ section_omd_core() ( done >>>>>>> Merge in latest tranche of changes to various *nix agents +======= + println "${_site};${_used_version};${_autostart}" + done + + unset -v _autostart _site _sitedir _statefile _statsfile _used_version _versiondir + unset -v _omd_demo _omd_edition _omd_number _omd_site _omd_version +} + +section_omd_core() ( +>>>>>>> Update merged script, include var_* functions and mac improvements # Get stats about OMD monitoring cores running on this machine. # Since cd is a shell builtin the check does not affect the performance # on non-OMD machines. if cd /omd/sites; then +<<<<<<< HEAD <<<<<<< HEAD println '<<>>' for _site in *; do @@ -2347,16 +2392,24 @@ section_omd_core() ( println -e "GET status" | ======= mkecho '<<>>' +======= + println '<<>>' +>>>>>>> Update merged script, include var_* functions and mac improvements for _site in *; do if [ -S "/omd/sites/${_site}/tmp/run/live" ]; then - mkecho "[${_site}]" + println "[${_site}]" # shellcheck disable=SC2039 +<<<<<<< HEAD mkecho -e "GET status" | >>>>>>> Merge in latest tranche of changes to various *nix agents +======= + println -e "GET status" | +>>>>>>> Update merged script, include var_* functions and mac improvements waitmax 3 "/omd/sites/${_site}/bin/unixcat" "/omd/sites/${_site}/tmp/run/live" fi done +<<<<<<< HEAD <<<<<<< HEAD println '<<>>' for _site in *; do @@ -2366,6 +2419,11 @@ section_omd_core() ( for _site in *; do mkecho "[${_site}]" >>>>>>> Merge in latest tranche of changes to various *nix agents +======= + println '<<>>' + for _site in *; do + println "[${_site}]" +>>>>>>> Update merged script, include var_* functions and mac improvements for _pem_path in "/omd/sites/${_site}/etc/ssl/ca.pem" "/omd/sites/${_site}/etc/ssl/sites/${_site}.pem"; do if [ -f "${_pem_path}" ]; then _cert_date=$( @@ -2374,15 +2432,20 @@ section_omd_core() ( awk '{printf("%s %02d %d %s\n", $1,$2,$4,$3)}' ) # TO-DO: Confirm that this works +<<<<<<< HEAD <<<<<<< HEAD println "${_pem_path}|$(calculate_cert_epoch "${_cert_date}")" ======= mkecho "${_pem_path}|$(calculate_cert_epoch "${_cert_date}")" >>>>>>> Merge in latest tranche of changes to various *nix agents +======= + println "${_pem_path}|$(calculate_cert_epoch "${_cert_date}")" +>>>>>>> Update merged script, include var_* functions and mac improvements fi done done +<<<<<<< HEAD <<<<<<< HEAD println '<<>>' for _site in *; do @@ -2392,16 +2455,24 @@ section_omd_core() ( println -e "GET status\\nOutputFormat: json" | ======= mkecho '<<>>' +======= + println '<<>>' +>>>>>>> Update merged script, include var_* functions and mac improvements for _site in *; do if [ -S "/omd/sites/${_site}/tmp/run/mkeventd/status" ]; then - mkecho "[\"${_site}\"]" + println "[\"${_site}\"]" # shellcheck disable=SC2039 +<<<<<<< HEAD mkecho -e "GET status\\nOutputFormat: json" | >>>>>>> Merge in latest tranche of changes to various *nix agents +======= + println -e "GET status\\nOutputFormat: json" | +>>>>>>> Update merged script, include var_* functions and mac improvements waitmax 3 "/omd/sites/${_site}/bin/unixcat" "/omd/sites/${_site}/tmp/run/mkeventd/status" fi done fi +<<<<<<< HEAD <<<<<<< HEAD unset -v _site _pem_path _cert_date ) @@ -2411,6 +2482,10 @@ section_omd_core() ( unset -v _omd_demo _omd_edition _omd_number _omd_site _omd_version } >>>>>>> Merge in latest tranche of changes to various *nix agents +======= + unset -v _site _pem_path _cert_date +) +>>>>>>> Update merged script, include var_* functions and mac improvements section_openvpn() { # OpenVPN Clients. These are our two known log locations. @@ -2559,6 +2634,7 @@ section_soft_raid() { ;; esac <<<<<<< HEAD +<<<<<<< HEAD ======= # RAID status of LSI controllers via cfggen if inpath cfggen; then @@ -2617,6 +2693,8 @@ section_soft_raid() { run_cached arc_raid_status 300 "cli64 rsf info | tail -n +3 | head -n -2" fi >>>>>>> Merge in latest tranche of changes to various *nix agents +======= +>>>>>>> Update merged script, include var_* functions and mac improvements } # Start new liveupdate process in background on each agent execution. From 066b5919996262d3650c7d48de6ceb93afcc1eca Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Sat, 16 May 2020 01:00:35 +1200 Subject: [PATCH 28/29] Merge in some changes from #145 and #179, as well as latest commits to Linux agent e.g. fce2188 --- agents/check_mk_agent.merged | 218 +---------------------------------- 1 file changed, 2 insertions(+), 216 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index 0f229b2d5bc..a26edfa3733 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -2022,14 +2022,14 @@ section_net() { case "${_ifData}" in (*full-duplex*) println -e "\\tDuplex: Full" ;; (*half-duplex*) println -e "\\tDuplex: Half" ;; - (*) println -e "\\tDuplex: Unknown" ;; + (*) println -e "\\tDuplex: Unknown" ;; esac # Auto-negotiation # shellcheck disable=SC2039 case "${_ifData}" in (*autoselect*) println -e "\\tAuto-negotiation: on" ;; - (*) println -e "\\tAuto-negotiation: off" ;; + (*) println -e "\\tAuto-negotiation: off" ;; esac # Detect detected link @@ -2199,13 +2199,6 @@ section_ntp() { unset -v _ntp_daemon ;; esac -<<<<<<< HEAD -<<<<<<< HEAD -======= - ->>>>>>> Split ntp and timesyncd into separate functions and plumb them together -======= ->>>>>>> Promote 'get_ntpq()' to toplevel } section_nvidia() { @@ -2218,11 +2211,7 @@ section_nvidia() { if inpath nvidia-settings && [ -S /tmp/.X11-unix/X0 ]; then println '<<>>' -<<<<<<< HEAD for _var in ${_nvidia_settings:-GPUErrors GPUCoreTemp}; do -======= - for _var in GPUErrors GPUCoreTemp; do ->>>>>>> Update merged script, include var_* functions and mac improvements DISPLAY=:0 waitmax 2 nvidia-settings -t -q "${_var}" | sed "s/^/${_var}: /" done fi @@ -2237,56 +2226,24 @@ section_omd() { println -j "cmk/check_mk_server" "yes" run_cached omd_status 60 "omd status --bare || true" -<<<<<<< HEAD -<<<<<<< HEAD - println '<<>>' -======= - mkecho '<<>>' ->>>>>>> Merge in latest tranche of changes to various *nix agents -======= println '<<>>' ->>>>>>> Update merged script, include var_* functions and mac improvements get_epoch for _statefile in /omd/sites/*/var/log/mknotifyd.state; do if [ -e "${_statefile}" ]; then _site=${_statefile%/var/log*} _site=${_site#/omd/sites/} -<<<<<<< HEAD -<<<<<<< HEAD - println "[${_site}]" -======= - mkecho "[${_site}]" ->>>>>>> Merge in latest tranche of changes to various *nix agents -======= println "[${_site}]" ->>>>>>> Update merged script, include var_* functions and mac improvements grep -v '^#' <"${_statefile}" fi unset -v _site done -<<<<<<< HEAD -<<<<<<< HEAD println '<<>>' -======= - mkecho '<<>>' ->>>>>>> Merge in latest tranche of changes to various *nix agents -======= - println '<<>>' ->>>>>>> Update merged script, include var_* functions and mac improvements for _statsfile in /omd/sites/*/var/log/apache/stats; do if [ -e "${_statsfile}" ]; then _site=${_statsfile%/var/log*} _site=${_site#/omd/sites/} -<<<<<<< HEAD -<<<<<<< HEAD - println "[${_site}]" -======= - mkecho "[${_site}]" ->>>>>>> Merge in latest tranche of changes to various *nix agents -======= println "[${_site}]" ->>>>>>> Update merged script, include var_* functions and mac improvements cat "${_statsfile}" : >"${_statsfile}" # prevent next section to fail caused by a missing newline at the end of the statsfile @@ -2296,21 +2253,9 @@ section_omd() { done fi -<<<<<<< HEAD -<<<<<<< HEAD println '<<>>' println '[versions]' println 'version;number;edition;demo' -======= - mkecho '<<>>' - mkecho '[versions]' - mkecho 'version;number;edition;demo' ->>>>>>> Merge in latest tranche of changes to various *nix agents -======= - println '<<>>' - println '[versions]' - println 'version;number;edition;demo' ->>>>>>> Update merged script, include var_* functions and mac improvements for _versiondir in /omd/versions/*; do _omd_version=${_versiondir#/omd/versions/} @@ -2327,24 +2272,10 @@ section_omd() { esac _omd_edition=${_omd_number##*.} _omd_number=${_omd_number%.*} -<<<<<<< HEAD -<<<<<<< HEAD println "${_omd_version};${_omd_number};${_omd_edition};${_omd_demo}" done println '[sites]' println 'site;used_version;autostart' -======= - mkecho "${_omd_version};${_omd_number};${_omd_edition};${_omd_demo}" - done - mkecho '[sites]' - mkecho 'site;used_version;autostart' ->>>>>>> Merge in latest tranche of changes to various *nix agents -======= - println "${_omd_version};${_omd_number};${_omd_edition};${_omd_demo}" - done - println '[sites]' - println 'site;used_version;autostart' ->>>>>>> Update merged script, include var_* functions and mac improvements for _sitedir in /omd/sites/*; do _site=${_sitedir#/omd/sites/} _used_version=$(readlink "${_sitedir}"/version) @@ -2353,22 +2284,6 @@ section_omd() { if grepq "CONFIG_AUTOSTART[[:blank:]]*=[[:blank:]]*'on'" "${_sitedir}"/etc/omd/site.conf; then _autostart="1" fi -<<<<<<< HEAD -<<<<<<< HEAD - println "${_site};${_used_version};${_autostart}" - done - - unset -v _autostart _site _sitedir _statefile _statsfile _used_version _versiondir - unset -v _omd_demo _omd_edition _omd_number _omd_site _omd_version -} - -section_omd_core() ( -======= - mkecho "${_site};${_used_version};${_autostart}" - done - ->>>>>>> Merge in latest tranche of changes to various *nix agents -======= println "${_site};${_used_version};${_autostart}" done @@ -2377,53 +2292,23 @@ section_omd_core() ( } section_omd_core() ( ->>>>>>> Update merged script, include var_* functions and mac improvements # Get stats about OMD monitoring cores running on this machine. # Since cd is a shell builtin the check does not affect the performance # on non-OMD machines. if cd /omd/sites; then -<<<<<<< HEAD -<<<<<<< HEAD println '<<>>' for _site in *; do if [ -S "/omd/sites/${_site}/tmp/run/live" ]; then println "[${_site}]" # shellcheck disable=SC2039 println -e "GET status" | -======= - mkecho '<<>>' -======= - println '<<>>' ->>>>>>> Update merged script, include var_* functions and mac improvements - for _site in *; do - if [ -S "/omd/sites/${_site}/tmp/run/live" ]; then - println "[${_site}]" - # shellcheck disable=SC2039 -<<<<<<< HEAD - mkecho -e "GET status" | ->>>>>>> Merge in latest tranche of changes to various *nix agents -======= - println -e "GET status" | ->>>>>>> Update merged script, include var_* functions and mac improvements waitmax 3 "/omd/sites/${_site}/bin/unixcat" "/omd/sites/${_site}/tmp/run/live" fi done -<<<<<<< HEAD -<<<<<<< HEAD println '<<>>' for _site in *; do println "[${_site}]" -======= - mkecho '<<>>' - for _site in *; do - mkecho "[${_site}]" ->>>>>>> Merge in latest tranche of changes to various *nix agents -======= - println '<<>>' - for _site in *; do - println "[${_site}]" ->>>>>>> Update merged script, include var_* functions and mac improvements for _pem_path in "/omd/sites/${_site}/etc/ssl/ca.pem" "/omd/sites/${_site}/etc/ssl/sites/${_site}.pem"; do if [ -f "${_pem_path}" ]; then _cert_date=$( @@ -2432,60 +2317,23 @@ section_omd_core() ( awk '{printf("%s %02d %d %s\n", $1,$2,$4,$3)}' ) # TO-DO: Confirm that this works -<<<<<<< HEAD -<<<<<<< HEAD - println "${_pem_path}|$(calculate_cert_epoch "${_cert_date}")" -======= - mkecho "${_pem_path}|$(calculate_cert_epoch "${_cert_date}")" ->>>>>>> Merge in latest tranche of changes to various *nix agents -======= println "${_pem_path}|$(calculate_cert_epoch "${_cert_date}")" ->>>>>>> Update merged script, include var_* functions and mac improvements fi done done -<<<<<<< HEAD -<<<<<<< HEAD - println '<<>>' - for _site in *; do - if [ -S "/omd/sites/${_site}/tmp/run/mkeventd/status" ]; then - println "[\"${_site}\"]" - # shellcheck disable=SC2039 - println -e "GET status\\nOutputFormat: json" | -======= - mkecho '<<>>' -======= println '<<>>' ->>>>>>> Update merged script, include var_* functions and mac improvements for _site in *; do if [ -S "/omd/sites/${_site}/tmp/run/mkeventd/status" ]; then println "[\"${_site}\"]" # shellcheck disable=SC2039 -<<<<<<< HEAD - mkecho -e "GET status\\nOutputFormat: json" | ->>>>>>> Merge in latest tranche of changes to various *nix agents -======= println -e "GET status\\nOutputFormat: json" | ->>>>>>> Update merged script, include var_* functions and mac improvements waitmax 3 "/omd/sites/${_site}/bin/unixcat" "/omd/sites/${_site}/tmp/run/mkeventd/status" fi done fi -<<<<<<< HEAD -<<<<<<< HEAD unset -v _site _pem_path _cert_date ) -======= - - unset -v _autostart _site _sitedir _statefile _statsfile _used_version _versiondir - unset -v _omd_demo _omd_edition _omd_number _omd_site _omd_version -} ->>>>>>> Merge in latest tranche of changes to various *nix agents -======= - unset -v _site _pem_path _cert_date -) ->>>>>>> Update merged script, include var_* functions and mac improvements section_openvpn() { # OpenVPN Clients. These are our two known log locations. @@ -2633,68 +2481,6 @@ section_soft_raid() { cat /proc/mdstat ;; esac -<<<<<<< HEAD -<<<<<<< HEAD -======= - # RAID status of LSI controllers via cfggen - if inpath cfggen; then - mkecho '<<>>' - cfggen 0 DISPLAY | - grep -E '(Target ID|State|Volume ID|Status of volume)[[:space:]]*:' | - sed -e 's/ *//g' -e 's/:/ /' - fi - - # RAID status of LSI MegaRAID controller via MegaCli. You can download that tool from: - # http://www.lsi.com/downloads/Public/MegaRAID%20Common%20Files/8.02.16_MegaCLI.zip - # From this list, the first that's found in PATH (if any) is mapped to lsicli() - for cliAlt in MegaCli MegaCli64 megacli storcli storcli64; do - if inpath "${cliAlt}"; then - lsicli() { "${cliAlt}"; } - break - fi - unset cliAlt - done - - if inpath lsicli; then - mkecho '<<>>' - for part in $(lsicli -EncInfo -aALL -NoLog >>' - lsicli -LDInfo -Lall -aALL -NoLog >>' - lsicli -AdpBbuCmd -GetBbuStatus -aALL -NoLog >>' - tw_cli "/${_tw_ctl}" show all | grep -E 'Model =|Firmware|Serial' - mkecho '<<<3ware_disks>>>' - tw_cli "/${_tw_ctl}" show drivestatus | grep -E 'p[0-9]' | sed "s/^/${_tw_ctl}\\//" - mkecho '<<<3ware_units>>>' - tw_cli "/${_tw_ctl}" show unitstatus | grep -E 'u[0-9]' | sed "s/^/${_tw_ctl}\\//" - done - unset -v _tw_ctl - fi - - # RAID controllers from areca (Taiwan) - # cli64 can be found at ftp://ftp.areca.com.tw/RaidCards/AP_Drivers/Linux/CLI/ - if inpath cli64; then - run_cached arc_raid_status 300 "cli64 rsf info | tail -n +3 | head -n -2" - fi ->>>>>>> Merge in latest tranche of changes to various *nix agents -======= ->>>>>>> Update merged script, include var_* functions and mac improvements } # Start new liveupdate process in background on each agent execution. From 4f8463674d15283b0df4538bda7a21e9aa653a79 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Thu, 24 Sep 2020 23:14:09 +1200 Subject: [PATCH 29/29] Merge changes from ccd182b, rename println() to write(), update get_shell() --- agents/check_mk_agent.merged | 706 +++++++++++++++++------------------ 1 file changed, 352 insertions(+), 354 deletions(-) diff --git a/agents/check_mk_agent.merged b/agents/check_mk_agent.merged index a26edfa3733..d1ddd00bf96 100755 --- a/agents/check_mk_agent.merged +++ b/agents/check_mk_agent.merged @@ -54,43 +54,43 @@ PATH="${newPath#:}" export PATH unset -v newPath -# 'println()' abstracts the portability of 'printf' and solves the major portability headaches -# caused by various implementations of 'echo'. This is called 'println()' rather than 'echo()' as +# 'write()' abstracts the portability of 'printf' and solves the major portability headaches +# caused by various implementations of 'echo'. This is called 'write()' rather than 'echo()' as # an override function, because some shells protect their builtins and complain. # Fun exercise: look at Oracle's man page for 'echo', specifically the USAGE section. # This also adds the '-j' option to output in json keypair format -println() { +write() { case "${1}" in (-e) case "${2}" in - (-n) shift 2; printf -- '%b' "${*}" ;; - (*) shift; printf -- '%b\n' "${*}" ;; + (-n|--end) shift 2; printf -- '%b' "${*}" ;; + (*) shift; printf -- '%b\n' "${*}" ;; esac ;; (-E) case "${2}" in - (-n) shift 2; printf -- '%s' "${*}" ;; - (*) shift; printf -- '%s\n' "${*}" ;; + (-n|--end) shift 2; printf -- '%s' "${*}" ;; + (*) shift; printf -- '%s\n' "${*}" ;; esac ;; - (-j) shift; printf -- '{"%s": "%s"}\n' "${1}" "${2}" ;; - (-n) + (-j) shift; printf -- '{"%s": "%s"}\n' "${1}" "${2}" ;; + (-n|--end) case "${2}" in - (-e) shift 2; printf -- '%b' "${*}" ;; - (-E) shift 2; printf -- '%s' "${*}" ;; - (*) shift; printf -- '%s' "${*}" ;; + (-e) shift 2; printf -- '%b' "${*}" ;; + (-E) shift 2; printf -- '%s' "${*}" ;; + (*) shift; printf -- '%s' "${*}" ;; esac ;; - (-en|-ne) shift; printf -- '%b' "${*}" ;; - (-En|-nE) shift; printf -- '%s' "${*}" ;; - (*) printf -- '%s\n' "${*}" ;; + (-en|-ne) shift; printf -- '%b' "${*}" ;; + (-En|-nE) shift; printf -- '%s' "${*}" ;; + (*) printf -- '%s\n' "${*}" ;; esac } # Functionalise and standardise 'quiet grep' based tests. # This gives us 'grep -q' cleanliness where '>/dev/null 2>&1' # would otherwise be required e.g. Solaris, older versions of grep etc -if println "word" | grep -q "word" >/dev/null 2>&1; then +if write "word" | grep -q "word" >/dev/null 2>&1; then grepq() { grep -q "$@" 2>/dev/null; } else grepq() { grep "$@" >/dev/null 2>&1; } @@ -155,16 +155,19 @@ get_shell() { elif ps -p "$$" >/dev/null 2>&1; then # This double-awk caters for situations where CMD/COMMAND # might be a full path e.g. /usr/bin/zsh - ps -p "$$" | tail -n 1 | awk '{print $NF}' | awk -F '/' '{print $NF}' | tr -d '()' + ps -p "$$" | awk -F'[\t /]' 'END {print $NF}' # This one works well except for busybox elif ps -o comm= -p "$$" >/dev/null 2>&1; then ps -o comm= -p "$$" elif ps -o pid,comm= >/dev/null 2>&1; then ps -o pid,comm= | awk -v ppid="$$" '$1==ppid {print $2}' + # FreeBSD, may require more parsing + elif inpath procstat; then + procstat -bh $$ else - case "${BASH_VERSION}" in (*.*) printf -- '%s\n' "bash";; esac; return 0 - case "${KSH_VERSION}" in (*.*) printf -- '%s\n' "ksh";; esac; return 0 - case "${ZSH_VERSION}" in (*.*) printf -- '%s\n' "zsh";; esac; return 0 + case "${BASH_VERSION}" in (*.*) printf -- '%s\n' "bash"; return 0 ;; esac + case "${KSH_VERSION}" in (*.*) printf -- '%s\n' "ksh"; return 0 ;; esac + case "${ZSH_VERSION}" in (*.*) printf -- '%s\n' "zsh"; return 0 ;; esac # If we get to this point, fail out: return 1 fi @@ -372,9 +375,9 @@ fi # If we are called via xinetd, try to find only_from configuration if var_is_set "${REMOTE_HOST}"; then # shellcheck disable=SC2039 - println -n 'OnlyFrom: ' + write -n 'OnlyFrom: ' sed -n '/^service[[:space:]]*'$XINETD_SERVICE_NAME'/,/}/s/^[[:space:]]*only_from[[:space:]]*=[[:space:]]*\(.*\)/\1/p' /etc/xinetd.d/* | head -n1 - println + write fi # Convert a three number style semantic version number to an integer for version comparisons @@ -384,12 +387,12 @@ semver_to_int() { _sem_ver="${1:?No version number supplied}" # Strip the variable of any non-numerics or dots - _sem_ver="$(println "${_sem_ver}" | sed 's/[^0-9.]//g')" + _sem_ver="$(write "${_sem_ver}" | sed 's/[^0-9.]//g')" # Swap the dots for spaces and assign the outcome to the positional param array # We want word splitting here, so we disable shellcheck's complaints # shellcheck disable=SC2046 - set -- $(println "${_sem_ver}" | tr '.' ' ') + set -- $(write "${_sem_ver}" | tr '.' ' ') # Assemble and print our integer printf -- '%d%02d%02d' "${1}" "${2:-0}" "${3:-0}" @@ -428,7 +431,7 @@ fi convert_time_to_epoch() { # Read our incoming date/time information into our variables _month="${1:?No date provided}"; _day="${2}"; _year="${3}"; _timestamp="${4}" - println "${_timestamp}" | while IFS=':' read -r _hours _min _sec; do + write "${_timestamp}" | while IFS=':' read -r _hours _min _sec; do # Convert the month to 0..11 range case "${_month}" in ([jJ]an*) _month=0 ;; @@ -487,7 +490,7 @@ get_nfs_mounts() { get_ntpq() { # If 'ntpq' isn't in PATH, there's no point going further inpath ntpq || return 1 - [ "${1}" = "--header" ] && println '<<>>' + [ "${1}" = "--header" ] && write '<<>>' ntpq -np | sed -e 1,2d -e 's/^\\(.\\)/\\1 /' -e 's/^ /%/' || true } @@ -527,7 +530,7 @@ is_valid_plugin() { # Setup a function to encrypt the output using openssl protect_output() { if ! inpath openssl; then - println "ERROR: protect_output(): 'openssl' not found in PATH" >&2 + write "ERROR: protect_output(): 'openssl' not found in PATH" >&2 return fi @@ -535,7 +538,7 @@ protect_output() { if [ "${1}" = "-rt" ]; then # Let's see if RTC_SECRET is defined if [ ! -r "${MK_CONFDIR}/real_time_checks.cfg" ]; then - println "ERROR: protect_output(): Unable to read real_time_checks.cfg" + write "ERROR: protect_output(): Unable to read real_time_checks.cfg" return fi # If we have a defined RTC_SECRET, then we prioritise that. @@ -560,9 +563,9 @@ protect_output() { # Print our protocol and/or epoch information if [ "${1}" = "-rt" ]; then - println -n "${_encCode}$(get_epoch)" + write -n "${_encCode}$(get_epoch)" else - println -n "${_encCode}" + write -n "${_encCode}" fi # Call openssl with our required digest and auth @@ -661,7 +664,7 @@ run_cached() { _cached_name="${1}" _cached_maxage="${2}" - _cached_section="println '<<<${_cached_name}:cached($(get_epoch),${_cached_maxage})>>>' ; " + _cached_section="write '<<<${_cached_name}:cached($(get_epoch),${_cached_maxage})>>>' ; " shift 2 _cached_cmd="${_cached_section}${*}" @@ -722,9 +725,9 @@ run_cached() { if var_is_unset "${_use_cachefile}" && [ ! -e "${_cached_file}".new ]; then # When the command fails, the output is throws away ignored if [ "${_cached_mrpe}" -eq 1 ]; then - println "set -o noclobber ; exec > \"$_cached_file.new\" || exit 1 ; run_mrpe $_cached_name \"$_cached_cmd\" && mv \"$_cached_file.new\" \"$_cached_file\" || rm -f \"$_cached_file\" \"$_cached_file.new\"" | nohup /bin/bash >/dev/null 2>&1 & + write "set -o noclobber ; exec > \"$_cached_file.new\" || exit 1 ; run_mrpe $_cached_name \"$_cached_cmd\" && mv \"$_cached_file.new\" \"$_cached_file\" || rm -f \"$_cached_file\" \"$_cached_file.new\"" | nohup /bin/bash >/dev/null 2>&1 & else - println "set -o noclobber ; exec > \"$_cached_file.new\" || exit 1 ; $_cached_cmd && mv \"$_cached_file.new\" \"$_cached_file\" || rm -f \"$_cached_file\" \"$_cached_file.new\"" | nohup /bin/bash >/dev/null 2>&1 & + write "set -o noclobber ; exec > \"$_cached_file.new\" || exit 1 ; $_cached_cmd && mv \"$_cached_file.new\" \"$_cached_file\" || rm -f \"$_cached_file\" \"$_cached_file.new\"" | nohup /bin/bash >/dev/null 2>&1 & fi fi unset -v _cached_section _cached_mrpe _cached_append_age _cached_name _cached_maxage _cached_cmd @@ -757,7 +760,7 @@ case $(waitmax 1 bash -c ": &1") in unset -v _bin_nc } else - println "send_rtc(): Unable to determine communication method" >&2 + write "send_rtc(): Unable to determine communication method" >&2 fi ;; esac @@ -767,7 +770,7 @@ esac # detailed graphing (if you configure your RRDs to this resolution). run_real_time_checks() { _rt_pid=${MK_VARDIR:?}/real_time_checks.pid - println "$$" >"${_rt_pid}" + write "$$" >"${_rt_pid}" while true; do # terminate when pidfile is gone or other Real-Time Check process started or configured timeout @@ -786,7 +789,7 @@ run_real_time_checks() { # protect_output() takes care of printing our protocol and epoch info section_"${_rt_section}" | protect_output -rt else - println -n "99$(get_epoch)" + write -n "99$(get_epoch)" section_"${_rt_section}" fi } | dd bs=9999 iflag=fullblock 2>/dev/null | send_rtc "${MK_RTC_HOST}" "${RTC_PORT}" @@ -802,7 +805,7 @@ run_real_time_checks() { if [ "${ENCRYPTED_RT}" != "no" ]; then ./"${_rt_plugin}" | protect_output -rt else - println -n "99$(get_epoch)" + write -n "99$(get_epoch)" ./"${_rt_plugin}" fi } | dd bs=9999 iflag=fullblock 2>/dev/null | send_rtc "${MK_RTC_HOST}" "${RTC_PORT}" @@ -823,11 +826,11 @@ run_real_time_checks() { section_3ware_raid() { if inpath tw_cli; then for _tw_ctl in $(tw_cli show | awk 'NR < 4 { next } { print $1 }'); do - println '<<<3ware_info>>>' + write '<<<3ware_info>>>' tw_cli "/${_tw_ctl}" show all | grep -E 'Model =|Firmware|Serial' - println '<<<3ware_disks>>>' + write '<<<3ware_disks>>>' tw_cli "/${_tw_ctl}" show drivestatus | grep -E 'p[0-9]' | sed "s/^/${_tw_ctl}\\//" - println '<<<3ware_units>>>' + write '<<<3ware_units>>>' tw_cli "/${_tw_ctl}" show unitstatus | grep -E 'u[0-9]' | sed "s/^/${_tw_ctl}\\//" done unset -v _tw_ctl @@ -837,49 +840,49 @@ section_3ware_raid() { # TO-DO: Determine if any of these can be merged into other functions section_aix() { if inpath lparstat; then - println '<<>>' + write '<<>>' lparstat 1 1 fi # powerHA if inpath lslpp; then _cluster_cmd_output=$(lslpp -l cluster.es.server.rte) - if ! println "${_cluster_cmd_output}" | grepq "not installed"; then + if ! write "${_cluster_cmd_output}" | grepq "not installed"; then # now the following commands should be available _nodes=$(cllsnode | grep "NODE" | sed -e s/NODE//g -e s/://g) _list_active_nodes="" for _node in ${_nodes}; do _active_nodes=$(clgetactivenodes -n "${_node}") - if println "${_active_nodes}" | grepq "${_node}"; then + if write "${_active_nodes}" | grepq "${_node}"; then _list_active_nodes=${_list_active_nodes}"\\n${_node}" fi done if [ "${_list_active_nodes}" ]; then - println '<<>>' + write '<<>>' # shellcheck disable=SC2039 - println -e "${_list_active_nodes}" + write -e "${_list_active_nodes}" cllsnode fi - println '<<>>' + write '<<>>' if inpath clshowsrv ; then waitmax 5 clshowsrv -v else # fallback, hardcoded base installation path waitmax 5 /usr/es/sbin/cluster/utilities/clshowsrv -v fi - println '<<>>' + write '<<>>' waitmax 5 clRGinfo -s unset -v _cluster_cmd_output _nodes _list_active_nodes _node _active_nodes fi fi - println '<<>>' + write '<<>>' mpstat -a | tail -n1 - println '<<>>' + write '<<>>' # -L disables LVM lock for the query. Avoids blocking while LVM is # doing changes. For rootvg that is fine. lsvg -L -l rootvg @@ -896,7 +899,7 @@ section_areca_raid() { # RAID status of LSI controllers via cfggen section_cfggen() { if inpath cfggen; then - println '<<>>' + write '<<>>' cfggen 0 DISPLAY | grep -E '(Target ID|State|Volume ID|Status of volume)[[:space:]]*:' | sed -e 's/ *//g' -e 's/:/ /' @@ -919,72 +922,69 @@ section_cpu() { case "${MK_OSSTR}" in (aix) # CPU output of Linux agent simulated (thanks to Cameron Pierce) - println '<<>>' + write '<<>>' _load=$(uptime|sed -e 's;.*average: \([[:digit:]]\{1,\}\.[[:digit:]]\{1,\}\), \([[:digit:]]\{1,\}\.[[:digit:]]\{1,\}\), \([[:digit:]]\{1,\}\.[[:digit:]]\{1,\}\);\1 \2 \3;') _ps=$(ps -eo thcount | awk '{SUM+=$1} END {print SUM}') _procs=$(vmstat|grep lcpu|sed -e 's;.*lcpu=\([[:digit:]]\{1,4\}\).*;\1;') - println "${_load} 1/${_ps} $$ ${_procs}" + write "${_load} 1/${_ps} $$ ${_procs}" unset -v _load _ps _procs ;; (freebsd) - println '<<>>' + write '<<>>' sysctl -n vm.loadavg | tr -d '{}' top -b -n 1 | grep -E '^[0-9]+ processes' | awk '{print $3"/"$1}' sysctl -n kern.lastpid sysctl -n hw.ncpu ;; (hpux) - println '<<>>' + write '<<>>' uptime # machinfo is unsupported addon thus not in $PATH /usr/contrib/bin/machinfo | grep -E 'logical proc|core' | tail -1 ;; (linux) - if [ "$(uname -m)" = "armv7l" ]; then - _cpu_regex='^processor' - else - _cpu_regex='^CPU|^processor' - fi + case "$(uname -m)" in + (armv71|armv61) _cpu_regex='^processor' ;; + (''|*) _cpu_regex='^CPU|^processor' ;; + esac _num_cpus=$(grep -c -E ${_cpu_regex} >>' - println "$(cat /proc/loadavg) $_num_cpus" - if [ -f "/proc/sys/kernel/threads-max" ]; then - cat /proc/sys/kernel/threads-max - fi + write '<<>>' + write "$(cat /proc/loadavg) $_num_cpus" + [ -r "/proc/sys/kernel/threads-max" ] && cat /proc/sys/kernel/threads-max else if var_is_set "${MK_IS_DOCKERIZED}"; then - println '<<>>' + write '<<>>' else - println '<<>>' + write '<<>>' fi grep "^cpu " /proc/stat - println "num_cpus ${_num_cpus}" + write "num_cpus ${_num_cpus}" cat /sys/fs/cgroup/cpuacct/cpuacct.stat fi - unset -v _cpu_regex _num_cpu + unset -v _cpu_regex _num_cpus ;; (mac) - println '<<>>' + write '<<>>' sysctl -n vm.loadavg | tr -d '{}' top -l 1 -n 1 | grep -E '^Processes:' | awk '{$4"/"$2;}' - println 'println $$' | bash + write 'write $$' | bash sysctl -n hw.ncpu ;; (netbsd|openbsd) - println '<<>>' + write '<<>>' sysctl -n vm.loadavg | tr -d '{}' top -b -n 1 | grep -E '^[0-9]+ processes' | awk '{print $3"/"$1}' sysctl -n hw.ncpu ;; (solaris) # Simulated Output of Linux /proc/cpu - println '<<>>' + write '<<>>' _load=$(uptime|sed -e 's;.*average: \([0-9]\{1,\}\.[0-9]\{1,\}\), \([0-9]\{1,\}\.[0-9]\{1,\}\), \([0-9]\{1,\}\.[0-9]\{1,\}\).*;\1 \2 \3;') _nthreads=$(($(ps -AL | wc -l))) _procs=$(($(psrinfo | wc -l))) - println "${_load} 1/${_nthreads} $$ ${_procs}" + write "${_load} 1/${_nthreads} $$ ${_procs}" unset -v _load _nthreads _procs ;; esac @@ -1007,18 +1007,18 @@ section_df() { /usr/opt/freeware/bin/df -PTlk ${_df_excludefs} | sed 1d # df inodes information - println '<<>>' - println '[df_inodes_start]' + write '<<>>' + write '[df_inodes_start]' # shellcheck disable=SC2086 /usr/opt/freeware/bin/df -PTli ${_df_excludefs} | sed 1d - println '[df_inodes_end]' + write '[df_inodes_end]' else df -kP | sed 's/ / - /' | grep -v ^/proc | grep -v ^Filesystem | grep -v : fi unset -v _df_excludefs ;; (freebsd) - println '<<>>' + write '<<>>' # no special zfs handling so far, the ZFS.pools plugin has been tested to # work on FreeBSD if df -T > /dev/null ; then @@ -1034,7 +1034,7 @@ section_df() { # Filesystems. HP-UX does not provide a filesystem type. We assume # modern systems with vxfs only here. The filesystem type is currently # not used by the check anyway. - println '<<>>' + write '<<>>' df -kP | sed 's/ / - /' | awk '/^(.*-.*)$/ { print $0 } /^([^-]+)$/ { printf $0 }' | @@ -1051,42 +1051,42 @@ section_df() { _df_excludefs="${_df_excludefs} -x zfs" fi - println '<<>>' + write '<<>>' # shellcheck disable=SC2086 df -PTlk ${_df_excludefs} | sed 1d # df inodes information - println '<<>>' - println '[df_inodes_start]' + write '<<>>' + write '[df_inodes_start]' # shellcheck disable=SC2086 df -PTli ${_df_excludefs} | sed 1d - println '[df_inodes_end]' + write '[df_inodes_end]' unset -v _df_excludefs ;; (mac) - println '<<>>' + write '<<>>' df -kPT hfs,apfs | grep -Ev "Time Machine|com.apple.TimeMachine.localsnapshots|/Volumes/|/private/var/vm" | sed 1d | while read -r _df_dev _df_rest; do _df_type=$(diskutil info "${_df_dev}" | grep '^\s*Type' | cut -d: -f2 | tr -d '[:space:]') - println "${_df_dev} ${_df_type} ${_df_rest}" + write "${_df_dev} ${_df_type} ${_df_rest}" done unset -v df_dev df_type df_rest ;; (netbsd|openbsd) - println '<<>>' + write '<<>>' df -kPt ffs | sed -e 's/^\([^ ][^ ]*\) \(.*\)$/\1 ffs \2/' | sed 1d ;; (solaris) # Filesystem usage for UFS and VXFS - println '<<>>' + write '<<>>' for _fs in ufs vxfs samfs lofs tmpfs; do df -l -k -F ${_fs} 2>/dev/null | sed 1d | grep -v "^[^ ]*/lib/[^ ]*\\.so\\.1 " | \ while read -r _Filesystem _kbytes _used _avail _capacity _Mountedon; do _kbytes=$((_used + _avail)) - println "${_Filesystem} ${_fs} ${_kbytes} ${_used} ${_avail} ${_capacity} ${_Mountedon}" + write "${_Filesystem} ${_fs} ${_kbytes} ${_used} ${_avail} ${_capacity} ${_Mountedon}" done done unset -v _fs _Filesystem _kbytes _used _avail _capacity _Mountedon @@ -1098,32 +1098,32 @@ section_df() { section_diskstat() { # Performancecounter Platten if var_is_unset "${MK_IS_DOCKERIZED}" && [ -r "/proc/diskstats" ]; then - println '<<>>' + write '<<>>' get_epoch _grepFilter=" (x?[shv]d[a-z]*[0-9]*|cciss/c[0-9]+d[0-9]+|emcpower[a-z]+|dm-[0-9]+" _grepFilter="${_grepFilter}|VxVM.*|mmcblk.*|dasd[a-z]*|bcache[0-9]+|nvme[0-9]+n[0-9]+) " grep -E "${_grepFilter}" >>' - println "[time]" + write '<<>>' + write "[time]" get_epoch for _ioFile in io_service_bytes io_serviced; do - println "[${_ioFile}]" + write "[${_ioFile}]" cat "/sys/fs/cgroup/blkio/blkio.throttle.${_ioFile}" done - println "[names]" + write "[names]" for _ioFile in /sys/block/*; do # shellcheck disable=SC2039 - println "${_ioFile##*/} $(cat "${_ioFile}/dev")" + write "${_ioFile##*/} $(cat "${_ioFile}/dev")" done unset -v _ioFile fi @@ -1132,18 +1132,18 @@ section_diskstat() { section_dm_raid() { # RAID status of Linux RAID via device mapper if inpath dmraid && _dmstatus=$(waitmax 3 dmraid -r); then - println '<<>>' + write '<<>>' # Output name and status waitmax 20 dmraid -s | grep -e ^name -e ^status # Output disk names of the RAID disks - _disks=$(println "${_dmstatus}" | cut -f1 -d":") + _disks=$(write "${_dmstatus}" | cut -f1 -d":") for _disk in ${_disks}; do _device=$(cat /sys/block/"$(basename "${_disk}")"/device/model) - _status=$(println "${_dmstatus}" | grep "^${_disk}") - println "${_status} Model: ${_device}" + _status=$(write "${_dmstatus}" | grep "^${_disk}") + write "${_status} Model: ${_device}" done fi unset -v _dmstatus _disks _disk _device _status @@ -1151,7 +1151,7 @@ section_dm_raid() { section_drbd() { if var_is_unset "${MK_IS_DOCKERIZED}" && var_is_unset "${MK_IS_LXC_CONTAINER}" && [ -r /proc/drbd ]; then - println '<<>>' + write '<<>>' cat /proc/drbd fi } @@ -1194,8 +1194,8 @@ section_fileinfo() { section_haproxy() { for HAPROXY_SOCK in /run/haproxy/admin.sock /var/lib/haproxy/stats; do if [ -r "$HAPROXY_SOCK" ] && inpath socat; then - println "<<>>" - println "show stat" | socat - "UNIX-CONNECT:$HAPROXY_SOCK" + write "<<>>" + write "show stat" | socat - "UNIX-CONNECT:$HAPROXY_SOCK" fi done } @@ -1225,24 +1225,24 @@ section_heartbeat() { pgrep crmd >/dev/null 2>&1 || pgrep -f pacemaker-controld >/dev/null 2>&1 }; then - println '<<>>' + write '<<>>' TZ=UTC crm_mon -1 -r | grep -v ^$ | sed 's/^ //; /^\sResource Group:/,$ s/^\s//; s/^\s/_/g' fi if inpath cl_status; then - println '<<>>' + write '<<>>' cl_status rscstatus - println '<<>>' + write '<<>>' for _node in $(cl_status listnodes); do - if [ "${_node}" != "$(println "${HOSTNAME}" | tr '[:upper:]' '[:lower:]')" ]; then + if [ "${_node}" != "$(write "${HOSTNAME}" | tr '[:upper:]' '[:lower:]')" ]; then _status=$(cl_status nodestatus "${_node}") # shellcheck disable=SC2039 - println -n "${_node} ${_status}" + write -n "${_node} ${_status}" for _link in $(cl_status listhblinks "${_node}" 2>/dev/null); do # shellcheck disable=SC2039 - println -n " ${_link} $(cl_status hblinkstatus "${_node}" "${_link}")" + write -n " ${_link} $(cl_status hblinkstatus "${_node}" "${_link}")" done - println + write fi done unset -v _node _status _link @@ -1251,24 +1251,24 @@ section_heartbeat() { section_hpux() { # Logical Volume Manager - println '<<>>' + write '<<>>' /sbin/vgdisplay -v -F - println '<<>>' + write '<<>>' if inpath cmviewcl; then cmviewcl -v -f line | grep summary fi # Kernel tunnables if inpath kcusage; then - println '<<>>' + write '<<>>' kcusage -l fi # State of FC HBAs - println '<<>>' + write '<<>>' for _hba in /dev/fcd*; do - println "${_hba}" + write "${_hba}" /opt/fcms/bin/fcdutil "${_hba}" | grep -e "Driver state" \ -e "Topology" \ @@ -1293,7 +1293,7 @@ section_iostat() { _grepFilter="^(x?[shv]d[a-z]*[0-9]*|cciss/c[0-9]+d[0-9]+|emcpower[a-z]+|dm-[0-9]+|VxVM.*" _grepFilter="${_grepFilter}|mmcblk.*|dasd[a-z]*|bcache[0-9]+|nvme[0-9]+n[0-9]+|hdisk) " - println "<<<${MK_OSSTR}_iostat>>>" + write "<<<${MK_OSSTR}_iostat>>>" # AIX was formerly under the header '<<>>' # TO-DO: Update checkman/aix_diskiod, checks/aix_diskiod etc @@ -1327,7 +1327,7 @@ section_ipmisensors() { # IPMI data via ipmi-sensors (of freeipmi). Please make sure, that if you # have installed freeipmi that IPMI is really support by your hardware. if (inpath ipmi-sensors && ls /dev/ipmi*) >/dev/null 2>&1; then - println '<<>>' + write '<<>>' # Newer ipmi-sensors version have new output format; Legacy format can be used if ipmi-sensors --help | grepq legacy-output; then _ipmi_format="--legacy-output" @@ -1353,14 +1353,14 @@ section_jobs() { # arbitrary files can be avoided. ( cd "${MK_VARDIR}/job" || return - println '<<>>' + write '<<>>' case "${MK_OSSTR}" in (aix) for _username in *; do if [ -d "${_username}" ] && cd "${_username}"; then for _filename in *; do # Maybe a cursory "if [ -r "${_filename}" ]" could go here? - println "==> ${_filename} <==" + write "==> ${_filename} <==" cat "${_filename}" done cd .. @@ -1386,7 +1386,7 @@ section_jobs() { if [ "${_count}" -eq "1" ]; then _filename=$(su -s "${SHELL}" "${_username}" -c "ls -1 *") - println "==> ${_filename} <==" + write "==> ${_filename} <==" fi su -s "${SHELL}" "${_username}" -c "head -n1000 *" @@ -1403,23 +1403,23 @@ section_kernel() { case "${MK_OSSTR}" in (freebsd) # Performancecounter Kernel - println "<<>>" + write "<<>>" get_epoch _forks=$(sysctl -n vm.stats.vm.v_forks) _vforks=$(sysctl -n vm.stats.vm.v_vforks) _rforks=$(sysctl -n vm.stats.vm.v_rforks) _kthreads=$(sysctl -n vm.stats.vm.v_kthreads) - println "cpu" "$(sysctl -n kern.cp_time | awk ' { print $1" "$2" "$3" "$5" "$4 } ')" - println "ctxt" "$(sysctl -n vm.stats.sys.v_swtch)" + write "cpu" "$(sysctl -n kern.cp_time | awk ' { print $1" "$2" "$3" "$5" "$4 } ')" + write "ctxt" "$(sysctl -n vm.stats.sys.v_swtch)" # TO-DO: confirm that these are all ints and if so, convert to $(()) # shellcheck disable=SC2003 - println "processes" "$(expr "${_forks}" + "${_vforks}" + "${_rforks}" + "${_kthreads}")" + write "processes" "$(expr "${_forks}" + "${_vforks}" + "${_rforks}" + "${_kthreads}")" unset -v _forks _vforks _rforks _kthreads ;; (linux) # Performancecounter Kernel if var_is_unset "${MK_IS_DOCKERIZED}" && var_is_unset "${MK_IS_LXC_CONTAINER}"; then - println '<<>>' + write '<<>>' get_epoch cat /proc/vmstat /proc/stat fi @@ -1429,7 +1429,7 @@ section_kernel() { section_local() { # Local checks - println '<<>>' + write '<<>>' # Contain the 'cd' within a subshell so that we return # where we came from once the subshell closes ( @@ -1442,7 +1442,7 @@ section_local() { # Call some plugins only every X'th second for _skript in [1-9]*/*; do if is_valid_plugin "${_skript}"; then - _skript_cache=$(println "${_skript}" | sed 's/\//\\/') + _skript_cache=$(write "${_skript}" | sed 's/\//\\/') run_cached "local_${_skript_cache}" "${_skript%/*}" "${_skript}" fi done @@ -1454,7 +1454,7 @@ section_local() { section_mac() { # OSX Timemachine if inpath tmutil; then - println '<<>>' + write '<<>>' tmutil latestbackup 2>&1 fi } @@ -1466,7 +1466,7 @@ section_mac_time() { systemsetup -getusingnetworktime | grepq "Network Time: On" || return 1 # Figure out our OS version so that we can determine our approach var_is_blank "${MK_OSVER}" && return 1 - _macver=$(println "${MK_OSVER}" | tr -d '.') + _macver=$(write "${MK_OSVER}" | tr -d '.') if [ "${_macver}" -ge "1014" ]; then # If this file is missing, create it [ -f /var/db/ntp-kod ] || touch /var/db/ntp-kod @@ -1494,16 +1494,16 @@ section_mailqueue() { read_postfix_queue_dirs() { _postfix_queue_dir="${1}" if var_is_set "${_postfix_queue_dir}"; then - println '<<>>' - println "[[[${2}]]]" + write '<<>>' + write "[[[${2}]]]" for _queue in deferred active; do _count=$(find "${_postfix_queue_dir}/${_queue}" -type f | wc -l) _size=$(du -s "${_postfix_queue_dir}/${_queue}" | awk '{print $1 }') if var_is_empty "${_count}"; then - println "Mail queue is empty" + write "Mail queue is empty" else - println "QUEUE_${_queue} ${_size:-0} ${_count}" + write "QUEUE_${_queue} ${_size:-0} ${_count}" fi done fi @@ -1525,14 +1525,14 @@ section_mailqueue() { # Only handle the last 6 lines (includes the summary line at the bottom and # the last message in the queue. The last message is not used at the moment # but it could be used to get the timestamp of the last message. - println '<<>>' + write '<<>>' postfix_queue_dir=$(postconf -h queue_directory) postfix_count=$(find "$postfix_queue_dir"/deferred -type f | wc -l) postfix_size=$(du -ks "$postfix_queue_dir"/deferred | awk '{print $1 }') if [ "$postfix_count" -gt 0 ]; then - println "$postfix_size" Kbytes in "$postfix_count" Requests. + write "$postfix_size" Kbytes in "$postfix_count" Requests. else - println Mail queue is empty + write Mail queue is empty fi ;; (linux) @@ -1553,54 +1553,54 @@ section_mailqueue() { esac elif [ -x /usr/sbin/ssmtp ]; then - println '<<>>' + write '<<>>' mailq 2>&1 | sed 's/^[^:]*: \(.*\)/\1/' | tail -n 6 # *bsd but should be a reasonable generic fallback elif inpath mailq && getent passwd postfix >/dev/null 2>&1; then - println '<<>>' + write '<<>>' mailq | tail -n 6 fi # From AIX, seems generic enough if [ -x /usr/sbin/sendmail ] ; then - println '<<>>'; + write '<<>>'; mailq 2>&1 | tail -n 6 fi # Postfix status monitoring. Can handle multiple instances. if inpath postfix; then - println "<<>>" + write "<<>>" for i in /var/spool/postfix*/; do if [ -e "$i/pid/master.pid" ]; then if [ -r "$i/pid/master.pid" ]; then postfix_pid=$(sed 's/ //g' <"$i/pid/master.pid") # handle possible spaces in output if readlink -- "/proc/${postfix_pid}/exe" | grepq ".*postfix/\\(s\\?bin/\\)\\?master.*"; then - println "$i:the Postfix mail system is running:PID:$postfix_pid" | sed 's/\/var\/spool\///g' + write "$i:the Postfix mail system is running:PID:$postfix_pid" | sed 's/\/var\/spool\///g' else - println "$i:PID file exists but instance is not running!" | sed 's/\/var\/spool\///g' + write "$i:PID file exists but instance is not running!" | sed 's/\/var\/spool\///g' fi else - println "$i:PID file exists but is not readable" + write "$i:PID file exists but is not readable" fi else - println "$i:the Postfix mail system is not running" | sed 's/\/var\/spool\///g' + write "$i:the Postfix mail system is not running" | sed 's/\/var\/spool\///g' fi done fi # Check status of qmail mailqueue if inpath qmail-qstat; then - println "<<>>" + write "<<>>" qmail-qstat fi # Nullmailer queue monitoring if inpath nullmailer-send && [ -d /var/spool/nullmailer/queue ]; then - println '<<>>' + write '<<>>' COUNT=$(find /var/spool/nullmailer/queue -type f | wc -l) SIZE=$(du -s /var/spool/nullmailer/queue | awk '{print $1 }') - println "$SIZE $COUNT" + write "$SIZE $COUNT" fi } @@ -1617,39 +1617,39 @@ section_megaraid() { done if inpath lsicli; then - println '<<>>' + write '<<>>' for part in $(lsicli -EncInfo -aALL -NoLog >>' + write '<<>>' lsicli -LDInfo -Lall -aALL -NoLog >>' + write '<<>>' lsicli -AdpBbuCmd -GetBbuStatus -aALL -NoLog >>" + # write "<<>>" # lsicli /call/eall/sall show - # println "<<>>" + # write "<<>>" # /opt/MegaRAID/storcli/storcli64 /call/vall show # fi fi } # TO-DO: Standardise section headers -# We ignore the shellcheck alerts for 'println -n' as our 'println()' solves this +# We ignore the shellcheck alerts for 'write -n' as our 'write()' solves this # shellcheck disable=SC2039 section_mem() { case "${MK_OSSTR}" in (aix) - println '<<>>' + write '<<>>' vmstat -v | tr -s ' ' swap -s # TO-DO: Possible candidates? @@ -1658,19 +1658,19 @@ section_mem() { # lsps -a ;; (hpux) - println '<<>>' + write '<<>>' machinfo | grep ^Memory vmstat | sed -n 3p ;; (linux) if var_is_unset "${MK_IS_DOCKERIZED}"; then - println '<<>>' + write '<<>>' grep -E -v '^Swap:|^Mem:|total:' >>' + write '<<>>' cat /sys/fs/cgroup/memory/memory.stat - println "usage_in_bytes $(cat /sys/fs/cgroup/memory/memory.usage_in_bytes)" - println "limit_in_bytes $(cat /sys/fs/cgroup/memory/memory.limit_in_bytes)" + write "usage_in_bytes $(cat /sys/fs/cgroup/memory/memory.usage_in_bytes)" + write "limit_in_bytes $(cat /sys/fs/cgroup/memory/memory.limit_in_bytes)" grep -F 'MemTotal:' /proc/meminfo fi ;; @@ -1682,27 +1682,27 @@ section_mem() { _pageSize=$(vm_stat | awk '/^Mach/{print $8}') _compressedPagesStored=$(vm_stat | awk '/stored in compressor:/{print $5}') _compressedPagesOccupied=$(vm_stat | awk '/occupied by compressor:/{print $5}') - _memFree=$(println "( ${_pagesSpeculative} + ${_pagesInactive} + ${_pagesFree} ) * ${_pageSize} / 1024" | bc) - _swapTotal=$(println "${_compressedPagesStored} * ${_pageSize} / 1024" | bc) - _swapFree=$(println "( ${_compressedPagesStored} - ${_compressedPagesOccupied} ) * ${_pageSize} / 1024" | bc) - println '<<>>' - println "MemTotal: $(println "$(sysctl -n hw.memsize)/1024" | bc) kB" - println "MemFree: ${_memFree} kB" - println "SwapTotal: ${_swapTotal} kB" - println "SwapFree: ${_swapFree} kB" + _memFree=$(write "( ${_pagesSpeculative} + ${_pagesInactive} + ${_pagesFree} ) * ${_pageSize} / 1024" | bc) + _swapTotal=$(write "${_compressedPagesStored} * ${_pageSize} / 1024" | bc) + _swapFree=$(write "( ${_compressedPagesStored} - ${_compressedPagesOccupied} ) * ${_pageSize} / 1024" | bc) + write '<<>>' + write "MemTotal: $(write "$(sysctl -n hw.memsize)/1024" | bc) kB" + write "MemFree: ${_memFree} kB" + write "SwapTotal: ${_swapTotal} kB" + write "SwapFree: ${_swapFree} kB" unset -v _pagesSpeculative _pagesInactive _pagesFree _pageSize _swapTotal _swapFree unset -v _compressedPagesStored _compressedPagesOccupied _memFree ;; (openbsd) - println "<<>>" + write "<<>>" MEM_FREE=$(vmstat | tail -n1 | awk '{ print $5 }') MEM_TOTAL=$(sysctl hw.usermem | cut -d= -f2) - MEM_TOTAL=$(println "$MEM_TOTAL/1024" | bc) + MEM_TOTAL=$(write "$MEM_TOTAL/1024" | bc) SWAPCTL_OUTPUT=$(swapctl -k -s) - SWAP_FREE=$(println "$SWAPCTL_OUTPUT" | awk '{ print $7 }') - SWAP_TOTAL=$(println "$SWAPCTL_OUTPUT" | awk '{ print $2 }') + SWAP_FREE=$(write "$SWAPCTL_OUTPUT" | awk '{ print $7 }') + SWAP_TOTAL=$(write "$SWAPCTL_OUTPUT" | awk '{ print $2 }') # if there is no swap space swap values are 0 if var_is_unset "$SWAPCTL_OUTPUT"; then @@ -1710,17 +1710,17 @@ section_mem() { SWAP_TOTAL=0 fi - println -e "MemTotal:\\t$MEM_TOTAL kB" - println -e "MemFree:\\t$MEM_FREE kB" - println -e "SwapTotal:\\t$SWAP_TOTAL kB" - println -e "SwapFree:\\t$SWAP_FREE kB" + write -e "MemTotal:\\t$MEM_TOTAL kB" + write -e "MemFree:\\t$MEM_FREE kB" + write -e "SwapTotal:\\t$SWAP_TOTAL kB" + write -e "SwapFree:\\t$SWAP_FREE kB" ;; (solaris) # We prefer to use 'statgrab' if it's available. See section_statgrab() # If 'statgrab' isn't available, we offer this workaround if ! inpath statgrab; then if [ -x /usr/bin/top ] || [ -x /usr/local/bin/top ]; then - println "<<>>" + write "<<>>" if [ -x /usr/bin/top ]; then /usr/bin/top | grep '^Memory:'; fi if [ -x /usr/local/bin/top ]; then /usr/local/bin/top | grep '^Memory:'; fi fi @@ -1732,7 +1732,7 @@ section_mem() { section_mkbackup() { # Collect states of configured Check_MK site backup jobs if ls /omd/sites/*/var/check_mk/backup/*.state >/dev/null 2>&1; then - println "<<>>" + write "<<>>" for _state_file in /omd/sites/*/var/check_mk/backup/*.state; do _omd_site=${_state_file#/*/*/*} _omd_site=${_omd_site%%/*} @@ -1741,9 +1741,9 @@ section_mkbackup() { _job_ident=${_job_ident##*/} if [ "${_job_ident}" != "restore" ]; then - println "[[[site:${_omd_site}:${_job_ident}]]]" + write "[[[site:${_omd_site}:${_job_ident}]]]" cat "${_state_file}" - println + write fi done unset -v _state_file _omd_site _job_ident @@ -1751,15 +1751,15 @@ section_mkbackup() { # Collect states of configured CMA backup jobs if inpath mkbackup && ls /var/lib/mkbackup/*.state >/dev/null 2>&1; then - println "<<>>" + write "<<>>" for _state_file in /var/lib/mkbackup/*.state; do _job_ident=${_state_file%.state} _job_ident=${_job_ident##*/} if [ "${_job_ident}" != "restore" ]; then - println "[[[system:${_job_ident}]]]" + write "[[[system:${_job_ident}]]]" cat "$F" - println + write fi done unset -v _state_file _job_ident @@ -1772,13 +1772,13 @@ section_mounts() { # Check mount options. # FreeBSD doesn't do remount-ro on errors, but the users might consider # security related mount options more important. - println '<<>>' + write '<<>>' mount -p -t ufs ;; (linux) # Check mount options. Filesystems may switch to 'ro' in case # of a read error. - println '<<>>' + write '<<>>' grep ^/dev >>' + write '<<>>' _mrpe_plugin=${_mrpe_cmdline%% *} _mrpe_output=$(eval "${_mrpe_cmdline}") - # We ignore the shellcheck alerts for 'println -n' as our 'println()' solves this + # We ignore the shellcheck alerts for 'write -n' as our 'write()' solves this # shellcheck disable=SC2039 - println -n "(${_mrpe_plugin##*/}) ${_mrpe_descr} ${?} ${_mrpe_output}" | tr \\n \\1 - println + write -n "(${_mrpe_plugin##*/}) ${_mrpe_descr} ${?} ${_mrpe_output}" | tr \\n \\1 + write # Unset the function variables unset -v _mrpe_descr _mrpe_cmdline _mrpe_plugin _mrpe_output @@ -1819,11 +1819,11 @@ section_mrpe() { (\(*) # If we do start with '(', then split 'params' out of '_mrpe_cmdline' # We strip the brackets from 'params' and rewrite '_mrpe_cmdline' without the params - _mrpe_params=$(println "${_mrpe_cmdline% *}" | tr -d '()') + _mrpe_params=$(write "${_mrpe_cmdline% *}" | tr -d '()') _mrpe_cmdline="${_mrpe_cmdline##* }" # split multiple parameter assignments - for _par in $(println "${_mrpe_params}" | tr ":" "\\n"); do + for _par in $(write "${_mrpe_params}" | tr ":" "\\n"); do # split each assignment _key="${_par%=*}" _value="${_par#*=}" @@ -1851,26 +1851,26 @@ section_multipathing() { (aix) # TO-DO: Consider merging in mpio_get_config, lsmpio, sanlun, # dlnkmgr, powermt and pcmpath handling - println '<<>>' + write '<<>>' lspath -F"name parent status" ;; (freebsd) # Multipathing is supported in FreeBSD by now # http://www.mywushublog.com/2010/06/freebsd-and-multipath/ if kldstat -v | grep g_multipath > /dev/null ; then - println '<<>>' + write '<<>>' gmultipath status | grep -v ^Name fi ;; (hpux) # Multipathing - println '<<>>' + write '<<>>' scsimgr lun_map | grep -E '^[[:space:]]*(LUN PATH|State|World Wide Identifier)' ;; (linux) if inpath multipath; then if [ -f /etc/multipath.conf ]; then - println '<<>>' + write '<<>>' multipath -l fi fi @@ -1878,7 +1878,7 @@ section_multipathing() { (solaris) if inpath mpathadm; then if [ "$zonename" = "global" ]; then - println '<<>>' + write '<<>>' mpathadm list LU | nawk '{if(NR%3==1){dev=$1} if(NR%3==2){tc=$NF} @@ -1892,16 +1892,16 @@ section_multipathing() { section_net() { case "${MK_OSSTR}" in (aix) - println "<<>>" + write "<<>>" for _ent in $(ifconfig -a | grep '^en' | cut -d ":" -f 1); do - println "[${_ent}]" + write "[${_ent}]" entstat "${_ent}" | grep -E "(^Hardware|^Bytes:|^Packets:|^Transmit|^Broadcast:|^Multicast:)" entstat "${_ent}" | grep -p "Driver Flags:" done unset -v _ent ;; (hpux) - println '<<>>' + write '<<>>' for _nic in $(nwmgr -g | sed -n '/^lan/s/\(^[^ ]* \).*/\1/p'); do nwmgr -g --st mib -c "${_nic}" done @@ -1910,50 +1910,50 @@ section_net() { (linux) # New variant: Information about speed and state in one section if inpath ip; then - println '<<>>' - println "[start_iplink]" + write '<<>>' + write "[start_iplink]" ip address - println "[end_iplink]" + write "[end_iplink]" fi - println '<<>>' + write '<<>>' sed 1,2d /proc/net/dev sed -e 1,2d /proc/net/dev | cut -d':' -f1 | sort | while read -r _eth; do - println "[${_eth}]" + write "[${_eth}]" if inpath ethtool; then ethtool "${_eth}" | grep -E '(Speed|Duplex|Link detected|Auto-negotiation):' else # If interface down we get "Invalid argument" _speed=$(cat "/sys/class/net/${_eth}/speed" 2>/dev/null) - var_is_set "${_speed}" && println -e "\tSpeed: ${_speed}Mb/s\n" + var_is_set "${_speed}" && write -e "\tSpeed: ${_speed}Mb/s\n" fi # shellcheck disable=SC2039 - println -e "\tAddress: $(cat "/sys/class/net/${_eth}/address")\n" + write -e "\tAddress: $(cat "/sys/class/net/${_eth}/address")\n" done unset -v _eth _speed ;; (mac) - println '<<>>' - println "[start_iplink]" + write '<<>>' + write "[start_iplink]" _linkNum=1 if inpath ip; then _interfaces=$(ip a | awk -F ':' '/^[a-z]/{print $1}' | grep -Ev '^(awdl0|utun|llw)') var_is_blank "${_interfaces}" && return for _link in ${_interfaces}; do - println "${_linkNum}: $(ip a show "${_link}")" + write "${_linkNum}: $(ip a show "${_link}")" _linkNum=$(( _linkNum + 1 )) done else _interfaces=$(netstat -inb | awk '/(^en|^lo).*Link/ && $7>0{print $1}') var_is_blank "${_interfaces}" && return for _link in ${_interfaces}; do - println "${_linkNum}: $(ifconfig "${_link}")" + write "${_linkNum}: $(ifconfig "${_link}")" _linkNum=$(( _linkNum + 1 )) done fi - println "[end_iplink]" + write "[end_iplink]" - println '<<>>'; + write '<<>>'; # Format: # Name, IBytes, IPckts, IErr, Drop, 0 (fifo), 0 (frame), 0 (compressed), 0 (multicast), # Coll, Obyts, OPckts, OErrs, 0 (drop), 0 (fifo), 0 (coll), 0 (drop) @@ -1967,24 +1967,24 @@ section_net() { for _iface in ${_interfaces}; do _cur_ifconfig=$(ifconfig -v "${_iface}") # Alt: grep -E "^\s*(down)?link rate:\s*" | cut -d " " -f3,4 | sed -E 's, (.)bps$,\1b/s,' - _ifspeed=$(println "${_cur_ifconfig}" | grep -Eo '[0-9]+baseT' | sed -e 's@baseT@Mb/s@') - println "${_cur_ifconfig}" | grepq "full-duplex" && _ifduplex="Full" - println "${_cur_ifconfig}" | grepq "media: autoselect" && _ifauto="on" - println "${_cur_ifconfig}" | grepq "status: active" && _iflink="yes" + _ifspeed=$(write "${_cur_ifconfig}" | grep -Eo '[0-9]+baseT' | sed -e 's@baseT@Mb/s@') + write "${_cur_ifconfig}" | grepq "full-duplex" && _ifduplex="Full" + write "${_cur_ifconfig}" | grepq "media: autoselect" && _ifauto="on" + write "${_cur_ifconfig}" | grepq "status: active" && _iflink="yes" [ "${_iface}" = "lo0" ] && _iflink="yes" - _ifaddr=$(println "${_cur_ifconfig}" | grep -E '^\s*ether' | cut -d " " -f2) - println "[${_iface}]" - println -e "\tSpeed: ${_ifspeed:-Unknown!}" - println -e "\tDuplex: ${_ifduplex:-Half}" - println -e "\tAuto-negotiation: ${_ifauto:-off}" - println -e "\tLink detected: ${_iflink:-no}" - println -e "\tAddress: ${_ifaddr:-00:00:00:00:00:00}" + _ifaddr=$(write "${_cur_ifconfig}" | grep -E '^\s*ether' | cut -d " " -f2) + write "[${_iface}]" + write -e "\tSpeed: ${_ifspeed:-Unknown!}" + write -e "\tDuplex: ${_ifduplex:-Half}" + write -e "\tAuto-negotiation: ${_ifauto:-off}" + write -e "\tLink detected: ${_iflink:-no}" + write -e "\tAddress: ${_ifaddr:-00:00:00:00:00:00}" done unset -v _linkNum _link _iface _cur_ifconfig _ifspeed _ifduplex _ifauto _iflink _ifaddr ;; (openbsd) - println '<<>>' + write '<<>>' # Example line: # em0 1500 08:00:27:e6:c4:70 16358 0 254 0 0 netstat -in | grep '' | grep -E -v "\\*|lo|pfsync|enc" | @@ -1996,14 +1996,14 @@ section_net() { while read -r _ _ _ _ _bytesIn _bytesOut; do _ifData="${_ifName}:${_bytesIn} ${_pktsIn} ${_errsIn} 0 0 0 0 0 ${_bytesOut}" _ifData="${_ifData} ${_pktsOut} ${_errsOut} 0 0 ${_collisions} 0 0" - println "${_ifData}" + write "${_ifData}" done done unset -v _ifName _pktsIn _errsIn _pktsOut _errsOut _collisions _ifData for _ifName in $(netstat -in | awk '//{print $1}' | grep -E -v "\\*|lo|pfsync|enc"); do - println "[${_ifName}]" + write "[${_ifName}]" _macAddr=$(ifconfig "${_ifName}" | awk '/lladdr/{print $NF}') @@ -2012,33 +2012,33 @@ section_net() { _ifData=$(ifconfig "${_ifName}" | grep "media:") # Speed - _ifSpeed=$(println "${_ifData}" | cut -d\( -f2 | cut -db -f1) + _ifSpeed=$(write "${_ifData}" | cut -d\( -f2 | cut -db -f1) # shellcheck disable=SC2039 - [ "${_ifSpeed}" ] && println -e "\\tSpeed: ${_ifSpeed}Mb/s" + [ "${_ifSpeed}" ] && write -e "\\tSpeed: ${_ifSpeed}Mb/s" # Detect duplexity - in reality only available for physical devices but # virtual ones like CARP devices will get at least a half duplex # shellcheck disable=SC2039 case "${_ifData}" in - (*full-duplex*) println -e "\\tDuplex: Full" ;; - (*half-duplex*) println -e "\\tDuplex: Half" ;; - (*) println -e "\\tDuplex: Unknown" ;; + (*full-duplex*) write -e "\\tDuplex: Full" ;; + (*half-duplex*) write -e "\\tDuplex: Half" ;; + (*) write -e "\\tDuplex: Unknown" ;; esac # Auto-negotiation # shellcheck disable=SC2039 case "${_ifData}" in - (*autoselect*) println -e "\\tAuto-negotiation: on" ;; - (*) println -e "\\tAuto-negotiation: off" ;; + (*autoselect*) write -e "\\tAuto-negotiation: on" ;; + (*) write -e "\\tAuto-negotiation: off" ;; esac # Detect detected link if ifconfig "${_ifName}" | grep "status:" | grepq -E "active|backup|master"; then # shellcheck disable=SC2039 - println -e "\\tLink detected: yes" + write -e "\\tLink detected: yes" fi # shellcheck disable=SC2039 - println -e "\\tAddress: ${_macAddr}" + write -e "\\tAddress: ${_macAddr}" done unset -v _ifName _ifData _ifSpeed _macAddr @@ -2049,7 +2049,7 @@ section_net() { section_net_bonding() { # Current state of bonding interfaces if [ -e /proc/net/bonding ]; then - println '<<>>' + write '<<>>' ( cd /proc/net/bonding || return head -v -n 1000 ./* @@ -2062,9 +2062,9 @@ section_net_ctr() { (freebsd) # Network device statistics (Packets, Collisions, etc) # only the "Link/Num" interface has all counters. - println '<<>>' + write '<<>>' get_epoch - if [ "$(println "${osver}" | cut -f1 -d\. )" -gt "8" ]; then + if [ "$(write "${osver}" | cut -f1 -d\. )" -gt "8" ]; then netstat -inb | grep -Ev '(^Name|lo|plip)' | grep Link | @@ -2078,14 +2078,14 @@ section_net_ctr() { fi ;; (mac) - println '<<>>'; + write '<<>>'; get_epoch netstat -inb | grep -Ev '(^Name|lo|plip)' | awk '/Link/{ print $1,$7,$5,$6,"0","0","0","0","0",$10,$8,$9,"0","0",$11,"0","0"; }' ;; (netbsd) - println '<<>>' + write '<<>>' # BI= Bytes in # PI= Packets in # EI= Errors in @@ -2109,7 +2109,7 @@ section_net_ctr() { CO=$( netstat -in | grep -Ev Name | awk '/Link/{print $9}' | sed -ne $Z1$Z2 ) FF2="0 0" if [ "$PI" -gt "0" ]; then - println "$BI $PI $EI $FF1 $BO $PO $EO $FF2 $CO $FF2" + write "$BI $PI $EI $FF1 $BO $PO $EO $FF2 $CO $FF2" fi Z1=$((Z1+1)) done @@ -2120,10 +2120,10 @@ section_net_openvswitch_bonding() { # Same as section_net_bonding(), but for Open vSwitch bonding if inpath ovs-appctl; then _bonds=$(ovs-appctl bond/list) - _col=$(println "${_bonds}" | awk '{for(i=1;i<=NF;i++) {if($i = "bond") printf("%d", i)} exit 0}') - println '<<>>' - for _bond in $(println "${_bonds}" | sed -e 1d | cut -f"${_col}"); do - println "[${_bond}]" + _col=$(write "${_bonds}" | awk '{for(i=1;i<=NF;i++) {if($i = "bond") printf("%d", i)} exit 0}') + write '<<>>' + for _bond in $(write "${_bonds}" | sed -e 1d | cut -f"${_col}"); do + write "[${_bond}]" ovs-appctl bond/show "${_bond}" done fi @@ -2138,19 +2138,19 @@ section_nfs() { (aix) statFmt="ok - - - -" ;; (linux) statFmt="ok %b %f %a %s" ;; esac - println '<<>>' + write '<<>>' get_nfs_mounts | while read -r mountPoint; do waitmax -s 9 5 stat -f -c "${mountPoint} ${statFmt}" "${mountPoint}" \ - || println "${mountPoint} hanging 0 0 0 0" + || write "${mountPoint} hanging 0 0 0 0" done - println '<<>>' + write '<<>>' get_cifs_mounts | while read -r mountPoint; do if [ ! -r "${mountPoint}" ]; then - println "${mountPoint} Permission denied" + write "${mountPoint} Permission denied" else waitmax -s 9 2 stat -f -c "${mountPoint} ${statFmt}" "${mountPoint}" \ - || println "${mountPoint} hanging 0 0 0 0" + || write "${mountPoint} hanging 0 0 0 0" fi done fi @@ -2205,12 +2205,12 @@ section_nvidia() { # See PR #129 / f8a96be if inpath nvidia-smi; then _nvidia_settings="GPUErrors" - println '<<>>' + write '<<>>' waitmax 2 nvidia-smi --query-gpu=temperature.gpu --format=csv,nounits,noheader | sed "s/^/GPUCoreTemp: /" fi if inpath nvidia-settings && [ -S /tmp/.X11-unix/X0 ]; then - println '<<>>' + write '<<>>' for _var in ${_nvidia_settings:-GPUErrors GPUCoreTemp}; do DISPLAY=:0 waitmax 2 nvidia-settings -t -q "${_var}" | sed "s/^/${_var}: /" done @@ -2221,41 +2221,41 @@ section_nvidia() { section_omd() { # Check status of OMD sites and Check_MK Notification spooler if inpath omd; then - println '<<>>' - # println '{"cmk/check_mk_server": "yes"}' - println -j "cmk/check_mk_server" "yes" + write '<<>>' + # write '{"cmk/check_mk_server": "yes"}' + write -j "cmk/check_mk_server" "yes" run_cached omd_status 60 "omd status --bare || true" - println '<<>>' + write '<<>>' get_epoch for _statefile in /omd/sites/*/var/log/mknotifyd.state; do if [ -e "${_statefile}" ]; then _site=${_statefile%/var/log*} _site=${_site#/omd/sites/} - println "[${_site}]" + write "[${_site}]" grep -v '^#' <"${_statefile}" fi unset -v _site done - println '<<>>' + write '<<>>' for _statsfile in /omd/sites/*/var/log/apache/stats; do if [ -e "${_statsfile}" ]; then _site=${_statsfile%/var/log*} _site=${_site#/omd/sites/} - println "[${_site}]" + write "[${_site}]" cat "${_statsfile}" : >"${_statsfile}" # prevent next section to fail caused by a missing newline at the end of the statsfile - println + write fi unset -v _site done fi - println '<<>>' - println '[versions]' - println 'version;number;edition;demo' + write '<<>>' + write '[versions]' + write 'version;number;edition;demo' for _versiondir in /omd/versions/*; do _omd_version=${_versiondir#/omd/versions/} @@ -2272,10 +2272,10 @@ section_omd() { esac _omd_edition=${_omd_number##*.} _omd_number=${_omd_number%.*} - println "${_omd_version};${_omd_number};${_omd_edition};${_omd_demo}" + write "${_omd_version};${_omd_number};${_omd_edition};${_omd_demo}" done - println '[sites]' - println 'site;used_version;autostart' + write '[sites]' + write 'site;used_version;autostart' for _sitedir in /omd/sites/*; do _site=${_sitedir#/omd/sites/} _used_version=$(readlink "${_sitedir}"/version) @@ -2284,7 +2284,7 @@ section_omd() { if grepq "CONFIG_AUTOSTART[[:blank:]]*=[[:blank:]]*'on'" "${_sitedir}"/etc/omd/site.conf; then _autostart="1" fi - println "${_site};${_used_version};${_autostart}" + write "${_site};${_used_version};${_autostart}" done unset -v _autostart _site _sitedir _statefile _statsfile _used_version _versiondir @@ -2296,19 +2296,19 @@ section_omd_core() ( # Since cd is a shell builtin the check does not affect the performance # on non-OMD machines. if cd /omd/sites; then - println '<<>>' + write '<<>>' for _site in *; do if [ -S "/omd/sites/${_site}/tmp/run/live" ]; then - println "[${_site}]" + write "[${_site}]" # shellcheck disable=SC2039 - println -e "GET status" | + write -e "GET status" | waitmax 3 "/omd/sites/${_site}/bin/unixcat" "/omd/sites/${_site}/tmp/run/live" fi done - println '<<>>' + write '<<>>' for _site in *; do - println "[${_site}]" + write "[${_site}]" for _pem_path in "/omd/sites/${_site}/etc/ssl/ca.pem" "/omd/sites/${_site}/etc/ssl/sites/${_site}.pem"; do if [ -f "${_pem_path}" ]; then _cert_date=$( @@ -2317,17 +2317,17 @@ section_omd_core() ( awk '{printf("%s %02d %d %s\n", $1,$2,$4,$3)}' ) # TO-DO: Confirm that this works - println "${_pem_path}|$(calculate_cert_epoch "${_cert_date}")" + write "${_pem_path}|$(calculate_cert_epoch "${_cert_date}")" fi done done - println '<<>>' + write '<<>>' for _site in *; do if [ -S "/omd/sites/${_site}/tmp/run/mkeventd/status" ]; then - println "[\"${_site}\"]" + write "[\"${_site}\"]" # shellcheck disable=SC2039 - println -e "GET status\\nOutputFormat: json" | + write -e "GET status\\nOutputFormat: json" | waitmax 3 "/omd/sites/${_site}/bin/unixcat" "/omd/sites/${_site}/tmp/run/mkeventd/status" fi done @@ -2346,7 +2346,7 @@ section_openvpn() { return 0 fi - println '<<>>' + write '<<>>' sed -n -e '/CLIENT LIST/,/ROUTING TABLE/p' < "${_openvpn_logfile}" | sed -e 1,3d -e '$d' @@ -2366,7 +2366,7 @@ section_plugins() { # Call some plugins only every Xth second for _skript in [1-9]*/*; do if is_valid_plugin "${_skript}"; then - _skript_cache=$(println "${_skript}" | sed 's/\//\\/') + _skript_cache=$(write "${_skript}" | sed 's/\//\\/') run_cached "plugins_${_skript_cache}" "${_skript%/*}" "${_skript}" fi done @@ -2378,9 +2378,9 @@ section_plugins() { section_proxmox() { # Proxmox Cluster if inpath pvecm; then - println "<<>>" + write "<<>>" pvecm status - println "<<>>" + write "<<>>" pvecm nodes fi } @@ -2388,13 +2388,13 @@ section_proxmox() { section_ps() { case "${MK_OSSTR}" in (aix) - println '<<>>' + write '<<>>' ps -ef -F user,vszsize,rssize,pcpu,etime,pid,args | sed -e 1d -e 's/ *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) */(\1,\2,\3,\4\/\5,\6) /' ;; (freebsd) # processes including username, without kernel processes - println '<<>>' + write '<<>>' COLUMNS=10000 if [ "$is_jailed" = "0" ]; then ps ax -o state,user,vsz,rss,pcpu,command | @@ -2407,32 +2407,30 @@ section_ps() { (hpux) # Process table: HP-UX does not provide a resident size of processes. # We send a 0 here for RSZ. - println '<<>>' + write '<<>>' UNIX95=yes ps -ef -o user,vsz,pcpu,args | sed -e 1d -e 's/ *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) */(\1,\2,0,\3) /' ;; (linux) if inpath ps; then # processes including username, without kernel processes - println '<<>>' - println 'dummy section -- refer to section ps_lnx' - println '<<>>' + write '<<>>' CGROUP="" if [ -e /sys/fs/cgroup ]; then CGROUP="cgroup:512," fi # shellcheck disable=SC2039 - println "[header] $(ps ax -o "$CGROUP"user:32,vsz,rss,cputime,etime,pid,command --columns 10000)" + write "[header] $(ps ax -o "$CGROUP"user:32,vsz,rss,cputime,etime,pid,command --columns 10000)" fi ;; (mac|netbsd|openbsd) - println '<<>>' + write '<<>>' COLUMNS=10000 ps ax -o user,vsz,rss,pcpu,command | sed -e 1d -e 's/ *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) */(\1,\2,\3,\4) /' ;; (solaris) - println '<<>>' + write '<<>>' # The default solaris ps command strips the command lines of the processes. But for good process # matching on the server we really need to whole command line. On linux there are arguments to # make ps output the whole command line, but on solaris this seems to be missing. We use the ucb @@ -2447,17 +2445,17 @@ section_ps() { # Directly use ps output when line is too slow to be stripped if [ ${#LINE} -lt 100 ]; then - println "$LINE" + write "$LINE" continue fi - CMD=$(println "$UCB_PS" | grep "^[ ]*$PID " | head -n1 | \ + CMD=$(write "$UCB_PS" | grep "^[ ]*$PID " | head -n1 | \ awk '{ s = ""; for (i = 5; i <= NF; i++) s = s $i " "; print s }') # Only use the ucb ps line when it's not empty (process might already been gone) if var_is_unset "$CMD"; then - println "$LINE" + write "$LINE" else - println "${STATS}) ${CMD}" + write "${STATS}) ${CMD}" fi done else @@ -2472,12 +2470,12 @@ section_soft_raid() { case "${MK_OSSTR}" in (freebsd) # Soft-RAID - println '<<>>' + write '<<>>' gmirror status | grep -v ^Name ;; (linux) # RAID status of Linux software RAID - println '<<>>' + write '<<>>' cat /proc/mdstat ;; esac @@ -2490,10 +2488,10 @@ section_realtime_checks() { # Validate that we're configured and equipped, otherwise return if [ -r "${MK_CONFDIR}/real_time_checks.cfg" ]; then if var_is_unset "${MK_RTC_HOST}"; then - println "ERROR: \${MK_RTC_HOST} not specified. Not starting Real-Time Checks." >&2 + write "ERROR: \${MK_RTC_HOST} not specified. Not starting Real-Time Checks." >&2 return elif ! inpath openssl; then - println "ERROR: openssl command is missing. Not starting Real-Time Checks." >&2 + write "ERROR: openssl command is missing. Not starting Real-Time Checks." >&2 return fi else @@ -2532,10 +2530,10 @@ section_runas() { (\(*) # If we do start with '(', then split 'params' out of 'cmdline' # We strip the brackets from 'params' and rewrite 'cmdline' without the params - params=$(println "${cmdline% *}" | tr -d '()') + params=$(write "${cmdline% *}" | tr -d '()') cmdline="${cmdline##* }" # split multiple parameter assignments - for par in $(println "${params}" | tr ":" "\\n"); do + for par in $(write "${params}" | tr ":" "\\n"); do # split each assignment key="${par%=*}" value="${par#*=}" @@ -2567,7 +2565,7 @@ section_runas() { done ;; (local|plugin) - [ "$type" = "local" ] && println "<<>>" + [ "$type" = "local" ] && write "<<>>" find "$include" -executable -type f | while read -r filename; do runas_user "${user}" "${filename}" @@ -2582,22 +2580,22 @@ section_services() { case "${MK_OSSTR}" in (linux) if inpath systemctl; then - println '<<>>' - println "[list-unit-files]" + write '<<>>' + write "[list-unit-files]" systemctl list-unit-files --no-pager - println "[all]" + write "[all]" systemctl --all --no-pager | sed '/^$/q' fi # Next we check for 'chkconfig' if inpath chkconfig; then - println '<<>>' + write '<<>>' chkconfig --list 2>&1 fi # Some debian hosts have sysv-rc-conf if inpath sysv-rc-conf; then - println '<<>>' + write '<<>>' sysv-rc-conf fi ;; @@ -2606,7 +2604,7 @@ section_services() { # We can get a list of all service instances, including disabled # or incomplete ones by 'svcs -a' if inpath svcs; then - println '<<>>' + write '<<>>' svcs -a fi ;; @@ -2617,14 +2615,14 @@ section_solaris() { if inpath prtdiag; then # prtdiag does not work in local zones if [ "${zonename}" = "global" ]; then - run_cached solaris_prtdiag_status 300 '/usr/sbin/prtdiag 1>/dev/null 2>&1; println $?' + run_cached solaris_prtdiag_status 300 '/usr/sbin/prtdiag 1>/dev/null 2>&1; write $?' fi fi # Displaying Information About Faults or Defects # If there are no faults the output of this command will be empty. if inpath fmadm; then - println '<<>>' + write '<<>>' fmadm faulty fi } @@ -2644,7 +2642,7 @@ section_spooldir() { # Split any leading digits from a filename and assign to 'maxage' # This should ignore further digits e.g. '600file20' will output '600' - _maxage="$(println "${_file}" | sed 's/^[^0-9]*//;s/[^0-9].*$//')" + _maxage="$(write "${_file}" | sed 's/^[^0-9]*//;s/[^0-9].*$//')" # If 'maxage' is set, then we grab the file's mtime, subtract it from # the epoch time, and compare that to 'maxage' @@ -2676,14 +2674,14 @@ section_statgrab() { statgrab "$statgrab_vars_mem" 1>>/tmp/statgrab.$$ for s in $statgrab_sections; do - println "<<>>" + write "<<>>" grep "^${s}\\." /tmp/statgrab.$$ | cut -d. -f2-99 | sed 's/ *= */ /' done - println '<<>>' + write '<<>>' statgrab net. 2>&1 | cut -d. -f2-99 | sed 's/ *= */ /' - println '<<>>' + write '<<>>' grep -E "^(swap|mem)\\." /tmp/statgrab.$$ | sed 's/ *= */ /' [ -f /tmp/statgrab.$$ ] && rm -f /tmp/statgrab.$$ @@ -2702,13 +2700,13 @@ section_statgrab() { statgrab "$statgrab_vars" | grep -v md 1> /tmp/statgrab.$$ for s in $statgrab_sections; do - println "<<>>" + write "<<>>" grep "^$s\\." /tmp/statgrab.$$ | cut -d. -f2-99 | sed 's/ *= */ /' done # <<>> info is preferred over <<>> # since solaris_mem is under suspicion to be buggy. - println '<<>>' + write '<<>>' grep -E "^(swap|mem)\\." /tmp/statgrab.$$ | sed 's/ *= */ /' [ -f /tmp/statgrab.$$ ] && rm -f /tmp/statgrab.$$ @@ -2723,7 +2721,7 @@ section_tcp_stats() { filter_netstats() { awk ' /^tcp/ { c[$6]++; } END { for (x in c) { print x, c[x]; } }' } - println '<<>>' + write '<<>>' case "${MK_OSSTR}" in (aix|mac) _netstat_opts="-ntfinet" ;; (freebsd) _netstat_opts="-na" ;; @@ -2734,7 +2732,7 @@ section_tcp_stats() { # We simply ignore this warning until we can come up with a cleaner way to do this # shellcheck disable=SC2181 if [ $? = 0 ]; then - println "${_tcp_stats}" + write "${_tcp_stats}" elif inpath ss; then ss -ant | grep -v ^State | @@ -2767,7 +2765,7 @@ section_thermal() { var_is_unset "${MK_IS_LXC_CONTAINER}" && ls /sys/class/thermal/thermal_zone* >/dev/null 2>&1 }; then - println '<<>>' + write '<<>>' for _sysPath in /sys/class/thermal/thermal_zone*; do _line="${_sysPath##*/}" if [ ! -e "${_sysPath}/mode" ]; then @@ -2782,7 +2780,7 @@ section_thermal() { for _type in "${_sysPath}"/trip_point_*_type; do _line="${_line}$(tr <"${_type}" \\n "|")" done - println "${_line%?}" + write "${_line%?}" done unset _sysPath _line _temp _type fi @@ -2792,7 +2790,7 @@ section_thermal() { section_timesyncd() { inpath timedatectl || return 1 timedatectl timesync-status >/dev/null 2>&1 || return 1 - println "<<>>" + write "<<>>" timedatectl timesync-status get_file_mtime /var/lib/systemd/timesync/clock | awk '{print "[[["$1"]]]"}' return 0 @@ -2801,13 +2799,13 @@ section_timesyncd() { # Libelle Business Shadow section_libelle() { if inpath trd; then - println "<<>>" + write "<<>>" trd -s fi } section_uptime() { - println '<<>>' + write '<<>>' case "${MK_OSSTR}" in (aix) # uptime formats @@ -2821,22 +2819,22 @@ section_uptime() { _uptime=$(uptime | sed -e 's/^.*up//g' -e 's/[0-9]* user.*//g') case ${_uptime} in - ( *day* ) _up_days=$(println "${_uptime}" | sed -e 's/days\{0,1\},.*//g') ;; + ( *day* ) _up_days=$(write "${_uptime}" | sed -e 's/days\{0,1\},.*//g') ;; ( * ) _up_days="0" ;; esac case ${_uptime} in ( *:* ) - _up_hours=$(println "${_uptime}" | sed -e 's/.*days\{0,1\},//g' -e 's/:.*//g') - _up_mins=$(println "${_uptime}" | sed -e 's/.*days\{0,1\},//g' -e 's/.*://g' -e 's/,.*//g') + _up_hours=$(write "${_uptime}" | sed -e 's/.*days\{0,1\},//g' -e 's/:.*//g') + _up_mins=$(write "${_uptime}" | sed -e 's/.*days\{0,1\},//g' -e 's/.*://g' -e 's/,.*//g') ;; ( *hr* ) - _up_hours=$(println "${_uptime}" | sed -e 's/hrs\{0,1\},.*//g' -e 's/.*,//g') + _up_hours=$(write "${_uptime}" | sed -e 's/hrs\{0,1\},.*//g' -e 's/.*,//g') _up_mins=0 ;; ( *min* ) _up_hours=0 - _up_mins=$(println "${_uptime}" | sed -e 's/mins\{0,1\},.*//g' -e 's/.*hrs\{0,1\},//g' -e 's/.*days\{0,1\},//g') + _up_mins=$(write "${_uptime}" | sed -e 's/mins\{0,1\},.*//g' -e 's/.*hrs\{0,1\},//g' -e 's/.*days\{0,1\},//g') ;; ( * ) _up_hours="0" @@ -2844,7 +2842,7 @@ section_uptime() { ;; esac - println $(((_up_days*86400)+(_up_hours*3600)+(_up_mins*60))) + write $(((_up_days*86400)+(_up_hours*3600)+(_up_mins*60))) unset -v _uptime _up_hours _up_mins ;; (freebsd) @@ -2853,31 +2851,31 @@ section_uptime() { # pgrep is not appropriate (or even available?) here # shellcheck disable=SC2009 _idle_seconds=$(ps axw | grep "[i]dle" | awk '/idle/{print $4}' | cut -f1 -d':' ) - println "${_up_seconds} ${_idle_seconds}" + write "${_up_seconds} ${_idle_seconds}" unset -v _up_seconds _idle_seconds ;; (linux) if var_is_unset "${MK_IS_DOCKERIZED}"; then cat /proc/uptime else - println "$(($(get_epoch) - $(stat -c %Z /dev/pts)))" + write "$(($(get_epoch) - $(stat -c %Z /dev/pts)))" fi ;; (mac|netbsd|openbsd) - println "$(get_epoch) - $(sysctl -n kern.boottime | cut -d' ' -f 4,7 | tr ',' '.' | tr -d ' ')" | bc + write "$(get_epoch) - $(sysctl -n kern.boottime | cut -d' ' -f 4,7 | tr ',' '.' | tr -d ' ')" | bc ;; (solaris) # Solaris doesn't always give a consistent output on uptime, thus include side information # Tested in VM for solaris 10/11 _ctime=$(nawk 'BEGIN{print srand()}') _btime=$(kstat '-p' 'unix:::boot_time' 2>&1|grep 'boot_time'|awk '{print $2}') - println $((_ctime - _btime)); - println '[uptime_solaris_start]' + write $((_ctime - _btime)); + write '[uptime_solaris_start]' uname -a zonename uptime kstat -p unix:0:system_misc:snaptime - println '[uptime_solaris_end]' + write '[uptime_solaris_end]' unset -v _ctime _btime ;; esac @@ -2885,7 +2883,7 @@ section_uptime() { # 'who -b' is a mostly portable way to report the boot time # TO-DO: is this information header the correct format? if who -b > /dev/null 2>&1; then - println "[who_b_boot_time]" + write "[who_b_boot_time]" who -b fi } @@ -2893,7 +2891,7 @@ section_uptime() { # HTTP Accelerator Statistics section_http_accelerator() { if inpath varnishstat; then - println "<<>>" + write "<<>>" varnishstat -1 fi } @@ -2902,13 +2900,13 @@ section_vbox_guest() { # VirtualBox Guests. Section must always been output. Otherwise the # check would not be executed in case no guest additions are installed. # And that is something the check wants to detect - println '<<>>' + write '<<>>' if inpath VBoxControl; then if lsmod | grepq vboxguest; then VBoxControl -nologo guestproperty enumerate | cut -d, -f1,2 fi else - println "ERROR" + write "ERROR" fi } @@ -2917,7 +2915,7 @@ section_veritas_cluster() { # Software is always installed in /opt/VRTSvcs. # Secure mode must be off to allow root to execute commands if [ -x /opt/VRTSvcs/bin/haclus ]; then - println "<<>>" + write "<<>>" vcshost=$(hostname | cut -d. -f1) waitmax -s 9 2 /opt/VRTSvcs/bin/haclus -display -localclus | grep -e ClusterName -e ClusState waitmax -s 9 2 /opt/VRTSvcs/bin/hasys -display -attribute SysState @@ -2931,12 +2929,12 @@ section_veritas_cluster() { section_vmstat() { case "${MK_OSSTR}" in (aix) - println '<<>>' + write '<<>>' vmstat | tail -n1 ;; (hpux) # Several machine performance counters - println '<<>>' + write '<<>>' vmstat -s ;; esac @@ -2948,24 +2946,24 @@ section_zfs() { case "${MK_OSSTR}" in (freebsd) if inpath zfs; then - println '<<>>' + write '<<>>' zfs get -t filesystem,volume -Hp name,quota,used,avail,mountpoint,type || zfs get -Hp name,quota,used,avail,mountpoint,type - println '[df]' + write '[df]' df -kP -t zfs | sed 1d # arc stats for zfs_arc_cache - println '<<>>' + write '<<>>' sysctl -q kstat.zfs.misc.arcstats | sed -e 's/kstat.zfs.misc.arcstats.//g' -e 's/: / = /g' fi ;; (linux|solaris) if inpath zfs; then - println '<<>>' + write '<<>>' zfs get -t filesystem,volume -Hp name,quota,used,avail,mountpoint,type || zfs get -Hp name,referenced,avail,mountpoint,type | sed 's/referenced/used/g' - println '<<>>' - println '[df]' + write '<<>>' + write '[df]' df -PTlk -t zfs | sed 1d fi ;; @@ -2974,13 +2972,13 @@ section_zfs() { if [ "${MK_OSSTR}" = "solaris" ]; then # ZFS arc cache # newer Solaris (>=11.3) do not provide hits and misses via mdb -k - println '<<>>' + write '<<>>' if inpath kstat; then kstat -p zfs:0:arcstats | sed -e 's/.*arcstats://g' | awk '{printf "%s = %s\n", $1, $2;}' elif inpath; then - println '::arc' | mdb -k + write '::arc' | mdb -k fi fi } @@ -2990,22 +2988,22 @@ section_zpool() { (freebsd) # check zpool status if [ -x /sbin/zpool ]; then - println "<<>>" + write "<<>>" /sbin/zpool status -x | grep -v "errors: No known data errors" fi ;; (linux) if inpath zpool; then - println "<<>>" + write "<<>>" zpool status -x - println "<<>>" + write "<<>>" zpool list fi ;; (solaris) if [ -x /sbin/zpool ]; then run_cached zpool_status 120 "/sbin/zpool status -x" - println '<<>>' + write '<<>>' zpool list fi ;;