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

Source Code for Module PyFoam.Infrastructure.FoamMetaServer

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