ia64/xen-unstable

view tools/python/xen/xm/XenAPI.py @ 13210:766eec31afab

Added __repr__ implementation, initialise last_login_method to None, and
use gettext's ugettext explicitly, rather than using gettext.install. These
things together improve the error messages that you get when using this
module incorrectly in the interactive interpreter.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Thu Dec 28 15:28:45 2006 +0000 (2006-12-28)
parents 4e079a8496b7
children 974fb31dcbe9
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')
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')
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)