forked from shaba/openuds
Upgrade OpenNebula
This commit is contained in:
parent
ce91840622
commit
103ad93cdf
@ -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):
|
||||
|
@ -28,5 +28,4 @@
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
from .Provider import Provider
|
||||
|
||||
from .provider import OpenNebulaProvider
|
||||
|
@ -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])
|
@ -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
|
||||
|
@ -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]:
|
||||
|
@ -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]
|
||||
|
||||
|
@ -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()
|
@ -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
|
||||
"""
|
@ -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)
|
Loading…
Reference in New Issue
Block a user