ia64/xen-unstable

view tools/python/xen/xend/server/SrvServer.py @ 12786:59f438d2739b

Added rudimentary "xend reload" functionality. This allows you to reconfigure
the services offered by Xend, without restarting the daemon itself.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Mon Dec 04 13:37:53 2006 +0000 (2006-12-04)
parents 952c2cddff0c
children 3629873ee1e6
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 threads_left = True
115 while threads_left:
116 threads_left = False
118 for server in self.servers:
119 if not server.ready:
120 threads_left = True
121 break
123 if threads_left:
124 time.sleep(.5)
126 if status:
127 status.write('0')
128 status.close()
129 status = None
131 # Interruptible Thread.join - Python Bug #1167930
132 # Replaces: for t in threads: t.join()
133 # Reason: The above will cause python signal handlers to be
134 # blocked so we're not able to catch SIGTERM in any
135 # way for cleanup
136 runningThreads = threads
137 while len(runningThreads) > 0:
138 try:
139 for t in threads:
140 t.join(1.0)
141 runningThreads = [t for t in threads
142 if t.isAlive() and not t.isDaemon()]
143 if self.cleaningUp and len(runningThreads) > 0:
144 log.debug("Waiting for %s." %
145 [x.getName() for x in runningThreads])
146 except:
147 pass
149 if self.reloadingConfig:
150 log.info("Restarting all servers...")
151 self.cleaningUp = False
152 self.reloadingConfig = False
153 xroot.set_config()
154 self.servers = []
155 _loadConfig(self)
156 else:
157 break
159 def _loadConfig(servers):
160 if xroot.get_xend_http_server():
161 servers.add(HttpServer(root,
162 xroot.get_xend_address(),
163 xroot.get_xend_port()))
164 if xroot.get_xend_unix_server():
165 path = xroot.get_xend_unix_path()
166 log.info('unix path=' + path)
167 servers.add(UnixHttpServer(root, path))
169 api_cfg = xroot.get_xen_api_server()
170 if api_cfg:
171 try:
172 addrs = [(str(x[0]).split(':'),
173 len(x) > 1 and x[1] or XendAPI.AUTH_PAM,
174 len(x) > 2 and x[2] and map(re.compile, x[2].split(" "))
175 or None)
176 for x in api_cfg]
177 for addrport, auth, allowed in addrs:
178 if auth not in [XendAPI.AUTH_PAM, XendAPI.AUTH_NONE]:
179 log.error('Xen-API server configuration %s is invalid, ' +
180 'as %s is not a valid authentication type.',
181 api_cfg, auth)
182 break
184 if len(addrport) == 1:
185 if addrport[0] == 'unix':
186 servers.add(XMLRPCServer(auth,
187 path = XEN_API_SOCKET,
188 hosts_allowed = allowed))
189 else:
190 servers.add(
191 XMLRPCServer(auth, True, '', int(addrport[0]),
192 hosts_allowed = allowed))
193 else:
194 addr, port = addrport
195 servers.add(XMLRPCServer(auth, True, addr, int(port),
196 hosts_allowed = allowed))
197 except ValueError, exn:
198 log.error('Xen-API server configuration %s is invalid.', api_cfg)
199 except TypeError, exn:
200 log.error('Xen-API server configuration %s is invalid.', api_cfg)
202 if xroot.get_xend_tcp_xmlrpc_server():
203 servers.add(XMLRPCServer(XendAPI.AUTH_PAM, True))
205 if xroot.get_xend_unix_xmlrpc_server():
206 servers.add(XMLRPCServer(XendAPI.AUTH_PAM))
209 def create():
210 root = SrvDir()
211 root.putChild('xend', SrvRoot())
212 servers = XendServers()
213 _loadConfig(servers)
214 return servers