direct-io.hg

view tools/python/xen/xm/XenAPI.py @ 14387:8645c726ce9c

Fix error logging when we get a 500 response.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Wed Mar 14 23:14:19 2007 +0000 (2007-03-14)
parents b2f0840bb88f
children effef488d448
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 XenSource Inc.
16 #============================================================================
17 #
18 # Parts of this file are based upon xmlrpclib.py, the XML-RPC client
19 # interface included in the Python distribution.
20 #
21 # Copyright (c) 1999-2002 by Secret Labs AB
22 # Copyright (c) 1999-2002 by Fredrik Lundh
23 #
24 # By obtaining, using, and/or copying this software and/or its
25 # associated documentation, you agree that you have read, understood,
26 # and will comply with the following terms and conditions:
27 #
28 # Permission to use, copy, modify, and distribute this software and
29 # its associated documentation for any purpose and without fee is
30 # hereby granted, provided that the above copyright notice appears in
31 # all copies, and that both that copyright notice and this permission
32 # notice appear in supporting documentation, and that the name of
33 # Secret Labs AB or the author not be used in advertising or publicity
34 # pertaining to distribution of the software without specific, written
35 # prior permission.
36 #
37 # SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
38 # TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
39 # ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
40 # BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
41 # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42 # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
43 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
44 # OF THIS SOFTWARE.
45 # --------------------------------------------------------------------
47 import gettext
48 import xmlrpclib
50 import xen.util.xmlrpclib2
53 translation = gettext.translation('xen-xm', fallback = True)
55 class Failure(Exception):
56 def __init__(self, details):
57 try:
58 # If this failure is MESSAGE_PARAMETER_COUNT_MISMATCH, then we
59 # correct the return values here, to account for the fact that we
60 # transparently add the session handle as the first argument.
61 if details[0] == 'MESSAGE_PARAMETER_COUNT_MISMATCH':
62 details[2] = str(int(details[2]) - 1)
63 details[3] = str(int(details[3]) - 1)
65 self.details = details
66 except Exception, exn:
67 self.details = ['INTERNAL_ERROR', 'Client-side: ' + str(exn)]
69 def __str__(self):
70 try:
71 return translation.ugettext(self.details[0]) % self._details_map()
72 except TypeError, exn:
73 return "Message database broken: %s.\nXen-API failure: %s" % \
74 (exn, str(self.details))
75 except Exception, exn:
76 import sys
77 print >>sys.stderr, exn
78 return "Xen-API failure: %s" % str(self.details)
80 def _details_map(self):
81 return dict([(str(i), self.details[i])
82 for i in range(len(self.details))])
85 _RECONNECT_AND_RETRY = (lambda _ : ())
88 class Session(xen.util.xmlrpclib2.ServerProxy):
89 """A server proxy and session manager for communicating with Xend using
90 the Xen-API.
92 Example:
94 session = Session('http://localhost:9363/')
95 session.login_with_password('me', 'mypassword')
96 session.xenapi.VM.start(vm_uuid)
97 session.xenapi.session.logout()
99 For now, this class also supports the legacy XML-RPC API, using
100 session.xend.domain('Domain-0') and similar. This support will disappear
101 once there is a working Xen-API replacement for every call in the legacy
102 API.
103 """
105 def __init__(self, uri, transport=None, encoding=None, verbose=0,
106 allow_none=1):
107 xen.util.xmlrpclib2.ServerProxy.__init__(self, uri, transport,
108 encoding, verbose,
109 allow_none)
110 self._session = None
111 self.last_login_method = None
112 self.last_login_params = None
115 def xenapi_request(self, methodname, params):
116 if methodname.startswith('login'):
117 self._login(methodname, params)
118 return None
119 else:
120 retry_count = 0
121 while retry_count < 3:
122 full_params = (self._session,) + params
123 result = _parse_result(getattr(self, methodname)(*full_params))
124 if result == _RECONNECT_AND_RETRY:
125 retry_count += 1
126 if self.last_login_method:
127 self._login(self.last_login_method,
128 self.last_login_params)
129 else:
130 raise xmlrpclib.Fault(401, 'You must log in')
131 else:
132 return result
133 raise xmlrpclib.Fault(
134 500, 'Tried 3 times to get a valid session, but failed')
137 def _login(self, method, params):
138 result = _parse_result(getattr(self, 'session.%s' % method)(*params))
139 if result == _RECONNECT_AND_RETRY:
140 raise xmlrpclib.Fault(
141 500, 'Received SESSION_INVALID when logging in')
142 self._session = result
143 self.last_login_method = method
144 self.last_login_params = params
147 def __getattr__(self, name):
148 if name == 'xenapi':
149 return _Dispatcher(self.xenapi_request, None)
150 elif name.startswith('login'):
151 return lambda *params: self._login(name, params)
152 else:
153 return xen.util.xmlrpclib2.ServerProxy.__getattr__(self, name)
156 def _parse_result(result):
157 if type(result) != dict or 'Status' not in result:
158 raise xmlrpclib.Fault(500, 'Missing Status in response from server: ' + str(result))
159 if result['Status'] == 'Success':
160 if 'Value' in result:
161 return result['Value']
162 else:
163 raise xmlrpclib.Fault(500,
164 'Missing Value in response from server')
165 else:
166 if 'ErrorDescription' in result:
167 if result['ErrorDescription'][0] == 'SESSION_INVALID':
168 return _RECONNECT_AND_RETRY
169 else:
170 raise Failure(result['ErrorDescription'])
171 else:
172 raise xmlrpclib.Fault(
173 500, 'Missing ErrorDescription in response from server')
176 # Based upon _Method from xmlrpclib.
177 class _Dispatcher:
178 def __init__(self, send, name):
179 self.__send = send
180 self.__name = name
182 def __repr__(self):
183 if self.__name:
184 return '<XenAPI._Dispatcher for %s>' % self.__name
185 else:
186 return '<XenAPI._Dispatcher>'
188 def __getattr__(self, name):
189 if self.__name is None:
190 return _Dispatcher(self.__send, name)
191 else:
192 return _Dispatcher(self.__send, "%s.%s" % (self.__name, name))
194 def __call__(self, *args):
195 return self.__send(self.__name, args)