ia64/xen-unstable

view tools/python/xen/util/xmlrpclib2.py @ 12725:36fe7ca48e54

Tidy up the creation of directories that Xend needs. This avoids potential
races in this creation.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Fri Dec 01 11:32:32 2006 +0000 (2006-12-01)
parents 6206685650f5
children e45948c4dba4
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 Inc.
17 #============================================================================
19 """
20 An enhanced XML-RPC client/server interface for Python.
21 """
23 import string
24 import fcntl
25 from types import *
28 from httplib import HTTPConnection, HTTP
29 from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
30 import SocketServer
31 import xmlrpclib, socket, os, stat
33 import mkdir
35 from xen.web import connection
36 from xen.xend.XendLogging import log
38 try:
39 import SSHTransport
40 ssh_enabled = True
41 except ImportError:
42 # SSHTransport is disabled on Python <2.4, because it uses the subprocess
43 # package.
44 ssh_enabled = False
46 #
47 # Convert all integers to strings as described in the Xen API
48 #
51 def stringify(value):
52 if isinstance(value, IntType) and not isinstance(value, BooleanType):
53 return str(value)
54 elif isinstance(value, DictType):
55 for k, v in value.items():
56 value[k] = stringify(v)
57 return value
58 elif isinstance(value, (TupleType, ListType)):
59 return [stringify(v) for v in value]
60 else:
61 return value
64 # A new ServerProxy that also supports httpu urls. An http URL comes in the
65 # form:
66 #
67 # httpu:///absolute/path/to/socket.sock
68 #
69 # It assumes that the RPC handler is /RPC2. This probably needs to be improved
71 # We're forced to subclass the RequestHandler class so that we can work around
72 # some bugs in Keep-Alive handling and also enabled it by default
73 class XMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
74 protocol_version = "HTTP/1.1"
76 def __init__(self, hosts_allowed, request, client_address, server):
77 self.hosts_allowed = hosts_allowed
78 SimpleXMLRPCRequestHandler.__init__(self, request, client_address,
79 server)
81 # this is inspired by SimpleXMLRPCRequestHandler's do_POST but differs
82 # in a few non-trivial ways
83 # 1) we never generate internal server errors. We let the exception
84 # propagate so that it shows up in the Xend debug logs
85 # 2) we don't bother checking for a _dispatch function since we don't
86 # use one
87 def do_POST(self):
88 addrport = self.client_address
89 if not connection.hostAllowed(addrport, self.hosts_allowed):
90 self.connection.shutdown(1)
91 return
93 data = self.rfile.read(int(self.headers["content-length"]))
94 rsp = self.server._marshaled_dispatch(data)
96 self.send_response(200)
97 self.send_header("Content-Type", "text/xml")
98 self.send_header("Content-Length", str(len(rsp)))
99 self.end_headers()
101 self.wfile.write(rsp)
102 self.wfile.flush()
103 if self.close_connection == 1:
104 self.connection.shutdown(1)
106 class HTTPUnixConnection(HTTPConnection):
107 def connect(self):
108 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
109 self.sock.connect(self.host)
111 class HTTPUnix(HTTP):
112 _connection_class = HTTPUnixConnection
114 class UnixTransport(xmlrpclib.Transport):
115 def request(self, host, handler, request_body, verbose=0):
116 self.__handler = handler
117 return xmlrpclib.Transport.request(self, host, '/RPC2',
118 request_body, verbose)
119 def make_connection(self, host):
120 return HTTPUnix(self.__handler)
123 # See _marshalled_dispatch below.
124 def conv_string(x):
125 if isinstance(x, StringTypes):
126 s = string.replace(x, "'", r"\047")
127 exec "s = '" + s + "'"
128 return s
129 else:
130 return x
133 class ServerProxy(xmlrpclib.ServerProxy):
134 def __init__(self, uri, transport=None, encoding=None, verbose=0,
135 allow_none=1):
136 if transport == None:
137 (protocol, rest) = uri.split(':', 1)
138 if protocol == 'httpu':
139 uri = 'http:' + rest
140 transport = UnixTransport()
141 elif protocol == 'ssh':
142 global ssh_enabled
143 if ssh_enabled:
144 (transport, uri) = SSHTransport.getHTTPURI(uri)
145 else:
146 raise ValueError(
147 "SSH transport not supported on Python <2.4.")
148 xmlrpclib.ServerProxy.__init__(self, uri, transport, encoding,
149 verbose, allow_none)
151 def __request(self, methodname, params):
152 response = xmlrpclib.ServerProxy.__request(self, methodname, params)
154 if isinstance(response, tuple):
155 return tuple([conv_string(x) for x in response])
156 else:
157 return conv_string(response)
160 # This is a base XML-RPC server for TCP. It sets allow_reuse_address to
161 # true, and has an improved marshaller that logs and serializes exceptions.
163 class TCPXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
164 allow_reuse_address = True
166 def __init__(self, addr, allowed, requestHandler=None,
167 logRequests = 1):
168 if requestHandler is None:
169 requestHandler = XMLRPCRequestHandler
170 SimpleXMLRPCServer.__init__(self, addr,
171 (lambda x, y, z:
172 requestHandler(allowed, x, y, z)),
173 logRequests)
175 flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
176 flags |= fcntl.FD_CLOEXEC
177 fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags)
179 def get_request(self):
180 (client, addr) = SimpleXMLRPCServer.get_request(self)
181 flags = fcntl.fcntl(client.fileno(), fcntl.F_GETFD)
182 flags |= fcntl.FD_CLOEXEC
183 fcntl.fcntl(client.fileno(), fcntl.F_SETFD, flags)
184 return (client, addr)
186 def _marshaled_dispatch(self, data, dispatch_method = None):
187 params, method = xmlrpclib.loads(data)
188 if False:
189 # Enable this block of code to exit immediately without sending
190 # a response. This allows you to test client-side crash handling.
191 import sys
192 sys.exit(1)
193 try:
194 if dispatch_method is not None:
195 response = dispatch_method(method, params)
196 else:
197 response = self._dispatch(method, params)
199 # With either Unicode or normal strings, we can only transmit
200 # \t, \n, \r, \u0020-\ud7ff, \ue000-\ufffd, and \u10000-\u10ffff
201 # in an XML document. xmlrpclib does not escape these values
202 # properly, and then breaks when it comes to parse the document.
203 # To hack around this problem, we use repr here and exec above
204 # to transmit the string using Python encoding.
205 # Thanks to David Mertz <mertz@gnosis.cx> for the trick (buried
206 # in xml_pickle.py).
207 if isinstance(response, StringTypes):
208 response = repr(response)[1:-1]
210 response = (response,)
211 response = xmlrpclib.dumps(response,
212 methodresponse=1,
213 allow_none=1)
214 except xmlrpclib.Fault, fault:
215 response = xmlrpclib.dumps(fault)
216 except Exception, exn:
217 import xen.xend.XendClient
218 log.exception(exn)
219 response = xmlrpclib.dumps(
220 xmlrpclib.Fault(xen.xend.XendClient.ERROR_INTERNAL, str(exn)))
222 return response
224 # This is a XML-RPC server that sits on a Unix domain socket.
225 # It implements proper support for allow_reuse_address by
226 # unlink()'ing an existing socket.
228 class UnixXMLRPCRequestHandler(XMLRPCRequestHandler):
229 def address_string(self):
230 try:
231 return XMLRPCRequestHandler.address_string(self)
232 except ValueError, e:
233 return self.client_address[:2]
235 class UnixXMLRPCServer(TCPXMLRPCServer):
236 address_family = socket.AF_UNIX
238 def __init__(self, addr, allowed, logRequests = 1):
239 mkdir.parents(os.path.dirname(addr), stat.S_IRWXU, True)
240 if self.allow_reuse_address and os.path.exists(addr):
241 os.unlink(addr)
243 TCPXMLRPCServer.__init__(self, addr, allowed,
244 UnixXMLRPCRequestHandler, logRequests)