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

Source Code for Module PyFoam.Infrastructure.FoamMetaServer

  1  #  ICE Revision: $Id: FoamMetaServer.py 7833 2007-08-28 15:28:57Z bgschaid $  
  2  """A XMLRPC-Server that knows all PyFoam-Runs in its subnet""" 
  3   
  4  from ServerBase import ServerBase 
  5  import xmlrpclib,socket 
  6  from threading import Lock,Thread,Timer 
  7   
  8  from PyFoam.Infrastructure.Logging import foamLogger 
  9  from PyFoam.Infrastructure.NetworkHelpers import checkFoamServers 
 10  from PyFoam import configuration as config 
 11  from PyFoam.ThirdParty.IPy import IP 
 12   
 13  import sys,time,copy,os 
 14  from traceback import extract_tb 
 15   
16 -class FoamMetaServer(object):
17 """The Metaserver. 18 19 Collects all the known FoamServers. Then waits for the servers to 20 register themselves. Checks at regular intervalls whether the processes are still alive 21 """
22 - def __init__(self,port=None):
23 """@param port: The port on which the server should listen""" 24 if port==None: 25 port=config().getint("Metaserver","port") 26 27 foamLogger("server").info("Starting Server up") 28 self.pid=os.getpid() 29 try: 30 self.servers={} 31 self.dataLock=Lock() 32 self.startupLock=Lock() 33 34 self.collect() 35 36 self.checker=MetaChecker(self) 37 self.checker.setDaemon(True) 38 self.checker.start() 39 40 self._server=ServerBase(('',port),logRequests=False) 41 self._server.register_instance(self) 42 self._server.register_introspection_functions() 43 self._server.serve_forever() 44 except KeyboardInterrupt: 45 foamLogger("server").warning("Keyboard interrupt") 46 except socket.error,reason: 47 foamLogger("server").error("Socket Error: "+str(reason)) 48 print "Can't start server, Problem with socket: ",reason[1] 49 except: 50 foamLogger("server").error("Unknown exception "+str(sys.exc_info()[0])) 51 foamLogger("server").error(str(sys.exc_info()[1])) 52 foamLogger("server").error("Traceback: "+str(extract_tb(sys.exc_info()[2])))
53
54 - def list(self):
55 """Returns a list of the found Foam-Runs""" 56 self.dataLock.acquire() 57 servers=copy.deepcopy(self.servers) 58 self.dataLock.release() 59 60 result={} 61 62 for idnum,info in servers.iteritems(): 63 result[idnum]=info._info 64 65 return result
66
67 - def collect(self):
68 """Starts a thread that collects the data of the servers from the net""" 69 collector=MetaCollector(self) 70 collector.setDaemon(True) 71 collector.start() 72 return True
73
74 - def scan(self,additional):
75 """Starts a thread that collects the data of the servers from the net 76 @param additional: a string with a list of additional subnets that should be scanned""" 77 collector=MetaCollector(self,additional=additional) 78 collector.setDaemon(True) 79 collector.start() 80 return True
81
82 - def kill(self):
83 """Exits the server""" 84 foamLogger("server").warning("Terminating due to request") 85 t=Timer(1.,self._suicide) 86 t.start() 87 return True
88
89 - def _suicide(self):
90 """The server kills itself""" 91 os.kill(self.pid,1)
92
93 - def registerServer(self,ip,pid,port,external=False):
94 """Registers a new server via XMLRPC 95 @param ip: IP of the server 96 @param pid: Die PID at the server 97 @param port: the port at which the server is listening 98 """ 99 return self._registerServer(ip,pid,port,external=True)
100
101 - def _registerServer(self,ip,pid,port,external=False):
102 """Registers a new server 103 @param ip: IP of the server 104 @param pid: Die PID at the server 105 @param port: the port at which the server is listening 106 @param external: was called via XMLRPC 107 """ 108 self.dataLock.acquire() 109 serverID="%s:%d" % (ip,port) 110 111 foamLogger("server").info("Registering: %s with PID: %d" % (serverID,pid)) 112 113 insertServer=False 114 try: 115 if self.servers.has_key(serverID): 116 # maybe it's another process 117 server=xmlrpclib.ServerProxy("http://%s:%d" % (ip,port)) 118 gotPid=server.pid() 119 if pid!=gotPid: 120 self.servers.pop(serverID) 121 foamLogger("server").warning("Server "+serverID+" changed PID from %d to %d" % (pid,gotPid)) 122 insertServer=True 123 else: 124 foamLogger("server").warning("Server "+serverID+" already registered") 125 else: 126 insertServer=True 127 128 if insertServer: 129 new=ServerInfo(ip,pid,port) 130 doIt=external 131 if not doIt: 132 doIt=new.checkValid() 133 134 if doIt: 135 new.queryData() 136 self.servers[serverID]=new 137 foamLogger("server").debug("Inserted "+serverID) 138 except: 139 foamLogger("server").error("Registering Server "+serverID+" failed:"+str(sys.exc_info()[0])) 140 foamLogger("server").error("Reason:"+str(sys.exc_info()[1])) 141 foamLogger("server").error("Trace:"+str(extract_tb(sys.exc_info()[2]))) 142 143 self.dataLock.release() 144 return True
145
146 - def deregisterServer(self,ip,pid,port):
147 """Deregisters a server 148 @param ip: IP of the server 149 @param pid: Die PID at the server 150 @param port: the port at which the server is listening 151 """ 152 self.dataLock.acquire() 153 serverID="%s:%d" % (ip,port) 154 foamLogger("server").info("Deregistering: %s with PID: %d" % (serverID,pid)) 155 156 try: 157 if self.servers.has_key(serverID): 158 self.servers.pop(serverID) 159 else: 160 foamLogger("server").warning("Server "+serverID+" not registered") 161 except: 162 foamLogger("server").error("Registering Server "+serverID+" failed:"+str(sys.exc_info()[0])) 163 foamLogger("server").error("Reason:"+str(sys.exc_info()[1])) 164 foamLogger("server").error("Trace:"+str(extract_tb(sys.exc_info()[2]))) 165 166 self.dataLock.release() 167 168 return True
169
170 - def forwardCommand(self,ip,port,cmd):
171 """Forwards a RPC to another machine 172 @param ip: IP of the server 173 @param port: the port at which the server is listening 174 @param cmd: the command that should be executed there 175 @return: the result of the command 176 """ 177 result="" 178 try: 179 server=xmlrpclib.ServerProxy("http://%s:%d" % (ip,port)) 180 result=eval("server."+cmd) 181 foamLogger("server").debug("Forwarding to "+ip+"the command\""+cmd+"\" Result:"+str(result)) 182 except xmlrpclib.Fault,reason: 183 result="xmlrpclib.Fault: "+str(reason) 184 except socket.error,reason: 185 result="socket.error: "+str(reason) 186 except TypeError,reason: 187 result="Type error: ",reason 188 except SyntaxError,reason: 189 result="Syntax Error in:"+cmd 190 191 if result==None: 192 result="" 193 194 return result
195
196 -class ServerInfo(object):
197 """Contains the information about a server"""
198 - def __init__(self,ip,pid,port):
199 """ 200 @param ip: IP of the server 201 @param pid: Die PID at the server 202 @param port: the port at which the server is listening 203 """ 204 self._info={} 205 self._info["ip"]=ip 206 self._info["pid"]=pid 207 self._info["port"]=port
208
209 - def checkValid(self):
210 """Check with server whether this data item is still valid""" 211 result=False 212 213 foamLogger("server").debug("Checking "+self["ip"]+"@"+str(self["port"])) 214 215 try: 216 server=xmlrpclib.ServerProxy("http://%s:%d" % (self["ip"],self["port"])) 217 pid=server.pid() 218 if pid==self["pid"]: 219 result=True 220 except socket.timeout,reason: 221 foamLogger("server").info(self["ip"]+"@"+str(self["port"])+" seems to be dead") 222 except: 223 foamLogger("server").debug("Checking Valid "+self["ip"]+" failed:"+str(sys.exc_info()[0])) 224 foamLogger("server").debug("Reason:"+str(sys.exc_info()[1])) 225 foamLogger("server").debug("Trace:"+str(extract_tb(sys.exc_info()[2]))) 226 227 foamLogger("server").debug("Result for "+self["ip"]+"@"+str(self["port"])+" = "+str(result)) 228 229 return result
230
231 - def queryData(self):
232 """Ask the server for additional data""" 233 server=xmlrpclib.ServerProxy("http://%s:%d" % (self["ip"],self["port"])) 234 for name in ["commandLine","cwd","foamVersion","isParallel","mpi","pyFoamVersion","scriptName","user","hostname"]: 235 result=eval("server."+name+"()") 236 self[name]=result
237
238 - def __getitem__(self,key):
239 return self._info[key]
240
241 - def __setitem__(self,key,value):
242 self._info[key]=value
243
244 -class MetaChecker(Thread):
245 """Checks regularily whether the registered Servers are still alive"""
246 - def __init__(self,parent):
247 """@param parent: the FoamMetaServer that gets the information""" 248 Thread.__init__(self) 249 self.parent=parent 250 self.sleepTime=config().getfloat("Metaserver","checkerSleeping")
251
252 - def run(self):
253 foamLogger("server").info("Checker starting") 254 while True: 255 self.parent.startupLock.acquire() 256 foamLogger("server").debug("Start Checking") 257 258 self.parent.dataLock.acquire() 259 servers=copy.deepcopy(self.parent.servers) 260 self.parent.dataLock.release() 261 262 for key,obj in servers.iteritems(): 263 isOK=obj.checkValid() 264 if not isOK: 265 foamLogger("server").info("Server "+key+" not OK. Deregistering") 266 self.parent.deregisterServer(obj["ip"],obj["pid"],obj["port"]) 267 268 foamLogger("server").debug("Stop Checking - sleeping") 269 self.parent.startupLock.release() 270 time.sleep(self.sleepTime)
271
272 -class MetaCollector(Thread):
273 """Scans the net in a separate thread"""
274 - def __init__(self,parent,additional=None):
275 """@param parent: the FoamMetaServer that gets the information 276 @param additional: A string with alist of additional subnets that should be scanned""" 277 Thread.__init__(self) 278 self.parent=parent 279 self.additional=additional
280
281 - def run(self):
282 self.parent.startupLock.acquire() 283 foamLogger("server").info("Collector starting") 284 285 port=config().getint("Network","startServerPort") 286 length=config().getint("Network","nrServerPorts") 287 288 machines=config().get("Network","searchservers") 289 290 addreses=machines.split(',') 291 if self.additional!=None: 292 addreses=self.additional.split(',')+addreses 293 294 for a in addreses: 295 foamLogger("server").info("Collecting in subnet "+a) 296 for host in IP(a): 297 try: 298 name,alias,rest =socket.gethostbyaddr(str(host)) 299 except socket.herror,reason: 300 # no name for the host 301 name="unknown" 302 303 foamLogger("server").debug("Collector Checking:"+str(host)+" "+name) 304 305 result=checkFoamServers(str(host),port,length) 306 if result!=None: 307 foamLogger("server").debug("Collector Found "+str(result)+" for "+name) 308 for p in result: 309 try: 310 server=xmlrpclib.ServerProxy("http://%s:%d" % (str(host),p)) 311 ip=server.ip() 312 pid=server.pid() 313 self.parent._registerServer(ip,pid,port) 314 except: 315 foamLogger("server").error("Unknown exception "+str(sys.exc_info()[0])+" while registering "+name) 316 foamLogger("server").error("Reason:"+str(sys.exc_info()[1])) 317 foamLogger("server").error("Trace:"+str(extract_tb(sys.exc_info()[2]))) 318 else: 319 foamLogger("server").debug("Collector Found "+str(result)+" for "+name) 320 321 self.parent.startupLock.release() 322 323 foamLogger("server").info("Collector finished")
324