| #============================================================================ |
| # Copyright 2012 Citrix Systems, Inc. Licensed under the |
| # Apache License, Version 2.0 (the "License"); you may not use this |
| # file except in compliance with the License. Citrix Systems, Inc. |
| # reserves all rights not expressly granted by the License. |
| # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| # Automatically generated by addcopyright.py at 04/02/2012 |
| # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| #============================================================================ |
| #============================================================================ |
| # prior permission. |
| # SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD |
| # TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- |
| # ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR |
| # BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY |
| # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
| # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS |
| # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE |
| # OF THIS SOFTWARE. |
| # -------------------------------------------------------------------- |
| |
| import gettext |
| import xmlrpclib |
| import httplib |
| import socket |
| |
| translation = gettext.translation('xen-xm', fallback = True) |
| |
| API_VERSION_1_1 = '1.1' |
| API_VERSION_1_2 = '1.2' |
| |
| class Failure(Exception): |
| def __init__(self, details): |
| self.details = details |
| |
| def __str__(self): |
| try: |
| return str(self.details) |
| except Exception, exn: |
| import sys |
| print >>sys.stderr, exn |
| return "Xen-API failure: %s" % str(self.details) |
| |
| def _details_map(self): |
| return dict([(str(i), self.details[i]) |
| for i in range(len(self.details))]) |
| |
| |
| _RECONNECT_AND_RETRY = (lambda _ : ()) |
| |
| class UDSHTTPConnection(httplib.HTTPConnection): |
| """HTTPConnection subclass to allow HTTP over Unix domain sockets. """ |
| def connect(self): |
| path = self.host.replace("_", "/") |
| self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) |
| self.sock.connect(path) |
| |
| class UDSHTTP(httplib.HTTP): |
| _connection_class = UDSHTTPConnection |
| |
| class UDSTransport(xmlrpclib.Transport): |
| def __init__(self, use_datetime=0): |
| self._use_datetime = use_datetime |
| self._extra_headers=[] |
| def add_extra_header(self, key, value): |
| self._extra_headers += [ (key,value) ] |
| def make_connection(self, host): |
| return UDSHTTP(host) |
| def send_request(self, connection, handler, request_body): |
| connection.putrequest("POST", handler) |
| for key, value in self._extra_headers: |
| connection.putheader(key, value) |
| |
| class Session(xmlrpclib.ServerProxy): |
| """A server proxy and session manager for communicating with xapi using |
| the Xen-API. |
| |
| Example: |
| |
| session = Session('http://localhost/') |
| session.login_with_password('me', 'mypassword') |
| session.xenapi.VM.start(vm_uuid) |
| session.xenapi.session.logout() |
| """ |
| |
| def __init__(self, uri, transport=None, encoding=None, verbose=0, |
| allow_none=1): |
| xmlrpclib.ServerProxy.__init__(self, uri, transport, encoding, |
| verbose, allow_none) |
| self.transport = transport |
| self._session = None |
| self.last_login_method = None |
| self.last_login_params = None |
| self.API_version = API_VERSION_1_1 |
| |
| |
| def xenapi_request(self, methodname, params): |
| if methodname.startswith('login'): |
| self._login(methodname, params) |
| return None |
| elif methodname == 'logout' or methodname == 'session.logout': |
| self._logout() |
| return None |
| else: |
| retry_count = 0 |
| while retry_count < 3: |
| full_params = (self._session,) + params |
| result = _parse_result(getattr(self, methodname)(*full_params)) |
| if result == _RECONNECT_AND_RETRY: |
| retry_count += 1 |
| if self.last_login_method: |
| self._login(self.last_login_method, |
| self.last_login_params) |
| else: |
| raise xmlrpclib.Fault(401, 'You must log in') |
| else: |
| return result |
| raise xmlrpclib.Fault( |
| 500, 'Tried 3 times to get a valid session, but failed') |
| |
| |
| def _login(self, method, params): |
| result = _parse_result(getattr(self, 'session.%s' % method)(*params)) |
| if result == _RECONNECT_AND_RETRY: |
| raise xmlrpclib.Fault( |
| 500, 'Received SESSION_INVALID when logging in') |
| self._session = result |
| self.last_login_method = method |
| self.last_login_params = params |
| self.API_version = self._get_api_version() |
| |
| def _logout(self): |
| try: |
| if self.last_login_method.startswith("slave_local"): |
| return _parse_result(self.session.local_logout(self._session)) |
| else: |
| return _parse_result(self.session.logout(self._session)) |
| finally: |
| self._session = None |
| self.last_login_method = None |
| self.last_login_params = None |
| self.API_version = API_VERSION_1_1 |
| |
| def _get_api_version(self): |
| pool = self.xenapi.pool.get_all()[0] |
| host = self.xenapi.pool.get_master(pool) |
| major = self.xenapi.host.get_API_version_major(host) |
| minor = self.xenapi.host.get_API_version_minor(host) |
| return "%s.%s"%(major,minor) |
| |
| def __getattr__(self, name): |
| if name == 'handle': |
| return self._session |
| elif name == 'xenapi': |
| return _Dispatcher(self.API_version, self.xenapi_request, None) |
| elif name.startswith('login') or name.startswith('slave_local'): |
| return lambda *params: self._login(name, params) |
| else: |
| return xmlrpclib.ServerProxy.__getattr__(self, name) |
| |
| def xapi_local(): |
| return Session("http://_var_xapi_xapi/", transport=UDSTransport()) |
| |
| def _parse_result(result): |
| if type(result) != dict or 'Status' not in result: |
| raise xmlrpclib.Fault(500, 'Missing Status in response from server' + result) |
| if result['Status'] == 'Success': |
| if 'Value' in result: |
| return result['Value'] |
| else: |
| raise xmlrpclib.Fault(500, |
| 'Missing Value in response from server') |
| else: |
| if 'ErrorDescription' in result: |
| if result['ErrorDescription'][0] == 'SESSION_INVALID': |
| return _RECONNECT_AND_RETRY |
| else: |
| raise Failure(result['ErrorDescription']) |
| else: |
| raise xmlrpclib.Fault( |
| 500, 'Missing ErrorDescription in response from server') |
| |
| |
| # Based upon _Method from xmlrpclib. |
| class _Dispatcher: |
| def __init__(self, API_version, send, name): |
| self.__API_version = API_version |
| self.__send = send |
| self.__name = name |
| |
| def __repr__(self): |
| if self.__name: |
| return '<XenAPI._Dispatcher for %s>' % self.__name |
| else: |
| return '<XenAPI._Dispatcher>' |
| |
| def __getattr__(self, name): |
| if self.__name is None: |
| return _Dispatcher(self.__API_version, self.__send, name) |
| else: |
| return _Dispatcher(self.__API_version, self.__send, "%s.%s" % (self.__name, name)) |
| |
| def __call__(self, *args): |
| return self.__send(self.__name, args) |