diff --git a/server/src/uds/services/Xen/xen_client/XenAPI.py b/server/src/uds/services/Xen/xen_client/XenAPI.py deleted file mode 100644 index 3204181d6..000000000 --- a/server/src/uds/services/Xen/xen_client/XenAPI.py +++ /dev/null @@ -1,293 +0,0 @@ -# Copyright (c) Citrix Systems, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1) Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2) Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -------------------------------------------------------------------- -# Parts of this file are based upon xmlrpclib.py, the XML-RPC client -# interface included in the Python distribution. -# -# Copyright (c) 1999-2002 by Secret Labs AB -# Copyright (c) 1999-2002 by Fredrik Lundh -# -# By obtaining, using, and/or copying this software and/or its -# associated documentation, you agree that you have read, understood, -# and will comply with the following terms and conditions: -# -# Permission to use, copy, modify, and distribute this software and -# its associated documentation for any purpose and without fee is -# hereby granted, provided that the above copyright notice appears in -# all copies, and that both that copyright notice and this permission -# notice appear in supporting documentation, and that the name of -# Secret Labs AB or the author not be used in advertising or publicity -# pertaining to distribution of the software without specific, written -# 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. -# -------------------------------------------------------------------- - -# Fixes and adaption by agomez@virtualcable.net - -import ssl -import gettext -import xmlrpc.client as xmlrpclib -import http.client as httplib -import socket -import sys -import typing - -translation = gettext.translation('xen-xm', fallback=True) - -API_VERSION_1_1 = '1.1' -API_VERSION_1_2 = '1.2' - - -class Failure(Exception): - details: typing.List[typing.Any] - - def __init__(self, details: typing.List[typing.Any]): - super().__init__() - self.details = details - - def __str__(self): - try: - return str(self.details) - except Exception as exn: - msg = "Xen-API failure: %s" % exn - sys.stderr.write(msg) - return msg - - def _details_map(self): - # dict([(str(i), self.details[i]) for i in range(len(self.details))]) - return {str(i): d for i, d in enumerate(self.details)} - - -# Just a "constant" that we use to decide whether to retry the RPC -_RECONNECT_AND_RETRY = object() - - -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.HTTPConnection): - _connection_class = UDSHTTPConnection - - -class UDSTransport(xmlrpclib.Transport): - _use_datetime: bool - _extra_headers: typing.List[typing.Tuple[str, str]] - _connection: typing.Tuple[typing.Any, typing.Any] - - def __init__(self, use_datetime: bool = False): - super().__init__() - self._use_datetime = use_datetime - self._extra_headers = [] - self._connection = (None, None) - - def add_extra_header(self, key: str, value: str) -> None: - self._extra_headers += [(key, value)] - - def make_connection(self, host: str) -> httplib.HTTPConnection: # type: ignore # In our case, host is always an string - return UDSHTTPConnection(host) - - def send_request( - self, connection, handler, request_body, debug - ): # pylint: disable=arguments-differ - 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', '1.0', 'xen-api-scripts-xenapi.py') - session.xenapi.VM.start(vm_uuid) - session.xenapi.session.logout() - """ - - def __init__( - self, - uri, - transport=None, - encoding=None, - verbose=0, - allow_none=1, - ignore_ssl=False, - ): - - # Fix for CA-172901 (+ Python 2.4 compatibility) - # Fix for context=ctx ( < Python 2.7.9 compatibility) - if ( - not ( - sys.version_info[0] <= 2 - and sys.version_info[1] <= 7 - and sys.version_info[2] <= 9 - ) - and ignore_ssl - ): - ctx = ssl._create_unverified_context() # nosec: Xen Server will not have a valid cert - xmlrpclib.ServerProxy.__init__( - self, uri, transport, encoding, bool(verbose), bool(allow_none), context=ctx - ) - else: - xmlrpclib.ServerProxy.__init__( - self, uri, transport, encoding, bool(verbose), bool(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 is _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): - try: - result = _parse_result(getattr(self, 'session.%s' % method)(*params)) - if result is _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() - except TimeoutError as e: - raise xmlrpclib.Fault(504, 'The connection timed out') - except socket.error: - raise - - def _logout(self): - try: - if self.last_login_method.startswith("slave_local"): # type: ignore - return _parse_result(self.session.local_logout(self._session)) # type: ignore - else: - return _parse_result(self.session.logout(self._session)) # type: ignore - 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] # type: ignore - host = self.xenapi.pool.get_master(pool) # type: ignore - major = self.xenapi.host.get_API_version_major(host) # type: ignore - minor = self.xenapi.host.get_API_version_minor(host) # type: ignore - 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) - elif name == 'logout': - return _Dispatcher(self.API_version, self.xenapi_request, "logout") - else: - return xmlrpclib.ServerProxy.__getattr__(self, name) - - -def xapi_local(): - return Session("http://_var_lib_xcp_xapi/", transport=UDSTransport()) - - -def _parse_result(result): - if not isinstance(result, dict) or 'Status' not in result: - raise xmlrpclib.Fault( - 500, 'Missing Status in response from server: {}'.format(result) - ) - if result['Status'] == 'Success': - if 'Value' in result: - return result['Value'] - raise xmlrpclib.Fault(500, 'Missing Value in response from server') - - if 'ErrorDescription' in result: - if result['ErrorDescription'][0] == 'SESSION_INVALID': - return _RECONNECT_AND_RETRY - raise Failure(result['ErrorDescription']) - 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 '' % self.__name - return '' - - 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) diff --git a/server/src/uds/services/Xen/xen_client/__init__.py b/server/src/uds/services/Xen/xen_client/__init__.py index 2c15e765e..ac4bd9900 100644 --- a/server/src/uds/services/Xen/xen_client/__init__.py +++ b/server/src/uds/services/Xen/xen_client/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (c) 2014-2019 Virtual Cable S.L. +# Copyright (c) 2014-2023 Virtual Cable S.L.U. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, @@ -30,7 +30,8 @@ import xmlrpc.client import logging import typing -from . import XenAPI +import XenAPI + logger = logging.getLogger(__name__) @@ -193,7 +194,9 @@ class XenServer: # pylint: disable=too-many-public-methods self._loggedIn = True self._apiVersion = self._session.API_version self._poolName = str(self.getPoolName()) - except XenAPI.Failure as e: # XenAPI.Failure: ['HOST_IS_SLAVE', '172.27.0.29'] indicates that this host is an slave of 172.27.0.29, connect to it... + except ( + XenAPI.Failure + ) as e: # XenAPI.Failure: ['HOST_IS_SLAVE', '172.27.0.29'] indicates that this host is an slave of 172.27.0.29, connect to it... if switchToMaster and e.details[0] == 'HOST_IS_SLAVE': logger.info( '%s is an Slave, connecting to master at %s', @@ -259,11 +262,7 @@ class XenServer: # pylint: disable=too-many-public-methods status = 'failure' # Removes if present - if ( - result - and not isinstance(result, XenFailure) - and result.startswith('') - ): + if result and not isinstance(result, XenFailure) and result.startswith(''): result = result[7:-8] if destroyTask: @@ -279,11 +278,7 @@ class XenServer: # pylint: disable=too-many-public-methods # Only valid SR shared, non iso name_label = self.SR.get_name_label(srId) # Skip non valid... - if ( - self.SR.get_content_type(srId) == 'iso' - or self.SR.get_shared(srId) is False - or name_label == '' - ): + if self.SR.get_content_type(srId) == 'iso' or self.SR.get_shared(srId) is False or name_label == '': continue valid = True @@ -310,12 +305,7 @@ class XenServer: # pylint: disable=too-many-public-methods def getNetworks(self) -> typing.Iterable[typing.MutableMapping[str, typing.Any]]: for netId in self.network.get_all(): - if ( - self.network.get_other_config(netId).get( - 'is_host_internal_management_network', False - ) - is False - ): + if self.network.get_other_config(netId).get('is_host_internal_management_network', False) is False: yield { 'id': netId, 'name': self.network.get_name_label(netId), @@ -408,9 +398,7 @@ class XenServer: # pylint: disable=too-many-public-methods return self.Async.VM.resume(vmId, False, False) return self.VM.resume(vmId, False, False) - def cloneVM( - self, vmId: str, targetName: str, targetSR: typing.Optional[str] = None - ) -> str: + def cloneVM(self, vmId: str, targetName: str, targetSR: typing.Optional[str] = None) -> str: """ If targetSR is NONE: Clones the specified VM, making a new VM. @@ -430,15 +418,11 @@ class XenServer: # pylint: disable=too-many-public-methods try: if targetSR: if 'copy' not in operations: - raise XenException( - 'Copy is not supported for this machine (maybe it\'s powered on?)' - ) + raise XenException('Copy is not supported for this machine (maybe it\'s powered on?)') task = self.Async.VM.copy(vmId, targetName, targetSR) else: if 'clone' not in operations: - raise XenException( - 'Clone is not supported for this machine (maybe it\'s powered on?)' - ) + raise XenException('Clone is not supported for this machine (maybe it\'s powered on?)') task = self.Async.VM.clone(vmId, targetName) return task except XenAPI.Failure as e: @@ -528,9 +512,7 @@ class XenServer: # pylint: disable=too-many-public-methods operations = self.VM.get_allowed_operations(vmId) logger.debug('Allowed operations: %s', operations) if 'make_into_template' not in operations: - raise XenException( - 'Convert in template is not supported for this machine' - ) + raise XenException('Convert in template is not supported for this machine') self.VM.set_is_a_template(vmId, True) # Apply that is an "UDS Template" taggint it @@ -546,7 +528,7 @@ class XenServer: # pylint: disable=too-many-public-methods try: self.VM.set_HVM_shadow_multiplier(vmId, float(shadowMultiplier)) except Exception: # nosec: Can't set shadowMultiplier, nothing happens - pass + pass except XenAPI.Failure as e: raise XenFailure(e.details)