#!/bin/bash
#######
# Script utilizes /proc/meminfo to pull memory information as per
# https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=34e431b0ae398fc54ea69ff85ec700722c9da773
# Where MemAvailable cannot be pulled from /proc/meminfo, it is calculated from free+cached as per the above link.
#######
set -e
while getopts ":i:H:c:w:u:" opt; do
  case $opt in
    i )
      KEYFILE="$OPTARG"
      ;;
    H )
      HSTNAME="$OPTARG" # Hostname is reserved var
      ;;
    c )
      CRITLEVEL="$OPTARG"
      ;;
    w )
      WARNLEVEL="$OPTARG"
      ;;
    u )
      USRNAME="$OPTARG" # Username is reserved var
      ;;
    ? )
      echo "script usage: $(basename $0) [-i keyfile] [-H hostname] [-u username] [-w warnLevel] [-c critLevel]" >&2
      exit 3
      ;;
  esac
done

# Defining limits
# init variables
CLEARUPPER=0
CRITMINUS=0
CLEARUPPER=0
WARNUPPER=0
regexPct='^[0-9]+$'
regexAbs='^[0-9]+[BKMGbkmg]$'
denomW=""
denomC=""
mode=""

if [[ $WARNLEVEL =~ $regexPct ]] && [[ $CRITLEVEL =~ $regexPct ]]; then
    mode="PCT"
elif [[ $WARNLEVEL =~ $regexAbs ]] && [[ $CRITLEVEL =~ $regexAbs ]]; then
    mode="ABS"
    # Get the value of denomination for multiplication purposes.
    denomW="${WARNLEVEL: -1}"
    denomC="${CRITLEVEL: -1}"

    # Conversion to bytes from K/M/B
    case $denomW in
        'B' | 'b')
            WARNLEVEL="${WARNLEVEL%?}"
            ;;
        'K' | 'k')
            WARNLEVEL="${WARNLEVEL%?}"
            WARNLEVEL=$(($WARNLEVEL*1024))
            ;;
        'M' | 'm')
            WARNLEVEL="${WARNLEVEL%?}"
            WARNLEVEL=$(($WARNLEVEL*1024*1024))
            ;;
        'G' | 'g')
            WARNLEVEL="${WARNLEVEL%?}"
            WARNLEVEL=$(($WARNLEVEL*1024*1024*1024))
            ;;
        *)
            echo "UNKNOWN - Bad UOM used for absolute memory warn level. Warn Level $WARNLEVEL and Crit Level $CRITLEVEL"
            exit 3
            ;;
    esac

    case $denomC in
        'B' | 'b')
            CRITLEVEL="${CRITLEVEL%?}"
            ;;
        'K' | 'k')
            CRITLEVEL="${CRITLEVEL%?}"
            CRITLEVEL=$(($CRITLEVEL*1024))
            ;;
        'M' | 'm')
            CRITLEVEL="${CRITLEVEL%?}"
            CRITLEVEL=$(($CRITLEVEL*1024*1024))
            ;;
        'G' | 'g')
            CRITLEVEL="${CRITLEVEL%?}"
            CRITLEVEL=$(($CRITLEVEL*1024*1024*1024))
            ;;
        *)
            echo "UNKNOWN - Bad UOM used for absolute memory crit level. Warn Level $WARNLEVEL and Crit Level $CRITLEVEL"
            exit 3
            ;;
    esac
else
    echo "UNKNOWN -- Arguments must be same type, either both percent or both absolute."
    exit 3
fi

if [ $WARNLEVEL -gt $CRITLEVEL ]; then
    echo "UNKNOWN - Warn level must be greater than crit level"
    exit 3
fi

# Subtracting 1 for nagios processing.
CLEARUPPER=$(($WARNLEVEL-1))
WARNUPPER=$(($CRITLEVEL-1))

# Initialize variables
MemTotal=0
MemFree=0
Buffers=0
Cached=0
MemAvailable=0
MemUsed=0
PctUsed=0
MemSimple=0
Power=0
ResDenom=""

# SSH into remote device, pull mem usage from /proc/meminfo
MemInfo=$(ssh -i $KEYFILE -o StrictHostKeyChecking=no $USRNAME@$HSTNAME cat /proc/meminfo)

# Pull individual values
MemTotal=$(echo "$MemInfo" | grep -i ^MemTotal | awk '{print $2}')
MemFree=$(echo "$MemInfo" | grep -i ^MemFree | awk '{print $2}')
Buffers=$(echo "$MemInfo" | grep -i ^Buffers | awk '{print $2}')
Cached=$(echo "$MemInfo" | grep -i ^Cached | awk '{print $2}')

# Some devices have MemAvailable, some do not.
if $(echo "$MemInfo" | grep -q MemAvailable); then
    MemAvailable=$(echo "$MemInfo" | grep -i ^MemAvailable | awk '{print $2}')
else
    MemAvailable=$(($MemFree + $Cached))
fi

# Convert from kB to B for Nagios
MemTotal=$(($MemTotal*1024))
MemFree=$(($MemFree*1024))
Buffers=$(($Buffers*1024))
Cached=$(($Cached*1024))
MemAvailable=$(($MemAvailable*1024))

# Calculate percentage of use
MemUsed=$(($MemTotal-$MemAvailable))
MemSimple=$MemUsed
PctUsed=$((($MemUsed*100)/$MemTotal))

# Adding unit of measurement
MemTotal+="B"
MemFree+="B"
Buffers+="B"
Cached+="B"
MemAvailable+="B"

if [ $mode == "ABS" ]; then
    # Get value into smallest form
    while [ $MemSimple -gt 1023 ]; do
        MemSimple=$(($MemSimple/1024))
        Power=$(($Power+1))
    done

    # Assign UOM
    case $Power in
        0)
            ResDenom="B"
            ;;
        1)
            ResDenom="K"
            ;;
        2)
            ResDenom="M"
            ;;
        3)
            ResDenom="G"
            ;;
        4)
            ResDenom="T"
            ;;
    esac

    if [ "$MemUsed" -le "$CLEARUPPER" ]; then
        echo "OK - RAM usage is $MemSimple$ResDenom.|MemTotal=$MemTotal;; MemFree=$MemFree;; MemAvailable=$MemAvailable;; Buffers=$Buffers;; Cached=$Cached;;"
        exit 0
    elif [ "$MemUsed" -ge "$WARNLEVEL" ] && [ "$MemUsed" -le "$WARNUPPER" ]; then
        echo "WARNING - RAM usage is $MemSimple$ResDenom.|MemTotal=$MemTotal;; MemFree=$MemFree;; MemAvailable=$MemAvailable;; Buffers=$Buffers;; Cached=$Cached;;"
        exit 1
    elif [ "$MemUsed" -ge "$CRITLEVEL" ]; then
        echo "CRITICAL - RAM usage is $MemSimple$ResDenom.|MemTotal=$MemTotal;; MemFree=$MemFree;; MemAvailable=$MemAvailable;; Buffers=$Buffers;; Cached=$Cached;;"
        exit 2
    else
        echo "UNKNOWN - RAM usage is $MemSimple$ResDenom.|MemTotal=$MemTotal;; MemFree=$MemFree;; MemAvailable=$MemAvailable;; Buffers=$Buffers;; Cached=$Cached;;"
        exit 3
    fi
elif [ $mode == "PCT" ]; then
    if [ "$PctUsed" -ge 0 ] && [ "$PctUsed" -le "$CLEARUPPER" ]; then
        echo "OK - RAM usage is $PctUsed%.|MemTotal=$MemTotal;; MemFree=$MemFree;; MemAvailable=$MemAvailable;; Buffers=$Buffers;; Cached=$Cached;;"
        exit 0
    elif [ "$PctUsed" -ge "$WARNLEVEL" ] && [ "$PctUsed" -le "$WARNUPPER" ]; then
        echo "WARNING - RAM usage is $PctUsed%.|MemTotal=$MemTotal;; MemFree=$MemFree;; MemAvailable=$MemAvailable;; Buffers=$Buffers;; Cached=$Cached;;"
        exit 1
    elif [ "$PctUsed" -ge "$CRITLEVEL" ] && [ "$PctUsed" -le 100 ]; then
        echo "CRITICAL - RAM usage is $PctUsed%.|MemTotal=$MemTotal;; MemFree=$MemFree;; MemAvailable=$MemAvailable;; Buffers=$Buffers;; Cached=$Cached;;"
        exit 2
    else
        echo "UNKNOWN - RAM usage is $PctUsed%.|MemTotal=$MemTotal;; MemFree=$MemFree;; MemAvailable=$MemAvailable;; Buffers=$Buffers;; Cached=$Cached;;"
        exit 3
    fi
fi
