ia64/xen-unstable

view tools/python/xen/xend/server/SrvServer.py @ 12787:3629873ee1e6

Diagnose a failing server, rather than just locking up the whole daemon.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Mon Dec 04 13:56:27 2006 +0000 (2006-12-04)
parents 59f438d2739b
children fb1291ffa26f
line source
1 #============================================================================
2 # This library is free software; you can redistribute it and/or
3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
4 # License as published by the Free Software Foundation.
5 #
6 # This library is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 # Lesser General Public License for more details.
10 #
11 # You should have received a copy of the GNU Lesser General Public
12 # License along with this library; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 #============================================================================
15 # Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
16 # Copyright (C) 2006 XenSource Ltd.
17 #============================================================================
19 """Example xend HTTP
21 Can be accessed from a browser or from a program.
22 Do 'python SrvServer.py' to run the server.
23 Then point a web browser at http://localhost:8000/xend and follow the links.
24 Most are stubs, except /domain which has a list of domains and a 'create domain'
25 button.
27 You can also access the server from a program.
28 Do 'python XendClient.py' to run a few test operations.
30 The data served differs depending on the client (as defined by User-Agent
31 and Accept in the HTTP headers). If the client is a browser, data
32 is returned in HTML, with interactive forms. If the client is a program,
33 data is returned in SXP format, with no forms.
35 The server serves to the world by default. To restrict it to the local host
36 change 'interface' in main().
38 Mike Wray <mike.wray@hp.com>
39 """
40 # todo Support security settings etc. in the config file.
41 # todo Support command-line args.
43 import fcntl
44 import re
45 import time
46 import signal
47 from threading import Thread
49 from xen.web.httpserver import HttpServer, UnixHttpServer
51 from xen.xend import XendRoot, XendAPI
52 from xen.xend import Vifctl
53 from xen.xend.XendLogging import log
54 from xen.xend.XendClient import XEN_API_SOCKET
55 from xen.web.SrvDir import SrvDir
57 from SrvRoot import SrvRoot
58 from XMLRPCServer import XMLRPCServer
60 xroot = XendRoot.instance()
63 class XendServers:
65 def __init__(self):
66 self.servers = []
67 self.cleaningUp = False
68 self.reloadingConfig = False
70 def add(self, server):
71 self.servers.append(server)
73 def cleanup(self, signum = 0, frame = None):
74 log.debug("SrvServer.cleanup()")
75 self.cleaningUp = True
76 for server in self.servers:
77 try:
78 server.shutdown()
79 except:
80 pass
82 def reloadConfig(self, signum = 0, frame = None):
83 log.debug("SrvServer.reloadConfig()")
84 self.reloadingConfig = True
85 self.cleanup(signum, frame)
87 def start(self, status):
88 # Running the network script will spawn another process, which takes
89 # the status fd with it unless we set FD_CLOEXEC. Failing to do this
90 # causes the read in SrvDaemon to hang even when we have written here.
91 if status:
92 fcntl.fcntl(status, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
94 Vifctl.network('start')
96 # Prepare to catch SIGTERM (received when 'xend stop' is executed)
97 # and call each server's cleanup if possible
98 signal.signal(signal.SIGTERM, self.cleanup)
99 signal.signal(signal.SIGHUP, self.reloadConfig)
101 while True:
102 threads = []
103 for server in self.servers:
104 thread = Thread(target=server.run, name=server.__class__.__name__)
105 if isinstance(server, HttpServer):
106 thread.setDaemon(True)
107 thread.start()
108 threads.append(thread)
111 # check for when all threads have initialized themselves and then
112 # close the status pipe
114 retryCount = 0
115 threads_left = True
116 while threads_left:
117 threads_left = False
119 for server in self.servers:
120 if not server.ready:
121 threads_left = True
122 break
124 if threads_left:
125 time.sleep(.5)
126 retryCount += 1
127 if retryCount > 60:
128 for server in self.servers:
129 if not server.ready:
130 log.error("Server " +
131 server.__class__.__name__ +
132 " did not initialise!")
133 break
135 if status:
136 status.write('0')
137 status.close()
138 status = None
140 # Interruptible Thread.join - Python Bug #1167930
141 # Replaces: for t in threads: t.join()
142 # Reason: The above will cause python signal handlers to be
143 # blocked so we're not able to catch SIGTERM in any
144 # way for cleanup
145 runningThreads = threads
146 while len(runningThreads) > 0:
147 try:
148 for t in threads:
149 t.join(1.0)
150 runningThreads = [t for t in threads
151 if t.isAlive() and not t.isDaemon()]
152 if self.cleaningUp and len(runningThreads) > 0:
153 log.debug("Waiting for %s." %
154 [x.getName() for x in runningThreads])
155 except:
156 pass
158 if self.reloadingConfig:
159 log.info("Restarting all servers...")
160 self.cleaningUp = False
161 self.reloadingConfig = False
162 xroot.set_config()
163 self.servers = []
164 _loadConfig(self)
165 else:
166 break
168 def _loadConfig(servers):
169 if xroot.get_xend_http_server():
170 servers.add(HttpServer(root,
171 xroot.get_xend_address(),
172 xroot.get_xend_port()))
173 if xroot.get_xend_unix_server():
174 path = xroot.get_xend_unix_path()
175 log.info('unix path=' + path)
176 servers.add(UnixHttpServer(root, path))
178 api_cfg = xroot.get_xen_api_server()
179 if api_cfg:
180 try:
181 addrs = [(str(x[0]).split(':'),
182 len(x) > 1 and x[1] or XendAPI.AUTH_PAM,
183 len(x) > 2 and x[2] and map(re.compile, x[2].split(" "))
184 or None)
185 for x in api_cfg]
186 for addrport, auth, allowed in addrs:
187 if auth not in [XendAPI.AUTH_PAM, XendAPI.AUTH_NONE]:
188 log.error('Xen-API server configuration %s is invalid, ' +
189 'as %s is not a valid authentication type.',
190 api_cfg, auth)
191 break
193 if len(addrport) == 1:
194 if addrport[0] == 'unix':
195 servers.add(XMLRPCServer(auth,
196 path = XEN_API_SOCKET,
197 hosts_allowed = allowed))
198 else:
199 servers.add(
200 XMLRPCServer(auth, True, '', int(addrport[0]),
201 hosts_allowed = allowed))
202 else:
203 addr, port = addrport
204 servers.add(XMLRPCServer(auth, True, addr, int(port),
205 hosts_allowed = allowed))
206 except ValueError, exn:
207 log.error('Xen-API server configuration %s is invalid.', api_cfg)
208 except TypeError, exn:
209 log.error('Xen-API server configuration %s is invalid.', api_cfg)
211 if xroot.get_xend_tcp_xmlrpc_server():
212 servers.add(XMLRPCServer(XendAPI.AUTH_PAM, True))
214 if xroot.get_xend_unix_xmlrpc_server():
215 servers.add(XMLRPCServer(XendAPI.AUTH_PAM))
218 def create():
219 root = SrvDir()
220 root.putChild('xend', SrvRoot())
221 servers = XendServers()
222 _loadConfig(servers)
223 return servers