Fix possible DB race conditions in REST controller
Two (or more) consecutive DB API calls must use the same transaction. Change-Id: I68f7fd7b205818d3049c456b717beccf17153727
This commit is contained in:
parent
9b39d7bc62
commit
ae06418726
@ -43,6 +43,7 @@ def _load_deferred_output_field(action_ex):
|
||||
|
||||
|
||||
def _get_action_execution(id):
|
||||
with db_api.transaction():
|
||||
action_ex = db_api.get_action_execution(id)
|
||||
|
||||
return _get_action_execution_resource(action_ex)
|
||||
@ -275,15 +276,18 @@ class ActionExecutionsController(rest.RestController):
|
||||
raise exc.NotAllowedException("Action execution deletion is not "
|
||||
"allowed.")
|
||||
|
||||
with db_api.transaction():
|
||||
action_ex = db_api.get_action_execution(id)
|
||||
|
||||
if action_ex.task_execution_id:
|
||||
raise exc.NotAllowedException("Only ad-hoc action execution can "
|
||||
"be deleted.")
|
||||
raise exc.NotAllowedException(
|
||||
"Only ad-hoc action execution can be deleted."
|
||||
)
|
||||
|
||||
if not states.is_completed(action_ex.state):
|
||||
raise exc.NotAllowedException("Only completed action execution "
|
||||
"can be deleted.")
|
||||
raise exc.NotAllowedException(
|
||||
"Only completed action execution can be deleted."
|
||||
)
|
||||
|
||||
return db_api.delete_action_execution(id)
|
||||
|
||||
|
@ -96,10 +96,11 @@ class EventTriggersController(rest.RestController):
|
||||
UPDATE_NOT_ALLOWED
|
||||
)
|
||||
|
||||
db_api.ensure_event_trigger_exists(id)
|
||||
|
||||
LOG.info('Update event trigger: [id=%s, values=%s]', id, values)
|
||||
|
||||
with db_api.transaction():
|
||||
db_api.ensure_event_trigger_exists(id)
|
||||
|
||||
db_model = triggers.update_event_trigger(id, values)
|
||||
|
||||
return resources.EventTrigger.from_dict(db_model.to_dict())
|
||||
@ -112,6 +113,7 @@ class EventTriggersController(rest.RestController):
|
||||
|
||||
LOG.info("Delete event trigger [id=%s]", id)
|
||||
|
||||
with db_api.transaction():
|
||||
event_trigger = db_api.get_event_trigger(id)
|
||||
|
||||
triggers.delete_event_trigger(event_trigger.to_dict())
|
||||
|
@ -95,6 +95,7 @@ class ExecutionsController(rest.RestController):
|
||||
|
||||
LOG.info('Update execution [id=%s, execution=%s]' % (id, wf_ex))
|
||||
|
||||
with db_api.transaction():
|
||||
db_api.ensure_workflow_execution_exists(id)
|
||||
|
||||
delta = {}
|
||||
@ -137,7 +138,6 @@ class ExecutionsController(rest.RestController):
|
||||
)
|
||||
|
||||
if not delta.get('state') and delta.get('env'):
|
||||
with db_api.transaction():
|
||||
wf_ex = db_api.get_workflow_execution(id)
|
||||
wf_ex = wf_service.update_workflow_execution_env(
|
||||
wf_ex,
|
||||
|
@ -121,6 +121,7 @@ class MembersController(rest.RestController):
|
||||
msg = "Member id must be provided."
|
||||
raise exc.WorkflowException(msg)
|
||||
|
||||
with db_api.transaction():
|
||||
wf_db = db_api.get_workflow_definition(self.resource_id)
|
||||
|
||||
if wf_db.scope != 'private':
|
||||
|
@ -140,6 +140,7 @@ class TasksController(rest.RestController):
|
||||
acl.enforce('tasks:get', context.ctx())
|
||||
LOG.info("Fetch task [id=%s]" % id)
|
||||
|
||||
with db_api.transaction():
|
||||
task_ex = db_api.get_task_execution(id)
|
||||
|
||||
return _get_task_resource_with_result(task_ex)
|
||||
@ -245,6 +246,7 @@ class TasksController(rest.RestController):
|
||||
|
||||
LOG.info("Update task execution [id=%s, task=%s]" % (id, task))
|
||||
|
||||
with db_api.transaction():
|
||||
task_ex = db_api.get_task_execution(id)
|
||||
task_spec = spec_parser.get_task_spec(task_ex.spec)
|
||||
task_name = task.name or None
|
||||
@ -254,7 +256,10 @@ class TasksController(rest.RestController):
|
||||
if task_name and task_name != task_ex.name:
|
||||
raise exc.WorkflowException('Task name does not match.')
|
||||
|
||||
wf_ex = db_api.get_workflow_execution(task_ex.workflow_execution_id)
|
||||
wf_ex = db_api.get_workflow_execution(
|
||||
task_ex.workflow_execution_id
|
||||
)
|
||||
|
||||
wf_name = task.workflow_name or None
|
||||
|
||||
if wf_name and wf_name != wf_ex.name:
|
||||
@ -262,7 +267,8 @@ class TasksController(rest.RestController):
|
||||
|
||||
if task.state != states.RUNNING:
|
||||
raise exc.WorkflowException(
|
||||
'Invalid task state. Only updating task to rerun is supported.'
|
||||
'Invalid task state. '
|
||||
'Only updating task to rerun is supported.'
|
||||
)
|
||||
|
||||
if task_ex.state != states.ERROR:
|
||||
@ -282,6 +288,7 @@ class TasksController(rest.RestController):
|
||||
env=env
|
||||
)
|
||||
|
||||
with db_api.transaction():
|
||||
task_ex = db_api.get_task_execution(id)
|
||||
|
||||
return _get_task_resource_with_result(task_ex)
|
||||
|
@ -158,7 +158,6 @@ def create_event_trigger(name, exchange, topic, event, workflow_id,
|
||||
|
||||
|
||||
def delete_event_trigger(event_trigger):
|
||||
with db_api.transaction():
|
||||
db_api.delete_event_trigger(event_trigger['id'])
|
||||
|
||||
trigs = db_api.get_event_triggers(
|
||||
@ -177,7 +176,6 @@ def delete_event_trigger(event_trigger):
|
||||
|
||||
|
||||
def update_event_trigger(id, values):
|
||||
with db_api.transaction():
|
||||
trig = db_api.update_event_trigger(id, values)
|
||||
|
||||
# NOTE(kong): Send RPC message within the db transaction, rollback if
|
||||
|
@ -25,6 +25,7 @@ import six
|
||||
import webob
|
||||
from wsme import exc as wsme_exc
|
||||
|
||||
from mistral.db.v2.sqlalchemy import api as db_api
|
||||
from mistral import exceptions as exc
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -163,6 +164,7 @@ def get_all(list_cls, cls, get_all_function, get_function,
|
||||
list_to_return = []
|
||||
|
||||
if resource_function:
|
||||
with db_api.transaction():
|
||||
# do not filter fields yet, resource_function needs the ORM object
|
||||
db_list = get_all_function(
|
||||
limit=limit,
|
||||
|
Loading…
Reference in New Issue
Block a user