Properly show update task success/failure

If a distro comparison update task fails (returning a non-zero value to
indicate as such) we were not able to see this easily from the frontend.
Show success/failure in the form of a label on the task page and general
update list/detail, and if the task fails while we're watching then make
the progress bar go red as well. Also make a distinction between the
process failing (retcode > 0) and being terminated (retcode < 0, e.g.
process was killed).

Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
This commit is contained in:
Paul Eggleton 2018-09-18 15:30:03 +12:00
parent d063aab917
commit ac73780bd9
7 changed files with 62 additions and 3 deletions

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.12 on 2018-09-18 00:46
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('layerindex', '0024_layerupdate_vcs_revs'),
]
operations = [
migrations.AddField(
model_name='update',
name='retcode',
field=models.IntegerField(default=0),
),
]

View File

@ -97,6 +97,7 @@ class Update(models.Model):
reload = models.BooleanField('Reloaded', default=False, help_text='Was this update a reload?') reload = models.BooleanField('Reloaded', default=False, help_text='Was this update a reload?')
task_id = models.CharField(max_length=50, blank=True, db_index=True) task_id = models.CharField(max_length=50, blank=True, db_index=True)
triggered_by = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL) triggered_by = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)
retcode = models.IntegerField(default=0)
def error_count(self): def error_count(self):
sums = self.layerupdate_set.aggregate(errors=models.Sum('errors')) sums = self.layerupdate_set.aggregate(errors=models.Sum('errors'))

View File

@ -47,13 +47,22 @@ def run_update_command(self, branch_name, update_command):
except FileExistsError: except FileExistsError:
pass pass
logfile = os.path.join(settings.TASK_LOG_DIR, 'task_%s.log' % str(self.request.id)) logfile = os.path.join(settings.TASK_LOG_DIR, 'task_%s.log' % str(self.request.id))
retcode = 0
erroutput = None
try: try:
output = utils.runcmd(update_command, os.path.dirname(os.path.dirname(__file__)), outfile=logfile) output = utils.runcmd(update_command, os.path.dirname(os.path.dirname(__file__)), outfile=logfile)
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
output = e.output output = e.output
erroutput = output
retcode = e.returncode
except Exception as e: except Exception as e:
print('ERROR: %s' % str(e))
output = str(e) output = str(e)
erroutput = output
retcode = -1
finally: finally:
updateobj.log = output updateobj.log = output
updateobj.finished = datetime.now() updateobj.finished = datetime.now()
updateobj.retcode = retcode
updateobj.save() updateobj.save()
return {'retcode': retcode, 'output': erroutput}

View File

@ -1401,6 +1401,11 @@ def task_log_view(request, task_id):
updateobj = get_object_or_404(Update, task_id=task_id) updateobj = get_object_or_404(Update, task_id=task_id)
response['Task-Duration'] = utils.timesince2(updateobj.started, updateobj.finished) response['Task-Duration'] = utils.timesince2(updateobj.started, updateobj.finished)
response['Task-Progress'] = 100 response['Task-Progress'] = 100
if result.info:
if isinstance(result.info, dict):
response['Task-Result'] = result.info.get('retcode', None)
else:
response['Task-Result'] = -1
else: else:
response['Task-Done'] = '0' response['Task-Done'] = '0'
preader = utils.ProgressReader(settings.TASK_LOG_DIR, task_id) preader = utils.ProgressReader(settings.TASK_LOG_DIR, task_id)

View File

@ -19,7 +19,7 @@
{% block content %} {% block content %}
{% autoescape on %} {% autoescape on %}
<p>Task status for {{ update.task_id }} started by {{ update.triggered_by }} on {{ update.started }}<span id="task_status_fragment">{% if update.finished %} (finished in {{ update.started | timesince2:update.finished }}){% endif %}</span>:</p> <p>Task status for {{ update.task_id }} started by {{ update.triggered_by }} on {{ update.started }}<span id="task_status_fragment">{% if update.finished %} (finished in {{ update.started | timesince2:update.finished }}){% endif %}</span>:<span id="status-label" class="label {% if update.finished %}{% if update.retcode %}label-danger{% else %}label-success{% endif %}{% endif %} pull-right">{% if update.finished %}{% if update.retcode < 0 %}TERMINATED ({{ update.retcode }}){% elif update.retcode %}FAILED{% else %}SUCCEEDED{% endif %}{% endif %}</span></p>
<pre id="task_log" class="vertical-scroll">{{ update.log }}</pre> <pre id="task_log" class="vertical-scroll">{{ update.log }}</pre>
@ -69,6 +69,25 @@
$('#progressbar').css('width', progress + '%').attr('aria-valuenow', progress); $('#progressbar').css('width', progress + '%').attr('aria-valuenow', progress);
$("#progressbar").html(progress + '%') $("#progressbar").html(progress + '%')
} }
result = xhr.getResponseHeader('Task-Result');
if(result && result != 0) {
progress = 100
$('#progressbar').css('width', progress + '%').attr('aria-valuenow', progress);
if(result < 0) {
failstr = "TERMINATED (" + result + ")";
}
else {
failstr = "FAILED";
}
$("#progressbar").html(failstr);
$("#progressbar").removeClass('progress-bar-info').addClass('progress-bar-danger');
$("#status-label").html(failstr);
$("#status-label").addClass('label-danger');
}
else if(done == '1') {
$("#status-label").html('SUCCEEDED');
$("#status-label").addClass('label-success');
}
} }
}).always(function () { }).always(function () {
if(done == '1') { if(done == '1') {

View File

@ -24,7 +24,9 @@
</ul> </ul>
<h2>{{ update.started }} {% if update.reload %}(reload){% endif %}</h2> <h2>{{ update.started }} {% if update.reload %}(reload){% endif %}
<span id="status-label" class="label {% if update.finished %}{% if update.retcode %}label-danger{% else %}label-success{% endif %}{% endif %} pull-right">{% if update.finished %}{% if update.retcode < 0 %}TERMINATED ({{ update.retcode }}){% elif update.retcode %}FAILED{% endif %}{% endif %}</span>
</h2>
{% if update.log %} {% if update.log %}
<pre>{{ update.log }}</pre> <pre>{{ update.log }}</pre>

View File

@ -37,7 +37,10 @@
{% for update in updates %} {% for update in updates %}
{% with error_count=update.error_count warning_count=update.warning_count %} {% with error_count=update.error_count warning_count=update.warning_count %}
<tr> <tr>
<td><a href="{% url 'update' update.id %}">{{ update.started }}{% if update.reload %} (reload){% endif %}</a></td> <td>
<a href="{% url 'update' update.id %}">{{ update.started }}{% if update.reload %} (reload){% endif %}</a>
{% if update.finished and update.retcode %}<span id="status-label" class="label label-danger">{% if update.retcode < 0 %}TERMINATED{% elif update.retcode %}FAILED{% endif %}{% endif %}
</td>
<td>{% if update.finished %}{{ update.started|timesince2:update.finished }}{% else %}(in progress){% endif %}</td> <td>{% if update.finished %}{{ update.started|timesince2:update.finished }}{% else %}(in progress){% endif %}</td>
<td>{% if error_count %}<span class="badge badge-important">{{ error_count }}</span>{% endif %}</td> <td>{% if error_count %}<span class="badge badge-important">{{ error_count }}</span>{% endif %}</td>
<td>{% if warning_count %}<span class="badge badge-warning">{{ warning_count }}</span>{% endif %}</td> <td>{% if warning_count %}<span class="badge badge-warning">{{ warning_count }}</span>{% endif %}</td>