#!/bin/sh # Copyright (C) 2019 Checkmk 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. # NOTE: This agent has been adapted from the Checkmk linux agent. inpath() { # replace "if type [somecmd]" idiom # 'command -v' tends to be more robust vs 'which' and 'type' based tests command -v "${1:?No command to test}" >/dev/null 2>&1 } get_epoch() { date +%s 2>/dev/null || perl -e 'print($^T."\n");' } # Remove locale settings to eliminate localized outputs where possible # Author: Christian Zigotzky export LC_ALL=C unset LANG export MK_LIBDIR="/to/be/changed" export MK_CONFDIR="/to/be/changed" # Optionally set a tempdir for all subsequent calls #export TMPDIR= # close standard input (for security reasons) and stderr if [ "$1" = -d ]; then set -xv else exec /dev/null fi section_checkmk() { echo "<<>>" echo "Version: 2.4.0p13" echo "AgentOS: macosx" echo "Hostname: $(hostname)" echo "AgentDirectory: $MK_CONFDIR" echo "DataDirectory: $MK_VARDIR" echo "SpoolDirectory: $SPOOLDIR" echo "PluginsDirectory: $PLUGINSDIR" echo "LocalDirectory: $LOCALDIR" echo "OSName: $(sw_vers -productName)" echo "OSVersion: $(sw_vers -productVersion)" echo "OSType: macos" } section_lnx_if() { echo '<<>>' netstat -inb | grep -E '^en|^lo' | grep Link | sed -e 's/[*]//g' | awk '{ print $1": "$7,$5,$6,"0","0","0","0","0",$10,$8,$9,"0","0",$11,"0","0"; }' printf "[lo0]\n Link detected: yes\n" for ifname in $(netstat -inb | sed -e 's/[*]//g' | grep en | grep Link | awk '{print $1;}'); do IFSPEED='Unknown!' IFDUPLEX="Half" if ifconfig "${ifname}" | grep -q "media: autoselect"; then IFAUTO="on" else IFAUTO="off" fi if ifconfig "${ifname}" | grep -q "full-duplex"; then IFDUPLEX="Full" fi if ifconfig "${ifname}" | grep -q "status: active"; then IFLINK="yes" else IFLINK="no" fi if ifconfig "${ifname}" | grep -Eq '[0-9]+baseT'; then IFSPEED=$(ifconfig "${ifname}" | grep -Eo '[0-9]+baseT' | sed -e 's@baseT@Mb/s@') fi echo "[${ifname}]" echo " Speed: $IFSPEED" echo " Duplex: $IFDUPLEX" echo " Auto-negotiation: $IFAUTO" echo " Link detected: $IFLINK" done } section_df() { echo '<<>>' # SC2162: read without -r will mangle backslashes. # The following suppression was added when we enabled the corresponding shellcheck. # It may well be that "read -r" would be more appropriate. # shellcheck disable=SC2162 df -kPT hfs,apfs | sed 1d | while read DEV REST; do TYPE=$(diskutil info "$DEV" | grep '^\s*Type' | cut -d: -f2 | tr -d '[:space:]') echo "$DEV $TYPE $REST" done } section_cpu() { echo '<<>>' echo "$(sysctl -n vm.loadavg | tr -d '{}') $(top -l 1 -n 1 | grep -E ^Processes: | awk '{ print $4"/"$2; }') $(echo 'echo $$' | bash) $(sysctl -n hw.ncpu)" } section_mem() { echo '<<>>' echo "MemTotal: $(echo "$(sysctl -n hw.memsize)/1024" | bc) kB" echo "MemFree: $(echo "( $(vm_stat | grep speculative: | awk '{print $3}') + $(vm_stat | grep inactive: | awk '{print $3}') + $(vm_stat | grep free: | awk '{print $3}') ) * $(vm_stat | grep Mach | awk '{print $8}') / 1024" | bc) kB" echo "SwapTotal: 0 kB" echo "SwapFree: 0 kB" # FIXME: Just call vm_stat here, write a check plugin that uses that # navite output of vm_stat } section_uptime() { echo '<<>>' echo "$(get_epoch) - $(sysctl -n kern.boottime | cut -d' ' -f 4,7 | tr ',' '.' | tr -d ' ')" | bc # FIXME: use sysctl -a for outputting *all* kernel values. Write # checks plugins with subchecks for parsing that output. Maybe reduce # the output size by grepping away totally useless parts } section_netctr() { echo '<<>>' date +'%s' netstat -inb | grep -v -E '(^Name|lo|plip)' | grep Link | awk '{ print $1,$7,$5,$6,"0","0","0","0","0",$10,$8,$9,"0","0",$11,"0","0"; }' # FIXME: send netstat -inb plain, write proper check plugins for # clean parsing of the output } section_ps() { echo '<<>>' echo "[time]" get_epoch echo "[processes]" ps ax -o user,vsz,rss,pcpu,command | sed -e 1d -e 's/ *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) */(\1,\2,\3,\4) /' } section_ntp() { # NTP seems to be enabled as a default if inpath ntpq; then echo '<<>>' ntpq -np | sed -e 1,2d -e 's/^\(.\)/\1 /' -e 's/^ /%/' fi } section_tcp_conn_stats() { # TCP Conn stats echo '<<>>' netstat -ntfinet | awk ' /^tcp/ { c[$6]++; } END { for (x in c) { print x, c[x]; } }' } 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; 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; my $file_stats = ""; foreach (@patterns) { foreach (bsd_glob("$_")) { if (! -f) { $file_stats .= "$_|missing\n" if ! -d; } elsif (my @infos = stat) { $file_stats .= "$_|ok|$infos[7]|$infos[9]\n"; } else { $file_stats .= "$_|stat failed: $!\n"; } } } print "<<>>\n", time, "\n[[[header]]]\nname|status|size|time\n[[[content]]]\n$file_stats"; ' -- "${MK_CONFDIR}" } section_timemachine() { if type tmutil >/dev/null; then echo '<<>>' tmutil latestbackup 2>&1 fi } run_purely_synchronous_sections() { section_checkmk section_lnx_if section_df section_cpu section_mem section_uptime section_netctr section_ps section_ntp section_tcp_conn_stats section_fileinfo section_timemachine } ############################### # Things up for takers: ############################### # *OSX SW Raid status # *launchctl daemon status # *hw sensors, how to query them? # *OSX Server specific stuff, LDAP, etc... # *Rewrite cpu / ps check to be faster - takes >1s on my laptop # ioreg -l zeigt etliche interessante Inventurdaten _non_comment_lines() { grep -Ev '^[[:space:]]*($|#)' "${1}" } run_mrpe_plugins() { configfile="${1}" if [ -e "/etc/mrpe.cfg" ]; then echo '<<>>' # SC2162: read without -r will mangle backslashes. # The following suppression was added when we enabled the corresponding shellcheck. # It may well be that "read -r" would be more appropriate. # shellcheck disable=SC2162 _non_comment_lines "${configfile}" | while read descr cmdline; do PLUGIN=${cmdline%% *} OUTPUT=$(eval "$cmdline") echo "(${PLUGIN##*/}) $descr $? $OUTPUT" | tr \\n \\1 echo done fi } main() { run_purely_synchronous_sections run_mrpe_plugins "/etc/mrpe.cfg" return 0 } main