#!/bin/bash
##
## CLUSTERPRO: DNS server monitoring agent
## Copyright (c) SATOH Fumiyasu @ OSS Technology Co., Japan,
##
## Date: 2007-03-29, since 2007-03-22
##

set -u

LC_ALL=C
PATH="/bin:/usr/bin:/sbin:/usr/sbin"
export LC_ALL PATH

log()
{
    local msg="$1"; shift
    local msg_suffix="${mon_id:+ [ID:$mon_id]}"

    if tty >/dev/null 2>&1; then
	echo "$0: $msg$msg_suffix"
    else
	clplogcmd -m "${cmd_name:+$cmd_name }$msg$msg_suffix" ${1:+"$@"}
    fi
}

log_info()
{
    log "$1" -l INFO
}

log_warn()
{
    log "$1" -l WARN
}

log_err()
{
    log "$1" -l ERR
}

## Options
## ======================================================================

mon_start_wait="2"
mon_server="127.0.0.1"
mon_port="53"
mon_query_type="A"
mon_query_name="localhost"
mon_nonrecursive=""
mon_query_timeout="4"
mon_retry="3"
mon_interval="60"

cmd_name="`basename "$0"`"
cmd_usage="Usage: $0 ID [OPTIONS]

Argument:
ID
  Monitoring identifier

Options for starting monitor:
-s SERVER
  DNS server name or IP address [$mon_server]
-n PORT
  DNS server port number [$mon_port]
-t TYPE
  Query type [$mon_query_type]
-h NAME
  Query name [$mon_query_name]
-R
  Non-recursive query
-r
  Query timeout (seconds) [$mon_query_timeout]
-c
  Query retry count [$mon_retry]
-i
  Monitoring interval (second) [$mon_interval]

Options for others:
--stop
  Stop monitoring
--pause
  Pause monitoring
--resume
  Resume monitoring
--disp
  Show monitor's PID if running
"

## Command-line options
## ----------------------------------------------------------------------

if [ $# -eq 0 ]; then
    echo "$cmd_usage"
    exit 0
fi

mon_id_raw="$1"; shift

mon_id="`expr x"$mon_id_raw" : x"\[*\([^]]*\)\]*$"`"
mon_daemon_id="[$mon_id]"
mon_daemon_re="`echo "$0 $mon_daemon_id" |sed 's/\([^A-Za-z_0-9]\)/\\\\\\1/g'`"

## Operations for a existing monitor process
## ======================================================================

mon_daemon_pid="`pgrep -f "$mon_daemon_re"`"

case "${1:-}" in
--stop)
    kill -TERM $mon_daemon_pid
    exit $?
    ;;
--pause)
    kill -STOP $mon_daemon_pid
    exit $?
    ;;
--resume)
    kill -CONT $mon_daemon_pid
    exit $?
    ;;
--disp)
    echo "$mon_daemon_pid"
    exit 0
    ;;
--del)
    ## Do nothing
    exit 0
    ;;
--)
    ## OK
    ;;
--*)
    log_err "invalid option: ${1:-}"
    exit 1
    ;;
esac

## Monitoring operation
## ======================================================================

if [ -n "$mon_daemon_pid" ] && [ x"$mon_daemon_pid" != x"$$" ]; then
    log_err "already running."
    exit 1
fi

if [ x"$mon_id_raw" = x"$mon_id" ]; then
    exec "$0" "[$mon_id]" ${1:+"$@"}
    exit 1
fi

trap 'log_info "will stop monitoring the DNS daemon."; exit 0' TERM INT

while getopts s:n:t:h:Rr:c:i: opt; do
    case "$opt" in
    s)
	mon_server="$OPTARG"
	;;
    n)
	mon_port="$OPTARG"
	;;
    t)
	mon_query_type="$OPTARG"
	;;
    h)
	mon_query_name="$OPTARG"
	;;
    R)
	mon_nonrecursive="yes"
	;;
    r)
	mon_query_timeout="$OPTARG"
	;;
    c)
	mon_retry="$OPTARG"
	;;
    i)
	mon_interval="$OPTARG"
	;;
    *)
	echo "$usage"
	exit 1
	;;
    esac
done
shift `expr $OPTIND - 1`

if expr x"$mon_query_name" : x".*[^.]$" >/dev/null; then
    mon_query_name="$mon_query_name."
fi

sleep "$mon_start_wait"

log_info "started monitoring the DNS daemon."

retry_count="0"
while true; do
    if [ "$retry_count" -gt 0 ]; then
	log_info "retry count $retry_count of $mon_retry."
    fi
    answer="`
	dig \
	    "@$mon_server" \
	    -p "$mon_port" \
	    -t "$mon_query_type" \
	    "$mon_query_name" \
	    "+${mon_nonrecursive:+no}recurse" \
	    "+time=$mon_query_timeout" \
	    "+retry=1" \
	    "+nocmd" \
	    "+noquestion" \
	    "+nostats" \
	    "+noauthority" \
	    "+noadditional" \
    `"
    if echo "$answer" |grep -i '^[a-z0-9]' >/dev/null; then
	if [ "$retry_count" -gt 0 ]; then
	    log_info "retry succeeded."
	    retry_count="0"
	fi
    else
	answer_error="`expr x"$answer" : x".*, status: \([^,]*\).*"`"
	if [ -z "$answer_error" ]; then
	    answer_error="`expr x"$answer" : x";; \(.*\)"`"
	fi
	log_warn "detected an error ($answer_error)."
	if [ "$retry_count" -ge "$mon_retry" ]; then
	    log_err "will be terminated."
	    exit 1
	fi
	retry_count="`expr "$retry_count" + 1`"
    fi

    sleep "$mon_interval"
done

