Merge "Remove output from list action executions API"
This commit is contained in:
commit
7ecb6ad423
@ -43,14 +43,17 @@ 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)
|
||||
return _get_action_execution_resource(db_api.get_action_execution(id))
|
||||
|
||||
|
||||
def _get_action_execution_resource(action_ex):
|
||||
_load_deferred_output_field(action_ex)
|
||||
|
||||
return _get_action_execution_resource_for_list(action_ex)
|
||||
|
||||
|
||||
def _get_action_execution_resource_for_list(action_ex):
|
||||
|
||||
# TODO(nmakhotkin): Get rid of using dicts for constructing resources.
|
||||
# TODO(nmakhotkin): Use db_model for this instead.
|
||||
res = resources.ActionExecution.from_dict(action_ex.to_dict())
|
||||
@ -64,7 +67,7 @@ def _get_action_execution_resource(action_ex):
|
||||
|
||||
def _get_action_executions(task_execution_id=None, marker=None, limit=None,
|
||||
sort_keys='created_at', sort_dirs='asc',
|
||||
fields='', **filters):
|
||||
fields='', include_output=False, **filters):
|
||||
"""Return all action executions.
|
||||
|
||||
Where project_id is the same as the requester or
|
||||
@ -89,12 +92,17 @@ def _get_action_executions(task_execution_id=None, marker=None, limit=None,
|
||||
if task_execution_id:
|
||||
filters['task_execution_id'] = task_execution_id
|
||||
|
||||
if include_output:
|
||||
resource_function = _get_action_execution_resource
|
||||
else:
|
||||
resource_function = _get_action_execution_resource_for_list
|
||||
|
||||
return rest_utils.get_all(
|
||||
resources.ActionExecutions,
|
||||
resources.ActionExecution,
|
||||
db_api.get_action_executions,
|
||||
db_api.get_action_execution,
|
||||
resource_function=_get_action_execution_resource,
|
||||
resource_function=resource_function,
|
||||
marker=marker,
|
||||
limit=limit,
|
||||
sort_keys=sort_keys,
|
||||
@ -186,13 +194,13 @@ class ActionExecutionsController(rest.RestController):
|
||||
wtypes.text, wtypes.text, wtypes.text,
|
||||
wtypes.text, wtypes.text, wtypes.text, types.uuid,
|
||||
wtypes.text, wtypes.text, bool, types.jsontype,
|
||||
types.jsontype, types.jsontype, wtypes.text)
|
||||
types.jsontype, types.jsontype, wtypes.text, bool)
|
||||
def get_all(self, marker=None, limit=None, sort_keys='created_at',
|
||||
sort_dirs='asc', fields='', created_at=None, name=None,
|
||||
tags=None, updated_at=None, workflow_name=None,
|
||||
task_name=None, task_execution_id=None, state=None,
|
||||
state_info=None, accepted=None, input=None, output=None,
|
||||
params=None, description=None):
|
||||
params=None, description=None, include_output=False):
|
||||
"""Return all tasks within the execution.
|
||||
|
||||
Where project_id is the same as the requester or
|
||||
@ -234,6 +242,8 @@ class ActionExecutionsController(rest.RestController):
|
||||
time and date.
|
||||
:param updated_at: Optional. Keep only resources with specific latest
|
||||
update time and date.
|
||||
:param include_output: Optional. Include the output for all executions
|
||||
in the list
|
||||
"""
|
||||
acl.enforce('action_executions:list', context.ctx())
|
||||
|
||||
@ -264,6 +274,7 @@ class ActionExecutionsController(rest.RestController):
|
||||
sort_keys=sort_keys,
|
||||
sort_dirs=sort_dirs,
|
||||
fields=fields,
|
||||
include_output=include_output,
|
||||
**filters
|
||||
)
|
||||
|
||||
@ -302,13 +313,14 @@ class TasksActionExecutionController(rest.RestController):
|
||||
wtypes.text, types.uniquelist, wtypes.text,
|
||||
wtypes.text, wtypes.text, wtypes.text, wtypes.text,
|
||||
wtypes.text, bool, types.jsontype, types.jsontype,
|
||||
types.jsontype, wtypes.text)
|
||||
types.jsontype, wtypes.text, bool)
|
||||
def get_all(self, task_execution_id, marker=None, limit=None,
|
||||
sort_keys='created_at', sort_dirs='asc', fields='',
|
||||
created_at=None, name=None, tags=None,
|
||||
updated_at=None, workflow_name=None, task_name=None,
|
||||
state=None, state_info=None, accepted=None, input=None,
|
||||
output=None, params=None, description=None):
|
||||
output=None, params=None, description=None,
|
||||
include_output=None):
|
||||
"""Return all tasks within the execution.
|
||||
|
||||
Where project_id is the same as the requester or
|
||||
@ -350,6 +362,8 @@ class TasksActionExecutionController(rest.RestController):
|
||||
time and date.
|
||||
:param updated_at: Optional. Keep only resources with specific latest
|
||||
update time and date.
|
||||
:param include_output: Optional. Include the output for all executions
|
||||
in the list
|
||||
"""
|
||||
acl.enforce('action_executions:list', context.ctx())
|
||||
|
||||
@ -380,6 +394,7 @@ class TasksActionExecutionController(rest.RestController):
|
||||
sort_keys=sort_keys,
|
||||
sort_dirs=sort_dirs,
|
||||
fields=fields,
|
||||
include_output=include_output,
|
||||
**filters
|
||||
)
|
||||
|
||||
|
@ -22,11 +22,13 @@ import mock
|
||||
from oslo_config import cfg
|
||||
import oslo_messaging
|
||||
|
||||
from mistral.api.controllers.v2 import action_execution
|
||||
from mistral.db.v2 import api as db_api
|
||||
from mistral.db.v2.sqlalchemy import models
|
||||
from mistral.engine.rpc_backend import rpc
|
||||
from mistral import exceptions as exc
|
||||
from mistral.tests.unit.api import base
|
||||
from mistral.utils import rest_utils
|
||||
from mistral.workflow import states
|
||||
from mistral.workflow import utils as wf_utils
|
||||
|
||||
@ -448,6 +450,29 @@ class TestActionExecutionsController(base.APITest):
|
||||
self.assertEqual(1, len(resp.json['action_executions']))
|
||||
self.assertDictEqual(ACTION_EX, resp.json['action_executions'][0])
|
||||
|
||||
@mock.patch.object(db_api, 'get_action_executions', MOCK_ACTIONS)
|
||||
@mock.patch.object(rest_utils, 'get_all')
|
||||
def test_get_all_with_and_without_output(self, mock_get_all):
|
||||
resp = self.app.get('/v2/action_executions')
|
||||
args, kwargs = mock_get_all.call_args
|
||||
resource_function = kwargs['resource_function']
|
||||
|
||||
self.assertEqual(200, resp.status_int)
|
||||
self.assertEqual(
|
||||
action_execution._get_action_execution_resource_for_list,
|
||||
resource_function
|
||||
)
|
||||
|
||||
resp = self.app.get('/v2/action_executions?include_output=true')
|
||||
args, kwargs = mock_get_all.call_args
|
||||
resource_function = kwargs['resource_function']
|
||||
|
||||
self.assertEqual(200, resp.status_int)
|
||||
self.assertEqual(
|
||||
action_execution._get_action_execution_resource,
|
||||
resource_function
|
||||
)
|
||||
|
||||
@mock.patch.object(db_api, 'get_action_executions', MOCK_EMPTY)
|
||||
def test_get_all_empty(self):
|
||||
resp = self.app.get('/v2/action_executions')
|
||||
@ -483,7 +508,7 @@ class TestActionExecutionsController(base.APITest):
|
||||
)
|
||||
|
||||
@mock.patch.object(db_api, 'get_action_execution', MOCK_ACTION)
|
||||
def test_delete_action_exeuction_with_task(self):
|
||||
def test_delete_action_execution_with_task(self):
|
||||
cfg.CONF.set_default('allow_action_execution_deletion', True, 'api')
|
||||
|
||||
resp = self.app.delete('/v2/action_executions/123', expect_errors=True)
|
||||
@ -499,7 +524,7 @@ class TestActionExecutionsController(base.APITest):
|
||||
'get_action_execution',
|
||||
MOCK_ACTION_NOT_COMPLETE
|
||||
)
|
||||
def test_delete_action_exeuction_not_complete(self):
|
||||
def test_delete_action_execution_not_complete(self):
|
||||
cfg.CONF.set_default('allow_action_execution_deletion', True, 'api')
|
||||
|
||||
resp = self.app.delete('/v2/action_executions/123', expect_errors=True)
|
||||
@ -516,7 +541,7 @@ class TestActionExecutionsController(base.APITest):
|
||||
MOCK_ACTION_COMPLETE_ERROR
|
||||
)
|
||||
@mock.patch.object(db_api, 'delete_action_execution', MOCK_DELETE)
|
||||
def test_delete_action_exeuction_complete_error(self):
|
||||
def test_delete_action_execution_complete_error(self):
|
||||
cfg.CONF.set_default('allow_action_execution_deletion', True, 'api')
|
||||
|
||||
resp = self.app.delete('/v2/action_executions/123', expect_errors=True)
|
||||
@ -529,7 +554,7 @@ class TestActionExecutionsController(base.APITest):
|
||||
MOCK_ACTION_COMPLETE_CANCELLED
|
||||
)
|
||||
@mock.patch.object(db_api, 'delete_action_execution', MOCK_DELETE)
|
||||
def test_delete_action_exeuction_complete_cancelled(self):
|
||||
def test_delete_action_execution_complete_cancelled(self):
|
||||
cfg.CONF.set_default('allow_action_execution_deletion', True, 'api')
|
||||
|
||||
resp = self.app.delete('/v2/action_executions/123', expect_errors=True)
|
||||
|
@ -75,6 +75,9 @@ class MistralClientV2(base.MistralClientBase):
|
||||
|
||||
return resp, json.loads(body)
|
||||
|
||||
def get_action_execution(self, action_execution_id):
|
||||
return self.get('action_executions/%s' % action_execution_id)
|
||||
|
||||
def create_execution(self, identifier, wf_input=None, params=None):
|
||||
if uuidutils.is_uuid_like(identifier):
|
||||
body = {"workflow_id": "%s" % identifier}
|
||||
@ -130,9 +133,11 @@ class MistralClientV2(base.MistralClientBase):
|
||||
return [t for t in all_tasks if t['workflow_name'] == wf_name]
|
||||
|
||||
def create_action_execution(self, request_body, extra_headers={}):
|
||||
resp, body = self.post_json('action_executions',
|
||||
request_body,
|
||||
extra_headers)
|
||||
resp, body = self.post_json(
|
||||
'action_executions',
|
||||
request_body,
|
||||
extra_headers
|
||||
)
|
||||
|
||||
params = json.loads(request_body.get('params', '{}'))
|
||||
if params.get('save_result', False):
|
||||
|
@ -28,6 +28,17 @@ LOG = logging.getLogger(__name__)
|
||||
class ActionExecutionTestsV2(base.TestCase):
|
||||
_service = 'workflowv2'
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ActionExecutionTestsV2, cls).resource_setup()
|
||||
|
||||
cls.client.create_action_execution(
|
||||
{
|
||||
'name': 'std.echo',
|
||||
'input': '{"output": "Hello, Mistral!"}'
|
||||
}
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def resource_cleanup(cls):
|
||||
for action_ex in cls.client.action_executions:
|
||||
@ -58,6 +69,60 @@ class ActionExecutionTestsV2(base.TestCase):
|
||||
output
|
||||
)
|
||||
|
||||
@test.attr(type='sanity')
|
||||
def test_list_action_executions(self):
|
||||
resp, body = self.client.get_list_obj('action_executions')
|
||||
|
||||
self.assertEqual(200, resp.status)
|
||||
|
||||
@test.attr(type='sanity')
|
||||
def test_output_appear_in_response_only_when_needed(self):
|
||||
resp, body = self.client.get_list_obj('action_executions')
|
||||
|
||||
self.assertEqual(200, resp.status)
|
||||
action_execution = body['action_executions'][0]
|
||||
self.assertNotIn("output", action_execution)
|
||||
|
||||
resp, body = self.client.get_list_obj(
|
||||
'action_executions?include_output=True'
|
||||
)
|
||||
|
||||
self.assertEqual(200, resp.status)
|
||||
action_execution = body['action_executions'][0]
|
||||
self.assertIn("output", action_execution)
|
||||
|
||||
resp, body = self.client.get_action_execution(action_execution['id'])
|
||||
self.assertIn("output", body)
|
||||
|
||||
# Test when passing task execution ID
|
||||
|
||||
resp, body = self.client.create_workflow('wf_v2.yaml')
|
||||
wf_name = body['workflows'][0]['name']
|
||||
self.assertEqual(201, resp.status)
|
||||
resp, body = self.client.create_execution(wf_name)
|
||||
self.assertEqual(201, resp.status)
|
||||
resp, body = self.client.get_list_obj('tasks')
|
||||
self.assertEqual(200, resp.status)
|
||||
task_id = body['tasks'][0]['id']
|
||||
|
||||
resp, body = self.client.get_list_obj(
|
||||
'action_executions?include_output=true&task_execution_id=%s' %
|
||||
task_id
|
||||
)
|
||||
|
||||
self.assertEqual(200, resp.status)
|
||||
action_execution = body['action_executions'][0]
|
||||
self.assertIn("output", action_execution)
|
||||
|
||||
resp, body = self.client.get_list_obj(
|
||||
'action_executions?&task_execution_id=%s' %
|
||||
task_id
|
||||
)
|
||||
|
||||
self.assertEqual(200, resp.status)
|
||||
action_execution = body['action_executions'][0]
|
||||
self.assertNotIn("output", action_execution)
|
||||
|
||||
@test.attr(type='sanity')
|
||||
def test_run_action_std_http(self):
|
||||
resp, body = self.client.create_action_execution(
|
||||
|
@ -28,6 +28,7 @@ class TasksTestsV2(base.TestCase):
|
||||
_, body = self.client.create_workflow('wf_v2.yaml')
|
||||
self.direct_wf_name = body['workflows'][0]['name']
|
||||
_, execution = self.client.create_execution(self.direct_wf_name)
|
||||
self.execution_id = execution['id']
|
||||
|
||||
def tearDown(self):
|
||||
for wf in self.client.workflows:
|
||||
@ -56,6 +57,17 @@ class TasksTestsV2(base.TestCase):
|
||||
self.direct_wf_name, body['tasks'][-1]['workflow_name']
|
||||
)
|
||||
|
||||
@test.attr(type='sanity')
|
||||
def test_get_tasks_of_execution(self):
|
||||
resp, body = self.client.get_list_obj(
|
||||
'tasks?workflow_execution_id=%s' % self.execution_id
|
||||
)
|
||||
|
||||
self.assertEqual(200, resp.status)
|
||||
self.assertEqual(
|
||||
self.direct_wf_name, body['tasks'][-1]['workflow_name']
|
||||
)
|
||||
|
||||
|
||||
class TaskTypesTestsV2(base.TestCase):
|
||||
|
||||
|
@ -0,0 +1,16 @@
|
||||
---
|
||||
|
||||
features:
|
||||
- |
|
||||
|
||||
New parameter called 'include_output' added to action execution api.
|
||||
By default output field does not return when calling list action executions
|
||||
API
|
||||
|
||||
critical:
|
||||
- |
|
||||
|
||||
By default, output field will not return when calling list action
|
||||
executions. In the previous version it did, so if a user used this, and/or
|
||||
wants to get output field when calling list action executions API, it will
|
||||
be possible only by using the new include output parameter.
|
Loading…
Reference in New Issue
Block a user