1
0
mirror of https://github.com/dkmstr/openuds.git synced 2025-01-10 01:17:59 +03:00

* Fixed "double cancel" of a publication (cancelling over an already

cancelling publication will "force" the cancellation, meaning that no
check is done, it simply stops publication and mark it as "cancelled"
(leaving a log on service pool, ofc)
This commit is contained in:
Adolfo Gómez García 2015-02-03 06:30:27 +01:00
parent 7d44bd7b65
commit e1f26d2157
6 changed files with 264 additions and 99 deletions

View File

@ -30,6 +30,8 @@
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
# pylint: disable=too-many-public-methods
from __future__ import unicode_literals
from django.contrib.sessions.backends.db import SessionStore
@ -134,18 +136,22 @@ class Handler(object):
def header(self, headerName):
'''
Get's an specific header name from REST request
:param headerName: name of header to get
'''
return self._headers.get(headerName)
def addHeader(self, header, value):
'''
Inserts a new header inside the headers list
:param header: name of header to insert
:param value: value of header
'''
self._headers[header] = value
def removeHeader(self, header):
'''
Removes an specific header from the headers list
:param header: Name of header to remove
'''
try:
del self._headers[header]
@ -163,6 +169,12 @@ class Handler(object):
def storeSessionAuthdata(session, id_auth, username, locale, is_admin, staff_member):
'''
Stores the authentication data inside current session
:param session: session handler (Djano user session object)
:param id_auth: Authenticator id (DB object id)
:param username: Name of user (login name)
:param locale: Assigned locale
:param is_admin: If user is considered admin or not
:param staff_member: If is considered as staff member
'''
if is_admin:
staff_member = True # Make admins also staff members :-)
@ -179,6 +191,11 @@ class Handler(object):
'''
Generates the authentication token from a session, that is basically
the session key itself
:param id_auth: Authenticator id (DB object id)
:param username: Name of user (login name)
:param locale: Assigned locale
:param is_admin: If user is considered admin or not
:param staf_member: If user is considered staff member or not
'''
session = SessionStore()
session.set_expiry(GlobalConfig.ADMIN_IDLE_TIME.getInt())

View File

@ -30,6 +30,9 @@
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
# pylint: disable=too-many-public-methods
from __future__ import unicode_literals
from django.utils.translation import ugettext as _
@ -40,7 +43,6 @@ from uds.core.util.State import State
from uds.core.util import log
from uds.REST.model import DetailHandler
from uds.REST import ResponseError
from uds.core.util.State import State
import logging
@ -155,7 +157,7 @@ class CachedService(AssignedService):
else:
k = parent.cachedUserServices().get(uuid=item)
return AssignedService.itemToDict(k, True)
except:
except Exception:
logger.exception('getItems')
self.invalidItemException()
@ -179,11 +181,14 @@ class CachedService(AssignedService):
item = parent.cachedUserServices().get(uuid=item)
logger.debug('Getting logs for {0}'.format(item))
return log.getLogs(item)
except:
except Exception:
self.invalidItemException()
class Groups(DetailHandler):
'''
Processes the groups detail requests of a Service Pool
'''
def getItems(self, parent, item):
return [{
'id': i.uuid,
@ -214,6 +219,9 @@ class Groups(DetailHandler):
class Transports(DetailHandler):
'''
Processes the transports detail requests of a Service Pool
'''
def getItems(self, parent, item):
return [{
'id': i.uuid,
@ -243,14 +251,27 @@ class Transports(DetailHandler):
class Publications(DetailHandler):
custom_methods = ['publish', 'cancel']
'''
Processes the publications detail requests of a Service Pool
'''
custom_methods = ['publish', 'cancel'] # We provided these custom methods
def publish(self, parent):
'''
Custom method "publish", provided to initiate a publication of a deployed service
:param parent: Parent service pool
'''
logger.debug('Custom "publish" invoked')
parent.publish()
return self.success()
def cancel(self, parent, uuid):
'''
Invoked to cancel a running publication
Double invocation (this means, invoking cancel twice) will mean that is a "forced cancelation"
:param parent: Parent service pool
:param uuid: uuid of the publication
'''
try:
ds = DeployedServicePublication.objects.get(uuid=uuid)
ds.cancel()

View File

@ -29,6 +29,8 @@
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
# pylint: disable=too-many-public-methods
from __future__ import unicode_literals
from uds.REST.handlers import NotFound, RequestError, ResponseError
@ -47,7 +49,7 @@ import logging
logger = logging.getLogger(__name__)
__updated__ = '2015-01-31'
__updated__ = '2015-02-03'
# a few constants
@ -73,9 +75,13 @@ class BaseModelHandler(Handler):
Base Handler for Master & Detail Handlers
'''
def addField(self, gui, field):
def addField(self, gui, field): # pylint: disable=no-self-use
'''
Add a field to a "gui" description
Add a field to a "gui" description.
This method checks that every required field element is in there.
If not, defaults are assigned
:param gui: List of "gui" items where the field will be added
:param field: Field to be added (dictionary)
'''
gui.append({
'name': field.get('name', ''),
@ -100,6 +106,8 @@ class BaseModelHandler(Handler):
def addDefaultFields(self, gui, flds):
'''
Adds default fields (based in a list) to a "gui" description
:param gui: Gui list where the "default" fielsds will be added
:param flds: List of fields names requested to be added. Valid values are 'name', 'comments', 'priority' and 'small_name'
'''
if 'name' in flds:
self.addField(gui, {
@ -141,7 +149,7 @@ class BaseModelHandler(Handler):
return gui
def typeInfo(self, type_):
def typeInfo(self, type_): # pylint: disable=no-self-use
'''
Returns info about the type
In fact, right now, it returns an empty dict, that will be extended by typeAsDict
@ -161,7 +169,7 @@ class BaseModelHandler(Handler):
})
return res
def processTableFields(self, title, fields, row_style):
def processTableFields(self, title, fields, row_style): # pylint: disable=no-self-use
'''
Returns a dict containing the table fields description
'''
@ -171,7 +179,12 @@ class BaseModelHandler(Handler):
'row-style': row_style
}
def readFieldsFromParams(self, fldList):
def readFieldsFromParams(self, fldList): # pylint: disable=no-self-use
'''
Reads the indicated fields from the parameters received, and if
:param fldList: List of required fields
:return: A dictionary containing all required fields
'''
args = {}
try:
for key in fldList:
@ -182,7 +195,13 @@ class BaseModelHandler(Handler):
return args
def fillIntanceFields(self, item, res):
def fillIntanceFields(self, item, res): # pylint: disable=no-self-use
'''
For Managed Objects (db element that contains a serialized object), fills a dictionary with the "field" parameters values.
For non managed objects, it does nothing
:param item: Item to extract fields
:param res: Dictionary to "extend" with instance key-values pairs
'''
if hasattr(item, 'getInstance'):
for key, value in item.getInstance().valuesDict().iteritems():
if type(value) in (unicode, str):
@ -195,6 +214,7 @@ class BaseModelHandler(Handler):
def invalidRequestException(self, message=None):
'''
Raises an invalid request error with a default translated string
:param message: Custom message to add to exception. If it is None, "Invalid Request" is used
'''
message = _('Invalid Request') if message is None else message
raise RequestError('{} {}: {}'.format(message, self.__class__, self._args))
@ -230,7 +250,7 @@ class BaseModelHandler(Handler):
# Details do not have types at all
# so, right now, we only process details petitions for Handling & tables info
class DetailHandler(BaseModelHandler):
class DetailHandler(BaseModelHandler): # pylint: disable=abstract-class-not-used
'''
Detail handler (for relations such as provider-->services, authenticators-->users,groups, deployed services-->cache,assigned, groups, transports
Urls recognized for GET are:
@ -253,8 +273,11 @@ class DetailHandler(BaseModelHandler):
'''
custom_methods = []
def __init__(self, parentHandler, path, params, *args, **kwargs):
# pylint: disable=super-init-not-called
def __init__(self, parentHandler, path, params, *args, **kwargs): # pylint: disable=super-init-not-called
'''
Detail Handlers in fact "disabled" handler most initialization, that is no needed because
parent modelhandler has already done it (so we must access through parent handler)
'''
self._parent = parentHandler
self._path = path
self._params = params
@ -272,16 +295,20 @@ class DetailHandler(BaseModelHandler):
if check in self.custom_methods:
try:
operation = getattr(self, check)
if arg is None:
return operation(parent)
else:
return operation(parent, arg)
except Exception:
self.invalidMethodException()
if arg is None:
return operation(parent)
else:
return operation(parent, arg)
return None
def get(self):
def get(self): # pylint: disable=too-many-branches,too-many-return-statements
'''
Processes GET method for a detail Handler
'''
# Process args
logger.debug("Detail args for GET: {0}".format(self._args))
nArgs = len(self._args)
@ -326,7 +353,9 @@ class DetailHandler(BaseModelHandler):
def put(self):
'''
Put is delegated to specific implementation
Process the "PUT" operation, making the correspondent checks.
Evaluates if it is a new element or a "modify" operation (based on if it has parameter),
and invokes "saveItem" with parent & item (that can be None for a new Item)
'''
# logger.debug("Detail args for PUT: {0}, {1}".format(self._args, self._params))
@ -345,13 +374,16 @@ class DetailHandler(BaseModelHandler):
def post(self):
'''
Post will be used for, for example, testing
Process the "POST" operation
Post can be used for, for example, testing.
Right now is an invalid method for Detail elements
'''
self.invalidRequestException('This method does not accepts POST')
def delete(self):
'''
Put is delegated to specific implementation
Process the "DELETE" operation, making the correspondent checks.
Extracts the item id and invokes deleteItem with parent item and item id (uuid)
'''
logger.debug("Detail args for DELETE: {0}".format(self._args))
@ -362,9 +394,10 @@ class DetailHandler(BaseModelHandler):
return self.deleteItem(parent, self._args[0])
# Invoked if default get can't process request
def fallbackGet(self):
'''
Invoked if default get can't process request.
Here derived classes can process "non default" (and so, not understood) GET constructions
'''
raise self.invalidRequestException('Fallback invoked')
@ -372,7 +405,7 @@ class DetailHandler(BaseModelHandler):
# Default (as sample) getItems
def getItems(self, parent, item):
'''
This must be overriden by desdendants
This MUST be overridden by derived classes
Excepts to return a list of dictionaries or a single dictionary, depending on "item" param
If "item" param is None, ALL items are expected to be returned as a list of dictionaries
If "Item" param has an id (normally an uuid), one item is expected to be returned as dictionary
@ -384,30 +417,83 @@ class DetailHandler(BaseModelHandler):
# Default save
def saveItem(self, parent, item):
'''
Invoked for a valid "put" operation
If this method is not overridden, the detail class will not have "Save/modify" operations.
Parameters (probably object fields) must be retrieved from "_params" member variable
:param parent: Parent of this detail (parent DB Object)
:param item: Item id (uuid)
:return: Normally "success" is expected, but can throw any "exception"
'''
logger.debug('Default saveItem handler caller for {0}'.format(self._path))
self.invalidRequestException()
# Default delete
def deleteItem(self, parent, item):
'''
Invoked for a valid "delete" operation.
If this method is not overriden, the detail class will not have "delete" operation.
:param parent: Parent of this detail (parent DB Object)
:param item: Item id (uuid)
:return: Normally "success" is expected, but can throw any "exception"
'''
self.invalidRequestException()
# A detail handler must also return title & fields for tables
def getTitle(self, parent):
def getTitle(self, parent): # pylint: disable=no-self-use
'''
A "generic" title for a view based on this detail.
If not overridden, defaults to ''
:param parent: Parent object
:return: Expected to return an string that is the "title".
'''
return ''
def getFields(self, parent):
def getFields(self, parent): # pylint: disable=no-self-use
'''
A "generic" list of fields for a view based on this detail.
If not overridden, defaults to emty list
:param parent: Parent object
:return: Expected to return a list of fields
'''
return []
def getRowStyle(self, parent):
def getRowStyle(self, parent): # pylint: disable=no-self-use
'''
A "generic" row style based on row field content.
If not overridden, defaults to {}
:param parent: Parent object
:return: Expected to return a dictionary that contains 'field' & 'prefix' fields
'''
return {}
def getGui(self, parent, forType):
def getGui(self, parent, forType): # pylint: disable=no-self-use
'''
Gets the gui that is needed in order to "edit/add" new items on this detail
If not overriden, means that the detail has no edit/new Gui
:param parent: Parent object
:param forType: Type of object needing gui
:return: a "gui" (list of gui fields)
'''
raise RequestError('Gui not provided for this type of object')
def getTypes(self, parent, forType):
def getTypes(self, parent, forType): # pylint: disable=no-self-use
'''
The default is that detail element will not have any types (they are "homogeneous")
but we provided this method, that can be overridden, in case one detail needs it
:param parent: Parent object
:param forType: Request argument in fact
:return: list of strings that repressents the detail types
'''
return [] # Default is that details do not have types
def getLogs(self, parent, item):
'''
If the detail has any log associated with it items, provide it overriding this method
:param parent:
:param item:
:return: a list of log elements (normally got using "uds.core.util.log.getLogs" method)
'''
self.invalidMethodException()

View File

@ -38,7 +38,8 @@ from uds.core.jobs.DelayedTaskRunner import DelayedTaskRunner
from uds.core.util.Config import GlobalConfig
from uds.core.services.Exceptions import PublishException
from uds.models import DeployedServicePublication, getSqlDatetime
from uds.core.util.State import State
from uds.core.util.State import State
from uds.core.util import log
import logging
logger = logging.getLogger(__name__)
@ -47,27 +48,32 @@ PUBTAG = 'pm-'
class PublicationOldMachinesCleaner(DelayedTask):
'''
This delayed task is for removing a pending "removable" publication
'''
def __init__(self, publicationId):
super(PublicationOldMachinesCleaner, self).__init__()
self._id = publicationId
def run(self):
try:
dsp = DeployedServicePublication.objects.get(pk=self._id)
if (dsp.state != State.REMOVABLE):
servicePoolPub = DeployedServicePublication.objects.get(pk=self._id)
if servicePoolPub.state != State.REMOVABLE:
logger.info('Already removed')
now = getSqlDatetime()
activePub = dsp.deployed_service.activePublication()
dsp.deployed_service.userServices.filter(in_use=True).update(in_use=False, state_date=now)
dsp.deployed_service.markOldUserServicesAsRemovables(activePub)
except:
activePub = servicePoolPub.deployed_service.activePublication()
servicePoolPub.deployed_service.userServices.filter(in_use=True).update(in_use=False, state_date=now)
servicePoolPub.deployed_service.markOldUserServicesAsRemovables(activePub)
except Exception:
logger.info("Machine removal for {0} not executed because publication is already removed")
# Removed provider, no problem at all, no update is done
pass
class PublicationLauncher(DelayedTask):
'''
This delayed task if for launching a new publication
'''
def __init__(self, publish):
super(PublicationLauncher, self).__init__()
self._publishId = publish.id
@ -76,97 +82,103 @@ class PublicationLauncher(DelayedTask):
logger.debug('Publishing')
try:
with transaction.atomic():
dsp = DeployedServicePublication.objects.select_for_update().get(pk=self._publishId)
if dsp.state != State.LAUNCHING: # If not preparing (may has been canceled by user) just return
servicePoolPub = DeployedServicePublication.objects.select_for_update().get(pk=self._publishId)
if servicePoolPub.state != State.LAUNCHING: # If not preparing (may has been canceled by user) just return
return
dsp.state = State.PREPARING
dsp.save()
pi = dsp.getInstance()
servicePoolPub.state = State.PREPARING
servicePoolPub.save()
pi = servicePoolPub.getInstance()
state = pi.publish()
deployedService = dsp.deployed_service
deployedService = servicePoolPub.deployed_service
deployedService.current_pub_revision += 1
deployedService.save()
PublicationFinishChecker.checkAndUpdateState(dsp, pi, state)
PublicationFinishChecker.checkAndUpdateState(servicePoolPub, pi, state)
except Exception:
logger.exception("Exception launching publication")
dsp.state = State.ERROR
dsp.save()
servicePoolPub.state = State.ERROR
servicePoolPub.save()
# Delayed Task that checks if a publication is done
class PublicationFinishChecker(DelayedTask):
def __init__(self, publish):
'''
This delayed task is responsible of checking if a publication is finished
'''
def __init__(self, servicePoolPub):
super(PublicationFinishChecker, self).__init__()
self._publishId = publish.id
self._state = publish.state
self._publishId = servicePoolPub.id
self._state = servicePoolPub.state
@staticmethod
def checkAndUpdateState(dsp, pi, state):
def checkAndUpdateState(servicePoolPub, pi, state):
'''
Checks the value returned from invocation to publish or checkPublishingState, updating the dsp database object
Checks the value returned from invocation to publish or checkPublishingState, updating the servicePoolPub database object
Return True if it has to continue checking, False if finished
'''
try:
prevState = dsp.state
prevState = servicePoolPub.state
checkLater = False
if State.isFinished(state):
# Now we mark, if it exists, the previous usable publication as "Removable"
if State.isPreparing(prevState):
for old in dsp.deployed_service.publications.filter(state=State.USABLE):
for old in servicePoolPub.deployed_service.publications.filter(state=State.USABLE):
old.state = State.REMOVABLE
old.save()
pc = PublicationOldMachinesCleaner(old.id)
pc.register(GlobalConfig.SESSION_EXPIRE_TIME.getInt(True) * 3600, 'pclean-' + str(old.id), True)
dsp.setState(State.USABLE)
dsp.deployed_service.markOldUserServicesAsRemovables(dsp)
servicePoolPub.setState(State.USABLE)
servicePoolPub.deployed_service.markOldUserServicesAsRemovables(servicePoolPub)
elif State.isRemoving(prevState):
dsp.setState(State.REMOVED)
servicePoolPub.setState(State.REMOVED)
else: # State is canceling
dsp.setState(State.CANCELED)
servicePoolPub.setState(State.CANCELED)
# Mark all previous publications deployed services as removables
# and make this usable
pi.finish()
dsp.updateData(pi)
servicePoolPub.updateData(pi)
elif State.isErrored(state):
dsp.updateData(pi)
dsp.state = State.ERROR
servicePoolPub.updateData(pi)
servicePoolPub.state = State.ERROR
else:
checkLater = True # The task is running
dsp.updateData(pi)
servicePoolPub.updateData(pi)
dsp.save()
servicePoolPub.save()
if checkLater:
PublicationFinishChecker.checkLater(dsp, pi)
except:
PublicationFinishChecker.checkLater(servicePoolPub, pi)
except Exception:
logger.exception('At checkAndUpdate for publication')
PublicationFinishChecker.checkLater(dsp, pi)
PublicationFinishChecker.checkLater(servicePoolPub, pi)
@staticmethod
def checkLater(dsp, pi):
def checkLater(servicePoolPub, pi):
'''
Inserts a task in the delayedTaskRunner so we can check the state of this publication
@param dps: Database object for DeployedServicePublication
@param pi: Instance of Publication manager for the object
'''
DelayedTaskRunner.runner().insert(PublicationFinishChecker(dsp), pi.suggestedTime, PUBTAG + str(dsp.id))
DelayedTaskRunner.runner().insert(PublicationFinishChecker(servicePoolPub), pi.suggestedTime, PUBTAG + str(servicePoolPub.id))
def run(self):
logger.debug('Checking publication finished {0}'.format(self._publishId))
try:
dsp = DeployedServicePublication.objects.get(pk=self._publishId)
if dsp.state != self._state:
servicePoolPub = DeployedServicePublication.objects.get(pk=self._publishId)
if servicePoolPub.state != self._state:
logger.debug('Task overrided by another task (state of item changed)')
else:
pi = dsp.getInstance()
pi = servicePoolPub.getInstance()
logger.debug("publication instance class: {0}".format(pi.__class__))
state = pi.checkState()
PublicationFinishChecker.checkAndUpdateState(dsp, pi, state)
PublicationFinishChecker.checkAndUpdateState(servicePoolPub, pi, state)
except Exception, e:
logger.debug('Deployed service not found (erased from database) {0} : {1}'.format(e.__class__, e))
class PublicationManager(object):
'''
Manager responsible of controlling publications
'''
_manager = None
def __init__(self):
@ -174,54 +186,83 @@ class PublicationManager(object):
@staticmethod
def manager():
'''
Returns the singleton to this manager
'''
if PublicationManager._manager is None:
PublicationManager._manager = PublicationManager()
return PublicationManager._manager
def publish(self, deployedService):
if deployedService.publications.filter(state__in=State.PUBLISH_STATES).count() > 0:
def publish(self, servicePool): # pylint: disable=no-self-use
'''
Initiates the publication of a service pool, or raises an exception if this cannot be done
:param servicePool: Service pool object (db object)
'''
if servicePool.publications.filter(state__in=State.PUBLISH_STATES).count() > 0:
raise PublishException(_('Already publishing. Wait for previous publication to finish and try again'))
if deployedService.isInMaintenance():
if servicePool.isInMaintenance():
raise PublishException(_('Service is in maintenance mode and new publications are not allowed'))
try:
now = getSqlDatetime()
dsp = deployedService.publications.create(state=State.LAUNCHING, state_date=now, publish_date=now, revision=deployedService.current_pub_revision)
dsp = None
dsp = servicePool.publications.create(state=State.LAUNCHING, state_date=now, publish_date=now, revision=servicePool.current_pub_revision)
DelayedTaskRunner.runner().insert(PublicationLauncher(dsp), 4, PUBTAG + str(dsp.id))
except Exception as e:
logger.debug('Caught exception at publish: {0}'.format(e))
if dsp is not None:
try:
dsp.delete()
except Exception:
logger.info('Could not delete {}'.format(dsp))
raise PublishException(str(e))
def cancel(self, dsp):
dsp = DeployedServicePublication.objects.get(pk=dsp.id)
if dsp.state not in State.PUBLISH_STATES:
raise PublishException(_('Can\'t cancel non running publication'))
def cancel(self, servicePoolPub): # pylint: disable=no-self-use
'''
Invoked to cancel a publication.
Double invokation (i.e. invokation over a "cancelling" item) will lead to a "forced" cancellation (unclean)
:param servicePoolPub: Service pool publication (db object for a publication)
'''
servicePoolPub = DeployedServicePublication.objects.get(pk=servicePoolPub.id)
if servicePoolPub.state not in State.PUBLISH_STATES:
if servicePoolPub.state == State.CANCELING: # Double cancel
logger.info('Double cancel invoked for a publication')
log.doLog(servicePoolPub.deployed_service, log.WARN, 'Forced cancel on publication, you must check uncleaned resources manually', log.ADMIN)
servicePoolPub.setState(State.CANCELED)
servicePoolPub.save()
return
else:
raise PublishException(_('Can\'t cancel non running publication'))
if dsp.state == State.LAUNCHING:
dsp.state = State.CANCELED
dsp.save()
return dsp
if servicePoolPub.state == State.LAUNCHING:
servicePoolPub.state = State.CANCELED
servicePoolPub.save()
return servicePoolPub
try:
pi = dsp.getInstance()
state = pi.cancel()
dsp.setState(State.CANCELING)
PublicationFinishChecker.checkAndUpdateState(dsp, pi, state)
return dsp
pubInstance = servicePoolPub.getInstance()
state = pubInstance.cancel()
servicePoolPub.setState(State.CANCELING)
PublicationFinishChecker.checkAndUpdateState(servicePoolPub, pubInstance, state)
return servicePoolPub
except Exception, e:
raise PublishException(str(e))
def unpublish(self, dsp):
if State.isUsable(dsp.state) == False and State.isRemovable(dsp.state) == False:
raise PublishException(_('Can\'t unpublish non usable publication'))
# TODO: Call assignation manager to remove removable items
if dsp.userServices.exclude(state__in=State.INFO_STATES).count() > 0:
def unpublish(self, servicePoolPub): # pylint: disable=no-self-use
'''
Unpublishes an active (usable) or removable publication
:param servicePoolPub: Publication to unpublish
'''
if State.isUsable(servicePoolPub.state) is False and State.isRemovable(servicePoolPub.state) is False:
raise PublishException(_('Can\'t unpublish non usable publication')
)
if servicePoolPub.userServices.exclude(state__in=State.INFO_STATES).count() > 0:
raise PublishException(_('Can\'t unpublish publications with services in process'))
try:
pi = dsp.getInstance()
state = pi.destroy()
dsp.setState(State.REMOVING)
PublicationFinishChecker.checkAndUpdateState(dsp, pi, state)
pubInstance = servicePoolPub.getInstance()
state = pubInstance.destroy()
servicePoolPub.setState(State.REMOVING)
PublicationFinishChecker.checkAndUpdateState(servicePoolPub, pubInstance, state)
except Exception, e:
raise PublishException(str(e))

View File

@ -71,7 +71,7 @@ class UserServiceOpChecker(DelayedTask):
@staticmethod
def checkAndUpdateState(userService, userServiceInstance, state):
'''
Checks the value returned from invocation to publish or checkPublishingState, updating the dsp database object
Checks the value returned from invocation to publish or checkPublishingState, updating the servicePoolPub database object
Return True if it has to continue checking, False if finished
'''
try:

View File

@ -113,7 +113,7 @@ class ClusterMigrationTask(DelayedTask):
@staticmethod
def checkAndUpdateState(userService, userServiceInstance, state):
'''
Checks the value returned from invocation to publish or checkPublishingState, updating the dsp database object
Checks the value returned from invocation to publish or checkPublishingState, updating the servicePoolPub database object
Return True if it has to continue checking, False if finished
'''
try: