annotate 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
rev   line source
gyorgy@0 1 """
gyorgy@0 2 ServerWrapper.py
gyorgy@0 3
gyorgy@0 4 Created by George Fazekas, QMUL on 2009-05-09.
gyorgy@0 5 Copyright (c) 2009 QMUL. All rights reserved.
gyorgy@0 6 """
gyorgy@0 7 from __future__ import with_statement
gyorgy@0 8 import os,sys
gyorgy@0 9 import cherrypy
gyorgy@0 10 from cherrypy.lib import static
gyorgy@0 11 import subprocess as sp
gyorgy@0 12 from subprocess import Popen as spopen
gyorgy@0 13
gyorgy@0 14 try :
gyorgy@0 15 from cherrypy.lib import safemime
gyorgy@0 16 except:
gyorgy@0 17 print "Warning: import safemime failed. (Probably newer cherrypy version.)"
gyorgy@0 18 #safemime.init()
gyorgy@0 19 #root._cp_config = {'tools.safe_multipart.on': True}
gyorgy@0 20
gyorgy@0 21 __localdir__ = os.path.realpath(os.path.dirname(os.path.abspath(__file__)))
gyorgy@0 22
gyorgy@0 23 # ============================================
gyorgy@0 24 # Shared Configuration data container
gyorgy@0 25 # ============================================
gyorgy@0 26
gyorgy@0 27 class Config(object):
gyorgy@0 28 '''A shared config object'''
gyorgy@0 29
gyorgy@0 30 def __init__(self,root=None,local=False,conf='not set'):
gyorgy@0 31 self.cherrypyVersion = 0
gyorgy@0 32 self.nice_value = 0
gyorgy@0 33 self.svn_revision = 0
gyorgy@0 34 self.hostname = str()
gyorgy@0 35 self.localdir = __localdir__
gyorgy@0 36 self.server_config_file = str()
gyorgy@0 37 self.local = local
gyorgy@0 38 self.server_config_file = conf
gyorgy@0 39 self.root = root
gyorgy@0 40
gyorgy@0 41
gyorgy@0 42 # ============================================
gyorgy@0 43 # Cherrypy ServerWrapper
gyorgy@0 44 # ============================================
gyorgy@0 45
gyorgy@0 46 # This is a thin wrapper on cherrypy
gyorgy@0 47 class ServerWrapper(object):
gyorgy@0 48
gyorgy@0 49 def __init__(self,config):
gyorgy@0 50 self.conf = config
gyorgy@0 51 self.config = self.conf
gyorgy@0 52
gyorgy@0 53
gyorgy@0 54 def quickstart(self,ip=None,retries=5):
gyorgy@0 55 '''Start fx-test'''
gyorgy@0 56 if not retries :
gyorgy@0 57 print 'Server: Error: Retry limit reached while trying to start service.'
gyorgy@0 58 # TDOD: maybe we want to shut the daemon here as well... to avoid external loop
gyorgy@0 59 return False
gyorgy@0 60 self.config.cherrypyVersion = cherrypy.__version__
gyorgy@0 61 print 'Server: Cherrypy version: %s' %str(cherrypy.__version__)
gyorgy@0 62
gyorgy@0 63 cherrypy.server.socket_timeout = 60
gyorgy@0 64 cherrypy.config.update({'tools.staticdir.root': __localdir__})
gyorgy@0 65 # cherrypy.config.update('./config/server.cfg')
gyorgy@0 66 cherrypy.config.update(self.config.server_config_file)
gyorgy@0 67 if type(ip) == str and ip.count('.') == 3:
gyorgy@0 68 _ip = ip.split(':')[0]
gyorgy@0 69 if ip.count(':') and len(ip.split(':')[-1]) == 4:
gyorgy@0 70 _port = int(ip.split(':')[-1])
gyorgy@0 71 cherrypy.config.update({'server.socket_port': _port})
gyorgy@0 72 else :
gyorgy@0 73 _port = int(cherrypy.server.socket_port)
gyorgy@0 74 print "Server: No valid port specified for service. Using default: %i" %_port
gyorgy@0 75 cherrypy.config.update({'server.socket_host': _ip})
gyorgy@0 76 else :
gyorgy@0 77 _ip = str(cherrypy.server.socket_host)
gyorgy@0 78 _port = int(cherrypy.server.socket_port)
gyorgy@0 79
gyorgy@0 80 # pass in the global config object to the session:
gyorgy@0 81 cherrypy.config.update({'tools.sessions.GLOBAL_CONFIG': self.config})
gyorgy@0 82
gyorgy@0 83 #enable safemime tool to avoid upload timeouts
gyorgy@0 84 try :
gyorgy@0 85 safemime.init()
gyorgy@0 86 cherrypy.config.update({'tools.safe_multipart.on': True})
gyorgy@0 87 except:
gyorgy@0 88 pass
gyorgy@0 89
gyorgy@0 90 # set hostname in config
gyorgy@0 91 if not self.config.hostname :
gyorgy@0 92 self.config.hostname = str(cherrypy.server.socket_host).strip()+":"+str(cherrypy.server.socket_port).strip()
gyorgy@0 93 print 'Server: hostname is set to: ',self.config.hostname
gyorgy@0 94
gyorgy@0 95 # report process pid and niceness
gyorgy@0 96 print "Server: pid: ", os.getpid()
gyorgy@0 97 # self.setProcessPriority(-3,'passwd')
gyorgy@0 98 self.config.nice_value = self.getProcessPriority()
gyorgy@0 99 print "Server: nice value: ", self.config.nice_value
gyorgy@0 100
gyorgy@0 101 # report subversion rev. number
gyorgy@0 102 self.config.svn_revision = self.getRevisionNumber()
gyorgy@0 103 print "Server: SVN revision: ", self.config.svn_revision
gyorgy@0 104
gyorgy@0 105 try :
gyorgy@0 106
gyorgy@0 107 print 'Server: quickstarting apps at >> %s << (bounded ip/port: %s:%i)\n' \
gyorgy@0 108 %(__localdir__,_ip,_port)
gyorgy@0 109 # this will block
gyorgy@0 110 if self.conf.root :
gyorgy@0 111 # cherrypy.quickstart(self.conf.root,script_name='',config=self.conf.server_config_file)
gyorgy@0 112 cherrypy.quickstart(self.conf.root, config=self.conf.server_config_file)
gyorgy@0 113 else :
gyorgy@0 114 # cherrypy.quickstart(script_name='',config=self.conf.server_config_file)
gyorgy@0 115 cherrypy.quickstart(config=self.conf.server_config_file)
gyorgy@0 116
gyorgy@0 117
gyorgy@0 118 except IOError, e:
gyorgy@0 119 print "\n\n>>>Server::quickstart: IOError: Port not free: ",_ip,":",_port,"\nException: ",str(e)
gyorgy@0 120 if self.getProcessPids(_port,kill=True) :
gyorgy@0 121 self.quickstart(ip,retries-1)
gyorgy@0 122
gyorgy@0 123 except cherrypy.server.interrupt, e:
gyorgy@0 124 print "\n\n>>>Server::quickstart: Server interrupt: Port may be used: ",_ip,":",_port,"\nException: ",str(e)
gyorgy@0 125 if self.getProcessPids(_port,kill=True) :
gyorgy@0 126 self.quickstart(ip,retries-1)
gyorgy@0 127
gyorgy@0 128 except BaseException, e:
gyorgy@0 129 print "\n\n>>>Server::quickstart: Exception caught while starting the service."
gyorgy@0 130 if 'Address already in use' in e :
gyorgy@0 131 print "Port already in use: ",_ip,":",_port
gyorgy@0 132 if self.getProcessPids(_port,kill=True) :
gyorgy@0 133 self.quickstart(ip,retries-1)
gyorgy@0 134 else:
gyorgy@0 135 print "Port may be in use: ",_ip,":",_port,"\nException: ",str(e)
gyorgy@0 136 raise
gyorgy@0 137
gyorgy@0 138 except :
gyorgy@0 139 print "\n\n>>>Server::quickstart: Unknown exception caught while starting the service."
gyorgy@0 140 print "Port may be in use: ",_ip,":",_port
gyorgy@0 141 raise
gyorgy@0 142 # cherrypy.quickstart(script_name='', config='config/server.cfg')
gyorgy@0 143
gyorgy@0 144
gyorgy@0 145 def mount(self,app,path_name=''):
gyorgy@0 146 # cherrypy.tree.mount(requesthandler,config=appconfig)
gyorgy@0 147 cherrypy.tree.mount(app,script_name=path_name,config=self.config.server_config_file)
gyorgy@0 148
gyorgy@0 149
gyorgy@0 150 def getProcessPids(self,port,kill=False):
gyorgy@0 151 '''Get the pid of the offending Python process given a port after an unsuccessful restart.'''
gyorgy@0 152 print "Running lsof -i :"+str(port)," ...\n\n"
gyorgy@0 153 command = "lsof -i :"+str(port)
gyorgy@0 154 w = spopen(command,stdout=sp.PIPE,stderr=sp.PIPE,shell=True)
gyorgy@0 155 se = w.stderr.readlines()
gyorgy@0 156 result = w.stdout.readlines()
gyorgy@0 157 exitcode = w.wait()
gyorgy@0 158 if not result :
gyorgy@0 159 print "getProcessPid:: Unable to obtain process pid. (lsof returned nothing. exitcode: %s)" %str(exitcode)
gyorgy@0 160 return False
gyorgy@0 161 import pprint
gyorgy@0 162 pprint.pprint(result)
gyorgy@0 163
gyorgy@0 164 # get heading:
gyorgy@0 165 ix = None
gyorgy@0 166 head = result[0].upper()
gyorgy@0 167 if 'PID' in head:
gyorgy@0 168 head = filter(lambda x: x != str(), head.split(' '))
gyorgy@0 169 head = map(lambda x: x.strip().replace(' ',''), head)
gyorgy@0 170 if 'PID' in head : ix = head.index('PID')
gyorgy@0 171 # get process pid
gyorgy@0 172 pids = []
gyorgy@0 173 for line in result :
gyorgy@0 174 if 'python' in line.lower() :
gyorgy@0 175 line = filter(lambda x: x != str(), line.split(' '))
gyorgy@0 176 line = map(lambda x: x.strip().replace(' ',''), line)
gyorgy@0 177 try :
gyorgy@0 178 if ix :
gyorgy@0 179 pids.append(int(line[ix]))
gyorgy@0 180 else:
gyorgy@0 181 numbers = filter(lambda x: x.isdigit(), line)
gyorgy@0 182 pids.append(int(numbers[0]))
gyorgy@0 183 except:
gyorgy@0 184 print 'Error parsing lsof results.'
gyorgy@0 185 return False
gyorgy@0 186 print 'Pids found: ',pids
gyorgy@0 187 # kill if specified
gyorgy@0 188 if kill :
gyorgy@0 189 pids_killed = []
gyorgy@0 190 import signal
gyorgy@0 191 for pid in pids:
gyorgy@0 192 print 'Killing process: ',pid
gyorgy@0 193 try :
gyorgy@0 194 os.kill(pid,signal.SIGKILL)
gyorgy@0 195 pids_killed.append(pid)
gyorgy@0 196 except :
gyorgy@0 197 print 'Failed: ',pid
gyorgy@0 198 if pids_killed :
gyorgy@0 199 print 'Processes killed:',pids_killed,' Waiting 10 secods...'
gyorgy@0 200 import time
gyorgy@0 201 time.sleep(10)
gyorgy@0 202 return True
gyorgy@0 203 return False
gyorgy@0 204
gyorgy@0 205
gyorgy@0 206 def getProcessPriority(self):
gyorgy@0 207 '''Get the priority of this Python process.'''
gyorgy@0 208 pid = os.getpid()
gyorgy@0 209 # print "Running ps -p %s -o nice" %str(pid)," ...\n\n"
gyorgy@0 210 command = "ps -p %s -o nice" %str(pid)
gyorgy@0 211 w = spopen(command,stdout=sp.PIPE,stderr=sp.PIPE,shell=True)
gyorgy@0 212 se = w.stderr.readlines()
gyorgy@0 213 result = w.stdout.readlines()
gyorgy@0 214 exitcode = w.wait()
gyorgy@0 215 if not result :
gyorgy@0 216 print "getProcessPriority:: Unable to obtain process proirity. (ps returned nothing. exitcode: %s)" %str(exitcode)
gyorgy@0 217 return None
gyorgy@0 218 try :
gyorgy@0 219 return int(result[1].strip())
gyorgy@0 220 except:
gyorgy@0 221 print "getProcessPriority:: Error parsing process proirity value. (ps returned: \n%s, \nexitcode: %s)" %(str(result),str(exitcode))
gyorgy@0 222 return None
gyorgy@0 223
gyorgy@0 224
gyorgy@0 225 def setProcessPriority(self,value,passwd):
gyorgy@0 226 '''Set the priority of this Python process.'''
gyorgy@0 227 pid = os.getpid()
gyorgy@0 228 command = "sudo -S renice -n %s -p %s" %(str(value),str(pid))
gyorgy@0 229 w = spopen(command,stdout=sp.PIPE,stdin=sp.PIPE,stderr=sp.PIPE,shell=True)
gyorgy@0 230 result,se = w.communicate(passwd)
gyorgy@0 231
gyorgy@0 232
gyorgy@0 233 def getRevisionNumber(self):
gyorgy@0 234 '''Get the Version control revision number by running svn info'''
gyorgy@0 235 w = spopen("svn info",stdout=sp.PIPE,stdin=None,stderr=sp.PIPE,shell=True)
gyorgy@0 236 try :
gyorgy@0 237 result,err = w.communicate(None)
gyorgy@0 238 rev = 0
gyorgy@0 239 for line in result.split('\n'):
gyorgy@0 240 if line.startswith('Revision') :
gyorgy@0 241 rev = int(line.split(':')[1].strip())
gyorgy@0 242 return rev
gyorgy@0 243 except:
gyorgy@0 244 return None
gyorgy@0 245
gyorgy@0 246
gyorgy@0 247
gyorgy@0 248 def getHitCount(self):
gyorgy@0 249 if hasattr(cherrypy,'session') :
gyorgy@0 250 count = cherrypy.session.get('count', 0) + 1
gyorgy@0 251 cherrypy.session['count'] = count
gyorgy@0 252 return count
gyorgy@0 253 else:
gyorgy@0 254 return 0
gyorgy@0 255
gyorgy@0 256 def getSessionID(self):
gyorgy@0 257 if hasattr(cherrypy,'session') :
gyorgy@0 258 self.getHitCount()
gyorgy@0 259 return str(cherrypy.session.id)
gyorgy@0 260 else:
gyorgy@0 261 raise RuntimeError('server::getSessionID: No session information available.')
gyorgy@0 262
gyorgy@0 263 def getRequestSessionID(self):
gyorgy@0 264 cookie = cherrypy.request.cookie
gyorgy@0 265 if cookie.has_key('session_id') :
gyorgy@0 266 cookie = cookie['session_id'].output(header='')
gyorgy@0 267 rsid = cookie.split('session_id=')[-1]
gyorgy@0 268 return str(rsid)
gyorgy@0 269 else :
gyorgy@0 270 return None
gyorgy@0 271
gyorgy@0 272 def validateSession(self):
gyorgy@0 273 if hasattr(cherrypy,'session') \
gyorgy@0 274 and self.getSessionID() == self.getRequestSessionID() :
gyorgy@0 275 return True
gyorgy@0 276 else:
gyorgy@0 277 if self.getRequestSessionID() is None :
gyorgy@0 278 cookie = cherrypy.request.cookie
gyorgy@0 279 log_msg = "SessionID mismatch: " + str(self.getSessionID()) + \
gyorgy@0 280 " Received: None, Coockie was: " + str(cookie)
gyorgy@0 281 cherrypy.log(log_msg)
gyorgy@0 282 return False
gyorgy@0 283
gyorgy@0 284 def adminSession(self):
gyorgy@0 285 if hasattr(cherrypy,'session') and cherrypy.session.has_key('auth') and cherrypy.session['auth'] :
gyorgy@0 286 return True
gyorgy@0 287 return False
gyorgy@0 288
gyorgy@0 289 def getFullPath(self,filelist):
gyorgy@0 290 if (type(filelist) == list) :
gyorgy@0 291 return map(lambda x: self.getFullPath(x),filelist)
gyorgy@0 292 else:
gyorgy@0 293 if type(filelist) != str and type(filelist) != unicode :
gyorgy@0 294 e ='server::getFullPath: Wrong path name in file list: %s' %(str(type(filelist)))
gyorgy@0 295 raise RuntimeError(e)
gyorgy@0 296 return os.path.join(self.getSessionPath(),filelist)
gyorgy@0 297
gyorgy@0 298 def getSessionPath(self):
gyorgy@0 299 if hasattr(cherrypy,'session') :
gyorgy@0 300 return cherrypy.session.get_session_path()
gyorgy@0 301 else:
gyorgy@0 302 raise RuntimeError('server::getSessionPath: No session information available.')
gyorgy@0 303
gyorgy@0 304 def getSessionCount(self) :
gyorgy@0 305 if hasattr(cherrypy,'session') :
gyorgy@0 306 return len(cherrypy.session)
gyorgy@0 307 else:
gyorgy@0 308 raise RuntimeError('server::getSessionPath: No session information available.')
gyorgy@0 309
gyorgy@0 310 def getActiveSessions(self) :
gyorgy@0 311 if hasattr(cherrypy,'session') :
gyorgy@0 312 return cherrypy.session.cache.keys()
gyorgy@0 313 else:
gyorgy@0 314 raise RuntimeError('server::getSessionPath: No session information available.')
gyorgy@0 315
gyorgy@0 316