Mercurial > hg > env-test-daniele
view ServerWrapper.py @ 25:4a4bd554b4c1 tip
Closing this sub branch.
author | Daniele Barchiesi <daniele.barchiesi@eecs.qmul.ac.uk> |
---|---|
date | Mon, 25 Mar 2013 14:02:54 +0000 |
parents | 032bc65ebafc |
children |
line wrap: on
line source
""" ServerWrapper.py Created by George Fazekas, QMUL on 2009-05-09. Copyright (c) 2009 QMUL. All rights reserved. """ from __future__ import with_statement import os,sys import cherrypy from cherrypy.lib import static import subprocess as sp from subprocess import Popen as spopen try : from cherrypy.lib import safemime except: print "Warning: import safemime failed. (Probably newer cherrypy version.)" #safemime.init() #root._cp_config = {'tools.safe_multipart.on': True} __localdir__ = os.path.realpath(os.path.dirname(os.path.abspath(__file__))) # ============================================ # Shared Configuration data container # ============================================ class Config(object): '''A shared config object''' def __init__(self,root=None,local=False,conf='not set'): self.cherrypyVersion = 0 self.nice_value = 0 self.svn_revision = 0 self.hostname = str() self.localdir = __localdir__ self.server_config_file = str() self.local = local self.server_config_file = conf self.root = root # ============================================ # Cherrypy ServerWrapper # ============================================ # This is a thin wrapper on cherrypy class ServerWrapper(object): def __init__(self,config): self.conf = config self.config = self.conf def quickstart(self,ip=None,retries=5): '''Start fx-test''' if not retries : print 'Server: Error: Retry limit reached while trying to start service.' # TDOD: maybe we want to shut the daemon here as well... to avoid external loop return False self.config.cherrypyVersion = cherrypy.__version__ print 'Server: Cherrypy version: %s' %str(cherrypy.__version__) cherrypy.server.socket_timeout = 60 cherrypy.config.update({'tools.staticdir.root': __localdir__}) # cherrypy.config.update('./config/server.cfg') cherrypy.config.update(self.config.server_config_file) if type(ip) == str and ip.count('.') == 3: _ip = ip.split(':')[0] if ip.count(':') and len(ip.split(':')[-1]) == 4: _port = int(ip.split(':')[-1]) cherrypy.config.update({'server.socket_port': _port}) else : _port = int(cherrypy.server.socket_port) print "Server: No valid port specified for service. Using default: %i" %_port cherrypy.config.update({'server.socket_host': _ip}) else : _ip = str(cherrypy.server.socket_host) _port = int(cherrypy.server.socket_port) # pass in the global config object to the session: cherrypy.config.update({'tools.sessions.GLOBAL_CONFIG': self.config}) #enable safemime tool to avoid upload timeouts try : safemime.init() cherrypy.config.update({'tools.safe_multipart.on': True}) except: pass # set hostname in config if not self.config.hostname : self.config.hostname = str(cherrypy.server.socket_host).strip()+":"+str(cherrypy.server.socket_port).strip() print 'Server: hostname is set to: ',self.config.hostname # report process pid and niceness print "Server: pid: ", os.getpid() # self.setProcessPriority(-3,'passwd') self.config.nice_value = self.getProcessPriority() print "Server: nice value: ", self.config.nice_value # report subversion rev. number self.config.svn_revision = self.getRevisionNumber() print "Server: SVN revision: ", self.config.svn_revision try : print 'Server: quickstarting apps at >> %s << (bounded ip/port: %s:%i)\n' \ %(__localdir__,_ip,_port) # this will block if self.conf.root : # cherrypy.quickstart(self.conf.root,script_name='',config=self.conf.server_config_file) cherrypy.quickstart(self.conf.root, config=self.conf.server_config_file) else : # cherrypy.quickstart(script_name='',config=self.conf.server_config_file) cherrypy.quickstart(config=self.conf.server_config_file) except IOError, e: print "\n\n>>>Server::quickstart: IOError: Port not free: ",_ip,":",_port,"\nException: ",str(e) if self.getProcessPids(_port,kill=True) : self.quickstart(ip,retries-1) except cherrypy.server.interrupt, e: print "\n\n>>>Server::quickstart: Server interrupt: Port may be used: ",_ip,":",_port,"\nException: ",str(e) if self.getProcessPids(_port,kill=True) : self.quickstart(ip,retries-1) except BaseException, e: print "\n\n>>>Server::quickstart: Exception caught while starting the service." if 'Address already in use' in e : print "Port already in use: ",_ip,":",_port if self.getProcessPids(_port,kill=True) : self.quickstart(ip,retries-1) else: print "Port may be in use: ",_ip,":",_port,"\nException: ",str(e) raise except : print "\n\n>>>Server::quickstart: Unknown exception caught while starting the service." print "Port may be in use: ",_ip,":",_port raise # cherrypy.quickstart(script_name='', config='config/server.cfg') def mount(self,app,path_name=''): # cherrypy.tree.mount(requesthandler,config=appconfig) cherrypy.tree.mount(app,script_name=path_name,config=self.config.server_config_file) def getProcessPids(self,port,kill=False): '''Get the pid of the offending Python process given a port after an unsuccessful restart.''' print "Running lsof -i :"+str(port)," ...\n\n" command = "lsof -i :"+str(port) w = spopen(command,stdout=sp.PIPE,stderr=sp.PIPE,shell=True) se = w.stderr.readlines() result = w.stdout.readlines() exitcode = w.wait() if not result : print "getProcessPid:: Unable to obtain process pid. (lsof returned nothing. exitcode: %s)" %str(exitcode) return False import pprint pprint.pprint(result) # get heading: ix = None head = result[0].upper() if 'PID' in head: head = filter(lambda x: x != str(), head.split(' ')) head = map(lambda x: x.strip().replace(' ',''), head) if 'PID' in head : ix = head.index('PID') # get process pid pids = [] for line in result : if 'python' in line.lower() : line = filter(lambda x: x != str(), line.split(' ')) line = map(lambda x: x.strip().replace(' ',''), line) try : if ix : pids.append(int(line[ix])) else: numbers = filter(lambda x: x.isdigit(), line) pids.append(int(numbers[0])) except: print 'Error parsing lsof results.' return False print 'Pids found: ',pids # kill if specified if kill : pids_killed = [] import signal for pid in pids: print 'Killing process: ',pid try : os.kill(pid,signal.SIGKILL) pids_killed.append(pid) except : print 'Failed: ',pid if pids_killed : print 'Processes killed:',pids_killed,' Waiting 10 secods...' import time time.sleep(10) return True return False def getProcessPriority(self): '''Get the priority of this Python process.''' pid = os.getpid() # print "Running ps -p %s -o nice" %str(pid)," ...\n\n" command = "ps -p %s -o nice" %str(pid) w = spopen(command,stdout=sp.PIPE,stderr=sp.PIPE,shell=True) se = w.stderr.readlines() result = w.stdout.readlines() exitcode = w.wait() if not result : print "getProcessPriority:: Unable to obtain process proirity. (ps returned nothing. exitcode: %s)" %str(exitcode) return None try : return int(result[1].strip()) except: print "getProcessPriority:: Error parsing process proirity value. (ps returned: \n%s, \nexitcode: %s)" %(str(result),str(exitcode)) return None def setProcessPriority(self,value,passwd): '''Set the priority of this Python process.''' pid = os.getpid() command = "sudo -S renice -n %s -p %s" %(str(value),str(pid)) w = spopen(command,stdout=sp.PIPE,stdin=sp.PIPE,stderr=sp.PIPE,shell=True) result,se = w.communicate(passwd) def getRevisionNumber(self): '''Get the Version control revision number by running svn info''' w = spopen("svn info",stdout=sp.PIPE,stdin=None,stderr=sp.PIPE,shell=True) try : result,err = w.communicate(None) rev = 0 for line in result.split('\n'): if line.startswith('Revision') : rev = int(line.split(':')[1].strip()) return rev except: return None def getHitCount(self): if hasattr(cherrypy,'session') : count = cherrypy.session.get('count', 0) + 1 cherrypy.session['count'] = count return count else: return 0 def getSessionID(self): if hasattr(cherrypy,'session') : self.getHitCount() return str(cherrypy.session.id) else: raise RuntimeError('server::getSessionID: No session information available.') def getRequestSessionID(self): cookie = cherrypy.request.cookie if cookie.has_key('session_id') : cookie = cookie['session_id'].output(header='') rsid = cookie.split('session_id=')[-1] return str(rsid) else : return None def validateSession(self): if hasattr(cherrypy,'session') \ and self.getSessionID() == self.getRequestSessionID() : return True else: if self.getRequestSessionID() is None : cookie = cherrypy.request.cookie log_msg = "SessionID mismatch: " + str(self.getSessionID()) + \ " Received: None, Coockie was: " + str(cookie) cherrypy.log(log_msg) return False def adminSession(self): if hasattr(cherrypy,'session') and cherrypy.session.has_key('auth') and cherrypy.session['auth'] : return True return False def getFullPath(self,filelist): if (type(filelist) == list) : return map(lambda x: self.getFullPath(x),filelist) else: if type(filelist) != str and type(filelist) != unicode : e ='server::getFullPath: Wrong path name in file list: %s' %(str(type(filelist))) raise RuntimeError(e) return os.path.join(self.getSessionPath(),filelist) def getSessionPath(self): if hasattr(cherrypy,'session') : return cherrypy.session.get_session_path() else: raise RuntimeError('server::getSessionPath: No session information available.') def getSessionCount(self) : if hasattr(cherrypy,'session') : return len(cherrypy.session) else: raise RuntimeError('server::getSessionPath: No session information available.') def getActiveSessions(self) : if hasattr(cherrypy,'session') : return cherrypy.session.cache.keys() else: raise RuntimeError('server::getSessionPath: No session information available.')