publicscripts/pbatch/pb
2009-02-25 09:10:38 +00:00

285 lines
6.3 KiB
Bash
Executable file

#!/usr/bin/env bash
counterfile=jobscounter
counterlock=counterlock
runninglock=runninglock
runningfile=runningcounter
basedir=$(pwd)
runmode=0755
waittime=${waittime:=3}
maxproc=${maxproc:=3}
pbcommand=$0
die() { echo "$*" >&2; exit 1; }
# We need unique jobs numbers, preferably sequentially.
# So just use a counter file.
increasejobscounter() {
(
flock -x 200
if [ -e $counterfile ]; then
jobscounter=$(cat $counterfile)
fi
jobscounter=$(expr $jobscounter + 1 )
echo $jobscounter > $counterfile
# nodig zodat aanroepende functies kunnen weten welk
# jobnummer ze mogen gebruiken
echo ${jobscounter}
) 200>$counterlock
# XXX hoe haal je lockfile weer netjes weg?
# het antwoord is waarschijnlijk: niet
}
addjob() {
# command
jobnumber=$(increasejobscounter)
echo "New job: ${jobnumber}"
if [ -e "${basedir}/jobs/${jobnumber}" ]; then
die "Job ${jobnumber} already scheduled. This should not happen."
fi
echo "$*" > "${basedir}/jobs/${jobnumber}"
chmod ${runmode} "${basedir}/jobs/${jobnumber}"
}
addjobfromfile() {
# filename
jobnumber=$(increasejobscounter)
echo "New job: ${jobnumber}"
filename=$1
if [ -f "${filename}" ]; then
if [ -e "${basedir}/jobs/${jobnumber}" ]; then
die "Job ${jobnumber} already scheduled. This should not happen."
fi
cp "${filename}" "${basedir}/jobs/${jobnumber}"
chmod ${runmode} "${basedir}/jobs/${jobnumber}"
else
die "file not found: ${filename}"
fi
}
deljob() {
# jobnumber
jobnumber=$1
if [ -f "${basedir}/jobs/${jobnumber}" ]; then
if rm "${basedir}/jobs/${jobnumber}" ; then
echo "Job removed: ${jobnumber}"
else
die "Couldn't remove job: ${jobnumber}"
fi
else
die "Job '${jobnumber}' not in queue"
fi
}
parkjobs() {
# XXX probably needs locking too, so it doens't clash with starting jobs
if [ -n "$(ls ${basedir}/jobs/*)" ]; then
mv ${basedir}/jobs/* ${basedir}/park/
fi
}
unparkjobs() {
if [ -n "$(ls ${basedir}/park/*)" ]; then
mv ${basedir}/park/* ${basedir}/jobs/
fi
}
unfail() {
# jobnumber
jobnumber=$1
if [ -d "${basedir}/failure/${jobnumber}" ]; then
if [ -f "${basedir}/failure/${jobnumber}/job" ]; then
mv "${basedir}/failure/${jobnumber}/job" "${basedir}/jobs/${jobnumber}"
rm -rf "${basedir}/failure/${jobnumber}"
fi
fi
}
changeprio() {
# prio
# jobnumber
echo unimplemented
}
status() {
readconfig
# show which jobs are running
echo "Running jobs ($(ls ${basedir}/processors/|wc -w)/${maxproc}):"
ls "${basedir}/processors/"
# show queues
echo "Jobs queued ($(ls ${basedir}/jobs/|wc -w)):"
ls "${basedir}/jobs/"
echo "Jobs parked: $(ls ${basedir}/park/|wc -w)"
echo "Jobs finished: $(ls ${basedir}/results/|wc -w)"
echo "Jobs failed ($(ls ${basedir}/failure/|wc -w)):"
ls "${basedir}/failure/"
}
stop() {
# stop a jobnumber
echo unimplemented
}
stopall() {
# stop all jobs and scheduler
echo unimplemented
}
usage() {
echo unimplemented
cat <<ENDTXT
Usage: pb <option>
add <command> Add the given command as a job.
addfile|af <file> Add the given file as a job.
createconfing Write a default configuration file.
run Start the master scheduler process.
del <jobnr> Delete the given job from the queue.
help|-h Show this help.
park Place all queued jobs in the parkinglot.
unpark Place all jobs from the parkinglot back in the queue.
retry <jobnr> Reschedule a failed job. Destroys all output.
prio <h|n|l> <jobnr> Change the priority of the given job. [unimplemented]
status|st Show the status of the current jobs.
stop <jobnr> Stop the given job. [unimplemented]
stopall Stop all running jobs. [unimplemented]
ENDTXT
}
readconfig() {
if [ -f ${basedir}/config ]; then
source ${basedir}/config
fi
}
createdirs() {
# setup dirs that will be used
dirs="jobs processors results failure monitor park"
for dir in $dirs; do
if [ ! -d "${basedir}/${dir}" ]; then
if ! mkdir "${basedir}/${dir}"; then
echo "couldn't create directory ${basedir}/${dir}"
exit 1
fi
fi
done
}
createconfig() {
if [ ! -e ${basedir}/config ]; then
echo "# how many parallel processes?" >> ${basedir}/config
echo "maxproc=${maxproc}" >> ${basedir}/config
echo "# take a break for how long between process end and starting a new one" >> ${basedir}/config
echo "waittime=${waittime}" >> ${basedir}/config
fi
}
incrementrunning() {
(
flock -x 210
if [ -e $runningfile ]; then
echo $(expr $(cat $runningfile) + 1) > $runningfile
fi
) 210>$runninglock
}
decrementrunning() {
(
flock -x 220
if [ -e $runningfile ]; then
runningcounter=$(cat $runningfile)
fi
runningcounter=$(expr $runningcounter - 1 )
if [ $runningcounter -lt 0 ]; then
echo 0 > $runningfile
else
echo $runningcounter > $runningfile
fi
) 220>$runninglock
}
getjob() {
# Meh, ik ken geen handige manier om er een uit
# het rijtje te halen. Dan maar zo.
# lock hier omheen?
for jl in ${basedir}/jobs/*;do
if [ -n "${jl}" ]; then
echo ${jl##*/}
mkdir ${basedir}/processors/${jl##*/}
mv $jl ${basedir}/processors/${jl##*/}/job
fi
break
done
}
failjob() {
jobnumber=$1
mv "${basedir}/processors/${jobnumber}" "${basedir}/failure"
}
finishjob() {
jobnumber=$1
mv "${basedir}/processors/${jobnumber}" "${basedir}/results"
}
runprocessor() {
incrementrunning
sleep 1
runjob=$(getjob)
if [ -n "${runjob}" ]; then
echo "Starting job: ${runjob}"
owd=$(pwd)
cd "${basedir}/processors/${runjob}"
if "${basedir}/processors/${runjob}/job" 2>&1 > "${basedir}/processors/${runjob}/output" ;then
finishjob ${runjob}
echo "Finished job: ${runjob}"
else
failjob ${runjob}
echo "Failed job: ${runjob}"
fi
cd $owd
fi
decrementrunning
}
master() {
echo 0 >"${basedir}/$runningfile"
while sleep $waittime; do
if [ $(cat "${basedir}/${runningfile}") -lt $maxproc ]; then
# via ls omdat anders de globbing klote is
jl=$(ls ${basedir}/jobs/)
if [ -n "$jl" ]; then
${pbcommand} process &
fi
readconfig
fi
done
}
###################################
# test voor voldoende args
command=$1
shift
createdirs
case "$command" in
add) addjob "$*" ;;
addfile|af) addjobfromfile "$*" ;;
createconfig) createconfig ;;
run) master ;;
del) deljob "$*" ;;
help) usage ;;
-h) usage ;;
park) parkjobs ;;
unpark) unparkjobs ;;
retry) unfail "$*" ;;
prio) changeprio "$*" ;;
process) runprocessor "$*" ;;
status|st) status ;;
stop) stop "$*" ;;
stopall) stopall ;;
*) die "Usage: pb (add|addfile) <command>" ;;
esac