Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

api: add endpoint for workflow status #46

Merged
merged 3 commits into from
Nov 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions docs/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,96 @@
"summary": "Create workflow and its workspace."
}
},
"/api/workflows/{workflow_id}/status": {
"get": {
"description": "This resource reports the status of workflow.",
"operationId": "get_workflow_status",
"parameters": [
{
"description": "Required. Organization which the workflow belongs to.",
"in": "query",
"name": "organization",
"required": true,
"type": "string"
},
{
"description": "Required. UUID of workflow owner.",
"in": "query",
"name": "user",
"required": true,
"type": "string"
},
{
"description": "Required. Workflow UUID.",
"in": "path",
"name": "workflow_id",
"required": true,
"type": "string"
}
],
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "Request succeeded. Info about workflow, including the status is returned.",
"examples": {
"application/json": {
"id": "256b25f4-4cfb-4684-b7a8-73872ef455a1",
"organization": "default_org",
"status": "running",
"user": "00000000-0000-0000-0000-000000000000"
}
},
"schema": {
"properties": {
"id": {
"type": "string"
},
"organization": {
"type": "string"
},
"status": {
"type": "string"
},
"user": {
"type": "string"
}
},
"type": "object"
}
},
"400": {
"description": "Request failed. The incoming data specification seems malformed.",
"examples": {
"application/json": {
"message": "Malformed request."
}
}
},
"403": {
"description": "Request failed. User is not allowed to access workflow.",
"examples": {
"application/json": {
"message": "User 00000000-0000-0000-0000-000000000000 is not allowed to access workflow 256b25f4-4cfb-4684-b7a8-73872ef455a1"
}
}
},
"404": {
"description": "Request failed. Either User or Workflow doesn't exist.",
"examples": {
"application/json": {
"message": "Workflow 256b25f4-4cfb-4684-b7a8-73872ef455a1 doesn't exist"
}
}
},
"500": {
"description": "Request failed. Internal controller error."
}
},
"summary": "Get workflow status."
}
},
"/api/workflows/{workflow_id}/workspace": {
"post": {
"consumes": [
Expand Down
111 changes: 111 additions & 0 deletions reana_workflow_controller/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -816,3 +816,114 @@ def run_yadage_workflow_from_spec_endpoint(): # noqa
except (KeyError, ValueError):
traceback.print_exc()
abort(400)


@restapi_blueprint.route('/workflows/<workflow_id>/status', methods=['GET'])
def get_workflow_status(workflow_id): # noqa
r"""Get workflow status.

---
get:
summary: Get workflow status.
description: >-
This resource reports the status of workflow.
operationId: get_workflow_status
produces:
- application/json
parameters:
- name: organization
in: query
description: Required. Organization which the workflow belongs to.
required: true
type: string
- name: user
in: query
description: Required. UUID of workflow owner.
required: true
type: string
- name: workflow_id
in: path
description: Required. Workflow UUID.
required: true
type: string
responses:
200:
description: >-
Request succeeded. Info about workflow, including the status is
returned.
schema:
type: object
properties:
id:
type: string
organization:
type: string
status:
type: string
user:
type: string
examples:
application/json:
{
"id": "256b25f4-4cfb-4684-b7a8-73872ef455a1",
"organization": "default_org",
"status": "running",
"user": "00000000-0000-0000-0000-000000000000"
}
400:
description: >-
Request failed. The incoming data specification seems malformed.
examples:
application/json:
{
"message": "Malformed request."
}
403:
description: >-
Request failed. User is not allowed to access workflow.
examples:
application/json:
{
"message": "User 00000000-0000-0000-0000-000000000000
is not allowed to access workflow
256b25f4-4cfb-4684-b7a8-73872ef455a1"
}
404:
description: >-
Request failed. Either User or Workflow doesn't exist.
examples:
application/json:
{
"message": "User 00000000-0000-0000-0000-000000000000 doesn't
exist"
}
application/json:
{
"message": "Workflow 256b25f4-4cfb-4684-b7a8-73872ef455a1
doesn't exist"
}
500:
description: >-
Request failed. Internal controller error.
"""

try:
organization = request.args['organization']
user_uuid = request.args['user']
workflow = Workflow.query.filter(Workflow.id_ == workflow_id).first()
if not workflow:
return jsonify({'message': 'Workflow {} does not exist'.
format(workflow_id)}), 404
if not str(workflow.owner_id) == user_uuid:
return jsonify(
{'message': 'User {} is not allowed to access workflow {}'
.format(user_uuid, workflow_id)}), 403

return jsonify({'id': workflow.id_,
'status': workflow.status.name,
'organization': organization,
'user': user_uuid}), 200
except KeyError as e:
return jsonify({"message": str(e)}), 400
except Exception as e:
return jsonify({"message": str(e)}), 500
115 changes: 113 additions & 2 deletions tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
# submit itself to any jurisdiction.
"""REANA-Workflow-Controller fsdb module tests."""

from __future__ import absolute_import, print_function

import json
import os
import uuid
Expand Down Expand Up @@ -367,3 +365,116 @@ def test_get_workflow_outputs_list(app, db_session, default_user,
data=json.dumps(data))
for file_ in json.loads(res.data.decode()):
assert file_.get('name') in test_files


def test_get_workflow_status(app, db_session, default_user):
"""Test get workflow status."""
with app.test_client() as client:
# create workflow
organization = 'default'
data = {'parameters': {'min_year': '1991',
'max_year': '2001'},
'specification': {'first': 'do this',
'second': 'do that'},
'type': 'cwl'}
res = client.post(url_for('api.create_workflow'),
query_string={
"user": default_user.id_,
"organization": organization},
content_type='application/json',
data=json.dumps(data))

response_data = json.loads(res.get_data(as_text=True))
workflow_created_uuid = response_data.get('workflow_id')
workflow_created = Workflow.query.filter(
Workflow.id_ == workflow_created_uuid).first()

res = client.get(url_for('api.get_workflow_status',
workflow_id=workflow_created_uuid),
query_string={
"user": default_user.id_,
"organization": organization},
content_type='application/json',
data=json.dumps(data))
json_response = json.loads(res.data.decode())
assert json_response.get('status') == workflow_created.status.name
# create second test workflow modifying status
res = client.post(url_for('api.create_workflow'),
query_string={
"user": default_user.id_,
"organization": organization},
content_type='application/json',
data=json.dumps(data))
response_data = json.loads(res.get_data(as_text=True))
workflow_finished_uuid = response_data.get('workflow_id')
workflow_finished = Workflow.query.filter(
Workflow.id_ == workflow_finished_uuid).first()
workflow_finished.status = WorkflowStatus.finished
db_session.commit()

res = client.get(url_for('api.get_workflow_status',
workflow_id=workflow_finished_uuid),
query_string={
"user": default_user.id_,
"organization": organization},
content_type='application/json',
data=json.dumps(data))
json_response = json.loads(res.data.decode())
assert json_response.get('status') == workflow_finished.status.name


def test_get_workflow_status_unauthorized(app, default_user):
"""Test get workflow status unauthorized."""
with app.test_client() as client:
# create workflow
organization = 'default'
data = {'parameters': {'min_year': '1991',
'max_year': '2001'},
'specification': {'first': 'do this',
'second': 'do that'},
'type': 'cwl'}
res = client.post(url_for('api.create_workflow'),
query_string={
"user": default_user.id_,
"organization": organization},
content_type='application/json',
data=json.dumps(data))

response_data = json.loads(res.get_data(as_text=True))
workflow_created_uuid = response_data.get('workflow_id')
random_user_uuid = uuid.uuid4()
res = client.get(url_for('api.get_workflow_status',
workflow_id=workflow_created_uuid),
query_string={
"user": random_user_uuid,
"organization": organization},
content_type='application/json',
data=json.dumps(data))
assert res.status_code == 403


def test_get_workflow_status_unknown_workflow(app, default_user):
"""Test get workflow status for unknown workflow."""
with app.test_client() as client:
# create workflow
organization = 'default'
data = {'parameters': {'min_year': '1991',
'max_year': '2001'},
'specification': {'first': 'do this',
'second': 'do that'},
'type': 'cwl'}
res = client.post(url_for('api.create_workflow'),
query_string={
"user": default_user.id_,
"organization": organization},
content_type='application/json',
data=json.dumps(data))
random_workflow_uuid = uuid.uuid4()
res = client.get(url_for('api.get_workflow_status',
workflow_id=random_workflow_uuid),
query_string={
"user": default_user.id_,
"organization": organization},
content_type='application/json',
data=json.dumps(data))
assert res.status_code == 404