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]
 | 
			
		||||
        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:
 | 
			
		||||
            resp = self.http_client.get(url, headers)
 | 
			
		||||
        except exceptions.HttpError as ex:
 | 
			
		||||
@@ -182,7 +184,9 @@ class ResourceManager(object):
 | 
			
		||||
        if resp.status_code != 200:
 | 
			
		||||
            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)]
 | 
			
		||||
 | 
			
		||||
    def _get(self, url, response_key=None, headers=None):
 | 
			
		||||
 
 | 
			
		||||
@@ -98,6 +98,15 @@ class ExecutionManager(base.ResourceManager):
 | 
			
		||||
 | 
			
		||||
        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):
 | 
			
		||||
        self._ensure_not_empty(id=id)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@
 | 
			
		||||
from oslo_serialization import jsonutils
 | 
			
		||||
 | 
			
		||||
from mistralclient.api import base
 | 
			
		||||
from mistralclient.api.v2 import executions
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Task(base.Resource):
 | 
			
		||||
@@ -50,6 +51,16 @@ class TaskManager(base.ResourceManager):
 | 
			
		||||
 | 
			
		||||
        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):
 | 
			
		||||
        url = '/tasks/%s' % task_ex_id
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@ from oslo_serialization import jsonutils
 | 
			
		||||
 | 
			
		||||
from osc_lib.command import command
 | 
			
		||||
 | 
			
		||||
from cliff.lister import Lister as cliff_lister
 | 
			
		||||
from mistralclient.commands.v2 import base
 | 
			
		||||
from mistralclient import utils
 | 
			
		||||
 | 
			
		||||
@@ -510,3 +511,71 @@ class GetPublished(command.Command):
 | 
			
		||||
            LOG.debug("Task result is not JSON.")
 | 
			
		||||
 | 
			
		||||
        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 mistralclient.commands.v2 import base
 | 
			
		||||
from mistralclient.commands.v2 import executions
 | 
			
		||||
from mistralclient import utils
 | 
			
		||||
 | 
			
		||||
LOG = logging.getLogger(__name__)
 | 
			
		||||
@@ -211,3 +212,14 @@ class Rerun(command.ShowOne):
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        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,
 | 
			
		||||
            'execution-get-published':
 | 
			
		||||
                mistralclient.commands.v2.executions.GetPublished,
 | 
			
		||||
            'execution-get-sub-executions':
 | 
			
		||||
                mistralclient.commands.v2.executions.SubExecutionsLister,
 | 
			
		||||
            'task-list': mistralclient.commands.v2.tasks.List,
 | 
			
		||||
            'task-get': mistralclient.commands.v2.tasks.Get,
 | 
			
		||||
            'task-get-published': mistralclient.commands.v2.tasks.GetPublished,
 | 
			
		||||
            'task-get-result': mistralclient.commands.v2.tasks.GetResult,
 | 
			
		||||
            'task-get-sub-executions':
 | 
			
		||||
                mistralclient.commands.v2.tasks.SubExecutionsLister,
 | 
			
		||||
            'task-rerun': mistralclient.commands.v2.tasks.Rerun,
 | 
			
		||||
            'action-list': mistralclient.commands.v2.actions.List,
 | 
			
		||||
            'action-get': mistralclient.commands.v2.actions.Get,
 | 
			
		||||
 
 | 
			
		||||
@@ -53,7 +53,7 @@ SUB_WF_EXEC = executions.Execution(
 | 
			
		||||
        'workflow_namespace': '',
 | 
			
		||||
        'root_execution_id': 'ROOT_EXECUTION_ID',
 | 
			
		||||
        'description': '',
 | 
			
		||||
        'state': 'RUNNING',
 | 
			
		||||
        'state': 'ERROR',
 | 
			
		||||
        'state_info': None,
 | 
			
		||||
        'created_at': '1',
 | 
			
		||||
        'updated_at': '1',
 | 
			
		||||
@@ -83,12 +83,13 @@ SUB_WF_EX_RESULT = (
 | 
			
		||||
    '',
 | 
			
		||||
    'abc',
 | 
			
		||||
    'ROOT_EXECUTION_ID',
 | 
			
		||||
    'RUNNING',
 | 
			
		||||
    'ERROR',
 | 
			
		||||
    None,
 | 
			
		||||
    '1',
 | 
			
		||||
    '1'
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
EXECS_LIST = [EXEC, SUB_WF_EXEC]
 | 
			
		||||
EXEC_PUBLISHED = {"bar1": "val1", "var2": 2}
 | 
			
		||||
EXEC_WITH_PUBLISHED_DICT = EXEC_DICT.copy()
 | 
			
		||||
EXEC_WITH_PUBLISHED_DICT.update(
 | 
			
		||||
@@ -241,6 +242,61 @@ class TestCLIExecutionsV2(base.BaseCommandTest):
 | 
			
		||||
            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):
 | 
			
		||||
        self.client.executions.list.return_value = [EXEC]
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@ from oslo_serialization import jsonutils
 | 
			
		||||
 | 
			
		||||
import mock
 | 
			
		||||
 | 
			
		||||
from mistralclient.api.v2.executions import Execution
 | 
			
		||||
from mistralclient.api.v2 import tasks
 | 
			
		||||
from mistralclient.commands.v2 import tasks as task_cmd
 | 
			
		||||
from mistralclient.tests.unit import base
 | 
			
		||||
@@ -35,6 +36,37 @@ TASK_DICT = {
 | 
			
		||||
    '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_PUBLISHED = {"bar1": "val1", "var2": 2}
 | 
			
		||||
 | 
			
		||||
@@ -131,3 +163,58 @@ class TestCLITasksV2(base.BaseCommandTest):
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        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['source_execution_id'] = EXEC['workflow_id']
 | 
			
		||||
URL_TEMPLATE = '/executions'
 | 
			
		||||
URL_TEMPLATE_ID = '/executions/%s'
 | 
			
		||||
URL_TEMPLATE_SUB_EXECUTIONS = '/executions/%s/executions%s'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestExecutionsV2(base.BaseClientV2Test):
 | 
			
		||||
@@ -279,3 +292,21 @@ class TestExecutionsV2(base.BaseClientV2Test):
 | 
			
		||||
        report = self.executions.get_report(EXEC['id'])
 | 
			
		||||
 | 
			
		||||
        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 mistralclient.api.v2.executions import Execution
 | 
			
		||||
from mistralclient.api.v2 import tasks
 | 
			
		||||
from mistralclient.tests.unit.v2 import base
 | 
			
		||||
 | 
			
		||||
@@ -30,9 +31,20 @@ TASK = {
 | 
			
		||||
    '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_ID = '/tasks/%s'
 | 
			
		||||
URL_TEMPLATE_SUB_EXECUTIONS = '/tasks/%s/executions%s'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestTasksV2(base.BaseClientV2Test):
 | 
			
		||||
@@ -136,3 +148,17 @@ class TestTasksV2(base.BaseClientV2Test):
 | 
			
		||||
            'env': jsonutils.dumps({'k1': 'foobar'})
 | 
			
		||||
        }
 | 
			
		||||
        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