diff options
author | Lianhao Lu <lianhao.lu@intel.com> | 2012-01-10 14:13:50 +0800 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2012-01-11 10:36:20 +0000 |
commit | 489cde8eb0e19ef6fe8078148199eaf5b52631ae (patch) | |
tree | cb85947000c8efb778362c136f1f6a0c14ed31dc /bitbake/lib/prserv/serv.py | |
parent | 30a9bc6c92a8920d6e9c4a4b93b83bdbe5d48e78 (diff) | |
download | poky-489cde8eb0e19ef6fe8078148199eaf5b52631ae.tar.gz |
bitbake: Automatically start local PR service.
[YOCTO #1126]
A local PR service will be started and stopped automatically along
with the bitbake invocation/ternimation.
This local PR service will be started only and if only when the
PRSERV_HOST is set to 'localhost' and PRSERV_PORT is set to '0'.
When started, the sqlite3 database is stored at
"${PERSISTEN_DIR}/prserv.sqlite3" or "${CACHE}/prserv.sqlite3".
(Bitbake rev: 9d8f45407c67ed0d3c4f820cf646de3c385067c7)
Signed-off-by: Lianhao Lu <lianhao.lu@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/prserv/serv.py')
-rw-r--r-- | bitbake/lib/prserv/serv.py | 144 |
1 files changed, 109 insertions, 35 deletions
diff --git a/bitbake/lib/prserv/serv.py b/bitbake/lib/prserv/serv.py index 7bcffa7744..a759fa7417 100644 --- a/bitbake/lib/prserv/serv.py +++ b/bitbake/lib/prserv/serv.py | |||
@@ -1,5 +1,5 @@ | |||
1 | import os,sys,logging | 1 | import os,sys,logging |
2 | import signal,time, atexit | 2 | import signal, time, atexit, threading |
3 | from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler | 3 | from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler |
4 | import xmlrpclib,sqlite3 | 4 | import xmlrpclib,sqlite3 |
5 | 5 | ||
@@ -7,6 +7,8 @@ import bb.server.xmlrpc | |||
7 | import prserv | 7 | import prserv |
8 | import prserv.db | 8 | import prserv.db |
9 | 9 | ||
10 | logger = logging.getLogger("BitBake.PRserv") | ||
11 | |||
10 | if sys.hexversion < 0x020600F0: | 12 | if sys.hexversion < 0x020600F0: |
11 | print("Sorry, python 2.6 or later is required.") | 13 | print("Sorry, python 2.6 or later is required.") |
12 | sys.exit(1) | 14 | sys.exit(1) |
@@ -22,9 +24,9 @@ class Handler(SimpleXMLRPCRequestHandler): | |||
22 | return value | 24 | return value |
23 | 25 | ||
24 | PIDPREFIX = "/tmp/PRServer_%s_%s.pid" | 26 | PIDPREFIX = "/tmp/PRServer_%s_%s.pid" |
27 | singleton = None | ||
25 | 28 | ||
26 | class PRServer(SimpleXMLRPCServer): | 29 | class PRServer(SimpleXMLRPCServer): |
27 | pidfile="/tmp/PRServer.pid" | ||
28 | def __init__(self, dbfile, logfile, interface, daemon=True): | 30 | def __init__(self, dbfile, logfile, interface, daemon=True): |
29 | ''' constructor ''' | 31 | ''' constructor ''' |
30 | SimpleXMLRPCServer.__init__(self, interface, | 32 | SimpleXMLRPCServer.__init__(self, interface, |
@@ -33,10 +35,11 @@ class PRServer(SimpleXMLRPCServer): | |||
33 | self.dbfile=dbfile | 35 | self.dbfile=dbfile |
34 | self.daemon=daemon | 36 | self.daemon=daemon |
35 | self.logfile=logfile | 37 | self.logfile=logfile |
38 | self.working_thread=None | ||
36 | self.host, self.port = self.socket.getsockname() | 39 | self.host, self.port = self.socket.getsockname() |
37 | self.db=prserv.db.PRData(dbfile) | 40 | self.db=prserv.db.PRData(dbfile) |
38 | self.table=self.db["PRMAIN"] | 41 | self.table=self.db["PRMAIN"] |
39 | self.pidfile=PIDPREFIX % interface | 42 | self.pidfile=PIDPREFIX % (self.host, self.port) |
40 | 43 | ||
41 | self.register_function(self.getPR, "getPR") | 44 | self.register_function(self.getPR, "getPR") |
42 | self.register_function(self.quit, "quit") | 45 | self.register_function(self.quit, "quit") |
@@ -44,12 +47,12 @@ class PRServer(SimpleXMLRPCServer): | |||
44 | self.register_function(self.export, "export") | 47 | self.register_function(self.export, "export") |
45 | self.register_function(self.importone, "importone") | 48 | self.register_function(self.importone, "importone") |
46 | self.register_introspection_functions() | 49 | self.register_introspection_functions() |
47 | 50 | ||
48 | def export(self, version=None, pkgarch=None, checksum=None, colinfo=True): | 51 | def export(self, version=None, pkgarch=None, checksum=None, colinfo=True): |
49 | try: | 52 | try: |
50 | return self.table.export(version, pkgarch, checksum, colinfo) | 53 | return self.table.export(version, pkgarch, checksum, colinfo) |
51 | except sqlite3.Error as exc: | 54 | except sqlite3.Error as exc: |
52 | logging.error(str(exc)) | 55 | logger.error(str(exc)) |
53 | return None | 56 | return None |
54 | 57 | ||
55 | def importone(self, version, pkgarch, checksum, value): | 58 | def importone(self, version, pkgarch, checksum, value): |
@@ -58,45 +61,47 @@ class PRServer(SimpleXMLRPCServer): | |||
58 | def ping(self): | 61 | def ping(self): |
59 | return not self.quit | 62 | return not self.quit |
60 | 63 | ||
64 | def getinfo(self): | ||
65 | return (self.host, self.port) | ||
66 | |||
61 | def getPR(self, version, pkgarch, checksum): | 67 | def getPR(self, version, pkgarch, checksum): |
62 | try: | 68 | try: |
63 | return self.table.getValue(version, pkgarch, checksum) | 69 | return self.table.getValue(version, pkgarch, checksum) |
64 | except prserv.NotFoundError: | 70 | except prserv.NotFoundError: |
65 | logging.error("can not find value for (%s, %s)",version, checksum) | 71 | logger.error("can not find value for (%s, %s)",version, checksum) |
66 | return None | 72 | return None |
67 | except sqlite3.Error as exc: | 73 | except sqlite3.Error as exc: |
68 | logging.error(str(exc)) | 74 | logger.error(str(exc)) |
69 | return None | 75 | return None |
70 | 76 | ||
71 | def quit(self): | 77 | def quit(self): |
72 | self.quit=True | 78 | self.quit=True |
73 | return | 79 | return |
74 | 80 | ||
75 | def _serve_forever(self): | 81 | def work_forever(self,): |
76 | self.quit = False | 82 | self.quit = False |
77 | self.timeout = 0.5 | 83 | self.timeout = 0.5 |
84 | logger.info("PRServer: started! DBfile: %s, IP: %s, PORT: %s, PID: %s" % | ||
85 | (self.dbfile, self.host, self.port, str(os.getpid()))) | ||
86 | |||
78 | while not self.quit: | 87 | while not self.quit: |
79 | self.handle_request() | 88 | self.handle_request() |
80 | 89 | ||
81 | logging.info("PRServer: stopping...") | 90 | logger.info("PRServer: stopping...") |
82 | self.server_close() | 91 | self.server_close() |
83 | return | 92 | return |
84 | 93 | ||
85 | def start(self): | 94 | def start(self): |
86 | if self.daemon is True: | 95 | if self.daemon is True: |
87 | logging.info("PRServer: try to start daemon...") | 96 | logger.info("PRServer: try to start daemon...") |
88 | self.daemonize() | 97 | self.daemonize() |
89 | else: | 98 | else: |
90 | atexit.register(self.delpid) | 99 | atexit.register(self.delpid) |
91 | pid = str(os.getpid()) | 100 | pid = str(os.getpid()) |
92 | pf = file(self.pidfile, 'w+') | 101 | pf = file(self.pidfile, 'w+') |
93 | pf.write("%s\n" % pid) | 102 | pf.write("%s\n" % pid) |
94 | pf.write("%s\n" % self.host) | ||
95 | pf.write("%s\n" % self.port) | ||
96 | pf.close() | 103 | pf.close() |
97 | logging.info("PRServer: start success! DBfile: %s, IP: %s, PORT: %d" % | 104 | self.work_forever() |
98 | (self.dbfile, self.host, self.port)) | ||
99 | self._serve_forever() | ||
100 | 105 | ||
101 | def delpid(self): | 106 | def delpid(self): |
102 | os.remove(self.pidfile) | 107 | os.remove(self.pidfile) |
@@ -144,17 +149,40 @@ class PRServer(SimpleXMLRPCServer): | |||
144 | pf.write("%s\n" % pid) | 149 | pf.write("%s\n" % pid) |
145 | pf.close() | 150 | pf.close() |
146 | 151 | ||
147 | logging.info("PRServer: starting daemon success! DBfile: %s, IP: %s, PORT: %s, PID: %s" % | 152 | self.work_forever() |
148 | (self.dbfile, self.host, self.port, pid)) | 153 | sys.exit(0) |
154 | |||
155 | class PRServSingleton(): | ||
156 | def __init__(self, dbfile, logfile, interface): | ||
157 | self.dbfile = dbfile | ||
158 | self.logfile = logfile | ||
159 | self.interface = interface | ||
160 | self.host = None | ||
161 | self.port = None | ||
162 | self.event = threading.Event() | ||
163 | |||
164 | def _work(self): | ||
165 | self.prserv = PRServer(self.dbfile, self.logfile, self.interface, False) | ||
166 | self.host, self.port = self.prserv.getinfo() | ||
167 | self.event.set() | ||
168 | self.prserv.work_forever() | ||
169 | del self.prserv.db | ||
170 | |||
171 | def start(self): | ||
172 | self.working_thread = threading.Thread(target=self._work) | ||
173 | self.working_thread.start() | ||
149 | 174 | ||
150 | self._serve_forever() | 175 | def getinfo(self): |
151 | exit(0) | 176 | self.event.wait() |
177 | return (self.host, self.port) | ||
152 | 178 | ||
153 | class PRServerConnection(): | 179 | class PRServerConnection(): |
154 | def __init__(self, host, port): | 180 | def __init__(self, host, port): |
155 | self.connection = bb.server.xmlrpc._create_server(host, port) | 181 | if is_local_special(host, port): |
182 | host, port = singleton.getinfo() | ||
156 | self.host = host | 183 | self.host = host |
157 | self.port = port | 184 | self.port = port |
185 | self.connection = bb.server.xmlrpc._create_server(self.host, self.port) | ||
158 | 186 | ||
159 | def terminate(self): | 187 | def terminate(self): |
160 | # Don't wait for server indefinitely | 188 | # Don't wait for server indefinitely |
@@ -173,13 +201,14 @@ class PRServerConnection(): | |||
173 | 201 | ||
174 | def export(self,version=None, pkgarch=None, checksum=None, colinfo=True): | 202 | def export(self,version=None, pkgarch=None, checksum=None, colinfo=True): |
175 | return self.connection.export(version, pkgarch, checksum, colinfo) | 203 | return self.connection.export(version, pkgarch, checksum, colinfo) |
176 | 204 | ||
177 | def importone(self, version, pkgarch, checksum, value): | 205 | def importone(self, version, pkgarch, checksum, value): |
178 | return self.connection.importone(version, pkgarch, checksum, value) | 206 | return self.connection.importone(version, pkgarch, checksum, value) |
179 | 207 | ||
180 | def start_daemon(dbfile, logfile, interface): | 208 | def start_daemon(dbfile, host, port, logfile): |
209 | pidfile = PIDPREFIX % (host, port) | ||
181 | try: | 210 | try: |
182 | pf = file(PRServer.pidfile,'r') | 211 | pf = file(pidfile,'r') |
183 | pid = int(pf.readline().strip()) | 212 | pid = int(pf.readline().strip()) |
184 | pf.close() | 213 | pf.close() |
185 | except IOError: | 214 | except IOError: |
@@ -187,10 +216,10 @@ def start_daemon(dbfile, logfile, interface): | |||
187 | 216 | ||
188 | if pid: | 217 | if pid: |
189 | sys.stderr.write("pidfile %s already exist. Daemon already running?\n" | 218 | sys.stderr.write("pidfile %s already exist. Daemon already running?\n" |
190 | % PRServer.pidfile) | 219 | % pidfile) |
191 | return 1 | 220 | return 1 |
192 | 221 | ||
193 | server = PRServer(os.path.abspath(dbfile), os.path.abspath(logfile), interface) | 222 | server = PRServer(os.path.abspath(dbfile), os.path.abspath(logfile), (host,port)) |
194 | server.start() | 223 | server.start() |
195 | return 0 | 224 | return 0 |
196 | 225 | ||
@@ -206,25 +235,70 @@ def stop_daemon(host, port): | |||
206 | if not pid: | 235 | if not pid: |
207 | sys.stderr.write("pidfile %s does not exist. Daemon not running?\n" | 236 | sys.stderr.write("pidfile %s does not exist. Daemon not running?\n" |
208 | % pidfile) | 237 | % pidfile) |
209 | return 1 | ||
210 | 238 | ||
211 | PRServerConnection(host, port).terminate() | 239 | try: |
240 | PRServerConnection(host, port).terminate() | ||
241 | except: | ||
242 | logger.critical("Stop PRService %s:%d failed" % (host,port)) | ||
212 | time.sleep(0.5) | 243 | time.sleep(0.5) |
213 | 244 | ||
214 | try: | 245 | try: |
215 | while 1: | 246 | if pid: |
247 | if os.path.exists(pidfile): | ||
248 | os.remove(pidfile) | ||
216 | os.kill(pid,signal.SIGTERM) | 249 | os.kill(pid,signal.SIGTERM) |
217 | time.sleep(0.1) | 250 | time.sleep(0.1) |
218 | except OSError as e: | 251 | except OSError as e: |
219 | err = str(e) | 252 | err = str(e) |
220 | if err.find("No such process") > 0: | 253 | if err.find("No such process") <= 0: |
221 | if os.path.exists(PRServer.pidfile): | 254 | raise e |
222 | os.remove(PRServer.pidfile) | ||
223 | else: | ||
224 | raise Exception("%s [%d]" % (e.strerror, e.errno)) | ||
225 | 255 | ||
226 | return 0 | 256 | return 0 |
227 | 257 | ||
258 | def is_local_special(host, port): | ||
259 | if host.strip().upper() == 'localhost'.upper() and (not port): | ||
260 | return True | ||
261 | else: | ||
262 | return False | ||
263 | |||
264 | def auto_start(d): | ||
265 | global singleton | ||
266 | if d.getVar('USE_PR_SERV', True) == '0': | ||
267 | return True | ||
268 | |||
269 | if is_local_special(d.getVar('PRSERV_HOST', True), int(d.getVar('PRSERV_PORT', True))) and not singleton: | ||
270 | import bb.utils | ||
271 | cachedir = (d.getVar("PERSISTENT_DIR", True) or d.getVar("CACHE", True)) | ||
272 | if not cachedir: | ||
273 | logger.critical("Please set the 'PERSISTENT_DIR' or 'CACHE' variable") | ||
274 | sys.exit(1) | ||
275 | bb.utils.mkdirhier(cachedir) | ||
276 | dbfile = os.path.join(cachedir, "prserv.sqlite3") | ||
277 | logfile = os.path.join(cachedir, "prserv.log") | ||
278 | singleton = PRServSingleton(os.path.abspath(dbfile), os.path.abspath(logfile), ("localhost",0)) | ||
279 | singleton.start() | ||
280 | if singleton: | ||
281 | host, port = singleton.getinfo() | ||
282 | else: | ||
283 | host = d.getVar('PRSERV_HOST', True) | ||
284 | port = int(d.getVar('PRSERV_PORT', True)) | ||
285 | |||
286 | try: | ||
287 | return PRServerConnection(host,port).ping() | ||
288 | except Exception: | ||
289 | logger.critical("PRservice %s:%d not available" % (host, port)) | ||
290 | return False | ||
291 | |||
292 | def auto_shutdown(d=None): | ||
293 | global singleton | ||
294 | if singleton: | ||
295 | host, port = singleton.getinfo() | ||
296 | try: | ||
297 | PRServerConnection(host, port).terminate() | ||
298 | except: | ||
299 | logger.critical("Stop PRService %s:%d failed" % (host,port)) | ||
300 | singleton = None | ||
301 | |||
228 | def ping(host, port): | 302 | def ping(host, port): |
229 | print PRServerConnection(host,port).ping() | 303 | conn=PRServerConnection(host, port) |
230 | return 0 | 304 | return conn.ping() |