debuggers.hg

view tools/python/xen/xend/server/SrvDaemon.py @ 4672:d781b9d08e80

bitkeeper revision 1.1327.2.4 (426918a34Af7gihN8mTkq-P3KrAZXg)

Remove twisted from save/migrate handling.
This needs to use threads, so add thread support for
http server requests.

Signed-off-by: Mike Wray <mike.wray@hp.com>
author mjw@wray-m-3.hpl.hp.com
date Fri Apr 22 15:30:43 2005 +0000 (2005-04-22)
parents a838a908e38e
children bd15906125a7
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 ###########################################################
7 import os
8 import os.path
9 import signal
10 import sys
11 import threading
12 import linecache
13 import socket
14 import pwd
15 import re
16 import StringIO
17 import traceback
18 import time
20 from xen.lowlevel import xu
22 from xen.xend import sxp
23 from xen.xend import PrettyPrint
24 from xen.xend import EventServer; eserver = EventServer.instance()
25 from xen.xend.XendError import XendError
26 from xen.xend.server import SrvServer
27 from xen.xend import XendRoot
28 from xen.xend.XendLogging import log
30 from xen.util.ip import _readline, _readlines
32 import channel
33 import controller
34 import event
35 from params import *
37 DAEMONIZE = 0
38 DEBUG = 1
40 class Daemon:
41 """The xend daemon.
42 """
43 def __init__(self):
44 self.shutdown = 0
45 self.traceon = 0
47 def daemon_pids(self):
48 pids = []
49 pidex = '(?P<pid>\d+)'
50 pythonex = '(?P<python>\S*python\S*)'
51 cmdex = '(?P<cmd>.*)'
52 procre = re.compile('^\s*' + pidex + '\s*' + pythonex + '\s*' + cmdex + '$')
53 xendre = re.compile('^/usr/sbin/xend\s*(start|restart)\s*.*$')
54 procs = os.popen('ps -e -o pid,args 2>/dev/null')
55 for proc in procs:
56 pm = procre.match(proc)
57 if not pm: continue
58 xm = xendre.match(pm.group('cmd'))
59 if not xm: continue
60 #print 'pid=', pm.group('pid'), 'cmd=', pm.group('cmd')
61 pids.append(int(pm.group('pid')))
62 return pids
64 def new_cleanup(self, kill=0):
65 err = 0
66 pids = self.daemon_pids()
67 if kill:
68 for pid in pids:
69 print "Killing daemon pid=%d" % pid
70 os.kill(pid, signal.SIGHUP)
71 elif pids:
72 err = 1
73 print "Daemon already running: ", pids
74 return err
76 def read_pid(self, pidfile):
77 """Read process id from a file.
79 @param pidfile: file to read
80 @return pid or 0
81 """
82 pid = 0
83 if os.path.isfile(pidfile) and os.path.getsize(pidfile):
84 try:
85 pid = open(pidfile, 'r').read()
86 pid = int(pid)
87 except:
88 pid = 0
89 return pid
91 def find_process(self, pid, name):
92 """Search for a process.
94 @param pid: process id
95 @param name: process name
96 @return: pid if found, 0 otherwise
97 """
98 running = 0
99 if pid:
100 lines = _readlines(os.popen('ps %d 2>/dev/null' % pid))
101 exp = '^ *%d.+%s' % (pid, name)
102 for line in lines:
103 if re.search(exp, line):
104 running = pid
105 break
106 return running
108 def cleanup_process(self, pidfile, name, kill):
109 """Clean up the pidfile for a process.
110 If a running process is found, kills it if 'kill' is true.
112 @param pidfile: pid file
113 @param name: process name
114 @param kill: whether to kill the process
115 @return running process id or 0
116 """
117 running = 0
118 pid = self.read_pid(pidfile)
119 if self.find_process(pid, name):
120 if kill:
121 os.kill(pid, 1)
122 else:
123 running = pid
124 if running == 0 and os.path.isfile(pidfile):
125 os.remove(pidfile)
126 return running
128 def cleanup_xend(self, kill=False):
129 return self.cleanup_process(XEND_PID_FILE, "xend", kill)
131 def cleanup_xfrd(self, kill=False):
132 return self.cleanup_process(XFRD_PID_FILE, "xfrd", kill)
134 def cleanup(self, kill=False):
135 self.cleanup_xend(kill=kill)
136 self.cleanup_xfrd(kill=kill)
138 def status(self):
139 """Returns the status of the xend and xfrd daemons.
140 The return value is defined by the LSB:
141 0 Running
142 3 Not running
143 """
144 if (self.cleanup_process(XEND_PID_FILE, "xend", False) == 0 or
145 self.cleanup_process(XFRD_PID_FILE, "xfrd", False) == 0):
146 return 3
147 else:
148 return 0
150 def install_child_reaper(self):
151 #signal.signal(signal.SIGCHLD, self.onSIGCHLD)
152 # Ensure that zombie children are automatically reaped.
153 xu.autoreap()
155 def onSIGCHLD(self, signum, frame):
156 code = 1
157 while code > 0:
158 code = os.waitpid(-1, os.WNOHANG)
160 def fork_pid(self, pidfile):
161 """Fork and write the pid of the child to 'pidfile'.
163 @param pidfile: pid file
164 @return: pid of child in parent, 0 in child
165 """
166 pid = os.fork()
167 if pid:
168 # Parent
169 pidfile = open(pidfile, 'w')
170 pidfile.write(str(pid))
171 pidfile.close()
172 return pid
174 def start_xfrd(self):
175 """Fork and exec xfrd, writing its pid to XFRD_PID_FILE.
176 """
177 if self.fork_pid(XFRD_PID_FILE):
178 # Parent
179 pass
180 else:
181 # Child
182 self.daemonize()
183 os.execl("/usr/sbin/xfrd", "xfrd")
185 def daemonize(self):
186 if not DAEMONIZE: return
187 # Detach from TTY.
188 os.setsid()
190 # Detach from standard file descriptors.
191 # I do this at the file-descriptor level: the overlying Python file
192 # objects also use fd's 0, 1 and 2.
193 os.close(0)
194 os.close(1)
195 os.close(2)
196 if DEBUG:
197 os.open('/dev/null', os.O_RDONLY)
198 # XXX KAF: Why doesn't this capture output from C extensions that
199 # fprintf(stdout) or fprintf(stderr) ??
200 os.open('/var/log/xend-debug.log', os.O_WRONLY|os.O_CREAT)
201 os.dup(1)
202 else:
203 os.open('/dev/null', os.O_RDWR)
204 os.dup(0)
205 os.open('/var/log/xend-debug.log', os.O_WRONLY|os.O_CREAT)
208 def start(self, trace=0):
209 """Attempts to start the daemons.
210 The return value is defined by the LSB:
211 0 Success
212 4 Insufficient privileges
213 """
214 xend_pid = self.cleanup_xend()
215 xfrd_pid = self.cleanup_xfrd()
218 if self.set_user():
219 return 4
220 os.chdir("/")
222 if xfrd_pid == 0:
223 self.start_xfrd()
224 if xend_pid > 0:
225 # Trying to run an already-running service is a success.
226 return 0
228 self.install_child_reaper()
230 if self.fork_pid(XEND_PID_FILE):
231 #Parent. Sleep to give child time to start.
232 time.sleep(1)
233 else:
234 # Child
235 self.tracing(trace)
236 self.run()
237 return 0
239 def tracing(self, traceon):
240 """Turn tracing on or off.
242 @param traceon: tracing flag
243 """
244 if traceon == self.traceon:
245 return
246 self.traceon = traceon
247 if traceon:
248 self.tracefile = open(XEND_TRACE_FILE, 'w+', 1)
249 self.traceindent = 0
250 sys.settrace(self.trace)
251 try:
252 threading.settrace(self.trace) # Only in Python >= 2.3
253 except:
254 pass
256 def print_trace(self, str):
257 for i in range(self.traceindent):
258 ch = " "
259 if (i % 5):
260 ch = ' '
261 else:
262 ch = '|'
263 self.tracefile.write(ch)
264 self.tracefile.write(str)
266 def trace(self, frame, event, arg):
267 if not self.traceon:
268 print >>self.tracefile
269 print >>self.tracefile, '-' * 20, 'TRACE OFF', '-' * 20
270 self.tracefile.close()
271 self.tracefile = None
272 return None
273 if event == 'call':
274 code = frame.f_code
275 filename = code.co_filename
276 m = re.search('.*xend/(.*)', filename)
277 if not m:
278 return None
279 modulename = m.group(1)
280 if re.search('sxp.py', modulename):
281 return None
282 self.traceindent += 1
283 self.print_trace("> %s:%s\n"
284 % (modulename, code.co_name))
285 elif event == 'line':
286 filename = frame.f_code.co_filename
287 lineno = frame.f_lineno
288 self.print_trace("%4d %s" %
289 (lineno, linecache.getline(filename, lineno)))
290 elif event == 'return':
291 code = frame.f_code
292 filename = code.co_filename
293 m = re.search('.*xend/(.*)', filename)
294 if not m:
295 return None
296 modulename = m.group(1)
297 self.print_trace("< %s:%s\n"
298 % (modulename, code.co_name))
299 self.traceindent -= 1
300 elif event == 'exception':
301 self.print_trace("! Exception:\n")
302 (ex, val, tb) = arg
303 traceback.print_exception(ex, val, tb, 10, self.tracefile)
304 #del tb
305 return self.trace
307 def set_user(self):
308 # Set the UID.
309 try:
310 os.setuid(pwd.getpwnam(XEND_USER)[2])
311 return 0
312 except KeyError, error:
313 print "Error: no such user '%s'" % XEND_USER
314 return 1
316 def stop(self):
317 return self.cleanup(kill=True)
319 def run(self):
320 try:
321 xroot = XendRoot.instance()
322 log.info("Xend Daemon started")
323 self.createFactories()
324 self.listenEvent(xroot)
325 self.listenChannels()
326 serverthread = SrvServer.create(bridge=1)
327 self.daemonize()
328 print 'running serverthread...'
329 serverthread.start()
330 except Exception, ex:
331 print >>sys.stderr, 'Exception starting xend:', ex
332 if DEBUG:
333 traceback.print_exc()
334 log.exception("Exception starting xend")
335 self.exit(1)
337 def createFactories(self):
338 self.channelF = channel.channelFactory()
340 def listenEvent(self, xroot):
341 port = xroot.get_xend_event_port()
342 interface = xroot.get_xend_address()
343 return event.listenEvent(self, port, interface)
345 def listenChannels(self):
346 def virqReceived(virq):
347 print 'virqReceived>', virq
348 eserver.inject('xend.virq', virq)
350 self.channelF.setVirqHandler(virqReceived)
351 self.channelF.start()
353 def exit(self, rc=0):
354 #reactor.disconnectAll()
355 self.channelF.stop()
356 # Calling sys.exit() raises a SystemExit exception, which only
357 # kills the current thread. Calling os._exit() makes the whole
358 # Python process exit immediately. There doesn't seem to be another
359 # way to exit a Python with running threads.
360 #sys.exit(rc)
361 os._exit(rc)
363 def instance():
364 global inst
365 try:
366 inst
367 except:
368 inst = Daemon()
369 return inst