ia64/xen-unstable

view tools/python/xen/xend/server/SrvDaemon.py @ 7464:82cdb5efc3a8

Output the Xen changeset in the logs at start of day.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@leeni.uk.xensource.com
date Fri Oct 21 11:08:48 2005 +0100 (2005-10-21)
parents 18eb059ae471
children b81723792274
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.server import SrvServer
20 from xen.xend.XendLogging import log
22 import event
23 import relocate
24 from params import *
27 class Daemon:
28 """The xend daemon.
29 """
30 def __init__(self):
31 self.shutdown = 0
32 self.traceon = 0
33 self.tracefile = None
34 self.traceindent = 0
35 self.child = 0
37 def read_pid(self, pidfile):
38 """Read process id from a file.
40 @param pidfile: file to read
41 @return pid or 0
42 """
43 if os.path.isfile(pidfile) and os.path.getsize(pidfile):
44 try:
45 f = open(pidfile, 'r')
46 try:
47 return int(f.read())
48 finally:
49 f.close()
50 except:
51 return 0
52 else:
53 return 0
55 def find_process(self, pid, name):
56 """Search for a process.
58 @param pid: process id
59 @param name: process name
60 @return: pid if found, 0 otherwise
61 """
62 running = 0
63 if pid:
64 lines = os.popen('ps %d 2>/dev/null' % pid).readlines()
65 exp = '^ *%d.+%s' % (pid, name)
66 for line in lines:
67 if re.search(exp, line):
68 running = pid
69 break
70 return running
72 def cleanup_process(self, pidfile, name, kill):
73 """Clean up the pidfile for a process.
74 If a running process is found, kills it if 'kill' is true.
76 @param pidfile: pid file
77 @param name: process name
78 @param kill: whether to kill the process
79 @return running process id or 0
80 """
81 running = 0
82 pid = self.read_pid(pidfile)
83 if self.find_process(pid, name):
84 if kill:
85 os.kill(pid, 1)
86 else:
87 running = pid
88 if running == 0 and os.path.isfile(pidfile):
89 os.remove(pidfile)
90 return running
92 def cleanup_xend(self, kill):
93 return self.cleanup_process(XEND_PID_FILE, "xend", kill)
95 def status(self):
96 """Returns the status of the xend daemon.
97 The return value is defined by the LSB:
98 0 Running
99 3 Not running
100 """
101 if self.cleanup_process(XEND_PID_FILE, "xend", False) == 0:
102 return 3
103 else:
104 return 0
106 def fork_pid(self, pidfile):
107 """Fork and write the pid of the child to 'pidfile'.
109 @param pidfile: pid file
110 @return: pid of child in parent, 0 in child
111 """
113 self.child = os.fork()
115 if self.child:
116 # Parent
117 pidfile = open(pidfile, 'w')
118 try:
119 pidfile.write(str(self.child))
120 finally:
121 pidfile.close()
123 return self.child
125 def daemonize(self):
126 if not XEND_DAEMONIZE: return
127 # Detach from TTY.
128 os.setsid()
130 # Detach from standard file descriptors, and redirect them to
131 # /dev/null or the log as appropriate.
132 os.close(0)
133 os.close(1)
134 os.close(2)
135 if XEND_DEBUG:
136 os.open('/dev/null', os.O_RDONLY)
137 os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT)
138 os.dup(1)
139 else:
140 os.open('/dev/null', os.O_RDWR)
141 os.dup(0)
142 os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT)
145 def start(self, trace=0):
146 """Attempts to start the daemons.
147 The return value is defined by the LSB:
148 0 Success
149 4 Insufficient privileges
150 """
151 xend_pid = self.cleanup_xend(False)
153 if self.set_user():
154 return 4
155 os.chdir("/")
157 if xend_pid > 0:
158 # Trying to run an already-running service is a success.
159 return 0
161 ret = 0
163 # we use a pipe to communicate between the parent and the child process
164 # this way we know when the child has actually initialized itself so
165 # we can avoid a race condition during startup
167 r,w = os.pipe()
168 if self.fork_pid(XEND_PID_FILE):
169 os.close(w)
170 r = os.fdopen(r, 'r')
171 try:
172 s = r.read()
173 finally:
174 r.close()
175 if not len(s):
176 ret = 1
177 else:
178 ret = int(s)
179 else:
180 os.close(r)
181 # Child
182 self.tracing(trace)
183 self.run(os.fdopen(w, 'w'))
185 return ret
187 def tracing(self, traceon):
188 """Turn tracing on or off.
190 @param traceon: tracing flag
191 """
192 if traceon == self.traceon:
193 return
194 self.traceon = traceon
195 if traceon:
196 self.tracefile = open(XEND_TRACE_FILE, 'w+', 1)
197 self.traceindent = 0
198 sys.settrace(self.trace)
199 try:
200 threading.settrace(self.trace) # Only in Python >= 2.3
201 except:
202 pass
204 def print_trace(self, string):
205 for i in range(self.traceindent):
206 ch = " "
207 if (i % 5):
208 ch = ' '
209 else:
210 ch = '|'
211 self.tracefile.write(ch)
212 self.tracefile.write(string)
214 def trace(self, frame, event, arg):
215 if not self.traceon:
216 print >>self.tracefile
217 print >>self.tracefile, '-' * 20, 'TRACE OFF', '-' * 20
218 self.tracefile.close()
219 self.tracefile = None
220 return None
221 if event == 'call':
222 code = frame.f_code
223 filename = code.co_filename
224 m = re.search('.*xend/(.*)', filename)
225 if not m:
226 return None
227 modulename = m.group(1)
228 if re.search('sxp.py', modulename):
229 return None
230 self.traceindent += 1
231 self.print_trace("> %s:%s\n"
232 % (modulename, code.co_name))
233 elif event == 'line':
234 filename = frame.f_code.co_filename
235 lineno = frame.f_lineno
236 self.print_trace("%4d %s" %
237 (lineno, linecache.getline(filename, lineno)))
238 elif event == 'return':
239 code = frame.f_code
240 filename = code.co_filename
241 m = re.search('.*xend/(.*)', filename)
242 if not m:
243 return None
244 modulename = m.group(1)
245 self.print_trace("< %s:%s\n"
246 % (modulename, code.co_name))
247 self.traceindent -= 1
248 elif event == 'exception':
249 self.print_trace("! Exception:\n")
250 (ex, val, tb) = arg
251 traceback.print_exception(ex, val, tb, 10, self.tracefile)
252 #del tb
253 return self.trace
255 def set_user(self):
256 # Set the UID.
257 try:
258 os.setuid(pwd.getpwnam(XEND_USER)[2])
259 return 0
260 except KeyError:
261 print >>sys.stderr, "Error: no such user '%s'" % XEND_USER
262 return 1
264 def stop(self):
265 result = self.cleanup_xend(True)
266 from xen.xend import Vifctl
267 Vifctl.network("stop")
268 return result
270 def run(self, status):
271 try:
272 log.info("Xend Daemon started")
274 xinfo = xen.lowlevel.xc.new().xeninfo()
275 log.info("Xend changeset: %s.", xinfo['xen_changeset'])
277 event.listenEvent(self)
278 relocate.listenRelocation()
279 servers = SrvServer.create()
280 self.daemonize()
281 servers.start(status)
282 except Exception, ex:
283 print >>sys.stderr, 'Exception starting xend:', ex
284 if XEND_DEBUG:
285 traceback.print_exc()
286 log.exception("Exception starting xend (%s)" % ex)
287 status.write('1')
288 status.close()
289 self.exit(1)
291 def exit(self, rc=0):
292 # Calling sys.exit() raises a SystemExit exception, which only
293 # kills the current thread. Calling os._exit() makes the whole
294 # Python process exit immediately. There doesn't seem to be another
295 # way to exit a Python with running threads.
296 #sys.exit(rc)
297 os._exit(rc)
299 def instance():
300 global inst
301 try:
302 inst
303 except:
304 inst = Daemon()
305 return inst