#!/usr/bin/env bash # # nagios-downtime(1) -- Shortcut to scheduling fixed downtime in Nagios, # because it's annoying to do with the web interface for large sets of hosts # or services. # # $ ndt (|-) [comment]\n' "$self" # # You can specify multiple objects by separating them with commas: # # $ ndt abc-example-ap-1,abc-example-ap-2/VOLTAGE 9am 10am 'Power problems at abc-example' # # Even easier is to pipe them into stdin by specifying - as the object: # # $ nds abc-example | ndt - 9am 10am 'Power problems at abc-example' # # Assumes date(1) with +%s format and --date option (probably only GNU date). # # Author: Tom Ryder # Copyright: 2016 # # Name self self=nagios-downtime # Usage printing function usage() { printf 'USAGE: %s [|-] [comment]\n' "$self" } # Process options (just help at the moment) OPTIND=1 while getopts 'h' opt ; do case "$opt" in h) usage exit 0 ;; '?') usage >&2 exit 1 ;; esac done shift "$((OPTIND-1))" # Bail if too few arguments left; we need at least the hostname, the start date, and the end date if (($# < 3)) ; then usage >&2 exit 1 fi # Define relatively fixed/guaranteed fields for Nagios command; note that the # comment has a default of 'no comment given' now=$(date +%s) spec=$1 fixed=1 trigger=0 duration=0 author=${SUDO_USER:-$USER} comment=${4:-'no comment given'} cmdfile=${NAGCMD_FILE:-/usr/local/nagios/var/rw/nagios.cmd} # How to get the objects depends on the spec (the first argument) declare -a objects case $spec in # If the spec is just "-", we just read unique objects from stdin -) while read -r object ; do [[ $object ]] || continue objects[${#objects[@]}]=$object done < <(sort -u) ;; # If the spec is anything else, we break it up with commas and read the # objects that way *) IFS=, read -a objects -r < <(printf '%s\n' "$spec") ;; esac # There must be at least one object if ! ((${#objects[@]})) ; then printf '%s: At least one host/service must be given\n' \ "$self" >&2 exit 1 fi # All the hosts or services must exist, just to be strict for object in "${objects[@]}" ; do nagios-exists "$object" && continue printf '%s: Host/service %s does not seem to exist\n' \ "$self" "$object" >&2 exit 1 done # Attempt to parse start and end dates; fail if the call doesn't work dta=$(date +%s --date "$2") || exit dtb=$(date +%s --date "$3") || exit # If the end time is less than right now, this is probably a mistake dtn=$(date +%s) if ((dtn > dtb)) ; then printf '%s: Refusing to schedule downtime ending in the past (%s)\n' \ "$self" "$(date -d @"$dtb" +%c)" exit 1 fi # If the end time is less than the start time, this is definitely a mistake if ((dta > dtb)) ; then printf '%s: Refusing to schedule downtime that ends (%s) before it starts (%s)\n' \ "$self" "$(date -d @"$dtb" +%c)" "$(date -d @"$dta" +%c)" exit 1 fi # Quietly replace semicolons in comment with commas comment=${comment//;/,} # Write commands to schedule downtime for each of the objects, bail if a single # one of them fails for object in "${objects[@]}" ; do case $object in */*) host=${object%/*} service=${object##*/} cmd=$(printf '[%lu] SCHEDULE_SVC_DOWNTIME;%s;%s;%s;%s;%u;%u;%u;%s;%s' \ "$now" "$host" "$service" "$dta" "$dtb" \ "$fixed" "$trigger" "$duration" "$author" "$comment") ;; *) host=$object cmd=$(printf '[%lu] SCHEDULE_HOST_DOWNTIME;%s;%s;%s;%u;%u;%u;%s;%s' \ "$now" "$host" "$dta" "$dtb" \ "$fixed" "$trigger" "$duration" "$author" "$comment") ;; esac printf '%s\n' "$cmd" > "$cmdfile" || exit done