From 320a530bbc2221464aba163e9c3c3293985fec0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20G=C3=B3mez=20Garc=C3=ADa?= Date: Tue, 28 Mar 2017 15:12:14 +0200 Subject: [PATCH] Several fixes so we can check availability of spice transport BEFORE user tries to access it. --- .../uds/services/OpenNebula/LiveService.py | 9 ++++++- .../src/uds/services/OpenNebula/Provider.py | 8 +++++- .../uds/services/OpenNebula/on/__init__.py | 26 ++++++++++++++----- server/src/uds/services/OpenNebula/on/vm.py | 14 +++++++++- .../transports/SPICE/BaseSPICETransport.py | 25 +++++++++++++++--- 5 files changed, 69 insertions(+), 13 deletions(-) diff --git a/server/src/uds/services/OpenNebula/LiveService.py b/server/src/uds/services/OpenNebula/LiveService.py index d4d00d4a3..0b9df432b 100644 --- a/server/src/uds/services/OpenNebula/LiveService.py +++ b/server/src/uds/services/OpenNebula/LiveService.py @@ -40,7 +40,7 @@ from uds.core.ui import gui import logging -__updated__ = '2017-02-02' +__updated__ = '2017-03-28' logger = logging.getLogger(__name__) @@ -214,6 +214,13 @@ class LiveService(Service): ''' return self.parent().getMachineState(machineId) + def getMachineSubState(self, machineId): + ''' + On OpenNebula, the machine can be "active" but not "running". + Any active machine will have a LCM_STATE, that is what we get here + ''' + return self.parent().getMachineSubState(machineId) + def startMachine(self, machineId): ''' Tries to start a machine. No check is done, it is simply requested to OpenNebula. diff --git a/server/src/uds/services/OpenNebula/Provider.py b/server/src/uds/services/OpenNebula/Provider.py index f0300d2f7..b8717afff 100644 --- a/server/src/uds/services/OpenNebula/Provider.py +++ b/server/src/uds/services/OpenNebula/Provider.py @@ -50,7 +50,7 @@ import six # Python bindings for OpenNebula # import oca -__updated__ = '2016-11-24' +__updated__ = '2017-03-28' logger = logging.getLogger(__name__) @@ -188,6 +188,12 @@ class Provider(ServiceProvider): ''' return on.vm.getMachineState(self.api, machineId) + def getMachineSubState(self, machineId): + ''' + Returns the LCM_STATE of a machine (must be ready) + ''' + return on.vm.getMachineSubstate(self.api, machineId) + def startMachine(self, machineId): ''' diff --git a/server/src/uds/services/OpenNebula/on/__init__.py b/server/src/uds/services/OpenNebula/on/__init__.py index 6915eb22a..847c2081f 100644 --- a/server/src/uds/services/OpenNebula/on/__init__.py +++ b/server/src/uds/services/OpenNebula/on/__init__.py @@ -40,10 +40,10 @@ import re import logging import six -import xmlrpclib +import six from uds.core.util import xml2dict -__updated__ = '2017-03-27' +__updated__ = '2017-03-28' logger = logging.getLogger(__name__) @@ -64,6 +64,7 @@ from . import template from . import vm from . import storage + # Decorator def ensureConnected(fnc): def inner(*args, **kwargs): @@ -71,19 +72,22 @@ def ensureConnected(fnc): return fnc(*args, **kwargs) return inner + # Result checker def checkResult(lst, parseResult=True): - if lst[0] == False: + if not lst[0]: raise Exception('OpenNebula error {}: "{}"'.format(lst[2], lst[1])) if parseResult: return xml2dict.parse(lst[1]) else: return lst[1] + def asList(element): if isinstance(element, (tuple, list)): return element - return (element,) + return element, + class OpenNebulaClient(object): def __init__(self, username, password, endpoint): @@ -111,7 +115,7 @@ class OpenNebulaClient(object): if self.connection is not None: return - self.connection = xmlrpclib.ServerProxy(self.endpoint) + self.connection = six.moves.xmlrpc_client.ServerProxy(self.endpoint) # @UndefinedVariable @ensureConnected def enumStorage(self, storageType=0): @@ -297,12 +301,20 @@ class OpenNebulaClient(object): return int(checkResult(result)['VM']['STATE']) @ensureConnected - def getVMLCMState(self, vmId): + def getVMSubstate(self, vmId): ''' Returns the VM State ''' result = self.connection.one.vm.info(self.sessionString, int(vmId)) - return int(checkResult(result)['VM']['LCM_STATE']) + r = checkResult(result) + try: + if int(r['VM']['STATE']) == VmState.ACTIVE: + return int(r['VM']['LCM_STATE']) + # Substate is not available if VM state is not active + return -1 + except Exception: + logger.exception('getVMSubstate') + return -1 @ensureConnected def VMAction(self, vmId, action): diff --git a/server/src/uds/services/OpenNebula/on/vm.py b/server/src/uds/services/OpenNebula/on/vm.py index 8efde47d2..6777d0964 100644 --- a/server/src/uds/services/OpenNebula/on/vm.py +++ b/server/src/uds/services/OpenNebula/on/vm.py @@ -39,7 +39,7 @@ from defusedxml import minidom # Python bindings for OpenNebula from .common import VmState -__updated__ = '2017-03-03' +__updated__ = '2017-03-28' logger = logging.getLogger(__name__) @@ -66,6 +66,18 @@ def getMachineState(api, machineId): return VmState.UNKNOWN +def getMachineSubstate(api, machineId): + ''' + Returns the lcm_state + ''' + try: + return api.getVMSubState(machineId) + except Exception as e: + logger.error('Error obtaining machine state for {} on opennebula: {}'.format(machineId, e)) + + return VmState.UNKNOWN + + def startMachine(api, machineId): ''' Tries to start a machine. No check is done, it is simply requested to OpenNebula. diff --git a/server/src/uds/transports/SPICE/BaseSPICETransport.py b/server/src/uds/transports/SPICE/BaseSPICETransport.py index c2cafddce..b7d30e64e 100644 --- a/server/src/uds/transports/SPICE/BaseSPICETransport.py +++ b/server/src/uds/transports/SPICE/BaseSPICETransport.py @@ -44,7 +44,7 @@ from uds.services.OVirt.OVirtProvider import Provider as oVirtProvider import logging import os -__updated__ = '2017-02-21' +__updated__ = '2017-03-28' logger = logging.getLogger(__name__) @@ -99,8 +99,27 @@ class BaseSpiceTransport(Transport): Checks if the transport is available for the requested destination ip Override this in yours transports ''' - logger.debug('Checking availability for {0}'.format(ip)) - return True # Spice is available, no matter what IP machine has (even if it does not have one) + ready = self.cache.get(ip) + if ready is None: + userServiceInstance = userService.getInstance() + con = userServiceInstance.getConsoleConnection() + + logger.debug('Connection data: {}'.format(con)) + + port, secure_port = con['port'], con['secure_port'] + port = -1 if port is None else port + secure_port = -1 if secure_port is None else secure_port + + # test ANY of the ports + port_to_test = port if port != -1 else secure_port + if port_to_test == -1: + logger.info('SPICE didn\'t find has any port: {}'.format(con)) + return False + + if connection.testServer(ip, port_to_test) is True: + self.cache.put(ip, 'Y', READY_CACHE_TIMEOUT) + + return ready == 'Y' def processedUser(self, userService, userName): v = self.processUserPassword(userService, userName, '')