diff --git a/server/src/uds/services/OpenNebula/LivePublication.py b/server/src/uds/services/OpenNebula/LivePublication.py index fbd6e8856..b3f0a20ef 100644 --- a/server/src/uds/services/OpenNebula/LivePublication.py +++ b/server/src/uds/services/OpenNebula/LivePublication.py @@ -38,7 +38,7 @@ from datetime import datetime import logging -__updated__ = '2016-02-08' +__updated__ = '2016-07-22' logger = logging.getLogger(__name__) @@ -87,7 +87,7 @@ class LivePublication(Publication): ''' self._name = self.service().sanitizeVmName('UDSP ' + self.dsName() + "-" + str(self.revision())) self._reason = '' # No error, no reason for it - self._state = 'ok' + self._state = 'running' try: self._templateId = self.service().makeTemplate(self._name) @@ -102,12 +102,18 @@ class LivePublication(Publication): ''' Checks state of publication creation ''' + if self._state == 'running': + if self.service().checkTemplatePublished(self._templateId) is False: + return + self._state = 'ok' + if self._state == 'error': return State.ERROR if self._state == 'ok': return State.FINISHED + self._state = 'ok' return State.FINISHED diff --git a/server/src/uds/services/OpenNebula/LiveService.py b/server/src/uds/services/OpenNebula/LiveService.py index a2d76e391..8de1049f0 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__ = '2016-07-11' +__updated__ = '2016-07-22' logger = logging.getLogger(__name__) @@ -153,6 +153,9 @@ class LiveService(Service): def makeTemplate(self, templateName): return self.parent().makeTemplate(self.template.value, templateName, self.datastore.value) + def checkTemplatePublished(self, templateId): + return self.parent().checkTemplatePublished(templateId) + def deployFromTemplate(self, name, templateId): ''' Deploys a virtual machine on selected cluster from selected template diff --git a/server/src/uds/services/OpenNebula/Provider.py b/server/src/uds/services/OpenNebula/Provider.py index 44e736497..eda2a6c10 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-07-11' +__updated__ = '2016-07-22' logger = logging.getLogger(__name__) @@ -166,6 +166,9 @@ class Provider(ServiceProvider): def makeTemplate(self, fromTemplateId, name, toDataStore): return on.template.create(self.api, fromTemplateId, name, toDataStore) + def checkTemplatePublished(self, templateId): + return on.template.checkPublished(self.api, templateId) + def removeTemplate(self, templateId): return on.template.remove(self.api, templateId) diff --git a/server/src/uds/services/OpenNebula/on/__init__.py b/server/src/uds/services/OpenNebula/on/__init__.py index 76fcf7ca3..a8b9c2a42 100644 --- a/server/src/uds/services/OpenNebula/on/__init__.py +++ b/server/src/uds/services/OpenNebula/on/__init__.py @@ -31,6 +31,8 @@ .. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com ''' +# pylint: disable=maybe-no-member + import sys import imp import re @@ -41,17 +43,20 @@ import six import xmlrpclib from uds.core.util import xml2dict -__updated__ = '2016-07-21' +__updated__ = '2016-07-22' logger = logging.getLogger(__name__) module = sys.modules[__name__] VmState = imp.new_module('VmState') +ImageState = imp.new_module('ImageState') for i in enumerate(['INIT', 'PENDING', 'HOLD', 'ACTIVE', 'STOPPED', 'SUSPENDED', 'DONE', 'FAILED', 'POWEROFF', 'UNDEPLOYED']): setattr(VmState, i[1], i[0]) +for i in enumerate(['INIT', 'READY', 'USED', 'DISABLED', 'LOCKED', 'ERROR', 'CLONE', 'DELETE', 'USED_PERS', 'LOCKED_USED', 'LOCKED_USED_PERS']): + setattr(ImageState, i[1], i[0]) # Import submodules from .common import * @@ -98,7 +103,7 @@ class OpenNebulaClient(object): if self.cachedVersion is None: # Retrieve Version & keep it result = self.connection.one.system.version(self.sessionString) - self.cachedVersion = checkResult(result, parseResult=False).split('.') # pylint: disable=maybe-no-member + self.cachedVersion = checkResult(result, parseResult=False).split('.') return self.cachedVersion @@ -215,6 +220,14 @@ class OpenNebulaClient(object): result = self.connection.one.image.clone(self.sessionString, int(srcId), name, int(datastoreId)) return checkResult(result, parseResult=False) + @ensureConnected + def makePersistentImage(self, imageId, persistent=False): + ''' + Clones the image. + ''' + result = self.connection.one.image.persistent(self.sessionString, int(imageId), persistent) + return checkResult(result, parseResult=False) + @ensureConnected def deleteImage(self, imageId): ''' @@ -223,6 +236,17 @@ class OpenNebulaClient(object): result = self.connection.one.image.delete(self.sessionString, int(imageId)) return checkResult(result, parseResult=False) + @ensureConnected + def imageInfo(self, imageInfo): + ''' + Returns a list + first element is a dictionary (built from XML) + second is original XML + ''' + result = self.connection.one.image.info(self.sessionString, int(imageInfo)) + res = checkResult(result) + return (res, result[1]) + @ensureConnected def enumVMs(self): ''' diff --git a/server/src/uds/services/OpenNebula/on/template.py b/server/src/uds/services/OpenNebula/on/template.py index fca72e660..9015ecbe7 100644 --- a/server/src/uds/services/OpenNebula/on/template.py +++ b/server/src/uds/services/OpenNebula/on/template.py @@ -38,7 +38,7 @@ from defusedxml import minidom # Python bindings for OpenNebula from .common import sanitizeName -__updated__ = '2016-07-18' +__updated__ = '2016-07-22' logger = logging.getLogger(__name__) @@ -97,6 +97,9 @@ def create(api, fromTemplateId, name, toDataStore): # Now clone the image imgName = sanitizeName(name + ' DSK ' + six.text_type(counter)) newId = api.cloneImage(imgId, imgName, toDataStore) # api.call('image.clone', int(imgId), imgName, int(toDataStore)) + # Ensure image is non persistent + api.makePersistentImage(newId, False) + # Now Store id/name if fromId is True: node.data = six.text_type(newId) else: @@ -164,3 +167,31 @@ def deployFrom(api, templateId, name): ''' vmId = api.instantiateTemplate(templateId, name, False, '', False) # api.call('template.instantiate', int(templateId), name, False, '') return six.text_type(vmId) + +def checkPublished(api, templateId): + ''' + checks if the template is fully published (images are ready...) + ''' + try: + imgs = dict(((i[1], i[0]) for i in api.enumImages())) + + info = api.templateInfo(templateId)[1] + template = minidom.parseString(info).getElementsByTagName('TEMPLATE')[0] + logger.debug('XML: {}'.format(template.toxml())) + + for dsk in template.getElementsByTagName('DISK'): + imgIds = dsk.getElementsByTagName('IMAGE_ID') + if len(imgIds) == 0: + node = dsk.getElementsByTagName('IMAGE')[0].childNodes[0] + imgId = imgs[node.data] + else: + node = imgIds[0].childNodes[0] + imgId = node.data + + logger.debug('Found {} for checking'.format(imgId)) + + if api.getImageInfo(imgId)[0]['IMAGE']['STATE'] == '4': + return False + except Exception: + logger.exception('Exception checking published') + raise