ia64/xen-unstable

view tools/python/xen/xend/server/XMLRPCServer.py @ 14621:7e6ef2b914aa

Fix to let TCP server run without SSL installed.

signed-off-by: Tom Wilkie <tom.wilkie@gmail.com>
author Tom Wilkie <tom.wilkie@gmail.com>
date Wed Mar 28 12:38:13 2007 +0100 (2007-03-28)
parents 966c65f0ddba
children 0c14d0bf369e
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) 2006 Anthony Liguori <aliguori@us.ibm.com>
16 # Copyright (C) 2006 XenSource Ltd.
17 #============================================================================
19 import errno
20 import socket
21 import types
22 import xmlrpclib
23 from xen.util.xmlrpclib2 import UnixXMLRPCServer, TCPXMLRPCServer
24 try:
25 from SSLXMLRPCServer import SSLXMLRPCServer
26 ssl_enabled = True
27 except ImportError:
28 ssl_enabled = False
30 from xen.xend import XendAPI, XendDomain, XendDomainInfo, XendNode
31 from xen.xend import XendLogging, XendDmesg
32 from xen.xend.XendClient import XML_RPC_SOCKET
33 from xen.xend.XendConstants import DOM_STATE_RUNNING
34 from xen.xend.XendLogging import log
35 from xen.xend.XendError import XendInvalidDomain
37 # vcpu_avail is a long and is not needed by the clients. It's far easier
38 # to just remove it then to try and marshal the long.
39 def fixup_sxpr(sexpr):
40 ret = []
41 for k in sexpr:
42 if type(k) in (list, tuple):
43 if len(k) != 2 or k[0] != 'vcpu_avail':
44 ret.append(fixup_sxpr(k))
45 else:
46 ret.append(k)
47 return ret
49 def lookup(domid):
50 info = XendDomain.instance().domain_lookup(domid)
51 return info
53 def dispatch(domid, fn, args):
54 info = lookup(domid)
55 return getattr(info, fn)(*args)
57 def domain(domid, full = 0):
58 info = lookup(domid)
59 return fixup_sxpr(info.sxpr(not full))
61 def domains(detail = True, full = False):
62 return domains_with_state(detail, DOM_STATE_RUNNING, full)
64 def domains_with_state(detail, state, full):
65 if detail:
66 domains = XendDomain.instance().list_sorted(state)
67 return map(lambda dom: fixup_sxpr(dom.sxpr(not full)), domains)
68 else:
69 return XendDomain.instance().list_names(state)
71 def domain_create(config):
72 info = XendDomain.instance().domain_create(config)
73 return fixup_sxpr(info.sxpr())
75 def domain_restore(src, paused=False):
76 info = XendDomain.instance().domain_restore(src, paused)
77 return fixup_sxpr(info.sxpr())
79 def get_log():
80 f = open(XendLogging.getLogFilename(), 'r')
81 try:
82 return f.read()
83 finally:
84 f.close()
86 methods = ['device_create', 'device_configure',
87 'destroyDevice','getDeviceSxprs',
88 'setMemoryTarget', 'setName', 'setVCpuCount', 'shutdown',
89 'send_sysrq', 'getVCPUInfo', 'waitForDevices',
90 'getRestartCount']
92 exclude = ['domain_create', 'domain_restore']
94 class XMLRPCServer:
95 def __init__(self, auth, use_xenapi, use_tcp = False,
96 ssl_key_file = None, ssl_cert_file = None,
97 host = "localhost", port = 8006, path = XML_RPC_SOCKET,
98 hosts_allowed = None):
100 self.use_tcp = use_tcp
101 self.port = port
102 self.host = host
103 self.path = path
104 self.hosts_allowed = hosts_allowed
106 self.ssl_key_file = ssl_key_file
107 self.ssl_cert_file = ssl_cert_file
109 self.ready = False
110 self.running = True
111 self.auth = auth
112 self.xenapi = use_xenapi and XendAPI.XendAPI(auth) or None
114 def run(self):
115 authmsg = (self.auth == XendAPI.AUTH_NONE and
116 "; authentication has been disabled for this server." or
117 ".")
119 try:
120 if self.use_tcp:
121 using_ssl = self.ssl_key_file and self.ssl_cert_file
123 log.info("Opening %s XML-RPC server on %s%d%s",
124 using_ssl and 'HTTPS' or 'TCP',
125 self.host and '%s:' % self.host or
126 'all interfaces, port ',
127 self.port, authmsg)
129 if using_ssl:
130 if not ssl_enabled:
131 raise ValueError("pyOpenSSL not installed. "
132 "Unable to start HTTPS XML-RPC server")
133 self.server = SSLXMLRPCServer(
134 (self.host, self.port),
135 self.hosts_allowed,
136 self.xenapi is not None,
137 logRequests = False,
138 ssl_key_file = self.ssl_key_file,
139 ssl_cert_file = self.ssl_cert_file)
140 else:
141 self.server = TCPXMLRPCServer(
142 (self.host, self.port),
143 self.hosts_allowed,
144 self.xenapi is not None,
145 logRequests = False)
147 else:
148 log.info("Opening Unix domain socket XML-RPC server on %s%s",
149 self.path, authmsg)
150 self.server = UnixXMLRPCServer(self.path, self.hosts_allowed,
151 self.xenapi is not None,
152 logRequests = False)
153 except socket.error, exn:
154 log.error('Cannot start server: %s!', exn.args[1])
155 ready = True
156 running = False
157 return
158 except Exception, e:
159 log.exception('Cannot start server: %s!', e)
160 ready = True
161 running = False
162 return
164 # Register Xen API Functions
165 # -------------------------------------------------------------------
166 # exportable functions are ones that do not begin with '_'
167 # and has the 'api' attribute.
169 for meth_name in dir(self.xenapi):
170 if meth_name[0] != '_':
171 meth = getattr(self.xenapi, meth_name)
172 if callable(meth) and hasattr(meth, 'api'):
173 self.server.register_function(meth, getattr(meth, 'api'))
175 self.server.register_instance(XendAPI.XendAPIAsyncProxy(self.xenapi))
177 # Legacy deprecated xm xmlrpc api
178 # --------------------------------------------------------------------
180 # Functions in XendDomainInfo
181 for name in methods:
182 fn = eval("lambda domid, *args: dispatch(domid, '%s', args)"%name)
183 self.server.register_function(fn, "xend.domain.%s" % name)
185 inst = XendDomain.instance()
187 for name in dir(inst):
188 fn = getattr(inst, name)
189 if name.startswith("domain_") and callable(fn):
190 if name not in exclude:
191 self.server.register_function(fn, "xend.domain.%s" % name[7:])
193 # Functions in XendNode and XendDmesg
194 for type, lst, n in [(XendNode, ['info', 'send_debug_keys'], 'node'),
195 (XendDmesg, ['info', 'clear'], 'node.dmesg')]:
196 inst = type.instance()
197 for name in lst:
198 self.server.register_function(getattr(inst, name),
199 "xend.%s.%s" % (n, name))
201 # A few special cases
202 self.server.register_function(domain, 'xend.domain')
203 self.server.register_function(domains, 'xend.domains')
204 self.server.register_function(domains_with_state,
205 'xend.domains_with_state')
206 self.server.register_function(get_log, 'xend.node.log')
207 self.server.register_function(domain_create, 'xend.domain.create')
208 self.server.register_function(domain_restore, 'xend.domain.restore')
210 self.server.register_introspection_functions()
211 self.ready = True
213 # Custom runloop so we can cleanup when exiting.
214 # -----------------------------------------------------------------
215 try:
216 while self.running:
217 self.server.handle_request()
218 finally:
219 self.shutdown()
221 def cleanup(self):
222 log.debug('XMLRPCServer.cleanup()')
223 if hasattr(self, 'server'):
224 try:
225 # This is here to make sure the socket is actually
226 # cleaned up when close() is called. Otherwise
227 # SO_REUSEADDR doesn't take effect. To replicate,
228 # try 'xend reload' and look for EADDRINUSE.
229 #
230 # May be caued by us calling close() outside of
231 # the listen()ing thread.
232 self.server.socket.shutdown(2)
233 except socket.error, e:
234 pass # ignore any socket errors
235 try:
236 self.server.socket.close()
237 except socket.error, e:
238 pass
240 def shutdown(self):
241 self.running = False
242 if self.ready:
243 self.ready = False
244 self.cleanup()