Fix workbook POST duplicate exception

* 400 status code response on duplicate error
 * new exceptions - Mistral, DBDuplicateEntry
 * import exception from openstack-common

Fixes bug: #1263942

Change-Id: Ia802db5c6b30be96cb0b8ce2cfc0f7fd04122302
This commit is contained in:
Nikolay Mahotkin 2013-12-26 13:13:53 +04:00
parent 0109320252
commit 2176d57d15
5 changed files with 195 additions and 18 deletions

View File

@ -17,6 +17,7 @@ from pecan import abort
from wsme import types as wtypes from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan import wsmeext.pecan as wsme_pecan
from mistral import exceptions as ex
from mistral.api.controllers.v1 import task from mistral.api.controllers.v1 import task
from mistral.openstack.common import log as logging from mistral.openstack.common import log as logging
from mistral.api.controllers import resource from mistral.api.controllers import resource
@ -73,9 +74,12 @@ class ExecutionsController(rest.RestController):
def post(self, workbook_name, execution): def post(self, workbook_name, execution):
LOG.debug("Create listener [workbook_name=%s, execution=%s]" % LOG.debug("Create listener [workbook_name=%s, execution=%s]" %
(workbook_name, execution)) (workbook_name, execution))
try:
values = engine.start_workflow_execution(execution.workbook_name, values = engine.start_workflow_execution(execution.workbook_name,
execution.target_task) execution.target_task)
except ex.MistralException as e:
#TODO(nmakhotkin) we should use thing such a decorator here
abort(400, e.message)
return Execution.from_dict(values) return Execution.from_dict(values)

View File

@ -19,6 +19,7 @@ from pecan import abort
from wsme import types as wtypes from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan import wsmeext.pecan as wsme_pecan
from mistral import exceptions as ex
from mistral.api.controllers.v1 import workbook_definition from mistral.api.controllers.v1 import workbook_definition
from mistral.api.controllers.v1 import listener from mistral.api.controllers.v1 import listener
from mistral.api.controllers.v1 import execution from mistral.api.controllers.v1 import execution
@ -71,9 +72,12 @@ class WorkbooksController(rest.RestController):
@wsme_pecan.wsexpose(Workbook, body=Workbook, status_code=201) @wsme_pecan.wsexpose(Workbook, body=Workbook, status_code=201)
def post(self, workbook): def post(self, workbook):
LOG.debug("Create workbook [workbook=%s]" % workbook) LOG.debug("Create workbook [workbook=%s]" % workbook)
try:
wb = workbooks.create_workbook(workbook.to_dict()) wb = workbooks.create_workbook(workbook.to_dict())
return Workbook.from_dict(wb) return Workbook.from_dict(wb)
except ex.MistralException as e:
#TODO(nmakhotkin) we should use thing such a decorator here
abort(400, e.message)
@wsme_pecan.wsexpose(None, wtypes.text, status_code=204) @wsme_pecan.wsexpose(None, wtypes.text, status_code=204)
def delete(self, name): def delete(self, name):

View File

@ -202,8 +202,8 @@ def event_create(values, session=None):
event.save(session) event.save(session)
except db_exc.DBDuplicateEntry as e: except db_exc.DBDuplicateEntry as e:
LOG.exception("Database registration exception: %s", e) LOG.exception("Database registration exception: %s", e)
##TODO(akuznetsov) create special exception for this case raise exc.DBDuplicateEntry("Duplicate entry for Event: %s"
raise Exception % e.columns)
return event return event
@ -263,8 +263,8 @@ def workbook_create(values, session=None):
workbook.save(session=session) workbook.save(session=session)
except db_exc.DBDuplicateEntry as e: except db_exc.DBDuplicateEntry as e:
LOG.exception("Database registration exception: %s", e) LOG.exception("Database registration exception: %s", e)
##TODO(akuznetsov) create special exception for this case raise exc.DBDuplicateEntry("Duplicate entry for Workbook: %s"
raise Exception % e.columns)
return workbook return workbook
@ -326,8 +326,8 @@ def execution_create(workbook_name, values, session=None):
execution.save(session=session) execution.save(session=session)
except db_exc.DBDuplicateEntry as e: except db_exc.DBDuplicateEntry as e:
LOG.exception("Database registration exception: %s", e) LOG.exception("Database registration exception: %s", e)
##TODO(akuznetsov) create special exception for this case raise exc.DBDuplicateEntry("Duplicate entry for Execution: %s"
raise Exception % e.columns)
return execution return execution
@ -394,8 +394,8 @@ def task_create(workbook_name, execution_id, values, session=None):
task.save(session=session) task.save(session=session)
except db_exc.DBDuplicateEntry as e: except db_exc.DBDuplicateEntry as e:
LOG.exception("Database registration exception: %s", e) LOG.exception("Database registration exception: %s", e)
##TODO(akuznetsov) create special exception for this case raise exc.DBDuplicateEntry("Duplicate entry for Task: %s"
raise Exception % e.columns)
return task return task

View File

@ -14,12 +14,42 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import mistral.openstack.common.exception as ex
class DataAccessException(Exception):
class MistralException(ex.Error):
"""Base Exception for the project
To correctly use this class, inherit from it and define
a 'message' and 'code' properties.
"""
message = "An unknown exception occurred"
code = "UNKNOWN_EXCEPTION"
def __str__(self):
return self.message
def __init__(self, message):
super(MistralException, self).__init__(
'%s: %s' % (self.code, self.message))
class DataAccessException(MistralException):
def __init__(self, message=None): def __init__(self, message=None):
super(Exception, self).__init__(message) if message:
self.message = message
class InvalidActionException(Exception): class InvalidActionException(MistralException):
def __init__(self, message=None): def __init__(self, message=None):
super(Exception, self).__init__(message) if message:
self.message = message
class DBDuplicateEntry(MistralException):
message = "Database object already exists"
code = "DB_DUPLICATE_ENTRY"
def __init__(self, message=None):
if message:
self.message = message

View File

@ -0,0 +1,139 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack Foundation.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
Exceptions common to OpenStack projects
"""
import logging
from mistral.openstack.common.gettextutils import _ # noqa
_FATAL_EXCEPTION_FORMAT_ERRORS = False
class Error(Exception):
def __init__(self, message=None):
super(Error, self).__init__(message)
class ApiError(Error):
def __init__(self, message='Unknown', code='Unknown'):
self.api_message = message
self.code = code
super(ApiError, self).__init__('%s: %s' % (code, message))
class NotFound(Error):
pass
class UnknownScheme(Error):
msg_fmt = "Unknown scheme '%s' found in URI"
def __init__(self, scheme):
msg = self.msg_fmt % scheme
super(UnknownScheme, self).__init__(msg)
class BadStoreUri(Error):
msg_fmt = "The Store URI %s was malformed. Reason: %s"
def __init__(self, uri, reason):
msg = self.msg_fmt % (uri, reason)
super(BadStoreUri, self).__init__(msg)
class Duplicate(Error):
pass
class NotAuthorized(Error):
pass
class NotEmpty(Error):
pass
class Invalid(Error):
pass
class BadInputError(Exception):
"""Error resulting from a client sending bad input to a server"""
pass
class MissingArgumentError(Error):
pass
class DatabaseMigrationError(Error):
pass
class ClientConnectionError(Exception):
"""Error resulting from a client connecting to a server"""
pass
def wrap_exception(f):
def _wrap(*args, **kw):
try:
return f(*args, **kw)
except Exception as e:
if not isinstance(e, Error):
logging.exception(_('Uncaught exception'))
raise Error(str(e))
raise
_wrap.func_name = f.func_name
return _wrap
class OpenstackException(Exception):
"""Base Exception class.
To correctly use this class, inherit from it and define
a 'msg_fmt' property. That message will get printf'd
with the keyword arguments provided to the constructor.
"""
msg_fmt = "An unknown exception occurred"
def __init__(self, **kwargs):
try:
self._error_string = self.msg_fmt % kwargs
except Exception:
if _FATAL_EXCEPTION_FORMAT_ERRORS:
raise
else:
# at least get the core message out if something happened
self._error_string = self.msg_fmt
def __str__(self):
return self._error_string
class MalformedRequestBody(OpenstackException):
msg_fmt = "Malformed message body: %(reason)s"
class InvalidContentType(OpenstackException):
msg_fmt = "Invalid content type %(content_type)s"