Package PyFoam :: Package Infrastructure :: Module FoamServer
[hide private]
[frames] | no frames]

Source Code for Module PyFoam.Infrastructure.FoamServer

  1  #  ICE Revision: $Id: FoamServer.py 7964 2007-09-20 08:33:20Z bgschaid $  
  2  """A XMLRPC-Server that answeres about the current state of a Foam-Run""" 
  3   
  4  from ServerBase import ServerBase 
  5   
  6  from xmlrpclib import ServerProxy 
  7   
  8  from PyFoam import configuration as config 
  9  from PyFoam import versionString 
 10  from PyFoam.Basics.RingBuffer import RingBuffer 
 11  from PyFoam.Infrastructure.NetworkHelpers import freeServerPort 
 12  from PyFoam.Infrastructure.Logging import foamLogger 
 13  from PyFoam.FoamInformation import foamMPI 
 14  from PyFoam.RunDictionary.ParameterFile import ParameterFile 
 15   
 16  from Hardcoded import userName 
 17   
 18  from threading import Lock,Thread,Timer 
 19  from time import time 
 20  from os import environ,uname,path,getpid 
 21  import socket 
 22   
 23  import sys,string 
 24  from traceback import extract_tb 
 25   
26 -def findFreePort():
27 """Finds a free server port on this machine and returns it 28 29 Valid server ports are in the range 18000 upward (the function tries to 30 find the lowest possible port number 31 32 ATTENTION: this part may introduce race conditions""" 33 34 return freeServerPort(config().getint("Network","startServerPort"), 35 length=config().getint("Network","nrServerPorts"))
36
37 -class FoamAnswerer(object):
38 """The class that handles the actual requests (only needed to hide the 39 Thread-methods from the world 40 """
41 - def __init__(self,run=None,master=None,lines=100):
42 """ 43 @param run: The thread that controls the run 44 @param master: The Runner-Object that controls everything 45 @param lines: the number of lines the server should remember 46 """ 47 self._run=run 48 self._master=master 49 self._lines=RingBuffer(nr=lines) 50 self._lastTime=time() 51 self._linesLock=Lock() 52 self._maxOutputTime=config().getfloat("IsAlive","maxTimeStart")
53
54 - def _insertLine(self,line):
55 """Inserts a new line, not to be called via XMLRPC""" 56 self._linesLock.acquire() 57 self._lines.insert(line) 58 tmp=time() 59 if (tmp-self._lastTime)>self._maxOutputTime: 60 self._maxOutputTime=tmp-self._lastTime 61 self._lastTime=tmp 62 self._linesLock.release()
63
64 - def isFoamServer(self):
65 """This is a Foam-Server (True by default)""" 66 return True
67
68 - def isLiving(self):
69 """The calculation still generates output and therefor seems to be living""" 70 return self.elapsedTime()<self._maxOutputTime
71
72 - def _kill(self):
73 """Interrupts the FOAM-process""" 74 if self._run: 75 foamLogger().warning("Killed by request") 76 self._run.interrupt() 77 return True 78 else: 79 return False
80
81 - def stop(self):
82 """Stops the run gracefully (after writing the last time-step to disk)""" 83 self._master.stopGracefully() 84 return True
85
86 - def write(self):
87 """Makes the program write the next time-step to disk and the continue""" 88 self._master.writeResults() 89 return True
90
91 - def argv(self):
92 """Argument vector with which the runner was called""" 93 if self._master: 94 return self._master.origArgv 95 else: 96 return []
97
98 - def usedArgv(self):
99 """Argument vector with which the runner started the run""" 100 if self._master: 101 return self._master.argv 102 else: 103 return []
104
105 - def isParallel(self):
106 """Is it a parallel run?""" 107 if self._master: 108 return self._master.lam!=None 109 else: 110 return False
111
112 - def procNr(self):
113 """How many processors are used?""" 114 if self._master: 115 if self._master.lam!=None: 116 return self._master.lam.cpuNr() 117 else: 118 return 1 119 else: 120 return 0
121
122 - def nrWarnings(self):
123 """Number of warnings the executable emitted""" 124 if self._master: 125 return self._master.warnings 126 else: 127 return 0
128
129 - def commandLine(self):
130 """The command line""" 131 if self._master: 132 return string.join(self._master.origArgv) 133 else: 134 return ""
135
136 - def actualCommandLine(self):
137 """The actual command line used""" 138 if self._master: 139 return self._master.cmd 140 else: 141 return ""
142
143 - def scriptName(self):
144 """Name of the Python-Script that runs the show""" 145 return sys.argv[0]
146
147 - def lastLine(self):
148 """@return: the last line that was output by the running FOAM-process""" 149 self._linesLock.acquire() 150 result=self._lines.last() 151 self._linesLock.release() 152 if not result: 153 return "" 154 return result
155
156 - def tail(self):
157 """@return: the current last lines as a string""" 158 self._linesLock.acquire() 159 tmp=self._lines.dump() 160 self._linesLock.release() 161 result="" 162 for l in tmp: 163 result+=l 164 165 return result
166
167 - def elapsedTime(self):
168 """@return: time in seconds since the last line was output""" 169 self._linesLock.acquire() 170 result=time()-self._lastTime 171 self._linesLock.release() 172 173 return result
174
175 - def getEnviron(self,name):
176 """@param name: name of an environment variable 177 @return: value of the variable, empty string if non-existing""" 178 result="" 179 if environ.has_key(name): 180 result=environ[name] 181 return result
182
183 - def mpi(self):
184 """@return: name of the MPI-implementation""" 185 return foamMPI()
186
187 - def foamVersion(self):
188 """Version number of the Foam-Version""" 189 return self.getEnviron("WM_PROJECT_VERSION")
190
191 - def pyFoamVersion(self):
192 """@return: Version number of the PyFoam""" 193 return versionString()
194
195 - def uname(self):
196 """@return: the complete uname-information""" 197 return uname()
198
199 - def ip(self):
200 """@return: the ip of this machine""" 201 return socket.gethostbyname(socket.gethostname())
202
203 - def hostname(self):
204 """@return: The name of the computer""" 205 return uname()[1]
206
207 - def configuration(self):
208 """@return: all the configured parameters""" 209 return config().dump()
210
211 - def cwd(self):
212 """@return: the current working directory""" 213 return path.abspath(path.curdir)
214
215 - def pid(self):
216 """@return: the PID of the script""" 217 return getpid()
218
219 - def user(self):
220 """@return: the user that runs this script""" 221 return userName()
222
223 - def id(self):
224 """@return: an ID for this run: IP and process-id""" 225 return "%s:%d" % (self.ip(),self.pid())
226
227 - def time(self):
228 """@return: the current time in the simulation""" 229 if self._master.nowTime: 230 return self._master.nowTime 231 else: 232 return 0
233
234 - def createTime(self):
235 """@return: the time in the simulation for which the mesh was created""" 236 if self._master.nowTime: 237 return self._master.createTime 238 else: 239 return 0
240
241 - def _readParameter(self,name):
242 """Reads a parametr from the controlDict 243 @param name: the parameter 244 @return: The value""" 245 control=ParameterFile(self._master.getSolutionDirectory().controlDict()) 246 return control.readParameter(name)
247
248 - def startTime(self):
249 """@return: parameter startTime from the controlDict""" 250 return float(self._readParameter("startTime"))
251
252 - def endTime(self):
253 """@return: parameter endTime from the controlDict""" 254 return float(self._readParameter("endTime"))
255
256 - def deltaT(self):
257 """@return: parameter startTime from the controlDict""" 258 return float(self._readParameter("deltaT"))
259
260 -class FoamServer(Thread):
261 """This is the class that serves the requests about the FOAM-Run"""
262 - def __init__(self,run=None,master=None,lines=100):
263 """ 264 @param run: The thread that controls the run 265 @param master: The Runner-Object that controls everything 266 @param lines: the number of lines the server should remember 267 """ 268 Thread.__init__(self) 269 self._port=findFreePort() 270 271 self._running=False 272 273 if self._port<0: 274 foamLogger().warning("Could not get a free port. Server not started") 275 return 276 277 foamLogger().info("Serving on port %d" % self._port) 278 self._server=ServerBase(('',self._port),logRequests=False) 279 self._server.register_introspection_functions() 280 self._answerer=FoamAnswerer(run=run,master=master,lines=lines) 281 self._server.register_instance(self._answerer) 282 self._server.register_function(self.killServer) 283 self._server.register_function(self.kill) 284 if run: 285 self._server.register_function(run.cpuTime) 286 self._server.register_function(run.cpuUserTime) 287 self._server.register_function(run.cpuSystemTime) 288 self._server.register_function(run.wallTime) 289 self._server.register_function(run.usedMemory)
290
291 - def run(self):
292 if self._port<0: 293 return 294 # wait befor registering to avoid timeouts 295 reg=Timer(5.,self.register) 296 reg.start() 297 298 self._running=True 299 300 while self._running: 301 self._server.handle_request() 302 303 # self._server.serve_forever() # the old way 304 self._server.server_close() 305 306 foamLogger().info("Stopped serving on port %d" % self._port)
307
308 - def info(self):
309 """Returns the IP, the PID and the port of the server (as one tuple)""" 310 311 return self._answerer.ip(),self._answerer.pid(),self._port
312
313 - def kill(self):
314 """Interrupts the FOAM-process (and kills the server)""" 315 self._answerer._kill() 316 return self.killServer()
317
318 - def killServer(self):
319 """Kills the server process""" 320 tmp=self._running 321 self._running=False 322 return tmp
323
324 - def register(self):
325 """Tries to register with the Meta-Server""" 326 327 try: 328 try: 329 meta=ServerProxy("http://%s:%d" % (config().get("Metaserver","ip"),config().getint("Metaserver","port"))) 330 meta.registerServer(self._answerer.ip(),self._answerer.pid(),self._port) 331 except socket.error, reason: 332 foamLogger().warning("Can't connect to meta-server - SocketError: "+str(reason)) 333 except: 334 foamLogger().error("Can't connect to meta-server - Unknown Error: "+str(sys.exc_info()[0])) 335 foamLogger().error(str(sys.exc_info()[1])) 336 foamLogger().error("Traceback: "+str(extract_tb(sys.exc_info()[2]))) 337 except: 338 # print "Error during registering (no socket module?)" 339 pass
340
341 - def deregister(self):
342 """Tries to deregister with the Meta-Server""" 343 self._server.server_close() 344 345 try: 346 meta=ServerProxy("http://%s:%d" % (config().get("Metaserver","ip"),config().getint("Metaserver","port"))) 347 meta.deregisterServer(self._answerer.ip(),self._answerer.pid(),self._port) 348 except socket.error, reason: 349 foamLogger().warning("Can't connect to meta-server - SocketError: "+str(reason)) 350 except: 351 foamLogger().error("Can't connect to meta-server - Unknown Error: "+str(sys.exc_info()[0])) 352 foamLogger().error(str(sys.exc_info()[1])) 353 foamLogger().error("Traceback: "+str(extract_tb(sys.exc_info()[2])))
354
355 - def _insertLine(self,line):
356 """Inserts a new line, not to be called via XMLRPC""" 357 self._answerer._insertLine(line)
358