source: trunk/packages/xen-common/xen-common/tools/python/xen/xend/server/SrvServer.py @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 9.3 KB
Line 
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#============================================================================
18
19"""Example xend HTTP
20
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.
26
27   You can also access the server from a program.
28   Do 'python XendClient.py' to run a few test operations.
29
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.
34
35   The server serves to the world by default. To restrict it to the local host
36   change 'interface' in main().
37
38   Mike Wray <mike.wray@hp.com>
39"""
40# todo Support security settings etc. in the config file.
41# todo Support command-line args.
42
43import fcntl
44import re
45import time
46import signal
47from threading import Thread
48
49from xen.web.httpserver import HttpServer, UnixHttpServer
50
51from xen.xend import XendNode, XendOptions, XendAPI
52from xen.xend import Vifctl
53from xen.xend.XendLogging import log
54from xen.xend.XendClient import XEN_API_SOCKET
55from xen.xend.XendDomain import instance as xenddomain
56from xen.web.SrvDir import SrvDir
57
58from SrvRoot import SrvRoot
59from XMLRPCServer import XMLRPCServer
60
61xoptions = XendOptions.instance()
62
63
64class XendServers:
65
66    def __init__(self, root):
67        self.servers = []
68        self.root = root
69        self.running = False
70        self.cleaningUp = False
71        self.reloadingConfig = False
72
73    def add(self, server):
74        self.servers.append(server)
75
76    def cleanup(self, signum = 0, frame = None, reloading = False):
77        log.debug("SrvServer.cleanup()")
78        self.cleaningUp = True
79        for server in self.servers:
80            try:
81                server.shutdown()
82            except:
83                pass
84
85        # clean up domains for those that have on_xend_stop
86        if not reloading:
87            xenddomain().cleanup_domains()
88       
89        self.running = False
90       
91
92    def reloadConfig(self, signum = 0, frame = None):
93        log.debug("SrvServer.reloadConfig()")
94        self.reloadingConfig = True
95        self.cleanup(signum, frame, reloading = True)
96
97    def start(self, status):
98        # Running the network script will spawn another process, which takes
99        # the status fd with it unless we set FD_CLOEXEC.  Failing to do this
100        # causes the read in SrvDaemon to hang even when we have written here.
101        if status:
102            fcntl.fcntl(status, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
103       
104        Vifctl.network('start')
105
106        # Prepare to catch SIGTERM (received when 'xend stop' is executed)
107        # and call each server's cleanup if possible
108        signal.signal(signal.SIGTERM, self.cleanup)
109        signal.signal(signal.SIGHUP, self.reloadConfig)
110
111        while True:
112            threads = []
113            for server in self.servers:
114                if server.ready:
115                    continue
116
117                thread = Thread(target=server.run,
118                                name=server.__class__.__name__)
119                thread.setDaemon(True)
120                thread.start()
121                threads.append(thread)
122
123            # check for when all threads have initialized themselves and then
124            # close the status pipe
125
126            retryCount = 0
127            threads_left = True
128            while threads_left:
129                threads_left = False
130
131                for server in self.servers:
132                    if not server.ready:
133                        threads_left = True
134                        break
135
136                if threads_left:
137                    time.sleep(.5)
138                    retryCount += 1
139                    if retryCount > 60:
140                        for server in self.servers:
141                            if not server.ready:
142                                log.error("Server " +
143                                          server.__class__.__name__ +
144                                          " did not initialise!")
145                        break
146
147            if status:
148                status.write('0')
149                status.close()
150                status = None
151
152            # Reaching this point means we can auto start domains
153            try:
154                xenddomain().autostart_domains()
155            except Exception, e:
156                log.exception("Failed while autostarting domains")
157
158            # loop to keep main thread alive until it receives a SIGTERM
159            self.running = True
160            while self.running:
161                time.sleep(100000000)
162               
163            if self.reloadingConfig:
164                log.info("Restarting all XML-RPC and Xen-API servers...")
165                self.cleaningUp = False
166                self.reloadingConfig = False
167                xoptions.set_config()
168                self.servers = []
169                _loadConfig(self, self.root, True)
170            else:
171                break
172
173def _loadConfig(servers, root, reload):
174    if xoptions.get_xend_http_server():
175        servers.add(HttpServer(root,
176                               xoptions.get_xend_address(),
177                               xoptions.get_xend_port()))
178    if  xoptions.get_xend_unix_server():
179        path = xoptions.get_xend_unix_path()
180        log.info('unix path=' + path)
181        servers.add(UnixHttpServer(root, path))
182
183    api_cfg = xoptions.get_xen_api_server()
184    if api_cfg:
185        try:
186            for server_cfg in api_cfg:
187                # Parse the xen-api-server config
188               
189                ssl_key_file = None
190                ssl_cert_file = None
191                auth_method = XendAPI.AUTH_NONE
192                hosts_allowed = None
193               
194                host_addr = server_cfg[0].split(':', 1)
195                if len(host_addr) == 1:
196                    if host_addr[0].lower() == 'unix':
197                        use_tcp = False
198                        host = 'localhost'
199                        port = 0
200                    else:
201                        use_tcp = True
202                        host = ''
203                        port = int(host_addr[0])
204                else:
205                    use_tcp = True
206                    host = str(host_addr[0])
207                    port = int(host_addr[1])
208
209                if len(server_cfg) > 1:
210                    if server_cfg[1] in [XendAPI.AUTH_PAM, XendAPI.AUTH_NONE]:
211                        auth_method = server_cfg[1]
212
213                if len(server_cfg) > 2 and len(server_cfg[2]):
214                    hosts_allowed = map(re.compile, server_cfg[2].split(' '))
215
216                if len(server_cfg) > 4:
217                    # SSL key and cert file
218                    ssl_key_file = server_cfg[3]
219                    ssl_cert_file = server_cfg[4]
220
221
222                servers.add(XMLRPCServer(auth_method, True, use_tcp = use_tcp,
223                                         ssl_key_file = ssl_key_file,
224                                         ssl_cert_file = ssl_cert_file,
225                                         host = host, port = port,
226                                         path = XEN_API_SOCKET,
227                                         hosts_allowed = hosts_allowed))
228
229        except (ValueError, TypeError), exn:
230            log.exception('Xen API Server init failed')
231            log.error('Xen-API server configuration %s is invalid.', api_cfg)
232
233    if xoptions.get_xend_tcp_xmlrpc_server():
234        addr = xoptions.get_xend_tcp_xmlrpc_server_address()
235        port = xoptions.get_xend_tcp_xmlrpc_server_port()
236        ssl_key_file = xoptions.get_xend_tcp_xmlrpc_server_ssl_key_file()
237        ssl_cert_file = xoptions.get_xend_tcp_xmlrpc_server_ssl_cert_file()
238
239        if ssl_key_file and ssl_cert_file:
240            servers.add(XMLRPCServer(XendAPI.AUTH_PAM, False, use_tcp = True,
241                                     ssl_key_file = ssl_key_file,
242                                     ssl_cert_file = ssl_cert_file,
243                                     host = addr, port = port))
244        else:
245            servers.add(XMLRPCServer(XendAPI.AUTH_PAM, False, use_tcp = True,
246                                     host = addr, port = port))
247
248    if xoptions.get_xend_unix_xmlrpc_server():
249        servers.add(XMLRPCServer(XendAPI.AUTH_PAM, False))
250
251
252def create():
253    root = SrvDir()
254    root.putChild('xend', SrvRoot())
255    servers = XendServers(root)
256    _loadConfig(servers, root, False)
257    return servers
Note: See TracBrowser for help on using the repository browser.