#! /bin/sh
OS=$(uname)
# MIT License
#
# Copyright (c) 2016 Josef Friedrich <josef@friedrich.rocks>
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
########################################################################
# Date functions
########################################################################
# This date function must be placed on the top of this file because
# they are used in some global variables.
# to_year ###
##
# Get the four digit year integer from now.
#
# Return:
# The current 4 digit year.
##
_now_to_year() {
date +%Y
}
##
# Convert a date in the format YYYY-MM-DD to a four digit year integer.
#
# Parameters:
# a date in the format YYYY-MM-DD
#
# Return:
# four digit year integer
##
_date_to_year() {
local OPTIONS
if [ "$OS" = 'Linux' ]; then
OPTIONS="--date $1"
# FreeBSD, Darwin
else
OPTIONS="-j -f %Y-%m-%d $1"
fi
date $OPTIONS +%Y
}
# to_datetime ###
##
# Convert a UNIX timestamp to a datetime string.
#
# Parameters:
# UNIX timestamp
#
# Return:
# %Y-%m-%d.%H:%M:%S
##
_timestamp_to_datetime() {
local OPTIONS
if [ "$OS" = 'Linux' ]; then
OPTIONS="--date @$1"
# FreeBSD, Darwin
else
OPTIONS="-j -f %s $1"
fi
date $OPTIONS +%Y-%m-%d.%H:%M:%S
}
# to_timestamp ###
##
# Get the current UNIX timestamp.
#
# Return:
# %current UNIX timestamp
##
_now_to_timestamp() {
date +%s
}
PROJECT_PAGES='https://github.com/Josef-Friedrich/check_zfs_snapshot
https://exchange.icinga.com/joseffriedrich/check_zfs_snapshot
https://exchange.nagios.org/directory/Plugins/System-Metrics/File-System/check_zfs_snapshot/details'
VERSION=1.2
FIRST_RELEASE=2016-09-08
SHORT_DESCRIPTION="Monitoring plugin to check how long ago the last \
snapshot of a ZFS dataset was created."
USAGE="check_zfs_snapshot v$VERSION
Copyright (c) $(_date_to_year $FIRST_RELEASE)-$(_now_to_year) \
Josef Friedrich <josef@friedrich.rocks>
$SHORT_DESCRIPTION
Usage: check_zfs_snapshot <options>
Options:
-c, --critical=OPT_CRITICAL
Interval in seconds for critical state.
-d, --dataset=OPT_DATASET
The ZFS dataset to check.
-h, --help
Show this help.
-s, --short-description
Show a short description of the command.
-v, --version
Show the version number.
-w, --warning=OPT_WARNING
Interval in seconds for warning state. Must be lower than -c
Performance data:
- last_ago
Time interval in seconds for last snapshot.
- warning
Interval in seconds.
- critical
Interval in seconds.
- snapshot_count
How many snapshot exists in the given dataset and all child
datasets exists.
"
# Exit codes
STATE_OK=0
STATE_WARNING=1
STATE_CRITICAL=2
STATE_UNKNOWN=3
_get_last_snapshot() {
zfs get creation -Hpr -t snapshot "$1" | \
awk 'BEGIN {max = 0} {if ($3>max) max=$3} END {print max}'
}
_getopts() {
while getopts ':c:d:hsvw:-:' OPT ; do
case $OPT in
c)
OPT_CRITICAL=$OPTARG
;;
d)
OPT_DATASET="$OPTARG"
;;
h)
echo "$USAGE"
exit 0
;;
s)
echo "$SHORT_DESCRIPTION"
exit 0
;;
v)
echo "$VERSION"
exit 0
;;
w)
OPT_WARNING=$OPTARG
;;
\?)
echo "Invalid option “-$OPTARG”!" >&2
exit 2
;;
:)
echo "Option “-$OPTARG” requires an argument!" >&2
exit 3
;;
-)
LONG_OPTARG="${OPTARG#*=}"
case $OPTARG in
critical=?*)
OPT_CRITICAL=$LONG_OPTARG
;;
dataset=?*)
OPT_DATASET="$LONG_OPTARG"
;;
help)
echo "$USAGE"
exit 0
;;
short-description)
echo "$SHORT_DESCRIPTION"
exit 0
;;
version)
echo "$VERSION"
exit 0
;;
warning=?*)
OPT_WARNING=$LONG_OPTARG
;;
critical*|dataset*|warning*)
echo "Option “--$OPTARG” requires an argument!" >&2
exit 3
;;
help*|short-description*|version*)
echo "No argument allowed for the option “--$OPTARG”!" >&2
exit 4
;;
'') # "--" terminates argument processing
break
;;
*)
echo "Invalid option “--$OPTARG”!" >&2
exit 2
;;
esac
;;
esac
done
}
_snapshot_count() {
# FreeBSD wc adds some whitespaces before the number!
# cat $HOME/debug | wc -l
# 7
local COUNT
COUNT="$(zfs list -t snapshot | grep "$1" | wc -l)"
echo $COUNT
}
_performance_data() {
echo "| \
last_ago=${DIFF}s;$OPT_WARNING;$OPT_CRITICAL;0 \
count=$(_snapshot_count "$OPT_DATASET");;;0\
"
}
## This SEPARATOR is required for test purposes. Please don’t remove! ##
_getopts $@
if [ -z "$OPT_WARNING" ]; then
# 1 day
OPT_WARNING=86400
fi
if [ -z "$OPT_CRITICAL" ]; then
# 3 day
OPT_CRITICAL=259200
fi
if [ -z "$OPT_DATASET" ]; then
echo "Dataset has to be set! Use option -d <dataset>" >&2
echo "$USAGE" >&2
exit $STATE_UNKNOWN
fi
if ! zfs list "$OPT_DATASET" > /dev/null 2>&1; then
echo "'$OPT_DATASET' is no ZFS dataset!" >&2
echo "$USAGE" >&2
exit $STATE_UNKNOWN
fi
NOW=$(_now_to_timestamp)
CREATION_DATE=$(_get_last_snapshot "$OPT_DATASET")
DIFF=$((NOW - CREATION_DATE))
if [ "$OPT_WARNING" -gt "$OPT_CRITICAL" ]; then
echo '-w OPT_WARNING must be smaller than -c OPT_CRITICAL'
_usage >&2
exit $STATE_UNKNOWN
fi
RETURN=STATE_UNKNOWN
if [ "$DIFF" -gt "$OPT_CRITICAL" ]; then
RETURN=$STATE_CRITICAL
MESSAGE="CRITICAL:"
elif [ "$DIFF" -gt "$OPT_WARNING" ]; then
RETURN=$STATE_WARNING
MESSAGE="WARNING:"
else
RETURN=$STATE_OK
MESSAGE="OK:"
fi
DATE="$(_timestamp_to_datetime "$CREATION_DATE")"
echo "$MESSAGE Last snapshot for dataset '$OPT_DATASET' was created on $DATE $(_performance_data)"
exit $RETURN