ia64/xen-unstable

annotate tools/python/xen/util/xmlrpclib2.py @ 12075:52bf7bbb0f36

[XEND] Make logging an optional parameter for the XMLRPCServer

Signed-off-by: Alastair Tse <atse@xensource.com>
author Alastair Tse <atse@xensource.com>
date Thu Oct 05 17:29:19 2006 +0100 (2006-10-05)
parents 5db6984e4503
children 91c7ee18c978
rev   line source
anthony@9421 1 #============================================================================
anthony@9421 2 # This library is free software; you can redistribute it and/or
anthony@9421 3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
anthony@9421 4 # License as published by the Free Software Foundation.
anthony@9421 5 #
anthony@9421 6 # This library is distributed in the hope that it will be useful,
anthony@9421 7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
anthony@9421 8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
anthony@9421 9 # Lesser General Public License for more details.
anthony@9421 10 #
anthony@9421 11 # You should have received a copy of the GNU Lesser General Public
anthony@9421 12 # License along with this library; if not, write to the Free Software
anthony@9421 13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
anthony@9421 14 #============================================================================
anthony@9421 15 # Copyright (C) 2006 Anthony Liguori <aliguori@us.ibm.com>
emellor@10495 16 # Copyright (C) 2006 XenSource Inc.
anthony@9421 17 #============================================================================
anthony@9421 18
anthony@9421 19 """
anthony@9421 20 An enhanced XML-RPC client/server interface for Python.
anthony@9421 21 """
anthony@9421 22
emellor@9598 23 import string
emellor@9580 24 import types
kfraser@11149 25 import fcntl
emellor@9580 26
anthony@9421 27 from httplib import HTTPConnection, HTTP
anthony@9421 28 from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
emellor@9465 29 import SocketServer
emellor@10495 30 import xmlrpclib, socket, os, stat
anthony@9421 31
emellor@9529 32 from xen.xend.XendLogging import log
emellor@9529 33
emellor@10495 34 try:
emellor@10495 35 import SSHTransport
emellor@10495 36 ssh_enabled = True
emellor@10495 37 except ImportError:
emellor@10495 38 # SSHTransport is disabled on Python <2.4, because it uses the subprocess
emellor@10495 39 # package.
emellor@10495 40 ssh_enabled = False
root@10488 41
emellor@9529 42
anthony@9421 43 # A new ServerProxy that also supports httpu urls. An http URL comes in the
anthony@9421 44 # form:
anthony@9421 45 #
anthony@9421 46 # httpu:///absolute/path/to/socket.sock
anthony@9421 47 #
anthony@9421 48 # It assumes that the RPC handler is /RPC2. This probably needs to be improved
anthony@9421 49
anthony@10486 50 # We're forced to subclass the RequestHandler class so that we can work around
anthony@10486 51 # some bugs in Keep-Alive handling and also enabled it by default
anthony@10486 52 class XMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
anthony@10486 53 protocol_version = "HTTP/1.1"
anthony@10486 54
anthony@10486 55 # this is inspired by SimpleXMLRPCRequestHandler's do_POST but differs
anthony@10486 56 # in a few non-trivial ways
anthony@10486 57 # 1) we never generate internal server errors. We let the exception
anthony@10486 58 # propagate so that it shows up in the Xend debug logs
anthony@10486 59 # 2) we don't bother checking for a _dispatch function since we don't
anthony@10486 60 # use one
anthony@10486 61 def do_POST(self):
anthony@10486 62 data = self.rfile.read(int(self.headers["content-length"]))
anthony@10486 63 rsp = self.server._marshaled_dispatch(data)
anthony@10486 64
anthony@10486 65 self.send_response(200)
anthony@10486 66 self.send_header("Content-Type", "text/xml")
anthony@10486 67 self.send_header("Content-Length", str(len(rsp)))
anthony@10486 68 self.end_headers()
anthony@10486 69
anthony@10486 70 self.wfile.write(rsp)
anthony@10486 71 self.wfile.flush()
kaf24@10509 72 if self.close_connection == 1:
kaf24@10509 73 self.connection.shutdown(1)
anthony@10486 74
anthony@9421 75 class HTTPUnixConnection(HTTPConnection):
anthony@9421 76 def connect(self):
anthony@9421 77 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
anthony@9421 78 self.sock.connect(self.host)
anthony@9421 79
anthony@9421 80 class HTTPUnix(HTTP):
anthony@9421 81 _connection_class = HTTPUnixConnection
anthony@9421 82
atse@12075 83 class UnixTransport(xmlrpclib.Transport):
anthony@9421 84 def request(self, host, handler, request_body, verbose=0):
anthony@9421 85 self.__handler = handler
atse@12075 86 return xmlrpclib.Transport.request(self, host, '/RPC2',
atse@12075 87 request_body, verbose)
anthony@9421 88 def make_connection(self, host):
anthony@9421 89 return HTTPUnix(self.__handler)
anthony@9421 90
emellor@9598 91
emellor@9598 92 # See _marshalled_dispatch below.
emellor@9598 93 def conv_string(x):
emellor@9598 94 if (isinstance(x, types.StringType) or
emellor@9598 95 isinstance(x, unicode)):
emellor@9598 96 s = string.replace(x, "'", r"\047")
emellor@9598 97 exec "s = '" + s + "'"
emellor@9598 98 return s
emellor@9598 99 else:
emellor@9598 100 return x
emellor@9598 101
emellor@9598 102
anthony@9421 103 class ServerProxy(xmlrpclib.ServerProxy):
anthony@9421 104 def __init__(self, uri, transport=None, encoding=None, verbose=0,
anthony@9421 105 allow_none=1):
anthony@9421 106 if transport == None:
anthony@9421 107 (protocol, rest) = uri.split(':', 1)
anthony@9421 108 if protocol == 'httpu':
anthony@9421 109 uri = 'http:' + rest
anthony@9421 110 transport = UnixTransport()
root@10488 111 elif protocol == 'ssh':
emellor@10495 112 global ssh_enabled
emellor@10495 113 if ssh_enabled:
emellor@10495 114 (transport, uri) = SSHTransport.getHTTPURI(uri)
root@10488 115 else:
emellor@10495 116 raise ValueError(
emellor@10495 117 "SSH transport not supported on Python <2.4.")
anthony@9421 118 xmlrpclib.ServerProxy.__init__(self, uri, transport, encoding,
anthony@9421 119 verbose, allow_none)
anthony@9421 120
emellor@9598 121 def __request(self, methodname, params):
emellor@9598 122 response = xmlrpclib.ServerProxy.__request(self, methodname, params)
emellor@9598 123
emellor@9598 124 if isinstance(response, tuple):
emellor@9598 125 return tuple([conv_string(x) for x in response])
emellor@9598 126 else:
emellor@9598 127 return conv_string(response)
emellor@9598 128
emellor@9598 129
anthony@9421 130 # This is a base XML-RPC server for TCP. It sets allow_reuse_address to
emellor@9529 131 # true, and has an improved marshaller that logs and serializes exceptions.
anthony@9421 132
emellor@9465 133 class TCPXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
anthony@9421 134 allow_reuse_address = True
anthony@9421 135
anthony@10486 136 def __init__(self, addr, requestHandler=XMLRPCRequestHandler,
atse@12075 137 logRequests = 1):
anthony@10486 138 SimpleXMLRPCServer.__init__(self, addr, requestHandler, logRequests)
anthony@10486 139
kfraser@11149 140 flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
kfraser@11149 141 flags |= fcntl.FD_CLOEXEC
kfraser@11149 142 fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags)
kfraser@11149 143
kfraser@11149 144 def get_request(self):
kfraser@11149 145 (client, addr) = SimpleXMLRPCServer.get_request(self)
kfraser@11149 146 flags = fcntl.fcntl(client.fileno(), fcntl.F_GETFD)
kfraser@11149 147 flags |= fcntl.FD_CLOEXEC
kfraser@11149 148 fcntl.fcntl(client.fileno(), fcntl.F_SETFD, flags)
kfraser@11149 149 return (client, addr)
kfraser@11149 150
anthony@9421 151 def _marshaled_dispatch(self, data, dispatch_method = None):
anthony@9421 152 params, method = xmlrpclib.loads(data)
emellor@11015 153 if False:
emellor@11015 154 # Enable this block of code to exit immediately without sending
emellor@11015 155 # a response. This allows you to test client-side crash handling.
emellor@11015 156 import sys
emellor@11015 157 sys.exit(1)
anthony@9421 158 try:
anthony@9421 159 if dispatch_method is not None:
anthony@9421 160 response = dispatch_method(method, params)
anthony@9421 161 else:
anthony@9421 162 response = self._dispatch(method, params)
anthony@9421 163
emellor@9598 164 # With either Unicode or normal strings, we can only transmit
emellor@9598 165 # \t, \n, \r, \u0020-\ud7ff, \ue000-\ufffd, and \u10000-\u10ffff
emellor@9598 166 # in an XML document. xmlrpclib does not escape these values
emellor@9598 167 # properly, and then breaks when it comes to parse the document.
emellor@9598 168 # To hack around this problem, we use repr here and exec above
emellor@9598 169 # to transmit the string using Python encoding.
emellor@9598 170 # Thanks to David Mertz <mertz@gnosis.cx> for the trick (buried
emellor@9598 171 # in xml_pickle.py).
emellor@9598 172 if (isinstance(response, types.StringType) or
emellor@9598 173 isinstance(response, unicode)):
emellor@9598 174 response = repr(response)[1:-1]
emellor@9580 175
anthony@9421 176 response = (response,)
anthony@9421 177 response = xmlrpclib.dumps(response,
anthony@9421 178 methodresponse=1,
anthony@9421 179 allow_none=1)
anthony@9421 180 except xmlrpclib.Fault, fault:
anthony@9421 181 response = xmlrpclib.dumps(fault)
emellor@9529 182 except Exception, exn:
root@10488 183 import xen.xend.XendClient
emellor@9529 184 log.exception(exn)
anthony@9421 185 response = xmlrpclib.dumps(
emellor@9529 186 xmlrpclib.Fault(xen.xend.XendClient.ERROR_INTERNAL, str(exn)))
anthony@9421 187
anthony@9421 188 return response
anthony@9421 189
anthony@9421 190 # This is a XML-RPC server that sits on a Unix domain socket.
anthony@9421 191 # It implements proper support for allow_reuse_address by
anthony@9421 192 # unlink()'ing an existing socket.
anthony@9421 193
anthony@10486 194 class UnixXMLRPCRequestHandler(XMLRPCRequestHandler):
anthony@9421 195 def address_string(self):
anthony@9421 196 try:
anthony@10486 197 return XMLRPCRequestHandler.address_string(self)
anthony@9421 198 except ValueError, e:
anthony@9421 199 return self.client_address[:2]
anthony@9421 200
anthony@9421 201 class UnixXMLRPCServer(TCPXMLRPCServer):
anthony@9421 202 address_family = socket.AF_UNIX
anthony@9421 203
atse@12075 204 def __init__(self, addr, logRequests = 1):
emellor@9543 205 parent = os.path.dirname(addr)
emellor@9543 206 if os.path.exists(parent):
emellor@9543 207 os.chown(parent, os.geteuid(), os.getegid())
emellor@9543 208 os.chmod(parent, stat.S_IRWXU)
emellor@9543 209 if self.allow_reuse_address and os.path.exists(addr):
anthony@9421 210 os.unlink(addr)
emellor@9543 211 else:
emellor@9543 212 os.makedirs(parent, stat.S_IRWXU)
emellor@9423 213 TCPXMLRPCServer.__init__(self, addr, UnixXMLRPCRequestHandler,
emellor@9423 214 logRequests)