Add new CLI commands for sub-executions new API endpoints
*2 new CLI commands were added:
- execution-get-sub-executions
returns the sub-executions of a given execution id
- task-get-sub-executions
returns the sub-executions of a given task-execution id
both commands have the options
--errors_only: returns only the error routes
- default is False
--max_depth: the max depth for the returned executions
- if a negative value is given, then the API will return
all sub-executions
- default is -1
Change-Id: Ifcd25cfdbfb99613ff1bdccf8b94b3929f02a71d
Implements: blueprint mistral-execution-origin
Signed-off-by: ali <ali.abdelal@nokia.com>
This commit is contained in:
@@ -173,7 +173,9 @@ class ResourceManager(object):
|
|||||||
for resource_data in resource]
|
for resource_data in resource]
|
||||||
return self.resource_class(self, resource)
|
return self.resource_class(self, resource)
|
||||||
|
|
||||||
def _list(self, url, response_key=None, headers=None):
|
def _list(self, url, response_key=None, headers=None,
|
||||||
|
returned_res_cls=None):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
resp = self.http_client.get(url, headers)
|
resp = self.http_client.get(url, headers)
|
||||||
except exceptions.HttpError as ex:
|
except exceptions.HttpError as ex:
|
||||||
@@ -182,7 +184,9 @@ class ResourceManager(object):
|
|||||||
if resp.status_code != 200:
|
if resp.status_code != 200:
|
||||||
self._raise_api_exception(resp)
|
self._raise_api_exception(resp)
|
||||||
|
|
||||||
return [self.resource_class(self, resource_data)
|
resource_class = returned_res_cls or self.resource_class
|
||||||
|
|
||||||
|
return [resource_class(self, resource_data)
|
||||||
for resource_data in extract_json(resp, response_key)]
|
for resource_data in extract_json(resp, response_key)]
|
||||||
|
|
||||||
def _get(self, url, response_key=None, headers=None):
|
def _get(self, url, response_key=None, headers=None):
|
||||||
|
|||||||
@@ -98,6 +98,15 @@ class ExecutionManager(base.ResourceManager):
|
|||||||
|
|
||||||
return self._get('/executions/%s' % id)
|
return self._get('/executions/%s' % id)
|
||||||
|
|
||||||
|
def get_ex_sub_executions(self, id, errors_only='', max_depth=-1):
|
||||||
|
ex_sub_execs_path = '/executions/%s/executions%s'
|
||||||
|
params = '?max_depth=%s&errors_only=%s' % (max_depth, errors_only)
|
||||||
|
|
||||||
|
return self._list(
|
||||||
|
ex_sub_execs_path % (id, params),
|
||||||
|
response_key='executions'
|
||||||
|
)
|
||||||
|
|
||||||
def delete(self, id, force=None):
|
def delete(self, id, force=None):
|
||||||
self._ensure_not_empty(id=id)
|
self._ensure_not_empty(id=id)
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
|
|
||||||
from mistralclient.api import base
|
from mistralclient.api import base
|
||||||
|
from mistralclient.api.v2 import executions
|
||||||
|
|
||||||
|
|
||||||
class Task(base.Resource):
|
class Task(base.Resource):
|
||||||
@@ -50,6 +51,16 @@ class TaskManager(base.ResourceManager):
|
|||||||
|
|
||||||
return self._get('/tasks/%s' % id)
|
return self._get('/tasks/%s' % id)
|
||||||
|
|
||||||
|
def get_task_sub_executions(self, id, errors_only='', max_depth=-1):
|
||||||
|
task_sub_execs_path = '/tasks/%s/executions%s'
|
||||||
|
params = '?max_depth=%s&errors_only=%s' % (max_depth, errors_only)
|
||||||
|
|
||||||
|
return self._list(
|
||||||
|
task_sub_execs_path % (id, params),
|
||||||
|
response_key='executions',
|
||||||
|
returned_res_cls=executions.Execution
|
||||||
|
)
|
||||||
|
|
||||||
def rerun(self, task_ex_id, reset=True, env=None):
|
def rerun(self, task_ex_id, reset=True, env=None):
|
||||||
url = '/tasks/%s' % task_ex_id
|
url = '/tasks/%s' % task_ex_id
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ from oslo_serialization import jsonutils
|
|||||||
|
|
||||||
from osc_lib.command import command
|
from osc_lib.command import command
|
||||||
|
|
||||||
|
from cliff.lister import Lister as cliff_lister
|
||||||
from mistralclient.commands.v2 import base
|
from mistralclient.commands.v2 import base
|
||||||
from mistralclient import utils
|
from mistralclient import utils
|
||||||
|
|
||||||
@@ -510,3 +511,71 @@ class GetPublished(command.Command):
|
|||||||
LOG.debug("Task result is not JSON.")
|
LOG.debug("Task result is not JSON.")
|
||||||
|
|
||||||
self.app.stdout.write(published or "\n")
|
self.app.stdout.write(published or "\n")
|
||||||
|
|
||||||
|
|
||||||
|
class SubExecutionsBaseLister(cliff_lister):
|
||||||
|
|
||||||
|
def _get_format_function(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def _get_resources_function(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(SubExecutionsBaseLister, self).get_parser(prog_name)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'id',
|
||||||
|
metavar='ID',
|
||||||
|
help='origin id'
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--errors-only',
|
||||||
|
dest='errors_only',
|
||||||
|
action='store_true',
|
||||||
|
help='Only error paths will be included.'
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--max-depth',
|
||||||
|
dest='max_depth',
|
||||||
|
nargs='?',
|
||||||
|
type=int,
|
||||||
|
default=-1,
|
||||||
|
help='Maximum depth of the workflow execution tree. '
|
||||||
|
'If 0, only the root workflow execution and its '
|
||||||
|
'tasks will be included'
|
||||||
|
)
|
||||||
|
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def _get_resources(self, parsed_args):
|
||||||
|
resource_function = self._get_resources_function()
|
||||||
|
errors_only = parsed_args.errors_only or ''
|
||||||
|
|
||||||
|
return resource_function(
|
||||||
|
parsed_args.id,
|
||||||
|
errors_only=errors_only,
|
||||||
|
max_depth=parsed_args.max_depth,
|
||||||
|
)
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
format_func = self._get_format_function()
|
||||||
|
execs_list = self._get_resources(parsed_args)
|
||||||
|
|
||||||
|
if not isinstance(execs_list, list):
|
||||||
|
execs_list = [execs_list]
|
||||||
|
|
||||||
|
data = [format_func(r)[1] for r in execs_list]
|
||||||
|
|
||||||
|
return (format_func()[0], data) if data else format_func()
|
||||||
|
|
||||||
|
|
||||||
|
class SubExecutionsLister(SubExecutionsBaseLister):
|
||||||
|
|
||||||
|
def _get_format_function(self):
|
||||||
|
return ExecutionFormatter.format_list
|
||||||
|
|
||||||
|
def _get_resources_function(self):
|
||||||
|
mistral_client = self.app.client_manager.workflow_engine
|
||||||
|
|
||||||
|
return mistral_client.executions.get_ex_sub_executions
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from oslo_serialization import jsonutils
|
|||||||
from osc_lib.command import command
|
from osc_lib.command import command
|
||||||
|
|
||||||
from mistralclient.commands.v2 import base
|
from mistralclient.commands.v2 import base
|
||||||
|
from mistralclient.commands.v2 import executions
|
||||||
from mistralclient import utils
|
from mistralclient import utils
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@@ -211,3 +212,14 @@ class Rerun(command.ShowOne):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return TaskFormatter.format(execution)
|
return TaskFormatter.format(execution)
|
||||||
|
|
||||||
|
|
||||||
|
class SubExecutionsLister(executions.SubExecutionsBaseLister):
|
||||||
|
|
||||||
|
def _get_format_function(self):
|
||||||
|
return executions.ExecutionFormatter.format_list
|
||||||
|
|
||||||
|
def _get_resources_function(self):
|
||||||
|
mistral_client = self.app.client_manager.workflow_engine
|
||||||
|
|
||||||
|
return mistral_client.tasks.get_task_sub_executions
|
||||||
|
|||||||
@@ -732,10 +732,14 @@ class MistralShell(app.App):
|
|||||||
mistralclient.commands.v2.executions.GetReport,
|
mistralclient.commands.v2.executions.GetReport,
|
||||||
'execution-get-published':
|
'execution-get-published':
|
||||||
mistralclient.commands.v2.executions.GetPublished,
|
mistralclient.commands.v2.executions.GetPublished,
|
||||||
|
'execution-get-sub-executions':
|
||||||
|
mistralclient.commands.v2.executions.SubExecutionsLister,
|
||||||
'task-list': mistralclient.commands.v2.tasks.List,
|
'task-list': mistralclient.commands.v2.tasks.List,
|
||||||
'task-get': mistralclient.commands.v2.tasks.Get,
|
'task-get': mistralclient.commands.v2.tasks.Get,
|
||||||
'task-get-published': mistralclient.commands.v2.tasks.GetPublished,
|
'task-get-published': mistralclient.commands.v2.tasks.GetPublished,
|
||||||
'task-get-result': mistralclient.commands.v2.tasks.GetResult,
|
'task-get-result': mistralclient.commands.v2.tasks.GetResult,
|
||||||
|
'task-get-sub-executions':
|
||||||
|
mistralclient.commands.v2.tasks.SubExecutionsLister,
|
||||||
'task-rerun': mistralclient.commands.v2.tasks.Rerun,
|
'task-rerun': mistralclient.commands.v2.tasks.Rerun,
|
||||||
'action-list': mistralclient.commands.v2.actions.List,
|
'action-list': mistralclient.commands.v2.actions.List,
|
||||||
'action-get': mistralclient.commands.v2.actions.Get,
|
'action-get': mistralclient.commands.v2.actions.Get,
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ SUB_WF_EXEC = executions.Execution(
|
|||||||
'workflow_namespace': '',
|
'workflow_namespace': '',
|
||||||
'root_execution_id': 'ROOT_EXECUTION_ID',
|
'root_execution_id': 'ROOT_EXECUTION_ID',
|
||||||
'description': '',
|
'description': '',
|
||||||
'state': 'RUNNING',
|
'state': 'ERROR',
|
||||||
'state_info': None,
|
'state_info': None,
|
||||||
'created_at': '1',
|
'created_at': '1',
|
||||||
'updated_at': '1',
|
'updated_at': '1',
|
||||||
@@ -83,12 +83,13 @@ SUB_WF_EX_RESULT = (
|
|||||||
'',
|
'',
|
||||||
'abc',
|
'abc',
|
||||||
'ROOT_EXECUTION_ID',
|
'ROOT_EXECUTION_ID',
|
||||||
'RUNNING',
|
'ERROR',
|
||||||
None,
|
None,
|
||||||
'1',
|
'1',
|
||||||
'1'
|
'1'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
EXECS_LIST = [EXEC, SUB_WF_EXEC]
|
||||||
EXEC_PUBLISHED = {"bar1": "val1", "var2": 2}
|
EXEC_PUBLISHED = {"bar1": "val1", "var2": 2}
|
||||||
EXEC_WITH_PUBLISHED_DICT = EXEC_DICT.copy()
|
EXEC_WITH_PUBLISHED_DICT = EXEC_DICT.copy()
|
||||||
EXEC_WITH_PUBLISHED_DICT.update(
|
EXEC_WITH_PUBLISHED_DICT.update(
|
||||||
@@ -241,6 +242,61 @@ class TestCLIExecutionsV2(base.BaseCommandTest):
|
|||||||
result[1]
|
result[1]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_sub_executions(self):
|
||||||
|
self.client.executions.get_ex_sub_executions.return_value = \
|
||||||
|
EXECS_LIST
|
||||||
|
|
||||||
|
result = self.call(
|
||||||
|
execution_cmd.SubExecutionsLister,
|
||||||
|
app_args=[EXEC_DICT['id']]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual([EX_RESULT, SUB_WF_EX_RESULT], result[1])
|
||||||
|
self.assertEqual(
|
||||||
|
1,
|
||||||
|
self.client.executions.get_ex_sub_executions.call_count
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
[mock.call(EXEC_DICT['id'], errors_only='', max_depth=-1)],
|
||||||
|
self.client.executions.get_ex_sub_executions.call_args_list
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_sub_executions_errors_only(self):
|
||||||
|
self.client.executions.get_ex_sub_executions.return_value = \
|
||||||
|
EXECS_LIST
|
||||||
|
|
||||||
|
self.call(
|
||||||
|
execution_cmd.SubExecutionsLister,
|
||||||
|
app_args=[EXEC_DICT['id'], '--errors-only']
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
1,
|
||||||
|
self.client.executions.get_ex_sub_executions.call_count
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
[mock.call(EXEC_DICT['id'], errors_only=True, max_depth=-1)],
|
||||||
|
self.client.executions.get_ex_sub_executions.call_args_list
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_sub_executions_with_max_depth(self):
|
||||||
|
self.client.executions.get_ex_sub_executions.return_value = \
|
||||||
|
EXECS_LIST
|
||||||
|
|
||||||
|
self.call(
|
||||||
|
execution_cmd.SubExecutionsLister,
|
||||||
|
app_args=[EXEC_DICT['id'], '--max-depth', '3']
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
1,
|
||||||
|
self.client.executions.get_ex_sub_executions.call_count
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
[mock.call(EXEC_DICT['id'], errors_only='', max_depth=3)],
|
||||||
|
self.client.executions.get_ex_sub_executions.call_args_list
|
||||||
|
)
|
||||||
|
|
||||||
def test_list_with_pagination(self):
|
def test_list_with_pagination(self):
|
||||||
self.client.executions.list.return_value = [EXEC]
|
self.client.executions.list.return_value = [EXEC]
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ from oslo_serialization import jsonutils
|
|||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
|
from mistralclient.api.v2.executions import Execution
|
||||||
from mistralclient.api.v2 import tasks
|
from mistralclient.api.v2 import tasks
|
||||||
from mistralclient.commands.v2 import tasks as task_cmd
|
from mistralclient.commands.v2 import tasks as task_cmd
|
||||||
from mistralclient.tests.unit import base
|
from mistralclient.tests.unit import base
|
||||||
@@ -35,6 +36,37 @@ TASK_DICT = {
|
|||||||
'updated_at': '1',
|
'updated_at': '1',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TASK_SUB_WF_EXEC = Execution(
|
||||||
|
mock,
|
||||||
|
{
|
||||||
|
'id': '456',
|
||||||
|
'workflow_id': '123e4567-e89b-12d3-a456-426655440000',
|
||||||
|
'workflow_name': 'some_sub_wf',
|
||||||
|
'workflow_namespace': '',
|
||||||
|
'root_execution_id': 'ROOT_EXECUTION_ID',
|
||||||
|
'description': '',
|
||||||
|
'state': 'ERROR',
|
||||||
|
'state_info': None,
|
||||||
|
'created_at': '1',
|
||||||
|
'updated_at': '1',
|
||||||
|
'task_execution_id': '123'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
TASK_SUB_WF_EX_RESULT = (
|
||||||
|
'456',
|
||||||
|
'123e4567-e89b-12d3-a456-426655440000',
|
||||||
|
'some_sub_wf',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'123',
|
||||||
|
'ROOT_EXECUTION_ID',
|
||||||
|
'ERROR',
|
||||||
|
None,
|
||||||
|
'1',
|
||||||
|
'1'
|
||||||
|
)
|
||||||
|
|
||||||
TASK_RESULT = {"test": "is", "passed": "successfully"}
|
TASK_RESULT = {"test": "is", "passed": "successfully"}
|
||||||
TASK_PUBLISHED = {"bar1": "val1", "var2": 2}
|
TASK_PUBLISHED = {"bar1": "val1", "var2": 2}
|
||||||
|
|
||||||
@@ -131,3 +163,58 @@ class TestCLITasksV2(base.BaseCommandTest):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(EXPECTED_TASK_RESULT, result[1])
|
self.assertEqual(EXPECTED_TASK_RESULT, result[1])
|
||||||
|
|
||||||
|
def test_sub_executions(self):
|
||||||
|
self.client.tasks.get_task_sub_executions.return_value = \
|
||||||
|
TASK_SUB_WF_EXEC
|
||||||
|
|
||||||
|
result = self.call(
|
||||||
|
task_cmd.SubExecutionsLister,
|
||||||
|
app_args=[TASK_DICT['id']]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual([TASK_SUB_WF_EX_RESULT], result[1])
|
||||||
|
self.assertEqual(
|
||||||
|
1,
|
||||||
|
self.client.tasks.get_task_sub_executions.call_count
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
[mock.call(TASK_DICT['id'], errors_only='', max_depth=-1)],
|
||||||
|
self.client.tasks.get_task_sub_executions.call_args_list
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_sub_executions_errors_only(self):
|
||||||
|
self.client.tasks.get_task_sub_executions.return_value = \
|
||||||
|
TASK_SUB_WF_EXEC
|
||||||
|
|
||||||
|
self.call(
|
||||||
|
task_cmd.SubExecutionsLister,
|
||||||
|
app_args=[TASK_DICT['id'], '--errors-only']
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
1,
|
||||||
|
self.client.tasks.get_task_sub_executions.call_count
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
[mock.call(TASK_DICT['id'], errors_only=True, max_depth=-1)],
|
||||||
|
self.client.tasks.get_task_sub_executions.call_args_list
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_sub_executions_with_max_depth(self):
|
||||||
|
self.client.tasks.get_task_sub_executions.return_value = \
|
||||||
|
TASK_SUB_WF_EXEC
|
||||||
|
|
||||||
|
self.call(
|
||||||
|
task_cmd.SubExecutionsLister,
|
||||||
|
app_args=[TASK_DICT['id'], '--max-depth', '3']
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
1,
|
||||||
|
self.client.tasks.get_task_sub_executions.call_count
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
[mock.call(TASK_DICT['id'], errors_only='', max_depth=3)],
|
||||||
|
self.client.tasks.get_task_sub_executions.call_args_list
|
||||||
|
)
|
||||||
|
|||||||
@@ -52,10 +52,23 @@ SUB_WF_EXEC = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ERROR_SUB_WF_EXEC = {
|
||||||
|
'id': "456",
|
||||||
|
'workflow_id': '123e4567-e89b-12d3-a456-426655440000',
|
||||||
|
'workflow_name': 'my_sub_wf',
|
||||||
|
'workflow_namespace': '',
|
||||||
|
'task_execution_id': "abc",
|
||||||
|
'description': '',
|
||||||
|
'state': 'ERROR',
|
||||||
|
'input': {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SOURCE_EXEC = EXEC
|
SOURCE_EXEC = EXEC
|
||||||
SOURCE_EXEC['source_execution_id'] = EXEC['workflow_id']
|
SOURCE_EXEC['source_execution_id'] = EXEC['workflow_id']
|
||||||
URL_TEMPLATE = '/executions'
|
URL_TEMPLATE = '/executions'
|
||||||
URL_TEMPLATE_ID = '/executions/%s'
|
URL_TEMPLATE_ID = '/executions/%s'
|
||||||
|
URL_TEMPLATE_SUB_EXECUTIONS = '/executions/%s/executions%s'
|
||||||
|
|
||||||
|
|
||||||
class TestExecutionsV2(base.BaseClientV2Test):
|
class TestExecutionsV2(base.BaseClientV2Test):
|
||||||
@@ -279,3 +292,21 @@ class TestExecutionsV2(base.BaseClientV2Test):
|
|||||||
report = self.executions.get_report(EXEC['id'])
|
report = self.executions.get_report(EXEC['id'])
|
||||||
|
|
||||||
self.assertDictEqual(expected_json, report)
|
self.assertDictEqual(expected_json, report)
|
||||||
|
|
||||||
|
def test_get_sub_executions(self):
|
||||||
|
url = self.TEST_URL + URL_TEMPLATE_SUB_EXECUTIONS \
|
||||||
|
% (EXEC['id'], '?max_depth=-1&errors_only=')
|
||||||
|
|
||||||
|
self.requests_mock.get(url, json={'executions': [EXEC, SUB_WF_EXEC]})
|
||||||
|
|
||||||
|
sub_execution_list = self.executions.get_ex_sub_executions(EXEC['id'])
|
||||||
|
|
||||||
|
self.assertEqual(2, len(sub_execution_list))
|
||||||
|
self.assertDictEqual(
|
||||||
|
executions.Execution(self.executions, EXEC).to_dict(),
|
||||||
|
sub_execution_list[0].to_dict()
|
||||||
|
)
|
||||||
|
self.assertDictEqual(
|
||||||
|
executions.Execution(self.executions, SUB_WF_EXEC).to_dict(),
|
||||||
|
sub_execution_list[1].to_dict()
|
||||||
|
)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
|
|
||||||
|
from mistralclient.api.v2.executions import Execution
|
||||||
from mistralclient.api.v2 import tasks
|
from mistralclient.api.v2 import tasks
|
||||||
from mistralclient.tests.unit.v2 import base
|
from mistralclient.tests.unit.v2 import base
|
||||||
|
|
||||||
@@ -30,9 +31,20 @@ TASK = {
|
|||||||
'result': {'some': 'result'}
|
'result': {'some': 'result'}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SUB_WF_EXEC = {
|
||||||
|
'id': "456",
|
||||||
|
'workflow_id': '123e4567-e89b-12d3-a456-426655440000',
|
||||||
|
'workflow_name': 'my_sub_wf',
|
||||||
|
'workflow_namespace': '',
|
||||||
|
'task_execution_id': "1",
|
||||||
|
'description': '',
|
||||||
|
'state': 'RUNNING',
|
||||||
|
'input': {}
|
||||||
|
}
|
||||||
|
|
||||||
URL_TEMPLATE = '/tasks'
|
URL_TEMPLATE = '/tasks'
|
||||||
URL_TEMPLATE_ID = '/tasks/%s'
|
URL_TEMPLATE_ID = '/tasks/%s'
|
||||||
|
URL_TEMPLATE_SUB_EXECUTIONS = '/tasks/%s/executions%s'
|
||||||
|
|
||||||
|
|
||||||
class TestTasksV2(base.BaseClientV2Test):
|
class TestTasksV2(base.BaseClientV2Test):
|
||||||
@@ -136,3 +148,17 @@ class TestTasksV2(base.BaseClientV2Test):
|
|||||||
'env': jsonutils.dumps({'k1': 'foobar'})
|
'env': jsonutils.dumps({'k1': 'foobar'})
|
||||||
}
|
}
|
||||||
self.assertDictEqual(body, self.requests_mock.last_request.json())
|
self.assertDictEqual(body, self.requests_mock.last_request.json())
|
||||||
|
|
||||||
|
def test_get_sub_executions(self):
|
||||||
|
url = self.TEST_URL + URL_TEMPLATE_SUB_EXECUTIONS \
|
||||||
|
% (TASK['id'], '?max_depth=-1&errors_only=')
|
||||||
|
|
||||||
|
self.requests_mock.get(url, json={'executions': [SUB_WF_EXEC]})
|
||||||
|
|
||||||
|
sub_execution_list = self.tasks.get_task_sub_executions(TASK['id'])
|
||||||
|
|
||||||
|
self.assertEqual(1, len(sub_execution_list))
|
||||||
|
self.assertDictEqual(
|
||||||
|
Execution(self.executions, SUB_WF_EXEC).to_dict(),
|
||||||
|
sub_execution_list[0].to_dict()
|
||||||
|
)
|
||||||
|
|||||||
9
releasenotes/notes/add_sub_executions_new_commands.yaml
Normal file
9
releasenotes/notes/add_sub_executions_new_commands.yaml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Added 2 new CLI commands, "execution-get-sub-executions" returns
|
||||||
|
sub-executions of a given execution id and "task-get-sub-executions"
|
||||||
|
returns the sub-executions of a given task execution id.
|
||||||
|
Both commands have the options "--max-depth" which is the max depth of a
|
||||||
|
sub-execution, and "--errors-only" that allows to find only ERROR paths of
|
||||||
|
the execution tree.
|
||||||
Reference in New Issue
Block a user