diff --git a/packages/flamenco/flamenco/tasks/__init__.py b/packages/flamenco/flamenco/tasks/__init__.py index f4ece6cca02f33f13e072e46bdd09d1d8b78b373..81049d11a475b463136759b36a33db15b8a894d8 100644 --- a/packages/flamenco/flamenco/tasks/__init__.py +++ b/packages/flamenco/flamenco/tasks/__init__.py @@ -20,6 +20,8 @@ COLOR_FOR_TASK_STATUS = { 'completed': '#bbe151', } +REQUEABLE_TASK_STATES = {'completed', 'canceled', 'failed'} + @attr.s class TaskManager(object): @@ -90,6 +92,15 @@ class TaskManager(object): return tasks + def web_set_task_status(self, task_id, new_status): + """Web-level call to updates the task status.""" + from .sdk import Task + + api = pillar_api() + task = Task({'_id': task_id}) + task.patch({'op': 'set-task-status', + 'status': new_status}, api=api) + def setup_app(app): from . import eve_hooks, patch diff --git a/packages/flamenco/flamenco/tasks/routes.py b/packages/flamenco/flamenco/tasks/routes.py index 51928332aa0aa81dae6e2b5bd515e271c9c8a6a7..e4a05043044e4d843814798a7ba0b512b31e3d1a 100644 --- a/packages/flamenco/flamenco/tasks/routes.py +++ b/packages/flamenco/flamenco/tasks/routes.py @@ -12,6 +12,9 @@ from flamenco import current_flamenco, ROLES_REQUIRED_TO_VIEW_ITEMS, ROLES_REQUI TASK_LOG_PAGE_SIZE = 10 +# The task statuses that can be set from the web-interface. +ALLOWED_TASK_STATUSES_FROM_WEB = {'cancel-requested', 'queued'} + perjob_blueprint = Blueprint('flamenco.tasks.perjob', __name__, url_prefix='/<project_url>/jobs/<job_id>') perproject_blueprint = Blueprint('flamenco.tasks.perproject', __name__, @@ -60,11 +63,34 @@ def view_task(project, flamenco_props, task_id): raise wz_exceptions.Forbidden() task = Task.find(task_id, api=api) + + from . import REQUEABLE_TASK_STATES + write_access = current_flamenco.current_user_is_flamenco_admin() + return render_template('flamenco/tasks/view_task_embed.html', task=task, project=project, flamenco_props=flamenco_props.to_dict(), - flamenco_context=request.args.get('context')) + flamenco_context=request.args.get('context'), + can_requeue_task=write_access and task['status'] in REQUEABLE_TASK_STATES) + + +@perproject_blueprint.route('/<task_id>/set-status', methods=['POST']) +@flask_login.login_required +@flamenco_project_view(extension_props=False) +def set_task_status(project, task_id): + from flask_login import current_user + + new_status = request.form['status'] + if new_status not in ALLOWED_TASK_STATUSES_FROM_WEB: + log.warning('User %s tried to set status of task %s to disallowed status "%s"; denied.', + current_user.objectid, task_id, new_status) + raise wz_exceptions.UnprocessableEntity('Status "%s" not allowed' % new_status) + + log.info('User %s set status of task %s to "%s"', current_user.objectid, task_id, new_status) + current_flamenco.task_manager.web_set_task_status(task_id, new_status) + + return '', 204 @perproject_blueprint.route('/<task_id>/log') diff --git a/packages/flamenco/flamenco/tasks/sdk.py b/packages/flamenco/flamenco/tasks/sdk.py index 270ff6457bf320b6ad25ff8bb9b8b7ae32826dc9..2c8bf68f8e5b623fd5bde73e342adf6bcc3b7cc6 100644 --- a/packages/flamenco/flamenco/tasks/sdk.py +++ b/packages/flamenco/flamenco/tasks/sdk.py @@ -1,8 +1,9 @@ from pillarsdk.resource import List from pillarsdk.resource import Find +from pillarsdk.resource import Patch -class Task(List, Find): +class Task(List, Find, Patch): """Task class wrapping the REST nodes endpoint """ path = 'flamenco/tasks' diff --git a/packages/flamenco/src/scripts/tutti/10_tasks.js b/packages/flamenco/src/scripts/tutti/10_tasks.js index 7c8e50f7c9e0fa5448057a6a3e45f3f434cfbcaa..9e6e59535133a8d3dcae8edb5efd6afaff5b50e4 100644 --- a/packages/flamenco/src/scripts/tutti/10_tasks.js +++ b/packages/flamenco/src/scripts/tutti/10_tasks.js @@ -157,7 +157,7 @@ $(function() { */ function setJobStatus(job_id, new_status) { if (typeof job_id === 'undefined' || typeof new_status === 'undefined') { - if (console) console.log("cancelJob(" + job_id + ", " + new_status + ") called"); + if (console) console.log("setJobStatus(" + job_id + ", " + new_status + ") called"); return; } @@ -186,3 +186,39 @@ function setJobStatus(job_id, new_status) { $('#job-action-panel .action-result-panel').html(show_html); }); } + +/** + * Request cancellation or re-queueing of the given task ID. + */ +function setTaskStatus(task_id, new_status) { + if (typeof task_id === 'undefined' || typeof new_status === 'undefined') { + if (console) console.log("setTaskStatus(" + task_id + ", " + new_status + ") called"); + return; + } + + project_url = ProjectUtils.projectUrl(); + return $.post('/flamenco/' + project_url + '/tasks/' + task_id + '/set-status', {status: new_status}) + .done(function(data) { + if(console) console.log('Job set-status request OK'); + // Reload the entire page, since both the view-embed and the task list need refreshing. + location.reload(true); + }) + .fail(function(xhr) { + if (console) { + console.log('Error setting task status'); + console.log('XHR:', xhr); + } + + statusBarSet('error', 'Error requesting task status change', 'pi-error'); + + var show_html; + if (xhr.status) { + show_html = xhr.responseText; + } else { + show_html = $('<p>').addClass('text-danger').text( + 'Setting task status failed. There possibly was an error connecting to the server. ' + + 'Please check your network connection and try again.'); + } + $('#task-action-panel .action-result-panel').html(show_html); + }); +} diff --git a/packages/flamenco/src/templates/flamenco/tasks/view_task_embed.jade b/packages/flamenco/src/templates/flamenco/tasks/view_task_embed.jade index 23b333dfd74486c7737aca50a9f0ff4dc7f3f4a8..fd263c7910e7562ec66a6d7f080c1eae79fc255e 100644 --- a/packages/flamenco/src/templates/flamenco/tasks/view_task_embed.jade +++ b/packages/flamenco/src/templates/flamenco/tasks/view_task_embed.jade @@ -28,17 +28,17 @@ .table.item-properties .table-body .table-row - .table-cell Belongs to job + .table-cell Belongs to task .table-cell a( - href="{{ url_for('flamenco.jobs.perproject.view_job', project_url=project.url, job_id=task.job) }}" - data-job-id="{{ task.job }}", - class="job-link" + href="{{ url_for('flamenco.tasks.perproject.view_task', project_url=project.url, task_id=task._id) }}" + data-task-id="{{ task._id }}", + class="task-link" ) - | {{ task.job }} + | {{ task.task }} .table-row - .table-cell Job Type - .table-cell {{ task.job_type | undertitle }} + .table-cell task Type + .table-cell {{ task.task_type | undertitle }} .table-row.properties-status.js-help( data-url="{{ url_for('flamenco.help', project_url=project.url) }}") .table-cell Status @@ -57,6 +57,14 @@ .table-cell Worker .table-cell {{ task.worker }} + #task-action-panel + | {% if can_requeue_task %} + button.btn.btn-success.requeue-task(onclick="setTaskStatus('{{ task._id }}', 'queued')") + i.pi-refresh + | Re-queue task + | {% endif %} + .action-result-panel + #item-view-feed #activities #comments-embed