diff --git a/beat/web/backend/templates/backend/scheduler.html b/beat/web/backend/templates/backend/scheduler.html index 2e1b407ff322333930325e0772273db4d3bbd3e1..ad86851828877ba01c7b10ecadc79662404b59c0 100644 --- a/beat/web/backend/templates/backend/scheduler.html +++ b/beat/web/backend/templates/backend/scheduler.html @@ -2,27 +2,27 @@ {% comment %} * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ * Contact: beat.support@idiap.ch - * + * * This file is part of the beat.web module of the BEAT platform. - * + * * Commercial License Usage * Licensees holding valid commercial BEAT licenses may use this file in * accordance with the terms contained in a written agreement between you * and Idiap. For further information contact tto@idiap.ch - * + * * Alternatively, this file may be used under the terms of the GNU Affero * Public License version 3 as published by the Free Software and appearing * in the file LICENSE.AGPL included in the packaging of this file. * The BEAT platform is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. - * + * * You should have received a copy of the GNU Affero Public License along * with the BEAT platform. If not, see http://www.gnu.org/licenses/. {% endcomment %} {% load fingerprint %} -{% load ui_tags %} +{% load backend_tags %} {% block title %}{{ block.super }} - Scheduler{% endblock %} @@ -37,10 +37,8 @@ <div class="row"> <div class="col-sm-12"> <div class="alert alert-success" role="alert" style="text-align: center;"> - <i class="fa fa-check fa-2x vertical-center"></i> Scheduler Version: {{ data.scheduler.beat_version }} (updated: {% now "H:i O, jS F Y" %}) + <i class="fa fa-clock-o fa-2x vertical-center"></i> Updated: {% now "H:i O, jS F Y" %} <div class="pull-right action-buttons"> - <a id="clean-cache-button" class="btn btn-default" data-toggle="tooltip" data-placement="bottom" title="Clean-up the cache"><i class="fa fa-trash"></i> Wipe cache</a> - <a id="reconfig-button" class="btn btn-default btn-share" data-toggle="tooltip" data-placement="bottom" title="Re-configure the scheduler"><i class="fa fa-refresh"></i> Re-configure</a> <a id="cancel-experiments-button" class="btn btn-default btn-delete" data-toggle="tooltip" data-placement="bottom" title="Cancel all running experiments"><i class="fa fa-times"></i> Cancel Experiments</a> </div> </div> @@ -52,7 +50,7 @@ <ul id="object-tabs" class="nav nav-tabs nav-justified" role="tablist"> - <li role="presentation" class="active"><a id="status-tab" href="#status" role="tab" data-toggle="tab" aria-controls="status">Status <span class="badge">{{ data.scheduler.jobs.running }}</a></li> + <li role="presentation" class="active"><a id="status-tab" href="#status" role="tab" data-toggle="tab" aria-controls="status">Status <span class="badge">{{ jobs.running }}</a></li> <li role="presentation"><a href="#experiments" role="tab" data-toggle="tab" aria-controls="experiments">Experiments <span class="badge">{{ data.scheduler.experiments.list|length }}</span></a></li> <li role="presentation"><a href="#workers" role="tab" data-toggle="tab" aria-controls="workers">Workers <span class="badge">{{ data.workers|length }}</span></a></li> <li role="presentation"><a href="#queues" role="tab" data-toggle="tab" aria-controls="queues">Queues <span class="badge">{{ data.scheduler.queues|length }}</span></a></li> @@ -67,19 +65,19 @@ <div class="col-sm-4"> <h3>Experiments</h3> <ul class="list-group"> - <li class="list-group-item">Running <span class="badge">{{ data.scheduler.experiments.running }}</span></li> - <li class="list-group-item">Completed <span class="badge">{{ data.scheduler.experiments.completed }}</span></li> + <li class="list-group-item">Running <span class="badge">{{ experiments.running }}</span></li> + <li class="list-group-item">Scheduled <span class="badge">{{ experiments.completed }}</span></li> </ul> </div> <div class="col-sm-4"> <h3>Jobs</h3> <ul class="list-group"> - <li class="list-group-item">Queued <span class="badge">{{ data.scheduler.jobs.queued }}</span></li> - <li class="list-group-item">Running <span class="badge">{{ data.scheduler.jobs.running }}</span></li> - <li class="list-group-item">Completed <span class="badge">{{ data.scheduler.jobs.completed }}</span></li> - <li class="list-group-item">Failed <span class="badge">{{ data.scheduler.jobs.failed }}</span></li> - <li class="list-group-item">Cancelled <span class="badge">{{ data.scheduler.jobs.cancelled }}</span></li> + <li class="list-group-item">Queued <span class="badge">{{ jobs.queued }}</span></li> + <li class="list-group-item">Running <span class="badge">{{ jobs.running }}</span></li> + <li class="list-group-item">Completed <span class="badge">{{ jobs.completed }}</span></li> + <li class="list-group-item">Failed <span class="badge">{{ jobs.failed }}</span></li> + <li class="list-group-item">Cancelled <span class="badge">{{ jobs.cancelled }}</span></li> </ul> </div> @@ -94,14 +92,14 @@ <!-- Experiments tab --> <div role="tabpanel" class="tab-pane" id="experiments"> - {% if data.scheduler.experiments.list %} + {% if experiments.list %} <div class="scrollable table-responsive"> <table class="table table-hover table-condensed"> <thead> <tr> <th>Name</th> - <th>Blocks</th> - <th>Jobs</th> + <th>Blocks/Jobs</th> + <th>Job Splits</th> <th>Running</th> <th>Completed</th> <th>Failed</th> @@ -110,18 +108,17 @@ </tr> </thead> <tbody> - {% for name,obj in data.scheduler.experiments.list.items %} + {% for obj in experiments.ls %} <tr> - {% with name|split_fullname as xp %} - <td><a href="{% url 'experiments:view' xp.0 xp.1 xp.2 xp.3 xp.4 %}">{{ name }}</a></td> + <td><a href="{{ obj.get_absolute_url }}">{{ obj.fullname }}</a></td> {% endwith %} - <td>{{ obj.blocks }}</td> - <td>{{ obj.jobs }}</td> - <td>{{ obj|getkey:"jobs-running" }}</td> - <td>{{ obj|getkey:"jobs-completed" }}</td> - <td>{{ obj|getkey:"jobs-failed" }}</td> - <td>{{ obj|getkey:"jobs-cancelled" }}</td> - <td>{{ obj|getkey:"jobs-skipped" }}</td> + <td>{{ obj.blocks.count }}</td> + <td>{{ obj|count_job_splits }}</td> + <td>{{ obj|count_job_splits:"P" }}</td> + <td>{{ obj|count_job_splits:"C" }}</td> + <td>{{ obj|count_job_splits:"F" }}</td> + <td>{{ obj|count_job_splits:"L" }}</td> + <td>{{ obj|count_job_splits:"S" }}</td> </tr> {% endfor %} </tbody> @@ -133,36 +130,23 @@ <!-- Workers tab --> <div role="tabpanel" class="tab-pane" id="workers"> - {% if data.workers %} + {% if workers %} <div class="scrollable table-responsive"> <table class="table table-hover object-list"> <thead> <tr> - <th class="status"></th> <th class="status"></th> <th>Name</th> <th>Available/Total Cores</th> - <th>Used Memory (in Gb)</th> - <th>Worker Version</th> - <th>Environments</th> + <th>Memory (in Gb)</th> + <th>Info</th> </tr> </thead> <tbody> - {% for name, obj in data.workers.items %} + {% for obj in workers %} <tr{% if obj.available_cores != obj.cores %} class="{% if obj.available_cores == 0 %}danger{% else %}warning{% endif %}"{% endif %}> <td class="status"> - <a title="{{ obj.db_status }}: {{ obj.info }}" data-toggle="tooltip" data-placement="top"> - {% if obj.db_status == 'Active' %} - <i class="fa fa-check fa-2x" style="color:green"></i> - {% elif obj.db_status == 'Inactive' %} - <i class="fa fa-power-off fa-2x" style="color:gray"></i> - {% elif obj.db_status == 'Unknown' %} - <i class="fa fa-bug fa-2x" style="color:red"></i> - {% endif %} - </a> - </td> - <td class="status"> - <a title="{% if obj.active %}On{% else %}Off{% endif %}" data-toggle="tooltip" data-placement="top"> + <a title="{% if obj.active %}Active{% else %}Off{% endif %}" data-toggle="tooltip" data-placement="top"> {% if obj.active %} <i class="fa fa-check fa-2x" style="color:green"></i> {% else %} @@ -170,11 +154,10 @@ {% endif %} </a> </td> - <td>{% if obj.id %}<a title="Click to admin" data-toggle="tooltip" data-placement="top" href="{% url 'admin:backend_worker_change' obj.id %}">{{ name }}</a>{% else %}{{ name }}{% endif %}</td> + <td><a title="Click to admin" data-toggle="tooltip" data-placement="top" href="{% url 'admin:backend_worker_change' obj.id %}">{{ obj.name }}</a></td> <td>{{ obj.available_cores }} / {{ obj.cores }}</td> - <td>{{ obj.virtual_memory.percent }}% ({% widthratio obj.memory_in_megabytes 1024 1 %})</td> - <td>{{ obj|getkey:'beat_version' }}</td> - <td>{{ obj|getkey:'environments'|length }}</td> + <td>{% widthratio obj.memory 1024 1 %}</td> + <td>{{ obj.info }}</td> {% endfor %} </tbody> </table> @@ -186,44 +169,32 @@ <!-- Queues tab --> <div role="tabpanel" class="tab-pane" id="queues"> - {% if data.scheduler.queues %} + {% if queues %} <div class="scrollable table-responsive"> <table class="table table-hover object-list"> <thead> <tr> - <th class="status"></th> <th>Name</th> <th>Memory (in Mb)</th> <th>Total Slots</th> <th>Cores/Slot</th> <th>Max Slots/User</th> + <th>Availability</th> <th>Time Limit (minutes)</th> <th>Environments</th> </tr> </thead> <tbody> - {% for name, obj in data.scheduler.queues.items %} + {% for obj in queues %} <tr> - <td class="status"> - <a title="{{ obj.info }}" data-toggle="tooltip" data-placement="top"> - {% if obj.db_status == 'Active' %} - <i class="fa fa-check fa-2x" style="color:green"></i> - {% elif obj.db_status == 'Inactive' %} - <i class="fa fa-power-off fa-2x" style="color:gray"></i> - {% elif obj.db_status == 'Mismatch' %} - <i class="fa fa-bug fa-2x" style="color:red"></i> - {% elif obj.db_status == 'Missing' %} - <i class="fa fa-question fa-2x" style="color:orange"></i> - {% endif %} - </a> - </td> - <td>{% if obj.id %}<a title="Click to admin" data-toggle="tooltip" data-placement="top" href="{% url 'admin:backend_queue_change' obj.id %}">{{ name }}</a>{% else %}{{ name }}{% endif %}</td> - <td>{{ obj|getkey:'memory-in-megabytes' }}</td> - <td>{{ obj|getkey:'total-slots' }}</td> - <td>{{ obj|getkey:'nb-cores-per-slot' }}</td> - <td>{{ obj|getkey:'max-slots-per-user' }}</td> - <td>{{ obj|getkey:'time-limit-in-minutes' }}</td> - <td>{{ obj|getkey:'environments'|length }}</td> + <td><a title="Click to admin" data-toggle="tooltip" data-placement="top" href="{% url 'admin:backend_queue_change' obj.id %}">{{ obj.name }}</a></td> + <td>{{ obj.memory_limit }}</td> + <td>{{ obj.number_of_slots }}</td> + <td>{{ obj.cores_per_slot }}</td> + <td>{{ obj.max_slots_per_user }}</td> + <td>{{ obj.availability }}</td> + <td>{{ obj.time_limit }}</td> + <td>{{ obj.environments.count }}</td> {% endfor %} </tbody> </table> @@ -272,46 +243,8 @@ $(document).ready(function() { }); function reload_on_success(data) { - var message = 'Command successfully sent to scheduler.'; - if (Array.isArray(data)) { //cache feedback - if (data.length == 0) message += ' No cache files erased.'; - else if (data.length == 1) message += ' One cache file erased.'; - else message += ' ' + data.length + ' cache files erased.'; - } - BootstrapDialog.show({ - title: '<i class="fa fa-info-circle"></i> Information', - message: message, - buttons: [{ - label: 'Close', - cssClass: 'btn-primary', - action: function(dialog) {dialog.close();} - }], - onhide: function() { - location.reload(); - }, - }); } - //rig buttons so to perform actions - $('a#reconfig-button').click(function() { - $this = $(this); - $this.disable(); - $this.find('i').addClass('fa-spin'); - - var d = $.ajax({ - type: 'POST', - url: '{% url "api_backend:backend-api-scheduler-configuration" %}', - }); - - d.done(reload_on_success); - - d.fail(function(data, status_text) { - process_error(data, status_text); - $this.find('i').removeClass('fa-spin'); - $this.enable(); - }); - }); - $('a#cancel-experiments-button').click(function() { $this = $(this); $this.disable(); @@ -322,37 +255,10 @@ $(document).ready(function() { url: '{% url 'api_backend:backend-api-cancel-all-experiments' %}', }); - d.done(reload_on_success); - - d.fail(function(data, status_text) { - process_error(data, status_text); - $this.find('i').removeClass('fa-spin'); - $this.enable(); - }); - }); - - $('a#clean-cache-button').click(function() { - $this = $(this); - $this.disable(); - $this.find('i').addClass('fa-spin'); - - //TODO: missing date picker to choose time - - data = { - 'olderthan': 0, //in minutes (0 means from now backwards) - 'nolist': false, //wheter we expect a list of hashes erased (negated) - }; - - var d = $.ajax({ - type: "POST", - url: '{% url 'api_backend:backend-api-cache-cleanup' %}', - data: JSON.stringify(data), - contentType: "application/json; charset=utf-8", - dataType: "json", + d.done(function(data) { + location.reload(); }); - d.done(reload_on_success); - d.fail(function(data, status_text) { process_error(data, status_text); $this.find('i').removeClass('fa-spin');