Add bitcron(1), an updater which pulls in diffs, and a crontab that runs every 5min.

git-svn-id: svn+ssh://svn.ipng.nl/usr/share/subversion/repositories/ircnet.ipng.ch@21 c5d60b8d-fdcb-4146-b734-af4215e9eb71
This commit is contained in:
pim
2009-09-07 19:17:47 +00:00
parent 6d28a1730b
commit e17c5c0a68
3 changed files with 358 additions and 0 deletions

329
cron/bitcron Executable file
View File

@ -0,0 +1,329 @@
#!/usr/local/bin/bash
# Original author: Pim van Pelt <pim@bit.nl>
# Taken from OSS publication upstream:
# debit.bit.nl:/debian/dists/stable/main/binary-i386/bit-cron-1.9-20060627.02.deb
# and modified for use at Google.
#
# Author: Pim van Pelt <pim@google.com>
# This is the master cron file format. It is designed to be quiet
# and not shout anything at all to stdout/stderr in normal use.
#
# Usage: bitcron [-n] /path/to/crondefinition.cron [arg [arg ..]]
#
# This program eats either one or two arguments from the commandline.
# If -n is given as the first argument, output is sent to stdout rather
# than MAILTO or ESCALATE_MAILTO (this is a `dryrun'). The next argument
# is a filename consisting of the cron definition. The file is sourced
# and executed, but within a framework that makes crons much easier to
# live with. You SHOULD have the filename of your crondefinition end
# in ".cron", so it is apparent to other people that this is indeed
# a cron definition. All other arguments are passed to the crontab's
# main function, called bitcron_main; see below.
#
# The cron definition file consists of the following shell variables:
#
# PATH: Optional. You can set a standard path for your cron to search
# programs in. Note that cron sets a minimal path, so you probably need
# this if you are going to call programs from weird places.
# Example: PATH=$PATH
#
# AUTHOR: Mandatory. Your full name, so we can track the author in case
# something goes horribly wrong.
# Example: AUTHOR="Pim van Pelt"
#
# NAME: Mandatory. The name of your script. This MUST be a terse
# descriptive name consisting of [A-Za-z0-9\-\_], and in particular
# no whitespace. It's used in logs and mails.
# Example: NAME="example"
#
# MASTERLOG: Optional. If this is set, the transcript of the log is copied
# to this file upon completion. If it is not set, the transcript is silently
# deleted. Please make sure that this filename is writable for the calling
# user, and that its name reveals who wrote it (including $NAME is a good
# idea.
# Example: MASTERLOG="/var/log/cron-${NAME}.log"
#
# MAILTO: Optional. If this is set, the transcript of the log is mailed to
# this user using /usr/sbin/sendmail -t, in the event of no warnings,
# errors, or fatal errors, aka 'if all went well'. If it is not set, the
# mail is not sent on succesful completion of this cronjob. Please use
# with care if your cron runs often.
# Example: MAILTO="pim+noise@google.com"
#
# ESCALATE_MAILTO: Mandatory. If this is set, the transcript of the log
# is mailed to this user using /usr/sbin/sendmail -t, in the event of
# any warning, error or fatal error, aka 'if anything borked'. Please
# make sure that this address is not a single person, but rather a role
# account. This ensures better closure and continuity.
# Example: ESCALATE_MAILTO="maps-alerts@google.com"
#
# Variables your script MUST NOT change are:
# ERR, WRN, HOSTNAME, FATAL, FQDN
#
# Your cron-definition does not shebang. It begins with these variables.
# It then has at least one function called bitcron_main(), in which you write
# your cron just like you normally would, but each step is prepended by a
# short oneliner describing what you are doing and appended with a line
# stating you are done doing it, followed by an empty line.
#
# In your bitcron_main() script, you have three functions at your disposal:
# warning $TEXT
# error $TEXT
# fatal $TEXT
#
# where warning() prints the TEXT and increments the warning counter, error()
# increments the error counter and fatal() increments the error counter and
# immediately halts execution of the cron.
#
# For example:
# bitcron_main()
# {
# echo "Running rsync"
# rsync blabla || warning "Could not rsync"
# echo "Done (rsync)"
# echo ""
#
# echo "Doing something crucial"
# /usr/local/bin/crucial.sh blabla || \
# fatal "Could not do the crucial stuff, aborting!"
# echo "Done (crucial)"
# echo ""
#
# echo "Succesfully executed the cron"
# }
#
# In the event of a fatal error (retval of crucial.sh != 0), the line
# 'echo "Done (crucial)"' will not be executed, rather the cronscript
# stops and mails to the escalation mail address that there was a serious
# error which needs human intervention.
#
# Return values of bitcron depend on the presence of errors or warnings.
# If there are no errors nor warnings, 0 is returned to the calling shell.
# If there are errors, 127 is returned. If there are no errors, but there
# are warnings, 126 is returned. If you somewhere set the RETVAL variable
# (which is optional), that value is returned instead.
#
# Please note that your bitcron_main() function MUST NOT use exit. This messes up
# the clean execution of this script, prohibiting it from mailing or
# returning a decent exitcode to the calling shell.
#
# BITCRON_SEARCHPATH="/usr/local/cronscripts/ /etc/cronscripts/ ./"
BITCRON_SEARCHPATH="~/cronscripts/ ./"
BITCRON_REPORTTOOL="/usr/sbin/sendmail -t"
function fatal()
{
echo ""
echo "===== FATAL ====="
echo $1
echo "===== FATAL ====="
ERR=$(($ERR + 1))
FATAL=1;
bitcron_end
}
function error()
{
echo ""
echo "===== ERROR ====="
echo $1
echo "===== ERROR ====="
ERR=$(($ERR + 1))
}
function warning()
{
echo ""
echo "===== WARNING ====="
echo $1
echo "===== WARNING ====="
WRN=$(($WRN + 1))
}
function bitcron_report()
{
if [ $WRN -eq 0 -a $ERR -eq 0 ]; then
if [ ! -z "$MAILTO" ]; then
(
echo "From: $HOSTNAME $NAME <`whoami`@$FQDN>"
echo "To: $MAILTO"
echo "Subject: bitcron $NAME - succesful"
echo "Date: `date '+%a, %d %b %Y %T %z'`"
echo "Errors-To: $MAILTO"
echo "Reply-To: $MAILTO"
echo "X-bitcron: $NAME"
echo "X-Precedence: automatic"
echo ""
echo "Dear reader,"
echo ""
echo "This is the $0 program on $HOSTNAME informing"
echo "you I have succesfully executed the bitcron $NAME."
echo ""
echo "The log that I have for this cronjob follows:"
cat $LOG
echo ""
echo "This mail is purely FYI, user intervention is not required."
echo ""
echo "-- "
echo "Cheers,"
echo " $HOSTNAME"
) | ${BITCRON_REPORTTOOL}
fi
else
(
echo "From: $HOSTNAME $NAME <`whoami`@$FQDN>"
echo "To: $ESCALATE_MAILTO"
if [ ! -z "$MAILTO" ]; then
echo "CC: $MAILTO"
fi
if [ $FATAL -eq 0 ]; then
echo "Subject: bitcron $NAME - $ERR error(s), $WRN warning(s)"
else
echo "Subject: bitcron $NAME - FATAL - $ERR error(s), $WRN warning(s)"
fi
echo "Date: `date '+%a, %d %b %Y %T %z'`"
echo "Errors-To: $ESCALATE_MAILTO"
echo "Reply-To: $ESCALATE_MAILTO"
echo "X-Precedence: automatic"
echo "X-bitcron: $NAME"
echo "X-Errors: $ERR"
echo "X-Warnings: $WRN"
echo ""
echo "Dear reader,"
echo ""
echo "This is the $0 program on $HOSTNAME informing"
echo "you that there was a problem running the bitcron $NAME."
echo ""
echo "The logfile that lead up to this:"
cat $LOG
echo ""
echo "I hope you can deal with this situation ASAP."
echo ""
echo "-- "
echo "Cheers,"
echo " $HOSTNAME"
) | ${BITCRON_REPORTTOOL}
fi
}
function bitcron_begin()
{
if [ -z "$MASTERLOG" ]; then
LOG="/tmp/bitcron-$NAME.$$"
else
LOG="${MASTERLOG}.$$"
fi
rm -f -- $LOG
exec 3>&1 4>&2 1>$LOG 2>&1
WRN=0
ERR=0
FATAL=0
FQDN=$(hostname)
HOSTNAME=$(hostname -s)
if [ "A`echo $FQDN | grep '\.'`" = "A" ]; then
FQDN="${FQDN}.corp.google.com"
fi
echo "Beginning $NAME cronjob at `date`"
echo ""
}
function bitcron_end()
{
echo ""
echo "Done with $NAME cronjob at `date`"
echo ""
echo "There were $ERR error(s) and $WRN warning(s)"
if [ $FATAL -ne 0 ]; then
echo "This script had a fatal error!"
fi
exec 1>&3 2>&4
bitcron_report
if [ ! -z "$MASTERLOG" ]; then
cp -f -- "$LOG" "$MASTERLOG"
fi
rm -f -- $LOG >/dev/null 2>&1
if [ ! -z $RETVAL ]; then
exit $RETVAL
elif [ $ERR -ne 0 ]; then
exit 127
elif [ $WRN -ne 0 ]; then
exit 126
fi
exit 0
}
function bitcron_usage()
{
echo ""
echo "Usage: bitcron [-n] /path/to/crondefinition.cron [arg [arg ..]]"
echo ""
echo "Please read the bitcron script. It has documentation at the"
echo "top of the file. Look in $0 for more details."
echo "-- Author: Pim van Pelt <pim@google.com>"
}
# Here goes!
if [ $# -lt 1 ]; then
bitcron_usage
exit 128
fi
# See if we are in dryrun mode.
if [ $1 = "-n" ]; then
BITCRON_REPORTTOOL="/bin/cat"
shift
fi
BITCRON_DEFINITION=$1
shift;
#
# Search through paths if the cron definition was not an absolute path.
#
if [ ${BITCRON_DEFINITION%%/*} ]; then
for BITCRON_DIR in ${BITCRON_SEARCHPATH}; do
if [ -r ${BITCRON_DIR}${BITCRON_DEFINITION} ]; then
break;
fi
done
else
BITCRON_DIR=""
fi
if [ ! -r ${BITCRON_DIR}${BITCRON_DEFINITION} ]; then
echo "bitcron: Unreadable cron definition: ${BITCRON_DIR}${BITCRON_DEFINITION}"
if [ ${BITCRON_DEFINITION%%/*} ]; then
echo "I tried in: ${BITCRON_SEARCHPATH}"
fi
bitcron_usage
exit 128
fi
. ${BITCRON_DIR}${BITCRON_DEFINITION}
if [ -z "$NAME" ]; then
echo "bitcron: Missing mandatory variable NAME in ${BITCRON_DIR}${BITCRON_DEFINITION}"
bitcron_usage
exit 128
fi
if [ -z "$AUTHOR" ]; then
echo "bitcron: Missing mandatory variable AUTHOR in ${BITCRON_DIR}${BITCRON_DEFINITION}"
bitcron_usage
exit 128
fi
if [ -z "$ESCALATE_MAILTO" ]; then
echo "bitcron: Missing mandatory variable ESCALATE_MAILTO in ${BITCRON_DIR}${BITCRON_DEFINITION}"
bitcron_usage
exit 128
fi
bitcron_begin
bitcron_main $*
bitcron_end