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 listing output files endpoint #45

Merged
merged 1 commit into from
Nov 6, 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
75 changes: 75 additions & 0 deletions docs/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,81 @@
"summary": "Returns the list of input files for a specific workflow."
}
},
"/api/workflows/{workflow_id}/workspace/outputs": {
"get": {
"description": "This resource is expecting a workflow UUID and a filename to return its outputs.",
"operationId": "get_workflow_outputs",
"parameters": [
{
"description": "Required. Organization which the worklow 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": [
"multipart/form-data"
],
"responses": {
"200": {
"description": "Requests succeeded. The list of output files has been retrieved.",
"schema": {
"items": {
"properties": {
"last-modified": {
"format": "date-time",
"type": "string"
},
"name": {
"type": "string"
},
"size": {
"type": "integer"
}
},
"type": "object"
},
"type": "array"
}
},
"400": {
"description": "Request failed. The incoming data specification seems malformed."
},
"404": {
"description": "Request failed. User doesn't exist.",
"examples": {
"application/json": {
"message": "User 00000000-0000-0000-0000-000000000000 doesn't exist"
}
}
},
"500": {
"description": "Request failed. Internal controller error.",
"examples": {
"application/json": {
"message": "Either organization or user doesn't exist."
}
}
}
},
"summary": "Returns the list of output files for a specific workflow."
}
},
"/api/workflows/{workflow_id}/workspace/outputs/{file_name}": {
"get": {
"description": "This resource is expecting a workflow UUID and a filename to return its content.",
Expand Down
3 changes: 3 additions & 0 deletions reana_workflow_controller/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,6 @@

INPUTS_RELATIVE_PATH = 'inputs'
"""Inputs directory name."""

OUTPUTS_RELATIVE_PATH = 'outputs'
"""Outputs directory name."""
93 changes: 93 additions & 0 deletions reana_workflow_controller/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,99 @@ def get_workflow_inputs(workflow_id): # noqa
return jsonify({"message": str(e)}), 500


@restapi_blueprint.route('/workflows/<workflow_id>/workspace/outputs',
methods=['GET'])
def get_workflow_outputs(workflow_id): # noqa
r"""List all workflow output files.

---
get:
summary: Returns the list of output files for a specific workflow.
description: >-
This resource is expecting a workflow UUID and a filename to return
its outputs.
operationId: get_workflow_outputs
produces:
- multipart/form-data
parameters:
- name: organization
in: query
description: Required. Organization which the worklow 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: >-
Requests succeeded. The list of output files has been retrieved.
schema:
type: array
items:
type: object
properties:
name:
type: string
last-modified:
type: string
format: date-time
size:
type: integer
400:
description: >-
Request failed. The incoming data specification seems malformed.
404:
description: >-
Request failed. User doesn't exist.
examples:
application/json:
{
"message": "User 00000000-0000-0000-0000-000000000000 doesn't
exist"
}
500:
description: >-
Request failed. Internal controller error.
examples:
application/json:
{
"message": "Either organization or user doesn't exist."
}
"""
try:
user_uuid = request.args['user']
user = User.query.filter(User.id_ == user_uuid).first()
if not user:
return jsonify(
{'message': 'User {} does not exist'.format(user)}), 404

workflow = Workflow.query.filter(Workflow.id_ == workflow_id).first()
if workflow:
outputs_directory = os.path.join(
current_app.config['SHARED_VOLUME_PATH'],
workflow.workspace_path,
current_app.config['OUTPUTS_RELATIVE_PATH'])

outputs_list = list_directory_files(outputs_directory)
return jsonify(outputs_list), 200
else:
return jsonify({'message': 'The workflow {} doesn\'t exist'.
format(str(workflow.id_))}), 404

except KeyError:
return jsonify({"message": "Malformed request."}), 400
except Exception as e:
return jsonify({"message": str(e)}), 500


@restapi_blueprint.route('/yadage/remote', methods=['POST'])
def run_yadage_workflow_from_remote_endpoint(): # noqa
r"""Create a new yadage workflow from a remote repository.
Expand Down
49 changes: 49 additions & 0 deletions tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,3 +318,52 @@ def test_get_workflow_inputs_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_outputs_list(app, db_session, default_user,
tmp_shared_volume_path):
"""Test get list of output files."""
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_uuid = response_data.get('workflow_id')
workflow = Workflow.query.filter(
Workflow.id_ == workflow_uuid).first()
# create file
absolute_path_workflow_workspace = \
os.path.join(tmp_shared_volume_path,
workflow.workspace_path)
fs_ = fs.open_fs(absolute_path_workflow_workspace)
# from config
outputs_realative_path = app.config['OUTPUTS_RELATIVE_PATH']
fs_.makedirs(outputs_realative_path)
test_files = []
for i in range(5):
file_name = '{0}.csv'.format(i)
subdir_name = str(uuid.uuid4())
subdir = fs.path.join(outputs_realative_path, subdir_name)
fs_.makedirs(subdir)
fs_.touch('{0}/{1}'.format(subdir, file_name))
test_files.append(os.path.join(subdir_name, file_name))

res = client.get(
url_for('api.get_workflow_outputs', workflow_id=workflow_uuid),
query_string={"user": default_user.id_,
"organization": organization},
content_type='application/json',
data=json.dumps(data))
for file_ in json.loads(res.data.decode()):
assert file_.get('name') in test_files