ia64/xen-unstable

view tools/python/xen/xend/server/SrvDaemon.py @ 8321:7ad6cf4260eb

Minor import tidy.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@leeni.uk.xensource.com
date Mon Dec 12 16:24:32 2005 +0000 (2005-12-12)
parents 1aaa1abab953
children fa5dddabda0c
line source
1 ###########################################################
2 ## Xen controller daemon
3 ## Copyright (c) 2004, K A Fraser (University of Cambridge)
4 ## Copyright (C) 2004, Mike Wray <mike.wray@hp.com>
5 ## Copyright (C) 2005, XenSource Ltd
6 ###########################################################
8 import os
9 import signal
10 import sys
11 import threading
12 import linecache
13 import pwd
14 import re
15 import traceback
17 import xen.lowlevel.xc
19 from xen.xend.XendLogging import log
21 import relocate
22 import SrvServer
23 from params import *
26 XEND_PROCESS_NAME = 'xend'
29 class Daemon:
30 """The xend daemon.
31 """
32 def __init__(self):
33 self.traceon = False
34 self.tracefile = None
35 self.traceindent = 0
36 self.child = 0
39 def cleanup_xend(self, kill):
40 """Clean up the Xend pidfile.
41 If a running process is found, kills it if 'kill' is true.
43 @param kill: whether to kill the process
44 @return running process id or 0
45 """
46 running = 0
47 pid = read_pid(XEND_PID_FILE)
48 if find_process(pid, XEND_PROCESS_NAME):
49 if kill:
50 os.kill(pid, signal.SIGTERM)
51 else:
52 running = pid
53 if running == 0 and os.path.isfile(XEND_PID_FILE):
54 os.remove(XEND_PID_FILE)
55 return running
58 def status(self):
59 """Returns the status of the xend daemon.
60 The return value is defined by the LSB:
61 0 Running
62 3 Not running
63 """
64 if self.cleanup_xend(False) == 0:
65 return 3
66 else:
67 return 0
70 def fork_pid(self):
71 """Fork and write the pid of the child to XEND_PID_FILE.
73 @return: pid of child in parent, 0 in child
74 """
76 self.child = os.fork()
78 if self.child:
79 # Parent
80 pidfile = open(XEND_PID_FILE, 'w')
81 try:
82 pidfile.write(str(self.child))
83 finally:
84 pidfile.close()
86 return self.child
89 def daemonize(self):
90 if not XEND_DAEMONIZE: return
92 # Detach from TTY.
94 # Become the group leader (already a child process)
95 os.setsid()
97 # Fork, this allows the group leader to exit,
98 # which means the child can never again regain control of the
99 # terminal
100 if os.fork():
101 os._exit(0)
103 # Detach from standard file descriptors, and redirect them to
104 # /dev/null or the log as appropriate.
105 os.close(0)
106 os.close(1)
107 os.close(2)
108 if XEND_DEBUG:
109 os.open('/dev/null', os.O_RDONLY)
110 os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT)
111 os.dup(1)
112 else:
113 os.open('/dev/null', os.O_RDWR)
114 os.dup(0)
115 os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT)
118 def start(self, trace=0):
119 """Attempts to start the daemons.
120 The return value is defined by the LSB:
121 0 Success
122 4 Insufficient privileges
123 """
124 xend_pid = self.cleanup_xend(False)
126 if self.set_user():
127 return 4
128 os.chdir("/")
130 if xend_pid > 0:
131 # Trying to run an already-running service is a success.
132 return 0
134 ret = 0
136 # we use a pipe to communicate between the parent and the child process
137 # this way we know when the child has actually initialized itself so
138 # we can avoid a race condition during startup
140 r,w = os.pipe()
141 if os.fork():
142 os.close(w)
143 r = os.fdopen(r, 'r')
144 try:
145 s = r.read()
146 finally:
147 r.close()
148 if not len(s):
149 ret = 1
150 else:
151 ret = int(s)
152 else:
153 os.close(r)
154 # Child
155 self.daemonize()
156 self.tracing(trace)
158 # If Xend proper segfaults, then we want to restart it. Thus,
159 # we fork a child for running Xend itself, and if it segfaults
160 # (or exits any way other than cleanly) then we run it again.
161 # The first time through we want the server to write to the (r,w)
162 # pipe created above, so that we do not exit until the server is
163 # ready to receive requests. All subsequent restarts we don't
164 # want this behaviour, or the pipe will eventually fill up, so
165 # we just pass None into run in subsequent cases (by clearing w
166 # in the parent of the first fork).
167 while True:
168 pid = self.fork_pid()
169 if pid:
170 os.close(w)
171 w = False
173 (_, status) = os.waitpid(pid, 0)
175 if os.WIFEXITED(status):
176 code = os.WEXITSTATUS(status)
177 log.info('Xend exited with status %d.', code)
178 sys.exit(code)
180 if os.WIFSIGNALED(status):
181 sig = os.WTERMSIG(status)
183 if sig in (signal.SIGINT, signal.SIGTERM):
184 log.info('Xend stopped due to signal %d.', sig)
185 sys.exit(0)
186 else:
187 log.fatal(
188 'Xend died due to signal %d! Restarting it.',
189 sig)
190 else:
191 self.run(w and os.fdopen(w, 'w') or None)
193 return ret
195 def tracing(self, traceon):
196 """Turn tracing on or off.
198 @param traceon: tracing flag
199 """
200 if traceon == self.traceon:
201 return
202 self.traceon = traceon
203 if traceon:
204 self.tracefile = open(XEND_TRACE_FILE, 'w+', 1)
205 self.traceindent = 0
206 sys.settrace(self.trace)
207 try:
208 threading.settrace(self.trace) # Only in Python >= 2.3
209 except:
210 pass
212 def print_trace(self, string):
213 for i in range(self.traceindent):
214 ch = " "
215 if (i % 5):
216 ch = ' '
217 else:
218 ch = '|'
219 self.tracefile.write(ch)
220 self.tracefile.write(string)
222 def trace(self, frame, event, arg):
223 if not self.traceon:
224 print >>self.tracefile
225 print >>self.tracefile, '-' * 20, 'TRACE OFF', '-' * 20
226 self.tracefile.close()
227 self.tracefile = None
228 return None
229 if event == 'call':
230 code = frame.f_code
231 filename = code.co_filename
232 m = re.search('.*xend/(.*)', filename)
233 if not m:
234 return None
235 modulename = m.group(1)
236 if re.search('sxp.py', modulename):
237 return None
238 self.traceindent += 1
239 self.print_trace("> %s:%s\n"
240 % (modulename, code.co_name))
241 elif event == 'line':
242 filename = frame.f_code.co_filename
243 lineno = frame.f_lineno
244 self.print_trace("%4d %s" %
245 (lineno, linecache.getline(filename, lineno)))
246 elif event == 'return':
247 code = frame.f_code
248 filename = code.co_filename
249 m = re.search('.*xend/(.*)', filename)
250 if not m:
251 return None
252 modulename = m.group(1)
253 self.print_trace("< %s:%s\n"
254 % (modulename, code.co_name))
255 self.traceindent -= 1
256 elif event == 'exception':
257 self.print_trace("! Exception:\n")
258 (ex, val, tb) = arg
259 traceback.print_exception(ex, val, tb, 10, self.tracefile)
260 #del tb
261 return self.trace
263 def set_user(self):
264 # Set the UID.
265 try:
266 os.setuid(pwd.getpwnam(XEND_USER)[2])
267 return 0
268 except KeyError:
269 print >>sys.stderr, "Error: no such user '%s'" % XEND_USER
270 return 1
272 def stop(self):
273 return self.cleanup_xend(True)
275 def run(self, status):
276 try:
277 log.info("Xend Daemon started")
279 xc = xen.lowlevel.xc.xc()
280 xinfo = xc.xeninfo()
281 log.info("Xend changeset: %s.", xinfo['xen_changeset'])
282 del xc
284 relocate.listenRelocation()
285 servers = SrvServer.create()
286 servers.start(status)
287 except Exception, ex:
288 print >>sys.stderr, 'Exception starting xend:', ex
289 if XEND_DEBUG:
290 traceback.print_exc()
291 log.exception("Exception starting xend (%s)" % ex)
292 if status:
293 status.write('1')
294 status.close()
295 sys.exit(1)
297 def instance():
298 global inst
299 try:
300 inst
301 except:
302 inst = Daemon()
303 return inst
306 def read_pid(pidfile):
307 """Read process id from a file.
309 @param pidfile: file to read
310 @return pid or 0
311 """
312 if os.path.isfile(pidfile) and os.path.getsize(pidfile):
313 try:
314 f = open(pidfile, 'r')
315 try:
316 return int(f.read())
317 finally:
318 f.close()
319 except:
320 return 0
321 else:
322 return 0
325 def find_process(pid, name):
326 """Search for a process.
328 @param pid: process id
329 @param name: process name
330 @return: pid if found, 0 otherwise
331 """
332 running = 0
333 if pid:
334 lines = os.popen('ps %d 2>/dev/null' % pid).readlines()
335 exp = '^ *%d.+%s' % (pid, name)
336 for line in lines:
337 if re.search(exp, line):
338 running = pid
339 break
340 return running
343 def main(argv = None):
344 global XEND_DAEMONIZE
346 XEND_DAEMONIZE = False
347 if argv is None:
348 argv = sys.argv
350 try:
351 daemon = instance()
353 r,w = os.pipe()
354 daemon.run(os.fdopen(w, 'w'))
355 return 0
356 except Exception, exn:
357 log.fatal(exn)
358 return 1
361 if __name__ == "__main__":
362 sys.exit(main())