ia64/xen-unstable

view tools/python/xen/xend/server/SrvDaemon.py @ 6689:7d0fb56b4a91

merge?
author cl349@firebug.cl.cam.ac.uk
date Wed Sep 07 19:01:31 2005 +0000 (2005-09-07)
parents 0e2b1e04d4cb 652bd7876153
children b2f4823b6ff0 b35215021b32 9af349b055e5 7985a4d8bae9
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 signal
9 import sys
10 import threading
11 import linecache
12 import socket
13 import pwd
14 import re
15 import StringIO
16 import traceback
17 import time
18 import glob
20 from xen.xend import sxp
21 from xen.xend import PrettyPrint
22 from xen.xend import EventServer; eserver = EventServer.instance()
23 from xen.xend.XendError import XendError
24 from xen.xend.server import SrvServer
25 from xen.xend.XendLogging import log
26 from xen.xend import XendRoot; xroot = XendRoot.instance()
28 import controller
29 import event
30 import relocate
31 from params import *
33 class Daemon:
34 """The xend daemon.
35 """
36 def __init__(self):
37 self.shutdown = 0
38 self.traceon = 0
39 self.tracefile = None
40 self.traceindent = 0
41 self.child = 0
43 def daemon_pids(self):
44 pids = []
45 pidex = '(?P<pid>\d+)'
46 pythonex = '(?P<python>\S*python\S*)'
47 cmdex = '(?P<cmd>.*)'
48 procre = re.compile('^\s*' + pidex + '\s*' + pythonex + '\s*' + cmdex + '$')
49 xendre = re.compile('^/usr/sbin/xend\s*(start|restart)\s*.*$')
50 procs = os.popen('ps -e -o pid,args 2>/dev/null')
51 for proc in procs:
52 pm = procre.match(proc)
53 if not pm: continue
54 xm = xendre.match(pm.group('cmd'))
55 if not xm: continue
56 pids.append(int(pm.group('pid')))
57 return pids
59 def new_cleanup(self, kill=0):
60 err = 0
61 pids = self.daemon_pids()
62 if kill:
63 for pid in pids:
64 print "Killing daemon pid=%d" % pid
65 os.kill(pid, signal.SIGHUP)
66 elif pids:
67 err = 1
68 print "Daemon already running: ", pids
69 return err
71 def read_pid(self, pidfile):
72 """Read process id from a file.
74 @param pidfile: file to read
75 @return pid or 0
76 """
77 pid = 0
78 if os.path.isfile(pidfile) and os.path.getsize(pidfile):
79 try:
80 pid = open(pidfile, 'r').read()
81 pid = int(pid)
82 except:
83 pid = 0
84 return pid
86 def find_process(self, pid, name):
87 """Search for a process.
89 @param pid: process id
90 @param name: process name
91 @return: pid if found, 0 otherwise
92 """
93 running = 0
94 if pid:
95 lines = os.popen('ps %d 2>/dev/null' % pid).readlines()
96 exp = '^ *%d.+%s' % (pid, name)
97 for line in lines:
98 if re.search(exp, line):
99 running = pid
100 break
101 return running
103 def cleanup_process(self, pidfile, name, kill):
104 """Clean up the pidfile for a process.
105 If a running process is found, kills it if 'kill' is true.
107 @param pidfile: pid file
108 @param name: process name
109 @param kill: whether to kill the process
110 @return running process id or 0
111 """
112 running = 0
113 pid = self.read_pid(pidfile)
114 if self.find_process(pid, name):
115 if kill:
116 os.kill(pid, 1)
117 else:
118 running = pid
119 if running == 0 and os.path.isfile(pidfile):
120 os.remove(pidfile)
121 return running
123 def cleanup_xend(self, kill=False):
124 return self.cleanup_process(XEND_PID_FILE, "xend", kill)
126 def cleanup(self, kill=False):
127 self.cleanup_xend(kill=kill)
129 def status(self):
130 """Returns the status of the xend daemon.
131 The return value is defined by the LSB:
132 0 Running
133 3 Not running
134 """
135 if self.cleanup_process(XEND_PID_FILE, "xend", False) == 0:
136 return 3
137 else:
138 return 0
140 def onSIGCHLD(self, signum, frame):
141 if self.child > 0:
142 try:
143 pid, sts = os.waitpid(self.child, os.WNOHANG)
144 except os.error, ex:
145 pass
147 def fork_pid(self, pidfile):
148 """Fork and write the pid of the child to 'pidfile'.
150 @param pidfile: pid file
151 @return: pid of child in parent, 0 in child
152 """
154 self.child = os.fork()
156 if self.child:
157 # Parent
158 pidfile = open(pidfile, 'w')
159 pidfile.write(str(self.child))
160 pidfile.close()
162 return self.child
164 def daemonize(self):
165 if not XEND_DAEMONIZE: return
166 # Detach from TTY.
167 os.setsid()
169 # Detach from standard file descriptors.
170 # I do this at the file-descriptor level: the overlying Python file
171 # objects also use fd's 0, 1 and 2.
172 os.close(0)
173 os.close(1)
174 os.close(2)
175 if XEND_DEBUG:
176 os.open('/dev/null', os.O_RDONLY)
177 # XXX KAF: Why doesn't this capture output from C extensions that
178 # fprintf(stdout) or fprintf(stderr) ??
179 os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT)
180 os.dup(1)
181 else:
182 os.open('/dev/null', os.O_RDWR)
183 os.dup(0)
184 os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT)
187 def start(self, trace=0):
188 """Attempts to start the daemons.
189 The return value is defined by the LSB:
190 0 Success
191 4 Insufficient privileges
192 """
193 xend_pid = self.cleanup_xend()
195 if self.set_user():
196 return 4
197 os.chdir("/")
199 if xend_pid > 0:
200 # Trying to run an already-running service is a success.
201 return 0
203 signal.signal(signal.SIGCHLD, self.onSIGCHLD)
204 if self.fork_pid(XEND_PID_FILE):
205 #Parent. Sleep to give child time to start.
206 time.sleep(1)
207 else:
208 # Child
209 self.tracing(trace)
210 self.run()
211 return 0
213 def tracing(self, traceon):
214 """Turn tracing on or off.
216 @param traceon: tracing flag
217 """
218 if traceon == self.traceon:
219 return
220 self.traceon = traceon
221 if traceon:
222 self.tracefile = open(XEND_TRACE_FILE, 'w+', 1)
223 self.traceindent = 0
224 sys.settrace(self.trace)
225 try:
226 threading.settrace(self.trace) # Only in Python >= 2.3
227 except:
228 pass
230 def print_trace(self, str):
231 for i in range(self.traceindent):
232 ch = " "
233 if (i % 5):
234 ch = ' '
235 else:
236 ch = '|'
237 self.tracefile.write(ch)
238 self.tracefile.write(str)
240 def trace(self, frame, event, arg):
241 if not self.traceon:
242 print >>self.tracefile
243 print >>self.tracefile, '-' * 20, 'TRACE OFF', '-' * 20
244 self.tracefile.close()
245 self.tracefile = None
246 return None
247 if event == 'call':
248 code = frame.f_code
249 filename = code.co_filename
250 m = re.search('.*xend/(.*)', filename)
251 if not m:
252 return None
253 modulename = m.group(1)
254 if re.search('sxp.py', modulename):
255 return None
256 self.traceindent += 1
257 self.print_trace("> %s:%s\n"
258 % (modulename, code.co_name))
259 elif event == 'line':
260 filename = frame.f_code.co_filename
261 lineno = frame.f_lineno
262 self.print_trace("%4d %s" %
263 (lineno, linecache.getline(filename, lineno)))
264 elif event == 'return':
265 code = frame.f_code
266 filename = code.co_filename
267 m = re.search('.*xend/(.*)', filename)
268 if not m:
269 return None
270 modulename = m.group(1)
271 self.print_trace("< %s:%s\n"
272 % (modulename, code.co_name))
273 self.traceindent -= 1
274 elif event == 'exception':
275 self.print_trace("! Exception:\n")
276 (ex, val, tb) = arg
277 traceback.print_exception(ex, val, tb, 10, self.tracefile)
278 #del tb
279 return self.trace
281 def set_user(self):
282 # Set the UID.
283 try:
284 os.setuid(pwd.getpwnam(XEND_USER)[2])
285 return 0
286 except KeyError, error:
287 print >>sys.stderr, "Error: no such user '%s'" % XEND_USER
288 return 1
290 def stop(self):
291 return self.cleanup(kill=True)
293 def run(self):
294 _enforce_dom0_cpus()
295 try:
296 log.info("Xend Daemon started")
297 event.listenEvent(self)
298 relocate.listenRelocation()
299 servers = SrvServer.create()
300 self.daemonize()
301 servers.start()
302 except Exception, ex:
303 print >>sys.stderr, 'Exception starting xend:', ex
304 if XEND_DEBUG:
305 traceback.print_exc()
306 log.exception("Exception starting xend (%s)" % ex)
307 self.exit(1)
309 def exit(self, rc=0):
310 # Calling sys.exit() raises a SystemExit exception, which only
311 # kills the current thread. Calling os._exit() makes the whole
312 # Python process exit immediately. There doesn't seem to be another
313 # way to exit a Python with running threads.
314 #sys.exit(rc)
315 os._exit(rc)
317 def _enforce_dom0_cpus():
318 dn = xroot.get_dom0_cpus()
320 for d in glob.glob("/sys/devices/system/cpu/cpu*"):
321 cpu = int(os.path.basename(d)[3:])
322 if (dn == 0) or (cpu < dn):
323 v = "1"
324 else:
325 v = "0"
326 try:
327 f = open("%s/online" %d, "r+")
328 c = f.read(1)
329 if (c != v):
330 if v == "0":
331 log.info("dom0 is trying to give back cpu %d", cpu)
332 else:
333 log.info("dom0 is trying to take cpu %d", cpu)
334 f.seek(0)
335 f.write(v)
336 f.close()
337 log.info("dom0 successfully enforced cpu %d", cpu)
338 else:
339 f.close()
340 except:
341 pass
343 def instance():
344 global inst
345 try:
346 inst
347 except:
348 inst = Daemon()
349 return inst