ia64/xen-unstable

view tools/python/xen/util/xmlrpclib2.py @ 12124:91c7ee18c978

[XEND] Updates to SR and VDI implementations

* Moved xenapi transport util method, stringify to xen.util.xmlrpclib2
* XenVDI now preserves configuration to an XML-ish file
* Update Xen API's class names to be all lowercase
* Update get_by_label to get_by_name_label and return sets as the API
expects.
* Add support for VBD creation with a VDI reference.

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