serv.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. import os,sys,logging
  2. import signal,time, atexit
  3. from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
  4. import xmlrpclib,sqlite3
  5. import bb.server.xmlrpc
  6. import prserv
  7. import prserv.db
  8. if sys.hexversion < 0x020600F0:
  9. print("Sorry, python 2.6 or later is required.")
  10. sys.exit(1)
  11. class Handler(SimpleXMLRPCRequestHandler):
  12. def _dispatch(self,method,params):
  13. try:
  14. value=self.server.funcs[method](*params)
  15. except:
  16. import traceback
  17. traceback.print_exc()
  18. raise
  19. return value
  20. PIDPREFIX = "/tmp/PRServer_%s_%s.pid"
  21. class PRServer(SimpleXMLRPCServer):
  22. pidfile="/tmp/PRServer.pid"
  23. def __init__(self, dbfile, logfile, interface, daemon=True):
  24. ''' constructor '''
  25. SimpleXMLRPCServer.__init__(self, interface,
  26. requestHandler=SimpleXMLRPCRequestHandler,
  27. logRequests=False, allow_none=True)
  28. self.dbfile=dbfile
  29. self.daemon=daemon
  30. self.logfile=logfile
  31. self.host, self.port = self.socket.getsockname()
  32. self.db=prserv.db.PRData(dbfile)
  33. self.table=self.db["PRMAIN"]
  34. self.pidfile=PIDPREFIX % interface
  35. self.register_function(self.getPR, "getPR")
  36. self.register_function(self.quit, "quit")
  37. self.register_function(self.ping, "ping")
  38. self.register_function(self.export, "export")
  39. self.register_function(self.importone, "importone")
  40. self.register_introspection_functions()
  41. def export(self, version=None, pkgarch=None, checksum=None, colinfo=True):
  42. try:
  43. return self.table.export(version, pkgarch, checksum, colinfo)
  44. except sqlite3.Error as exc:
  45. logging.error(str(exc))
  46. return None
  47. def importone(self, version, pkgarch, checksum, value):
  48. return self.table.importone(version, pkgarch, checksum, value)
  49. def ping(self):
  50. return not self.quit
  51. def getPR(self, version, pkgarch, checksum):
  52. try:
  53. return self.table.getValue(version, pkgarch, checksum)
  54. except prserv.NotFoundError:
  55. logging.error("can not find value for (%s, %s)",version, checksum)
  56. return None
  57. except sqlite3.Error as exc:
  58. logging.error(str(exc))
  59. return None
  60. def quit(self):
  61. self.quit=True
  62. return
  63. def _serve_forever(self):
  64. self.quit = False
  65. self.timeout = 0.5
  66. while not self.quit:
  67. self.handle_request()
  68. logging.info("PRServer: stopping...")
  69. self.server_close()
  70. return
  71. def start(self):
  72. if self.daemon is True:
  73. logging.info("PRServer: try to start daemon...")
  74. self.daemonize()
  75. else:
  76. atexit.register(self.delpid)
  77. pid = str(os.getpid())
  78. pf = file(self.pidfile, 'w+')
  79. pf.write("%s\n" % pid)
  80. pf.write("%s\n" % self.host)
  81. pf.write("%s\n" % self.port)
  82. pf.close()
  83. logging.info("PRServer: start success! DBfile: %s, IP: %s, PORT: %d" %
  84. (self.dbfile, self.host, self.port))
  85. self._serve_forever()
  86. def delpid(self):
  87. os.remove(self.pidfile)
  88. def daemonize(self):
  89. """
  90. See Advanced Programming in the UNIX, Sec 13.3
  91. """
  92. try:
  93. pid = os.fork()
  94. if pid > 0:
  95. #parent return instead of exit to give control
  96. return
  97. except OSError as e:
  98. raise Exception("%s [%d]" % (e.strerror, e.errno))
  99. os.setsid()
  100. """
  101. fork again to make sure the daemon is not session leader,
  102. which prevents it from acquiring controlling terminal
  103. """
  104. try:
  105. pid = os.fork()
  106. if pid > 0: #parent
  107. sys.exit(0)
  108. except OSError as e:
  109. raise Exception("%s [%d]" % (e.strerror, e.errno))
  110. os.umask(0)
  111. os.chdir("/")
  112. sys.stdout.flush()
  113. sys.stderr.flush()
  114. si = file('/dev/null', 'r')
  115. so = file(self.logfile, 'a+')
  116. se = so
  117. os.dup2(si.fileno(),sys.stdin.fileno())
  118. os.dup2(so.fileno(),sys.stdout.fileno())
  119. os.dup2(se.fileno(),sys.stderr.fileno())
  120. # write pidfile
  121. atexit.register(self.delpid)
  122. pid = str(os.getpid())
  123. pf = file(self.pidfile, 'w')
  124. pf.write("%s\n" % pid)
  125. pf.close()
  126. logging.info("PRServer: starting daemon success! DBfile: %s, IP: %s, PORT: %s, PID: %s" %
  127. (self.dbfile, self.host, self.port, pid))
  128. self._serve_forever()
  129. exit(0)
  130. class PRServerConnection():
  131. def __init__(self, host, port):
  132. self.connection = bb.server.xmlrpc._create_server(host, port)
  133. self.host = host
  134. self.port = port
  135. def terminate(self):
  136. # Don't wait for server indefinitely
  137. import socket
  138. socket.setdefaulttimeout(2)
  139. try:
  140. self.connection.quit()
  141. except Exception as exc:
  142. sys.stderr.write("%s\n" % str(exc))
  143. def getPR(self, version, pkgarch, checksum):
  144. return self.connection.getPR(version, pkgarch, checksum)
  145. def ping(self):
  146. return self.connection.ping()
  147. def export(self,version=None, pkgarch=None, checksum=None, colinfo=True):
  148. return self.connection.export(version, pkgarch, checksum, colinfo)
  149. def importone(self, version, pkgarch, checksum, value):
  150. return self.connection.importone(version, pkgarch, checksum, value)
  151. def start_daemon(dbfile, logfile, interface):
  152. try:
  153. pf = file(PRServer.pidfile,'r')
  154. pid = int(pf.readline().strip())
  155. pf.close()
  156. except IOError:
  157. pid = None
  158. if pid:
  159. sys.stderr.write("pidfile %s already exist. Daemon already running?\n"
  160. % PRServer.pidfile)
  161. return 1
  162. server = PRServer(os.path.abspath(dbfile), os.path.abspath(logfile), interface)
  163. server.start()
  164. return 0
  165. def stop_daemon(host, port):
  166. pidfile = PIDPREFIX % (host, port)
  167. try:
  168. pf = file(pidfile,'r')
  169. pid = int(pf.readline().strip())
  170. pf.close()
  171. except IOError:
  172. pid = None
  173. if not pid:
  174. sys.stderr.write("pidfile %s does not exist. Daemon not running?\n"
  175. % pidfile)
  176. return 1
  177. PRServerConnection(host, port).terminate()
  178. time.sleep(0.5)
  179. try:
  180. while 1:
  181. os.kill(pid,signal.SIGTERM)
  182. time.sleep(0.1)
  183. except OSError as e:
  184. err = str(e)
  185. if err.find("No such process") > 0:
  186. if os.path.exists(PRServer.pidfile):
  187. os.remove(PRServer.pidfile)
  188. else:
  189. raise Exception("%s [%d]" % (e.strerror, e.errno))
  190. return 0
  191. def ping(host, port):
  192. print PRServerConnection(host,port).ping()
  193. return 0