#!/bin/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 < add Add the given command as a job. addfile|af Add the given file as a job. createconfing Write a default configuration file. run Start the master scheduler process. del 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 Reschedule a failed job. Destroys all output. prio Change the priority of the given job. [unimplemented] status|st Show the status of the current jobs. stop 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) " ;; esac