Blame | Last modification | View Log | Download
#!/usr/bin/env python# Written by kboy# v 1.01 Mar 20, 06import commands, os, re, sysfrom os import popen, getpid, removefrom sys import argv, stdoutfrom time import time, strftimeimport thread, threading, timeDEBUG = Falseif __debug__: LOGFILE=open(argv[1]+"tfQManager.log","w")def run(qDirectory,maxSvrThreads,maxUsrThreads,sleepInterval,execPath):displayParams(qDirectory,maxSvrThreads,maxUsrThreads,sleepInterval,execPath)#Check to see if already running.lastPID = "0"try:f=open(qDirectory+"tfQManager.pid",'r')lastPID = f.readline().strip()f.close()if __debug__: traceMsg("Last QManager pid" + str(lastPID))except:passif (int(lastPID) > 0):if (checkPIDStatus(lastPID) > 0):if __debug__: traceMsg("Already Running on pid:" + lastPID)raise KeyboardInterruptif __debug__: traceMsg("QManager Starting")f=open(qDirectory+"tfQManager.pid",'w')f.write(str(getpid()) + "\n")f.flush()f.close()if __debug__: traceMsg("QManager PID :" + str(getpid()))# Extract from the execPath the Btphptornado.py script line.# this will be used during the process Counts to ensure we are# unique from other running instances.ePath = execPath.split(" ")for x in ePath:if (re.search('btphptornado', x) > 0 ):btphp = xif __debug__: traceMsg("btphp ->"+btphp)if (re.search('btphptornado', btphp) > 0 ):try:while 1:threadCount = checkThreadCount(btphp)if __debug__: traceMsg("CurrentThreadCount = " + str( threadCount ))## Start Looping untill we have maxSvrThreads.# Or no Qinfo Files.#while int(threadCount) <= int(maxSvrThreads):try:## Get the Next File.# Check to see if we got a file back.# if not break out of looping we don't have any files.#fileList = []fileList = getFileList(qDirectory)for currentFile in fileList:if currentFile == "":break# set the name of the current statsFilestatsFile = currentFile.replace('/queue','').strip('.Qinfo')if __debug__: traceMsg("statsFile = " + statsFile)## get the User name if we didn't get one# something was wrong with this file.#currentUser = getUserName(statsFile)if currentUser == "":if __debug__: traceMsg("No User Found : " + currentFile)# Prep StatsFileupdateStats(statsFile, '0')removeFile(currentFile)breakelse:if __debug__: traceMsg("Current User: " + currentUser)## Now check user thread count#usrThreadCount = getUserThreadCount(currentUser, btphp)## check UserThreadCount#if int(usrThreadCount) < int(maxUsrThreads):## Now check to see if we start a new thread will we be over the max ?#threadCount = checkThreadCount(btphp)if int(threadCount) + 1 <= int(maxSvrThreads):if int(usrThreadCount) + 1 <= int(maxUsrThreads):cmdToRun = getCommandToRun(currentFile)#if __debug__: traceMsg(" Cmd :" + cmdToRun)if (re.search(currentUser,cmdToRun) == 0):if __debug__: traceMsg("Incorrect User found in Cmd")cmdToRun = ''if (re.search('\|',cmdToRun) > 0):if __debug__: traceMsg(" Failed pipe ")cmdToRun = ''else:cmdToRun = execPath + cmdToRuncmdToRun = cmdToRun.replace('TFQUSERNAME', currentUser)#if __debug__: traceMsg(" Cmd :" + cmdToRun)if cmdToRun != "":#PrepStatsFileupdateStats(statsFile, '1')if __debug__: traceMsg("Fire off command")try:garbage = doCommand(cmdToRun)## wait until the torrent process starts# and creates a pid file.# once this happens we can remove the Qinfo.#while 1:try:time.sleep(2)f=open(statsFile+".pid",'r')f.close()breakexcept:continue# Ok this one started Remove Qinfo File.if __debug__: traceMsg("Removing : " + currentFile)removeFile(currentFile)except:continueelse:## Something wrong with command file.#if __debug__: traceMsg("Unable to obtain valid cmdToRun : " + currentFile)removeFile(currentFile)else:if __debug__: traceMsg("Skipping this file since the User has to many threads")if __debug__: traceMsg("Skipping : " + currentFile)else:if __debug__: traceMsg("Skipping this file since the Server has to many threads")if __debug__: traceMsg("Skipping : " + currentFile)breakexcept:breakthreadCount = checkThreadCount(btphp)if __debug__: traceMsg("CurrentThreadCount = " + str( threadCount ))if __debug__: traceMsg("Sleeping...")time.sleep(float(sleepInterval))except:removeFile(qDirectory+"tfQManager.pid")else:LOG = Trueif __debug__: traceMsg("Only supported client is btphptornado.")removeFile(qDirectory+"tfQManager.pid")def checkThreadCount(btphp):if __debug__: traceMsg("->checkTreadCount")psLine = []line = ""counter = 0list = doCommand("ps x -o pid,ppid,command -ww | grep '" + btphp + "' | grep -v tfQManager | grep -v grep")try:for c in list:line += cif c == '\n':psLine.append(line.strip())line = ""# look for the grep linefor line in psLine:if (re.search('btphptornado.py',line) > 0):# now see if this is the main process and not a child.if (re.search(' 1 /',line) > 0):counter += 1if __debug__: traceMsg(" -- Counted -- ")if __debug__: traceMsg(line)except:counter = 0return counterdef checkPIDStatus(pid):if __debug__: traceMsg("->checkPIDStatus (" + pid + ")")counter = 0list = doCommand("ps -p "+pid+" -o pid= -ww")try:counter = len(list)except:counter = 0return counterdef getUserThreadCount(userName, btphp):if __debug__: traceMsg("->getUserThreadCount (" + userName + ")")psLine = []line = ""counter = 0list = doCommand("ps x -o pid,ppid,command -ww | grep '" + btphp + "' | grep -v tfQManager | grep -v grep")try:for c in list:line += cif c == '\n':psLine.append(line.strip())line = ""# look for the grep linefor line in psLine:if (re.search('btphptornado.py',line) > 0):# now see if this is the main process and not a child.if (re.search(' 1 /',line) > 0):# look for the userNameif re.search(userName,line) > 0:counter += 1if __debug__: traceMsg(" -- Counted -- ")if __debug__: traceMsg(line)except:counter = 0if __debug__: traceMsg("->getUserThreadCount is (" + str(counter)+")")return counterdef removeFile(currentFile):if __debug__: traceMsg("->removeFile (" + currentFile + ")")os.remove(currentFile)returndef doCommand( command ):if __debug__: traceMsg("->doCommand (" + command + ")")## Fire off a command returning the output#return popen(command).read()def doCommandPID( command ):if __debug__: traceMsg("->doCommandPID (" + command + ")")## Fire off a command returning the pid##return popen2.Popen4(command).pidgarbage = doCommand(command)return getPIDofCmd(command)def getPIDofCmd(command):if __debug__: traceMsg("->getPIDofCmd (" + command + ")")cmdPID = ""psLine = []endOfPID = Falseline = ""list = doCommand("ps x -ww | grep \'"+command+"\' | grep -v grep")if DEBUG:print listtry:for c in list:line += cif c == '\n':psLine.append(line.strip(' '))# look for the grep linefor line in psLine:for e in line:if e.isdigit() and endOfPID == False:cmdPID += eelse:endOfPID = Truebreakexcept:cmdPID = "0"if __debug__: traceMsg(cmdPID)return cmdPIDdef getCommandToRun(currentFile):if __debug__: traceMsg("->getCommandToRun (" + currentFile + ")")#Open the File and return the Command to Run.cmdToExec = ""try:f=open(currentFile,'r')cmdToExec = f.readline()f.closeexcept:cmdToExec = ""return cmdToExecdef getFileList(fDirectory):if __debug__: traceMsg("->getFileList (" + fDirectory + ")")# Get the list of Qinfo files.fileList = []try:times = {}for fName in os.listdir(fDirectory):if re.search('\.Qinfo',fName) > 0:p = os.path.join(fDirectory,fName)times.setdefault(str(os.path.getmtime(p)),[]).append(p)l = times.keys()l.sort()for i in l:for f in times[i]:fileList.append(f)except:fileList = ""return fileListdef getUserName(fName):if __debug__: traceMsg("->getUserName (" + fName + ")")userName = ""try:f=open(fName,'r')garbage = f.readline()garbage = f.readline()garbage = f.readline()garbage = f.readline()garbage = f.readline()userName = f.readline().strip()f.close()if __debug__: traceMsg("userName : " + userName)except:userName = ""return userNamedef updateStats(fName, status = '1'):if __debug__: traceMsg("->updateStats (" + fName + ")")fp=open(fName,'r+')fp.seek(0)fp.write(status)fp.flush()fp.closedef displayParams(qDirectory,maxSvrThreads,maxUsrThreads,sleepInterval,execPath):if __debug__:traceMsg("qDir : " + qDirectory)traceMsg("maxSvr : " + str(maxSvrThreads))traceMsg("maxUsr : " + str(maxUsrThreads))traceMsg("sleepI : " + str(sleepInterval))traceMsg("execPath : " + str(execPath))returndef traceMsg(msg):if DEBUG:print msgif __debug__:LOGFILE.write(msg + "\n")LOGFILE.flush()if __name__ == '__main__':run(argv[1],argv[2],argv[3],argv[4],argv[5])