#!/usr/bin/env ruby # $Id$ # $URL$ require 'fileutils' require 'thread' require 'open3' JOBSDIR = "jobs" PARKDIR = "park" PROCDIR = "processors" RESULTDIR = "results" FAILDIR = "failure" MONITORDIR = "monitor" RUNMODE = 0755 CONFIG = "config" @config = { "waittime" => 3, "maxproc" => 3 } @processor_threads = [] @jobclaimlock = Mutex.new COUNTERFILE="jobscounter" RUNNINGFILE="runningcounter" def usage puts < 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 exit end def readconfig if FileTest.exists?("#{@basedir}/#{CONFIG}") File.open("#{@basedir}/#{CONFIG}").each_line {|line| line.sub!(/#.*/, "") line.sub!(/^\s*/, "") line.sub!(/\s*$/, "") if line.match(/^$/) next end line.match(/([^=]*?)\s*=\s*(.*)/) case $1 when "maxproc" then @config["maxproc"] = $2 when "waittime" then @config["waittime"] = $2 else puts "unknown option #{$1}" end } end end def status readconfig # show which jobs are running puts "Running jobs (#{Dir.entries("#{@basedir}/#{PROCDIR}").size - 2}/#{@config["maxproc"]}):" # just call 'ls' instead of trying to figure out how to format it nicely for the screen system("ls" ,"#{@basedir}/#{PROCDIR}/") # show queues puts "Jobs queued (#{Dir.entries("#{@basedir}/#{JOBSDIR}").size - 2}):" system("ls", "#{@basedir}/#{JOBSDIR}/") puts "Jobs parked (#{Dir.entries("#{@basedir}/#{PARKDIR}").size - 2}):" puts "Jobs finished: #{Dir.entries("#{@basedir}/#{RESULTDIR}").size - 2}" puts "Jobs failed (#{Dir.entries("#{@basedir}/#{FAILDIR}").size - 2}):" system("ls", "#{@basedir}/#{FAILDIR}/") end def createdirs [ JOBSDIR, PARKDIR, PROCDIR, RESULTDIR, FAILDIR, MONITORDIR ].each{|dir| if ! FileTest.directory?("#{@basedir}/#{dir}") Dir.mkdir("#{@basedir}/#{dir}") end } end def increasejobscounter jobscounter = 0 if FileTest.exists?(COUNTERFILE) File.new(COUNTERFILE).flock(File::LOCK_EX) File.open(COUNTERFILE, "r+"){|file| jobscounter = file.read if jobscounter.empty? jobscounter = 0 end jobscounter = jobscounter.to_i jobscounter += 1 file.seek(0) file.puts jobscounter } File.new(COUNTERFILE).flock(File::LOCK_UN) else # XXX wellicht eerst een touch ofzo doen en dan locken voor de schrijf loop # geopend wordt FileUtils.touch(COUNTERFILE) File.new(COUNTERFILE).flock(File::LOCK_EX) File.open(COUNTERFILE, "w"){|file| jobscounter = 1 file.puts jobscounter } File.new(COUNTERFILE).flock(File::LOCK_UN) end return jobscounter end def addjob jobnumber=sprintf("%06d", increasejobscounter) puts "New job: #{jobnumber}" if FileTest.exists?("#{@basedir}/#{JOBSDIR}/#{jobnumber}") puts "Job #{jobnumber} already scheduled. This should not happen." exit end File.open("#{@basedir}/#{JOBSDIR}/#{jobnumber}", "w"){|file| file.puts ARGV.join(" ") } File.chmod(RUNMODE, "#{@basedir}/#{JOBSDIR}/#{jobnumber}") end def addjobfromfile filename = ARGV[0] if filename.nil? puts "Missing filename" usage else if ! FileTest.exists?(filename) puts "File #{filename} doesn't exist" usage end end jobnumber = sprintf("%06d", increasejobscounter) puts "New job: #{jobnumber}" FileUtils.cp(filename, "#{@basedir}/#{JOBSDIR}/#{jobnumber}") File.chmod(RUNMODE, "#{@basedir}/#{JOBSDIR}/#{jobnumber}") end def createconfig if ! FileTest.exists?("#{@basedir}/#{CONFIG}") File.open("#{@basedir}/#{CONFIG}", "w"){|file| file.puts <