Upgrade OpenNebula

This commit is contained in:
Adolfo Gómez García 2019-11-08 11:29:12 +01:00
parent ce91840622
commit 103ad93cdf
9 changed files with 190 additions and 223 deletions

View File

@ -49,10 +49,6 @@ if typing.TYPE_CHECKING:
from uds.core import Module
from uds.core.environment import Environment
__updated__ = '2017-10-16'
logger = logging.getLogger(__name__)
class OGProvider(ServiceProvider):

View File

@ -28,5 +28,4 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from .Provider import Provider
from .provider import OpenNebulaProvider

View File

@ -40,6 +40,12 @@ from uds.core.util import log
from . import on
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
from uds import models
from .service import LiveService
from .publication import LivePublication
from uds.core.util.storage import Storage
logger = logging.getLogger(__name__)
@ -62,11 +68,11 @@ class LiveDeployment(UserDeployment):
suggestedTime = 6
#
_name = ''
_ip = ''
_mac = ''
_vmid = ''
_reason = ''
_name: str = ''
_ip: str = ''
_mac: str = ''
_vmid: str = ''
_reason: str = ''
_queue: typing.List[int] = []
@ -78,8 +84,17 @@ class LiveDeployment(UserDeployment):
self._reason = ''
self._queue = []
def service(self) -> 'LiveService':
return typing.cast('LiveService', super().service())
def publication(self) -> 'LivePublication':
pub = super().publication()
if pub is None:
raise Exception('No publication for this element!')
return typing.cast('LivePublication', pub)
# Serializable needed methods
def marshal(self):
def marshal(self) -> bytes:
"""
Does nothing right here, we will use envoronment storage in this sample
"""
@ -93,7 +108,7 @@ class LiveDeployment(UserDeployment):
pickle.dumps(self._queue, protocol=0)
])
def unmarshal(self, data):
def unmarshal(self, data: bytes) -> None:
"""
Does nothing here also, all data are keeped at environment storage
"""
@ -106,7 +121,7 @@ class LiveDeployment(UserDeployment):
self._reason = vals[5].decode('utf8')
self._queue = pickle.loads(vals[6])
def getName(self):
def getName(self) -> str:
"""
We override this to return a name to display. Default inplementation
(in base class), returns getUniqueIde() value
@ -134,7 +149,7 @@ class LiveDeployment(UserDeployment):
return NO_MORE_NAMES
return self._name
def setIp(self, ip):
def setIp(self, ip: str) -> None:
"""
In our case, there is no OS manager associated with this, so this method
will never get called, but we put here as sample.
@ -149,7 +164,7 @@ class LiveDeployment(UserDeployment):
logger.debug('Setting IP to %s', ip)
self._ip = ip
def getUniqueId(self):
def getUniqueId(self) -> str:
"""
Return and unique identifier for this service.
In our case, we will generate a mac name, that can be also as sample
@ -161,7 +176,7 @@ class LiveDeployment(UserDeployment):
"""
return self._mac.upper()
def getIp(self):
def getIp(self) -> str:
"""
We need to implement this method, so we can return the IP for transports
use. If no IP is known for this service, this must return None
@ -181,7 +196,7 @@ class LiveDeployment(UserDeployment):
"""
return self._ip
def setReady(self):
def setReady(self) -> str:
"""
The method is invoked whenever a machine is provided to an user, right
before presenting it (via transport rendering) to the user.
@ -191,7 +206,7 @@ class LiveDeployment(UserDeployment):
state = self.service().getMachineState(self._vmid)
if state == on.VmState.UNKNOWN: # @UndefinedVariable
if state == on.types.VmState.UNKNOWN: # @UndefinedVariable
return self.__error('Machine is not available anymore')
self.service().startMachine(self._vmid)
@ -199,17 +214,17 @@ class LiveDeployment(UserDeployment):
self.cache.put('ready', '1')
return State.FINISHED
def reset(self):
def reset(self) -> None:
if self._vmid != '':
self.service().resetMachine(self._vmid)
def getConsoleConnection(self):
def getConsoleConnection(self) -> typing.Dict[str, typing.Any]:
return self.service().getConsoleConnection(self._vmid)
def desktopLogin(self, username, password, domain=''):
return self.service().desktopLogin(self._vmId, username, password, domain)
def desktopLogin(self, username: str, password: str, domain: str = ''):
return self.service().desktopLogin(self._vmid, username, password, domain)
def notifyReadyFromOsManager(self, data):
def notifyReadyFromOsManager(self, data: typing.Any) -> str:
# Here we will check for suspending the VM (when full ready)
logger.debug('Checking if cache 2 for %s', self._name)
if self.__getCurrentOp() == opWait:
@ -219,7 +234,7 @@ class LiveDeployment(UserDeployment):
# Do not need to go to level 2 (opWait is in fact "waiting for moving machine to cache level 2)
return State.FINISHED
def deployForUser(self, user):
def deployForUser(self, user: 'models.User') -> str:
"""
Deploys an service instance for an user.
"""
@ -227,26 +242,25 @@ class LiveDeployment(UserDeployment):
self.__initQueueForDeploy(False)
return self.__executeQueue()
def deployForCache(self, cacheLevel):
def deployForCache(self, cacheLevel: int) -> str:
"""
Deploys an service instance for cache
"""
self.__initQueueForDeploy(cacheLevel == self.L2_CACHE)
return self.__executeQueue()
def __initQueueForDeploy(self, forLevel2=False):
def __initQueueForDeploy(self, forLevel2: bool = False) -> None:
if forLevel2 is False:
self._queue = [opCreate, opStart, opFinish]
else:
self._queue = [opCreate, opStart, opWait, opSuspend, opFinish]
def __checkMachineState(self, chkState):
def __checkMachineState(self, chkState: on.types.VmState) -> str:
logger.debug('Checking that state of machine %s (%s) is %s', self._vmid, self._name, chkState)
state = self.service().getMachineState(self._vmid)
# If we want to check an state and machine does not exists (except in case that we whant to check this)
if state in [on.VmState.UNKNOWN, on.VmState.DONE]: # @UndefinedVariable
if state in [on.types.VmState.UNKNOWN, on.types.VmState.DONE]: # @UndefinedVariable
return self.__error('Machine not found')
ret = State.RUNNING
@ -260,46 +274,47 @@ class LiveDeployment(UserDeployment):
return ret
def __getCurrentOp(self):
def __getCurrentOp(self) -> int:
if not self._queue:
return opFinish
return self._queue[0]
def __popCurrentOp(self):
def __popCurrentOp(self) -> int:
if not self._queue:
return opFinish
res = self._queue.pop(0)
return res
def __pushFrontOp(self, op):
def __pushFrontOp(self, op) -> None:
self._queue.insert(0, op)
def __pushBackOp(self, op):
def __pushBackOp(self, op) -> None:
self._queue.append(op)
def __error(self, reason):
def __error(self, reason: typing.Any) -> str:
"""
Internal method to set object as error state
Returns:
State.ERROR, so we can do "return self.__error(reason)"
"""
reason = str(reason)
logger.debug('Setting error state, reason: %s', reason)
self.doLog(log.ERROR, reason)
if self._vmid != '': # Powers off & delete it
if self._vmid: # Powers off & delete it
try:
self.service().removeMachine(self._vmid)
except Exception:
logger.debug('Can\'t set machine state to stopped')
logger.warning('Can\'t set remove errored machine: %s', self._vmid)
self._queue = [opError]
self._reason = str(reason)
return State.ERROR
def __executeQueue(self):
def __executeQueue(self) -> str:
self.__debug('executeQueue')
op = self.__getCurrentOp()
@ -309,7 +324,7 @@ class LiveDeployment(UserDeployment):
if op == opFinish:
return State.FINISHED
fncs = {
fncs: typing.Dict[int, typing.Optional[typing.Callable[[], str]]] = {
opCreate: self.__create,
opRetry: self.__retry,
opStart: self.__startMachine,
@ -319,7 +334,7 @@ class LiveDeployment(UserDeployment):
}
try:
execFnc = fncs.get(op, None)
execFnc: typing.Optional[typing.Callable[[], str]] = fncs.get(op, None)
if execFnc is None:
return self.__error('Unknown operation found at execution queue ({0})'.format(op))
@ -332,7 +347,7 @@ class LiveDeployment(UserDeployment):
return self.__error(e)
# Queue execution methods
def __retry(self):
def __retry(self) -> str:
"""
Used to retry an operation
In fact, this will not be never invoked, unless we push it twice, because
@ -342,13 +357,13 @@ class LiveDeployment(UserDeployment):
"""
return State.FINISHED
def __wait(self):
def __wait(self) -> str:
"""
Executes opWait, it simply waits something "external" to end
"""
return State.RUNNING
def __create(self):
def __create(self) -> str:
"""
Deploys a machine from template for user/cache
"""
@ -366,62 +381,68 @@ class LiveDeployment(UserDeployment):
# Get IP & MAC (early stage)
self._mac, self._ip = self.service().getNetInfo(self._vmid)
def __remove(self):
return State.RUNNING
def __remove(self) -> str:
"""
Removes a machine from system
"""
state = self.service().getMachineState(self._vmid)
if state == on.VmState.UNKNOWN: # @UndefinedVariable
if state == on.types.VmState.UNKNOWN: # @UndefinedVariable
raise Exception('Machine not found')
if state == on.VmState.ACTIVE: # @UndefinedVariable
if state == on.types.VmState.ACTIVE: # @UndefinedVariable
subState = self.service().getMachineSubstate(self._vmid)
if subState < 3: # Less than running
logger.info('Must wait before remove: %s', subState)
self.__pushFrontOp(opRetry)
return
return State.RUNNING
self.service().removeMachine(self._vmid)
def __startMachine(self):
return State.RUNNING
def __startMachine(self) -> str:
"""
Powers on the machine
"""
self.service().startMachine(self._vmid)
return State.RUNNING
def __suspendMachine(self):
def __suspendMachine(self) -> str:
"""
Suspends the machine
"""
self.service().suspendMachine(self._vmid)
return State.RUNNING
# Check methods
def __checkCreate(self):
def __checkCreate(self) -> str:
"""
Checks the state of a deploy for an user or cache
"""
return self.__checkMachineState(on.VmState.ACTIVE) # @UndefinedVariable
return self.__checkMachineState(on.types.VmState.ACTIVE) # @UndefinedVariable
def __checkStart(self):
def __checkStart(self) -> str:
"""
Checks if machine has started
"""
return self.__checkMachineState(on.VmState.ACTIVE) # @UndefinedVariable
return self.__checkMachineState(on.types.VmState.ACTIVE) # @UndefinedVariable
def __checkSuspend(self):
def __checkSuspend(self) -> str:
"""
Check if the machine has suspended
"""
return self.__checkMachineState(on.VmState.SUSPENDED) # @UndefinedVariable
return self.__checkMachineState(on.types.VmState.SUSPENDED) # @UndefinedVariable
def __checkRemoved(self):
def __checkRemoved(self) -> str:
"""
Checks if a machine has been removed
"""
return State.FINISHED # No check at all, always true
def checkState(self):
def checkState(self) -> str:
"""
Check what operation is going on, and acts based on it
"""
@ -434,7 +455,7 @@ class LiveDeployment(UserDeployment):
if op == opFinish:
return State.FINISHED
fncs = {
fncs: typing.Dict[int, typing.Optional[typing.Callable[[], str]]] = {
opCreate: self.__checkCreate,
opRetry: self.__retry,
opWait: self.__wait,
@ -444,7 +465,7 @@ class LiveDeployment(UserDeployment):
}
try:
chkFnc = fncs.get(op, None)
chkFnc: typing.Optional[typing.Callable[[], str]] = fncs.get(op, None)
if chkFnc is None:
return self.__error('Unknown operation found at check queue ({0})'.format(op))
@ -458,14 +479,7 @@ class LiveDeployment(UserDeployment):
except Exception as e:
return self.__error(e)
def finish(self):
"""
Invoked when the core notices that the deployment of a service has finished.
(No matter wether it is for cache or for an user)
"""
self.__debug('finish')
def moveToCache(self, newLevel):
def moveToCache(self, newLevel: int) -> str:
"""
Moves machines between cache levels
"""
@ -479,7 +493,7 @@ class LiveDeployment(UserDeployment):
return self.__executeQueue()
def reasonOfError(self):
def reasonOfError(self) -> str:
"""
Returns the reason of the error.
@ -489,7 +503,7 @@ class LiveDeployment(UserDeployment):
"""
return self._reason
def destroy(self):
def destroy(self) -> str:
"""
Invoked for destroying a deployed service
"""
@ -509,7 +523,7 @@ class LiveDeployment(UserDeployment):
# Do not execute anything.here, just continue normally
return State.RUNNING
def cancel(self):
def cancel(self) -> str:
"""
This is a task method. As that, the excepted return values are
State values RUNNING, FINISHED or ERROR.
@ -522,7 +536,7 @@ class LiveDeployment(UserDeployment):
return self.destroy()
@staticmethod
def __op2str(op):
def __op2str(op) -> str:
return {
opCreate: 'create',
opStart: 'start',
@ -534,9 +548,5 @@ class LiveDeployment(UserDeployment):
opRetry: 'retry',
}.get(op, '????')
def __debug(self, txt):
logger.debug('_name %s: %s', txt, self._name)
logger.debug('_ip %s: %s', txt, self._ip)
logger.debug('_mac %s: %s', txt, self._mac)
logger.debug('_vmid %s: %s', txt, self._vmid)
logger.debug('Queue at %s: %s', txt, [LiveDeployment.__op2str(op) for op in self._queue])
def __debug(self, txt: str) -> None:
logger.debug('State at %s: name: %s, ip: %s, mac: %s, vmid:%s, queue: %s', txt, self._name, self._ip, self._mac, self._vmid, [LiveDeployment.__op2str(op) for op in self._queue])

View File

@ -2,6 +2,6 @@ from . import storage
from . import template
from . import vm
from . import client
from . import types
# Import common
from .common import VmState, ImageState, sanitizeName
from .common import sanitizeName

View File

@ -62,7 +62,7 @@ def checkResultRaw(lst: typing.List) -> str:
if not lst[0]:
raise Exception('OpenNebula error {}: "{}"'.format(lst[2], lst[1]))
return lst[1]
return str(lst[1])
def checkResult(lst: typing.List) -> typing.Tuple[typing.Dict, str]:

View File

@ -175,12 +175,12 @@ def enumerateMachines(api: 'client.OpenNebulaClient') -> typing.Iterable[types.V
yield from api.enumVMs()
def getNetInfo(api, machineId, networkId=None):
def getNetInfo(api: 'client.OpenNebulaClient', machineId: str, networkId: typing.Optional[str] = None) -> typing.Tuple[str, str]:
'''
Changes the mac address of first nic of the machine to the one specified
Get the MAC and the IP for the network and machine. If network is None, for the first network
'''
# md = minidom.parseString(api.call('vm.info', int(machineId)))
md = minidom.parseString(api.VMInfo(machineId)[1])
md = minidom.parseString(api.VMInfo(machineId).xml)
node = md
try:
@ -206,12 +206,12 @@ def getNetInfo(api, machineId, networkId=None):
raise Exception('No network interface found on template. Please, add a network and republish.')
def getDisplayConnection(api, machineId):
def getDisplayConnection(api: 'client.OpenNebulaClient', machineId: str) -> typing.Optional[typing.Dict[str, typing.Any]]:
'''
If machine is not running or there is not a display, will return NONE
SPICE connections should check that 'type' is 'SPICE'
'''
md = minidom.parseString(api.VMInfo(machineId)[1])
md = minidom.parseString(api.VMInfo(machineId).xml)
try:
graphics = md.getElementsByTagName('GRAPHICS')[0]

View File

@ -38,29 +38,18 @@ from uds.core.services import ServiceProvider
from uds.core.ui import gui
from uds.core.util import validators
from .LiveService import LiveService
from .service import LiveService
from . import on
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
from uds.core import Module
from uds.core.environment import Environment
logger = logging.getLogger(__name__)
class Provider(ServiceProvider): # pylint: disable=too-many-public-methods
'''
This class represents the sample services provider
In this class we provide:
* The Provider functionality
* The basic configuration parameters for the provider
* The form fields needed by administrators to configure this provider
:note: At class level, the translation must be simply marked as so
using ugettext_noop. This is so cause we will translate the string when
sent to the administration client.
For this class to get visible at administration client as a provider type,
we MUST register it at package __init__.
'''
class OpenNebulaProvider(ServiceProvider): # pylint: disable=too-many-public-methods
# : What kind of services we offer, this are classes inherited from Service
offers = [LiveService]
# : Name to show the administrator. This string will be translated BEFORE
@ -99,7 +88,7 @@ class Provider(ServiceProvider): # pylint: disable=too-many-public-methods
# Own variables
_api: typing.Optional[on.client.OpenNebulaClient] = None
def initialize(self, values=None):
def initialize(self, values: 'Module.ValuesType') -> None:
'''
We will use the "autosave" feature for form fields
'''
@ -120,16 +109,15 @@ class Provider(ServiceProvider): # pylint: disable=too-many-public-methods
if self._api is None:
self._api = on.client.OpenNebulaClient(self.username.value, self.password.value, self.endpoint)
logger.debug('Api: %s', self._api)
return self._api
def resetApi(self):
def resetApi(self) -> None:
self._api = None
def sanitizeVmName(self, name):
def sanitizeVmName(self, name: str) -> str:
return on.sanitizeName(name)
def testConnection(self):
def testConnection(self) -> typing.List[typing.Any]:
'''
Test that conection to OpenNebula server is fine
@ -146,25 +134,25 @@ class Provider(ServiceProvider): # pylint: disable=too-many-public-methods
return [True, _('Opennebula test connection passed')]
def getDatastores(self, datastoreType=0):
return on.storage.enumerateDatastores(self.api, datastoreType)
def getDatastores(self, datastoreType: int = 0) -> typing.Iterable[on.types.StorageType]:
yield from on.storage.enumerateDatastores(self.api, datastoreType)
def getTemplates(self, force=False):
return on.template.getTemplates(self.api, force)
def getTemplates(self, force: bool = False) -> typing.Iterable[on.types.TemplateType]:
yield from on.template.getTemplates(self.api, force)
def makeTemplate(self, fromTemplateId, name, toDataStore):
def makeTemplate(self, fromTemplateId: str, name, toDataStore: str) -> str:
return on.template.create(self.api, fromTemplateId, name, toDataStore)
def checkTemplatePublished(self, templateId):
def checkTemplatePublished(self, templateId: str) -> bool:
return on.template.checkPublished(self.api, templateId)
def removeTemplate(self, templateId):
return on.template.remove(self.api, templateId)
def removeTemplate(self, templateId: str) -> None:
on.template.remove(self.api, templateId)
def deployFromTemplate(self, name, templateId):
def deployFromTemplate(self, name: str, templateId: str) -> str:
return on.template.deployFrom(self.api, templateId, name)
def getMachineState(self, machineId):
def getMachineState(self, machineId: str) -> on.types.VmState:
'''
Returns the state of the machine
This method do not uses cache at all (it always tries to get machine state from OpenNebula server)
@ -177,13 +165,13 @@ class Provider(ServiceProvider): # pylint: disable=too-many-public-methods
'''
return on.vm.getMachineState(self.api, machineId)
def getMachineSubstate(self, machineId):
def getMachineSubstate(self, machineId: str) -> int:
'''
Returns the LCM_STATE of a machine (must be ready)
Returns the LCM_STATE of a machine (STATE must be ready or this will return -1)
'''
return on.vm.getMachineSubstate(self.api, machineId)
def startMachine(self, machineId):
def startMachine(self, machineId: str) -> None:
'''
Tries to start a machine. No check is done, it is simply requested to OpenNebula.
@ -195,9 +183,8 @@ class Provider(ServiceProvider): # pylint: disable=too-many-public-methods
Returns:
'''
on.vm.startMachine(self.api, machineId)
return True
def stopMachine(self, machineId):
def stopMachine(self, machineId: str) -> None:
'''
Tries to start a machine. No check is done, it is simply requested to OpenNebula
@ -207,9 +194,8 @@ class Provider(ServiceProvider): # pylint: disable=too-many-public-methods
Returns:
'''
on.vm.stopMachine(self.api, machineId)
return True
def suspendMachine(self, machineId):
def suspendMachine(self, machineId: str) -> None:
'''
Tries to start a machine. No check is done, it is simply requested to OpenNebula
@ -219,15 +205,14 @@ class Provider(ServiceProvider): # pylint: disable=too-many-public-methods
Returns:
'''
on.vm.suspendMachine(self.api, machineId)
return True
def resetMachine(self, machineId):
def resetMachine(self, machineId: str) -> None:
'''
Resets a machine (hard-reboot)
'''
on.vm.resetMachine(self.api, machineId)
def removeMachine(self, machineId):
def removeMachine(self, machineId: str) -> None:
'''
Tries to delete a machine. No check is done, it is simply requested to OpenNebula
@ -237,17 +222,19 @@ class Provider(ServiceProvider): # pylint: disable=too-many-public-methods
Returns:
'''
on.vm.removeMachine(self.api, machineId)
return True
def getNetInfo(self, machineId, networkId=None):
def getNetInfo(self, machineId: str, networkId: typing.Optional[str] = None) -> typing.Tuple[str, str]:
'''
Changes the mac address of first nic of the machine to the one specified
'''
return on.vm.getNetInfo(self.api, machineId, networkId)
def getConsoleConnection(self, machineId):
def getConsoleConnection(self, machineId: str) -> typing.Dict[str, typing.Any]:
display = on.vm.getDisplayConnection(self.api, machineId)
if display is None:
raise Exception('Invalid console connection on OpenNebula!!!')
return {
'type': display['type'],
'address': display['host'],
@ -261,27 +248,12 @@ class Provider(ServiceProvider): # pylint: disable=too-many-public-methods
}
}
def desktopLogin(self, machineId, username, password, domain):
def desktopLogin(self, machineId: str, username: str, password: str, domain: str):
'''
Not provided by OpenNebula API right now
'''
return
@staticmethod
def test(env, data):
'''
Test ovirt Connectivity
Args:
env: environment passed for testing (temporal environment passed)
data: data passed for testing (data obtained from the form
definition)
Returns:
Array of two elements, first is True of False, depending on test
(True is all right, false is error),
second is an String with error, preferably internacionalizated..
'''
return Provider(env, data).testConnection()
def test(env: 'Environment', data: 'Module.ValuesType') -> typing.List[typing.Any]:
return OpenNebulaProvider(env, data).testConnection()

View File

@ -31,10 +31,14 @@
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
"""
import logging
import typing
from uds.core.services import Publication
from uds.core.util.state import State
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
from .service import LiveService
logger = logging.getLogger(__name__)
@ -46,33 +50,21 @@ class LivePublication(Publication):
suggestedTime = 2 # : Suggested recheck time if publication is unfinished in seconds
_name = ''
_reason = ''
_templateId = ''
_state = ''
_name: str = ''
_reason: str = ''
_templateId: str = ''
_state: str = 'r'
def initialize(self):
"""
This method will be invoked by default __init__ of base class, so it gives
us the oportunity to initialize whataver we need here.
def service(self) -> 'LiveService':
return typing.cast('LiveService', super().service())
In our case, we setup a few attributes..
"""
# We do not check anything at marshal method, so we ensure that
# default values are correctly handled by marshal.
self._name = ''
self._reason = ''
self._templateId = ''
self._state = 'r'
def marshal(self):
def marshal(self) -> bytes:
"""
returns data from an instance of Sample Publication serialized
"""
return '\t'.join(['v1', self._name, self._reason, self._templateId, self._state]).encode('utf8')
def unmarshal(self, data):
def unmarshal(self, data: bytes) -> None:
"""
deserializes the data and loads it inside instance.
"""
@ -81,7 +73,7 @@ class LivePublication(Publication):
if vals[0] == 'v1':
self._name, self._reason, self._templateId, self._state = vals[1:]
def publish(self):
def publish(self) -> str:
"""
Realizes the publication of the service
"""
@ -98,14 +90,14 @@ class LivePublication(Publication):
return State.RUNNING
def checkState(self):
def checkState(self) -> str:
"""
Checks state of publication creation
"""
if self._state == 'running':
try:
if self.service().checkTemplatePublished(self._templateId) is False:
return
return State.RUNNING
self._state = 'ok'
except Exception as e:
self._state = 'error'
@ -120,12 +112,7 @@ class LivePublication(Publication):
self._state = 'ok'
return State.FINISHED
def finish(self):
"""
In our case, finish does nothing
"""
def reasonOfError(self):
def reasonOfError(self) -> str:
"""
If a publication produces an error, here we must notify the reason why
it happened. This will be called just after publish or checkState
@ -135,7 +122,7 @@ class LivePublication(Publication):
"""
return self._reason
def destroy(self):
def destroy(self) -> str:
"""
This is called once a publication is no more needed.
@ -156,7 +143,7 @@ class LivePublication(Publication):
return State.FINISHED
def cancel(self):
def cancel(self) -> str:
"""
Do same thing as destroy
"""
@ -166,7 +153,7 @@ class LivePublication(Publication):
# Methods provided below are specific for this publication
# and will be used by user deployments that uses this kind of publication
def getTemplateId(self):
def getTemplateId(self) -> str:
"""
Returns the template id associated with the publication
"""

View File

@ -31,6 +31,7 @@
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
"""
import logging
import typing
from django.utils.translation import ugettext_noop as _
from uds.core.transports import protocols
@ -38,9 +39,14 @@ from uds.core.services import Service, types as serviceTypes
from uds.core.util import tools
from uds.core.ui import gui
from .LivePublication import LivePublication
from .LiveDeployment import LiveDeployment
from .publication import LivePublication
from .deployment import LiveDeployment
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
from . import on
from .provider import OpenNebulaProvider
from uds.core import Module
logger = logging.getLogger(__name__)
@ -127,7 +133,7 @@ class LiveService(Service):
required=True
)
def initialize(self, values):
def initialize(self, values: 'Module.ValuesType') -> None:
"""
We check here form values to see if they are valid.
@ -137,37 +143,34 @@ class LiveService(Service):
if values:
tools.checkValidBasename(self.baseName.value, self.lenName.num())
def initGui(self):
def parent(self) -> 'OpenNebulaProvider':
return typing.cast('OpenNebulaProvider', super().parent())
def initGui(self) -> None:
"""
Loads required values inside
"""
templates = self.parent().getTemplates()
vals = []
for t in templates:
vals.append(gui.choiceItem(t[0], t[1]))
t: 'on.types.TemplateType'
self.template.setValues(
[gui.choiceItem(t.id, t.name) for t in self.parent().getTemplates()]
)
# This is not the same case, values is not the "value" of the field, but
# the list of values shown because this is a "ChoiceField"
self.template.setValues(vals)
d: 'on.types.StorageType'
self.datastore.setValues(
[gui.choiceItem(d.id, d.name) for d in self.parent().getDatastores()]
)
datastores = self.parent().getDatastores()
vals = []
for d in datastores:
vals.append(gui.choiceItem(d[0], d[1]))
self.datastore.setValues(vals)
def sanitizeVmName(self, name):
def sanitizeVmName(self, name: str) -> str:
return self.parent().sanitizeVmName(name)
def makeTemplate(self, templateName):
def makeTemplate(self, templateName: str) -> str:
return self.parent().makeTemplate(self.template.value, templateName, self.datastore.value)
def checkTemplatePublished(self, templateId):
def checkTemplatePublished(self, templateId: str) -> bool:
return self.parent().checkTemplatePublished(templateId)
def deployFromTemplate(self, name, templateId):
def deployFromTemplate(self, name: str, templateId: str) -> str:
"""
Deploys a virtual machine on selected cluster from selected template
@ -186,13 +189,13 @@ class LiveService(Service):
# self.datastoreHasSpace()
return self.parent().deployFromTemplate(name, templateId)
def removeTemplate(self, templateId):
def removeTemplate(self, templateId: str) -> None:
"""
invokes removeTemplate from parent provider
"""
return self.parent().removeTemplate(templateId)
self.parent().removeTemplate(templateId)
def getMachineState(self, machineId):
def getMachineState(self, machineId: str) -> 'on.types.VmState':
"""
Invokes getMachineState from parent provider
(returns if machine is "active" or "inactive"
@ -210,14 +213,14 @@ class LiveService(Service):
"""
return self.parent().getMachineState(machineId)
def getMachineSubstate(self, machineId):
def getMachineSubstate(self, machineId: str) -> int:
"""
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):
def startMachine(self, machineId: str) -> None:
"""
Tries to start a machine. No check is done, it is simply requested to OpenNebula.
@ -228,9 +231,9 @@ class LiveService(Service):
Returns:
"""
return self.parent().startMachine(machineId)
self.parent().startMachine(machineId)
def stopMachine(self, machineId):
def stopMachine(self, machineId: str) -> None:
"""
Tries to stop a machine. No check is done, it is simply requested to OpenNebula
@ -239,9 +242,9 @@ class LiveService(Service):
Returns:
"""
return self.parent().stopMachine(machineId)
self.parent().stopMachine(machineId)
def suspendMachine(self, machineId):
def suspendMachine(self, machineId: str) -> None:
"""
Tries to suspend machine. No check is done, it is simply requested to OpenNebula
@ -250,12 +253,12 @@ class LiveService(Service):
Returns:
"""
return self.parent().suspendMachine(machineId)
self.parent().suspendMachine(machineId)
def resetMachine(self, machineId):
return self.parent().resetMachine(machineId)
def resetMachine(self, machineId: str) -> None:
self.parent().resetMachine(machineId)
def removeMachine(self, machineId):
def removeMachine(self, machineId: str) -> None:
"""
Tries to delete a machine. No check is done, it is simply requested to OpenNebula
@ -264,28 +267,28 @@ class LiveService(Service):
Returns:
"""
return self.parent().removeMachine(machineId)
self.parent().removeMachine(machineId)
def getNetInfo(self, machineId, networkId=None):
def getNetInfo(self, machineId: str, networkId: typing.Optional[str] = None) -> typing.Tuple[str, str]:
"""
Changes the mac address of first nic of the machine to the one specified
"""
return self.parent().getNetInfo(machineId, networkId=None)
def getBaseName(self):
def getBaseName(self) -> str:
"""
Returns the base name
"""
return self.baseName.value
def getLenName(self):
def getLenName(self) -> int:
"""
Returns the length of numbers part
"""
return int(self.lenName.value)
return self.lenName.num()
def getConsoleConnection(self, machineId):
def getConsoleConnection(self, machineId: str) -> typing.Dict[str, typing.Any]:
return self.parent().getConsoleConnection(machineId)
def desktopLogin(self, machineId, username, password, domain):
def desktopLogin(self, machineId: str, username: str, password: str, domain: str) -> typing.Dict[str, typing.Any]:
return self.parent().desktopLogin(machineId, username, password, domain)