1
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
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
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
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
65 """This is a Foam-Server (True by default)"""
66 return True
67
69 """The calculation still generates output and therefor seems to be living"""
70 return self.elapsedTime()<self._maxOutputTime
71
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
82 """Stops the run gracefully (after writing the last time-step to disk)"""
83 self._master.stopGracefully()
84 return True
85
87 """Makes the program write the next time-step to disk and the continue"""
88 self._master.writeResults()
89 return True
90
92 """Argument vector with which the runner was called"""
93 if self._master:
94 return self._master.origArgv
95 else:
96 return []
97
99 """Argument vector with which the runner started the run"""
100 if self._master:
101 return self._master.argv
102 else:
103 return []
104
106 """Is it a parallel run?"""
107 if self._master:
108 return self._master.lam!=None
109 else:
110 return False
111
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
123 """Number of warnings the executable emitted"""
124 if self._master:
125 return self._master.warnings
126 else:
127 return 0
128
130 """The command line"""
131 if self._master:
132 return string.join(self._master.origArgv)
133 else:
134 return ""
135
137 """The actual command line used"""
138 if self._master:
139 return self._master.cmd
140 else:
141 return ""
142
144 """Name of the Python-Script that runs the show"""
145 return sys.argv[0]
146
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
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
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
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
184 """@return: name of the MPI-implementation"""
185 return foamMPI()
186
188 """Version number of the Foam-Version"""
189 return self.getEnviron("WM_PROJECT_VERSION")
190
192 """@return: Version number of the PyFoam"""
193 return versionString()
194
196 """@return: the complete uname-information"""
197 return uname()
198
200 """@return: the ip of this machine"""
201 return socket.gethostbyname(socket.gethostname())
202
204 """@return: The name of the computer"""
205 return uname()[1]
206
208 """@return: all the configured parameters"""
209 return config().dump()
210
212 """@return: the current working directory"""
213 return path.abspath(path.curdir)
214
216 """@return: the PID of the script"""
217 return getpid()
218
220 """@return: the user that runs this script"""
221 return userName()
222
224 """@return: an ID for this run: IP and process-id"""
225 return "%s:%d" % (self.ip(),self.pid())
226
228 """@return: the current time in the simulation"""
229 if self._master.nowTime:
230 return self._master.nowTime
231 else:
232 return 0
233
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
247
249 """@return: parameter startTime from the controlDict"""
250 return float(self._readParameter("startTime"))
251
253 """@return: parameter endTime from the controlDict"""
254 return float(self._readParameter("endTime"))
255
257 """@return: parameter startTime from the controlDict"""
258 return float(self._readParameter("deltaT"))
259
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
292 if self._port<0:
293 return
294
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
304 self._server.server_close()
305
306 foamLogger().info("Stopped serving on port %d" % self._port)
307
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
314 """Interrupts the FOAM-process (and kills the server)"""
315 self._answerer._kill()
316 return self.killServer()
317
319 """Kills the server process"""
320 tmp=self._running
321 self._running=False
322 return tmp
323
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
339 pass
340
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
356 """Inserts a new line, not to be called via XMLRPC"""
357 self._answerer._insertLine(line)
358