Add Executions and Tasks root API endpoints

Change-Id: I580086c81b26db6a5f51b4ada4b0eb697e8dea49
Implements: blueprint mistral-ui
This commit is contained in:
Kirill Izotov 2014-06-20 14:17:42 +07:00
parent ca1b448aab
commit 201c902b99
6 changed files with 250 additions and 35 deletions

View File

@ -83,7 +83,28 @@ class Executions(resource.Resource):
class ExecutionsController(rest.RestController):
tasks = task.TasksController()
def _get(self, id):
values = db_api.execution_get(id)
return Execution.from_dict(values)
def _put(self, id, execution):
values = db_api.execution_update(id, execution.to_dict())
return Execution.from_dict(values)
def _delete(self, id):
db_api.execution_delete(id)
def _get_all(self, **kwargs):
executions = [Execution.from_dict(values) for values
in db_api.executions_get(**kwargs)]
return Executions(executions=executions)
class WorkbookExecutionsController(ExecutionsController):
tasks = task.WorkbookTasksController()
@rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(Execution, wtypes.text, wtypes.text)
@ -91,8 +112,7 @@ class ExecutionsController(rest.RestController):
"""Return the specified Execution."""
LOG.debug("Fetch execution [workbook_name=%s, id=%s]" %
(workbook_name, id))
values = db_api.execution_get(id)
return Execution.from_dict(values)
return self._get(id)
@rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(Execution, wtypes.text, wtypes.text, body=Execution)
@ -100,11 +120,7 @@ class ExecutionsController(rest.RestController):
"""Update the specified Execution."""
LOG.debug("Update execution [workbook_name=%s, id=%s, execution=%s]" %
(workbook_name, id, execution))
values = db_api.execution_update(id,
execution.to_dict())
return Execution.from_dict(values)
return self._put(id, execution)
@rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(Execution, wtypes.text, body=Execution,
@ -133,7 +149,7 @@ class ExecutionsController(rest.RestController):
"""Delete the specified Execution."""
LOG.debug("Delete execution [workbook_name=%s, id=%s]" %
(workbook_name, id))
db_api.execution_delete(id)
return self._delete(id)
@wsme_pecan.wsexpose(Executions, wtypes.text)
def get_all(self, workbook_name):
@ -141,9 +157,38 @@ class ExecutionsController(rest.RestController):
LOG.debug("Fetch executions [workbook_name=%s]" % workbook_name)
if db_api.workbook_get(workbook_name):
executions = [
Execution.from_dict(values) for values
in db_api.executions_get(workbook_name=workbook_name)
]
return self._get_all(workbook_name=workbook_name)
return Executions(executions=executions)
class RootExecutionsController(ExecutionsController):
tasks = task.ExecutionTasksController()
@rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(Execution, wtypes.text)
def get(self, id):
"""Return the specified Execution."""
LOG.debug("Fetch execution [id=%s]" % id)
return self._get(id)
@rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(Execution, wtypes.text, body=Execution)
def put(self, id, execution):
"""Update the specified Execution."""
LOG.debug("Update execution [id=%s, execution=%s]" %
(id, execution))
return self._put(id, execution)
@rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(None, wtypes.text, status_code=204)
def delete(self, id):
"""Delete the specified Execution."""
LOG.debug("Delete execution [id=%s]" % id)
return self._delete(id)
@wsme_pecan.wsexpose(Executions)
def get_all(self):
"""Return all Executions."""
LOG.debug("Fetch executions")
return self._get_all()

View File

@ -19,6 +19,8 @@ from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from mistral.api.controllers import resource
from mistral.api.controllers.v1 import execution
from mistral.api.controllers.v1 import task
from mistral.api.controllers.v1 import workbook
@ -39,6 +41,8 @@ class Controller(object):
"""API root controller for version 1."""
workbooks = workbook.WorkbooksController()
executions = execution.RootExecutionsController()
tasks = task.RootTasksController()
@wsme_pecan.wsexpose(RootResource)
def index(self):

View File

@ -85,6 +85,27 @@ class Tasks(resource.Resource):
class TasksController(rest.RestController):
def _get(self, id):
values = db_api.task_get(id)
return Task.from_dict(values)
def _put(self, id, task):
if db_api.task_get(id):
# TODO(rakhmerov): pass task result once it's implemented
engine = pecan.request.context['engine']
values = engine.convey_task_result(id,
task.state, None)
return Task.from_dict(values)
def _get_all(self, **kwargs):
tasks = [Task.from_dict(values)
for values in db_api.tasks_get(**kwargs)]
return Tasks(tasks=tasks)
class WorkbookTasksController(TasksController):
@rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(Task, wtypes.text, wtypes.text, wtypes.text)
def get(self, workbook_name, execution_id, id):
@ -92,8 +113,7 @@ class TasksController(rest.RestController):
LOG.debug("Fetch task [workbook_name=%s, execution_id=%s, id=%s]" %
(workbook_name, execution_id, id))
values = db_api.task_get(id)
return Task.from_dict(values)
return self._get(id)
@rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(Task, wtypes.text, wtypes.text, wtypes.text,
@ -104,13 +124,7 @@ class TasksController(rest.RestController):
"[workbook_name=%s, execution_id=%s, id=%s, task=%s]" %
(workbook_name, execution_id, id, task))
if db_api.task_get(id):
# TODO(rakhmerov): pass task result once it's implemented
engine = pecan.request.context['engine']
values = engine.convey_task_result(id,
task.state, None)
return Task.from_dict(values)
return self._put(id, task)
@rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(Tasks, wtypes.text, wtypes.text)
@ -121,8 +135,62 @@ class TasksController(rest.RestController):
LOG.debug("Fetch tasks [workbook_name=%s, execution_id=%s]" %
(workbook_name, execution_id))
tasks = [Task.from_dict(values)
for values in db_api.tasks_get(workbook_name=workbook_name,
execution_id=execution_id)]
return self._get_all(workbook_name=workbook_name,
execution_id=execution_id)
return Tasks(tasks=tasks)
class ExecutionTasksController(TasksController):
@rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(Task, wtypes.text, wtypes.text)
def get(self, execution_id, id):
"""Return the specified task."""
LOG.debug("Fetch task [execution_id=%s, id=%s]" %
(execution_id, id))
return self._get(id)
@rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(Task, wtypes.text, wtypes.text,
body=Task)
def put(self, execution_id, id, task):
"""Update the specified task."""
LOG.debug("Update task "
"[execution_id=%s, id=%s, task=%s]" %
(execution_id, id, task))
return self._put(id, task)
@wsme_pecan.wsexpose(Tasks, wtypes.text)
def get_all(self, execution_id):
"""Return all tasks within the execution."""
LOG.debug("Fetch tasks [execution_id=%s]" % execution_id)
return self._get_all(execution_id=execution_id)
class RootTasksController(TasksController):
@rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(Task, wtypes.text)
def get(self, id):
"""Return the specified task."""
LOG.debug("Fetch task [id=%s]" % id)
return self._get(id)
@rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(Task, wtypes.text,
body=Task)
def put(self, id, task):
"""Update the specified task."""
LOG.debug("Update task "
"[id=%s, task=%s]" %
(id, task))
return self._put(id, task)
@wsme_pecan.wsexpose(Tasks)
def get_all(self):
"""Return all tasks within the execution."""
LOG.debug("Fetch tasks")
return self._get_all()

View File

@ -57,7 +57,7 @@ class Workbooks(resource.Resource):
class WorkbooksController(rest.RestController):
definition = workbook_definition.WorkbookDefinitionController()
listeners = listener.ListenersController()
executions = execution.ExecutionsController()
executions = execution.WorkbookExecutionsController()
@rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(Workbook, wtypes.text)

View File

@ -65,12 +65,20 @@ def canonize(json_dict):
class TestExecutionsController(base.FunctionalTest):
@mock.patch.object(db_api, 'execution_get',
mock.MagicMock(return_value=EXECS[0]))
def test_get(self):
def test_workbook_get(self):
resp = self.app.get('/v1/workbooks/my_workbook/executions/123')
self.assertEqual(resp.status_int, 200)
self.assertDictEqual(EXECS[0], canonize(resp.json))
@mock.patch.object(db_api, 'execution_get',
mock.MagicMock(return_value=EXECS[0]))
def test_root_get(self):
resp = self.app.get('/v1/executions/123')
self.assertEqual(resp.status_int, 200)
self.assertDictEqual(EXECS[0], canonize(resp.json))
@mock.patch.object(db_api, 'execution_get',
mock.MagicMock(side_effect=ex.NotFoundException()))
def test_get_empty(self):
@ -80,13 +88,22 @@ class TestExecutionsController(base.FunctionalTest):
@mock.patch.object(db_api, 'execution_update',
mock.MagicMock(return_value=UPDATED_EXEC))
def test_put(self):
def test_workbook_put(self):
resp = self.app.put_json('/v1/workbooks/my_workbook/executions/123',
dict(state='STOPPED'))
self.assertEqual(resp.status_int, 200)
self.assertDictEqual(UPDATED_EXEC, canonize(resp.json))
@mock.patch.object(db_api, 'execution_update',
mock.MagicMock(return_value=UPDATED_EXEC))
def test_root_put(self):
resp = self.app.put_json('/v1/executions/123',
dict(state='STOPPED'))
self.assertEqual(resp.status_int, 200)
self.assertDictEqual(UPDATED_EXEC, canonize(resp.json))
@mock.patch.object(db_api, 'execution_update',
mock.MagicMock(
side_effect=ex.NotFoundException()))
@ -137,11 +154,18 @@ class TestExecutionsController(base.FunctionalTest):
@mock.patch.object(db_api, 'execution_delete',
mock.MagicMock(return_value=None))
def test_delete(self):
def test_workbook_delete(self):
resp = self.app.delete('/v1/workbooks/my_workbook/executions/123')
self.assertEqual(resp.status_int, 204)
@mock.patch.object(db_api, 'execution_delete',
mock.MagicMock(return_value=None))
def test_root_delete(self):
resp = self.app.delete('/v1/executions/123')
self.assertEqual(resp.status_int, 204)
@mock.patch.object(db_api, 'execution_delete',
mock.MagicMock(side_effect=ex.NotFoundException))
def test_delete_not_found(self):
@ -154,7 +178,7 @@ class TestExecutionsController(base.FunctionalTest):
mock.MagicMock(return_value=EXECS))
@mock.patch.object(db_api, 'workbook_get',
mock.MagicMock(return_value={'name': 'my_workbook'}))
def test_get_all(self):
def test_workbook_get_all(self):
resp = self.app.get('/v1/workbooks/my_workbook/executions')
self.assertEqual(resp.status_int, 200)
@ -162,6 +186,18 @@ class TestExecutionsController(base.FunctionalTest):
self.assertEqual(len(resp.json), 1)
self.assertDictEqual(EXECS[0], canonize(resp.json['executions'][0]))
@mock.patch.object(db_api, 'executions_get',
mock.MagicMock(return_value=EXECS))
@mock.patch.object(db_api, 'workbook_get',
mock.MagicMock(return_value={'name': 'my_workbook'}))
def test_root_get_all(self):
resp = self.app.get('/v1/executions')
self.assertEqual(resp.status_int, 200)
self.assertEqual(len(resp.json), 1)
self.assertDictEqual(EXECS[0], canonize(resp.json['executions'][0]))
@mock.patch.object(db_api, 'executions_get',
mock.MagicMock(return_value=EXECS))
def test_get_all_no_workbook(self):

View File

@ -58,23 +58,61 @@ def canonize(json_dict):
class TestTasksController(base.FunctionalTest):
@mock.patch.object(db_api, "task_get",
mock.MagicMock(return_value=TASKS[0]))
def test_get(self):
def test_workbook_get(self):
resp = self.app.get('/v1/workbooks/my_workbook/executions/123/tasks/1')
self.assertEqual(resp.status_int, 200)
self.assertDictEqual(TASKS[0], canonize(resp.json))
@mock.patch.object(db_api, "task_get",
mock.MagicMock(return_value=TASKS[0]))
def test_execution_get(self):
resp = self.app.get('/v1/executions/123/tasks/1')
self.assertEqual(resp.status_int, 200)
self.assertDictEqual(TASKS[0], canonize(resp.json))
@mock.patch.object(db_api, "task_get",
mock.MagicMock(return_value=TASKS[0]))
def test_root_get(self):
resp = self.app.get('/v1/tasks/1')
self.assertEqual(resp.status_int, 200)
self.assertDictEqual(TASKS[0], canonize(resp.json))
@mock.patch.object(engine.EngineClient, "convey_task_result",
mock.MagicMock(return_value=UPDATED_TASK))
@mock.patch.object(db_api, "task_get",
mock.MagicMock(return_value=TASKS[0]))
def test_put(self):
def test_workbook_put(self):
resp = self.app.put_json(
'/v1/workbooks/my_workbook/executions/123/tasks/1',
dict(state='STOPPED'))
self.assertEqual(resp.status_int, 200)
self.assertDictEqual(UPDATED_TASK, canonize(resp.json))
@mock.patch.object(engine.EngineClient, "convey_task_result",
mock.MagicMock(return_value=UPDATED_TASK))
@mock.patch.object(db_api, "task_get",
mock.MagicMock(return_value=TASKS[0]))
def test_execution_put(self):
resp = self.app.put_json(
'/v1/executions/123/tasks/1',
dict(state='STOPPED'))
self.assertEqual(resp.status_int, 200)
self.assertDictEqual(UPDATED_TASK, canonize(resp.json))
@mock.patch.object(engine.EngineClient, "convey_task_result",
mock.MagicMock(return_value=UPDATED_TASK))
@mock.patch.object(db_api, "task_get",
mock.MagicMock(return_value=TASKS[0]))
def test_root_put(self):
resp = self.app.put_json(
'/v1/tasks/1',
dict(state='STOPPED'))
self.assertEqual(resp.status_int, 200)
self.assertDictEqual(UPDATED_TASK, canonize(resp.json))
@mock.patch.object(engine.EngineClient, "convey_task_result",
mock.MagicMock(return_value=UPDATED_TASK))
def test_put_no_task(self):
@ -87,7 +125,7 @@ class TestTasksController(base.FunctionalTest):
mock.MagicMock(return_value=TASKS))
@mock.patch.object(db_api, "ensure_execution_exists",
mock.MagicMock(return_value={'id': "abc123"}))
def test_get_all(self):
def test_workbook_get_all(self):
resp = self.app.get('/v1/workbooks/my_workbook/executions/123/tasks')
self.assertEqual(resp.status_int, 200)
@ -95,6 +133,30 @@ class TestTasksController(base.FunctionalTest):
self.assertEqual(len(resp.json), 1)
self.assertDictEqual(TASKS[0], canonize(resp.json['tasks'][0]))
@mock.patch.object(db_api, "tasks_get",
mock.MagicMock(return_value=TASKS))
@mock.patch.object(db_api, "ensure_execution_exists",
mock.MagicMock(return_value={'id': "abc123"}))
def test_execution_get_all(self):
resp = self.app.get('/v1/executions/123/tasks')
self.assertEqual(resp.status_int, 200)
self.assertEqual(len(resp.json), 1)
self.assertDictEqual(TASKS[0], canonize(resp.json['tasks'][0]))
@mock.patch.object(db_api, "tasks_get",
mock.MagicMock(return_value=TASKS))
@mock.patch.object(db_api, "ensure_execution_exists",
mock.MagicMock(return_value={'id': "abc123"}))
def test_root_get_all(self):
resp = self.app.get('/v1/tasks')
self.assertEqual(resp.status_int, 200)
self.assertEqual(len(resp.json), 1)
self.assertDictEqual(TASKS[0], canonize(resp.json['tasks'][0]))
@mock.patch.object(db_api, "tasks_get",
mock.MagicMock(return_value=TASKS))
def test_get_all_nonexistent_execution(self):