From 96f2196d99e8e7ce761c73dffe55f81a30f5ff71 Mon Sep 17 00:00:00 2001 From: Sebastian Wagner Date: Thu, 3 May 2018 16:41:34 +0200 Subject: [PATCH] mgr/dashboard: Add task info to exception result Signed-off-by: Sebastian Wagner --- .../mgr/dashboard/services/exception.py | 12 +++++++-- .../mgr/dashboard/tests/test_exceptions.py | 5 ++-- src/pybind/mgr/dashboard/tests/test_task.py | 26 ++++++++++++++----- src/pybind/mgr/dashboard/tools.py | 2 +- 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/pybind/mgr/dashboard/services/exception.py b/src/pybind/mgr/dashboard/services/exception.py index 93dff9a84cf..b5c0bd58a17 100644 --- a/src/pybind/mgr/dashboard/services/exception.py +++ b/src/pybind/mgr/dashboard/services/exception.py @@ -59,9 +59,12 @@ if sys.version_info < (3, 0): return helper -def serialize_dashboard_exception(e): +def serialize_dashboard_exception(e, include_http_status=False, task=None): + """ + :type e: Exception + :param include_http_status: Used for Tasks, where the HTTP status code is not available. + """ from ..tools import ViewCache - cherrypy.response.status = getattr(e, 'status', 400) if isinstance(e, ViewCacheNoDataException): return {'status': ViewCache.VALUE_NONE, 'value': None} @@ -72,6 +75,10 @@ def serialize_dashboard_exception(e): pass component = getattr(e, 'component', None) out['component'] = component if component else None + if include_http_status: + out['status'] = getattr(e, 'status', 500) + if task: + out['task'] = dict(name=task.name, metadata=task.metadata) return out @@ -83,6 +90,7 @@ def dashboard_exception_handler(handler, *args, **kwargs): except (ViewCacheNoDataException, DashboardException) as e: logger.exception('dashboard_exception_handler') cherrypy.response.headers['Content-Type'] = 'application/json' + cherrypy.response.status = getattr(e, 'status', 400) return json.dumps(serialize_dashboard_exception(e)).encode('utf-8') diff --git a/src/pybind/mgr/dashboard/tests/test_exceptions.py b/src/pybind/mgr/dashboard/tests/test_exceptions.py index 78472022a4c..a60ceaa7f09 100644 --- a/src/pybind/mgr/dashboard/tests/test_exceptions.py +++ b/src/pybind/mgr/dashboard/tests/test_exceptions.py @@ -73,7 +73,7 @@ class FooResource(RESTController): @cherrypy.expose @cherrypy.tools.json_out() - @Task('task_exceptions/task_exception', {}, 1.0, + @Task('task_exceptions/task_exception', {1: 2}, 1.0, exception_handler=serialize_dashboard_exception) @handle_rados_error('foo') def task_exception(self): @@ -152,7 +152,8 @@ class RESTControllerTest(ControllerTestCase): self._get('/foo/task_exception') self.assertStatus(400) self.assertJsonBody( - {'detail': '[errno -42] hi', 'code': "42", 'component': 'foo'} + {'detail': '[errno -42] hi', 'code': "42", 'component': 'foo', + 'task': {'name': 'task_exceptions/task_exception', 'metadata': {'1': 2}}} ) self._get('/foo/wait_task_exception') diff --git a/src/pybind/mgr/dashboard/tests/test_task.py b/src/pybind/mgr/dashboard/tests/test_task.py index 872deb6fa1e..c10af640bc2 100644 --- a/src/pybind/mgr/dashboard/tests/test_task.py +++ b/src/pybind/mgr/dashboard/tests/test_task.py @@ -6,7 +6,9 @@ import unittest import threading import time from collections import defaultdict +from functools import partial +from ..services.exception import serialize_dashboard_exception from ..tools import NotificationQueue, TaskManager, TaskExecutor @@ -41,13 +43,11 @@ class MyTask(object): self.handle_ex = handle_ex self._event = threading.Event() - def _handle_exception(self, ex): - return {'status': 409, 'detail': str(ex)} - def run(self, ns, timeout=None): args = ['dummy arg'] kwargs = {'dummy': 'arg'} - h_ex = self._handle_exception if self.handle_ex else None + h_ex = partial(serialize_dashboard_exception, + include_http_status=True) if self.handle_ex else None if not self.is_async: task = TaskManager.run( ns, self.metadata(), self.task_op, args, kwargs, @@ -416,6 +416,18 @@ class TaskTest(unittest.TestCase): self.assertEqual(fn_t[0]['progress'], 50) self.assertFalse(fn_t[0]['success']) self.assertIsNotNone(fn_t[0]['exception']) - self.assertEqual(fn_t[0]['exception'], - {"status": 409, - "detail": "Task Unexpected Exception"}) + self.assertEqual(fn_t[0]['exception'], { + 'component': None, + 'detail': 'Task Unexpected Exception', + 'status': 500, + 'task': { + 'metadata': { + 'fail': True, + 'handle_ex': True, + 'is_async': False, + 'op_seconds': 1, + 'progress': 50, + 'wait': False}, + 'name': 'test15/task1' + } + }) diff --git a/src/pybind/mgr/dashboard/tools.py b/src/pybind/mgr/dashboard/tools.py index 8e8e536288e..890a9c6129b 100644 --- a/src/pybind/mgr/dashboard/tools.py +++ b/src/pybind/mgr/dashboard/tools.py @@ -602,7 +602,7 @@ class Task(object): if exception and self.ex_handler: # pylint: disable=broad-except try: - ret_value = self.ex_handler(exception) + ret_value = self.ex_handler(exception, task=self) except Exception as ex: exception = ex with self.lock: -- 2.39.5