From patchwork Thu Dec 15 16:07:17 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Larson X-Patchwork-Id: 5775 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 7B9FB23E03 for ; Thu, 15 Dec 2011 16:07:19 +0000 (UTC) Received: from mail-ey0-f180.google.com (mail-ey0-f180.google.com [209.85.215.180]) by fiordland.canonical.com (Postfix) with ESMTP id 5BFE6A188CB for ; Thu, 15 Dec 2011 16:07:19 +0000 (UTC) Received: by eaak10 with SMTP id k10so2377410eaa.11 for ; Thu, 15 Dec 2011 08:07:19 -0800 (PST) Received: by 10.205.129.137 with SMTP id hi9mr1498559bkc.90.1323965239057; Thu, 15 Dec 2011 08:07:19 -0800 (PST) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.205.129.2 with SMTP id hg2cs45807bkc; Thu, 15 Dec 2011 08:07:18 -0800 (PST) Received: by 10.204.154.200 with SMTP id p8mr1530160bkw.4.1323965237520; Thu, 15 Dec 2011 08:07:17 -0800 (PST) Received: from indium.canonical.com (indium.canonical.com. [91.189.90.7]) by mx.google.com with ESMTPS id fj12si4083128wbb.118.2011.12.15.08.07.17 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 15 Dec 2011 08:07:17 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) client-ip=91.189.90.7; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) smtp.mail=bounces@canonical.com Received: from ackee.canonical.com ([91.189.89.26]) by indium.canonical.com with esmtp (Exim 4.71 #1 (Debian)) id 1RbDq1-0002np-8J for ; Thu, 15 Dec 2011 16:07:17 +0000 Received: from ackee.canonical.com (localhost [127.0.0.1]) by ackee.canonical.com (Postfix) with ESMTP id 33B4CE01FF for ; Thu, 15 Dec 2011 16:07:17 +0000 (UTC) MIME-Version: 1.0 X-Launchpad-Project: lava-scheduler X-Launchpad-Branch: ~linaro-validation/lava-scheduler/trunk X-Launchpad-Message-Rationale: Subscriber X-Launchpad-Branch-Revision-Number: 108 X-Launchpad-Notification-Type: branch-revision To: Linaro Patch Tracker From: noreply@launchpad.net Subject: [Branch ~linaro-validation/lava-scheduler/trunk] Rev 108: Overhaul of the job view Message-Id: <20111215160717.7947.22159.launchpad@ackee.canonical.com> Date: Thu, 15 Dec 2011 16:07:17 -0000 Reply-To: noreply@launchpad.net Sender: bounces@canonical.com Errors-To: bounces@canonical.com Precedence: bulk X-Generated-By: Launchpad (canonical.com); Revision="14487"; Instance="launchpad-lazr.conf" X-Launchpad-Hash: 05e9ae48cd22e1cc8720e6ce34a3741745714c48 Merge authors: Le Chi Thu le.chi.thu@linaro.org Michael Hudson-Doyle (mwhudson) Related merge proposals: https://code.launchpad.net/~mwhudson/lava-scheduler/redesign-job-view/+merge/85425 proposed by: Michael Hudson-Doyle (mwhudson) review: Approve - Paul Larson (pwlars) review: Approve - Le Chi Thu (le-chi-thu) https://code.launchpad.net/~le-chi-thu/lava-scheduler/redesign-job-view/+merge/83493 proposed by: Le Chi Thu (le-chi-thu) review: Resubmit - Le Chi Thu (le-chi-thu) review: Needs Fixing - Michael Hudson-Doyle (mwhudson) review: Needs Fixing - Zygmunt Krynicki (zkrynicki) ------------------------------------------------------------ revno: 108 [merge] committer: Paul Larson branch nick: lava-scheduler timestamp: Thu 2011-12-15 10:03:59 -0600 message: Overhaul of the job view added: lava_scheduler_app/logfile_helper.py lava_scheduler_app/static/ lava_scheduler_app/static/css/ lava_scheduler_app/static/css/logfile.css lava_scheduler_app/static/css/scheduler.css lava_scheduler_app/static/css/shCore.css lava_scheduler_app/static/css/shThemeDefault.css lava_scheduler_app/static/images/ lava_scheduler_app/static/images/ajax-progress.gif lava_scheduler_app/static/js/ lava_scheduler_app/static/js/jQuery.Rule.js lava_scheduler_app/static/js/shBrushJScript.js lava_scheduler_app/static/js/shCore.js lava_scheduler_app/templates/lava_scheduler_app/job_definition.html lava_scheduler_app/templates/lava_scheduler_app/job_log_file.html lava_scheduler_app/templates/lava_scheduler_app/job_sidebar.html modified: .bzrignore lava_scheduler_app/templates/lava_scheduler_app/alljobs.html lava_scheduler_app/templates/lava_scheduler_app/job.html lava_scheduler_app/urls.py lava_scheduler_app/views.py --- lp:lava-scheduler https://code.launchpad.net/~linaro-validation/lava-scheduler/trunk You are subscribed to branch lp:lava-scheduler. To unsubscribe from this branch go to https://code.launchpad.net/~linaro-validation/lava-scheduler/trunk/+edit-subscription === modified file '.bzrignore' --- .bzrignore 2011-07-26 05:31:17 +0000 +++ .bzrignore 2011-11-26 21:49:36 +0000 @@ -1,4 +1,5 @@ *.egg-info +.idea ./twistd.pid ./_trial_temp ./twisted/plugins/dropin.cache === added file 'lava_scheduler_app/logfile_helper.py' --- lava_scheduler_app/logfile_helper.py 1970-01-01 00:00:00 +0000 +++ lava_scheduler_app/logfile_helper.py 2011-12-13 04:22:40 +0000 @@ -0,0 +1,86 @@ +import os +import re + +def getDispatcherErrors(logfile): + if not logfile: + return "Log file is missing" + errors = "" + for line in logfile: + if line.find("CriticalError:") != -1 or \ + line.find("Lava failed on test:") != -1 : + errors += line + + return errors + +def getDispatcherLogSize(logfile): + if not logfile: + return 0 + else: + logfile.seek(0, os.SEEK_END) + size = logfile.tell() + return size + +def getDispatcherLogMessages(logfile): + if not logfile: + return ('', "Log file is missing") + + logs = [] + log_prefix = '' + level_pattern = re.compile('....-..-.. ..:..:.. .. ([A-Z]+):') + for line in logfile: + if not line.startswith(log_prefix): + continue + line = line[len(log_prefix):].strip() + match = level_pattern.match(line) + if not match: + continue + if len(line) > 90: + line = line[:90] + '...' + logs.append((match.group(1), line)) + return logs + +class Sections: + def __init__(self): + self.sections = [] + self.cur_section_type = None + self.cur_section = [] + def push(self, type, line): + if type != self.cur_section_type: + self.close() + self.cur_section_type = type + self.cur_section.append(line) + def close(self): + if self.cur_section_type is not None: + self.sections.append( + (self.cur_section_type, + len(self.cur_section), + ''.join(self.cur_section))) + self.cur_section_type = None + self.cur_section = [] + +def formatLogFile(logfile): + if not logfile: + return [('log', 1, "Log file is missing")] + + sections = Sections() + + for line in logfile: + line = line.replace('\r', '') + if not line: + continue + if line == 'Traceback (most recent call last):\n': + sections.push('traceback', line) + elif sections.cur_section_type == 'traceback': + sections.push('traceback', line) + if not line.startswith(' '): + sections.close() + continue + elif line.find("") != -1 or \ + line.find("lava_dispatcher") != -1 or \ + line.find("CriticalError:") != -1 : + sections.push('log', line) + else: + sections.push('console', line) + sections.close() + + return sections.sections === added directory 'lava_scheduler_app/static' === added directory 'lava_scheduler_app/static/css' === added file 'lava_scheduler_app/static/css/logfile.css' --- lava_scheduler_app/static/css/logfile.css 1970-01-01 00:00:00 +0000 +++ lava_scheduler_app/static/css/logfile.css 2011-12-13 04:22:40 +0000 @@ -0,0 +1,26 @@ + +#logfile_content +{ + margin-left: 5px; +} + +.log_log +{ + color: #a23212; +} + +.console_log +{ + margin-left: 10px; +} +.traceback_log +{ + color: #ee1111; +} + +.clickable +{ + border-style: solid; + border-width: medium; +} + === added file 'lava_scheduler_app/static/css/scheduler.css' --- lava_scheduler_app/static/css/scheduler.css 1970-01-01 00:00:00 +0000 +++ lava_scheduler_app/static/css/scheduler.css 2011-12-09 01:53:59 +0000 @@ -0,0 +1,43 @@ +.column { + position: relative; + float: left; + padding-right: 2em; + padding-bottom: 1em; + width: 20%; +} +#tab-definition { + width: 70%; +} + +#tab-definition pre { + overflow-x: auto; /* Use horizontal scroller if needed; for Firefox 2, not needed in Firefox 3 */ + white-space: pre-wrap; /* css-3 */ + white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + /* width: 99%; */ + word-wrap: break-word; /* Internet Explorer 5.5+ */ + max-height: 400px; +} + +#tab-output pre { + max-height: 400px; + max-width: 800px; + margin: 25px; +} + +.skip { + color:red; +} + +#dispatcher-error pre { + color: red; +} + +pre.log { + margin: 0; +} + +.logbuttons .ui-button-text { + padding: 0.1em 0.4em; +} \ No newline at end of file === added file 'lava_scheduler_app/static/css/shCore.css' --- lava_scheduler_app/static/css/shCore.css 1970-01-01 00:00:00 +0000 +++ lava_scheduler_app/static/css/shCore.css 2011-11-26 21:49:36 +0000 @@ -0,0 +1,226 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +.syntaxhighlighter a, +.syntaxhighlighter div, +.syntaxhighlighter code, +.syntaxhighlighter table, +.syntaxhighlighter table td, +.syntaxhighlighter table tr, +.syntaxhighlighter table tbody, +.syntaxhighlighter table thead, +.syntaxhighlighter table caption, +.syntaxhighlighter textarea { + -moz-border-radius: 0 0 0 0 !important; + -webkit-border-radius: 0 0 0 0 !important; + background: none !important; + border: 0 !important; + bottom: auto !important; + float: none !important; + height: auto !important; + left: auto !important; + line-height: 1.1em !important; + margin: 0 !important; + outline: 0 !important; + overflow: visible !important; + padding: 0 !important; + position: static !important; + right: auto !important; + text-align: left !important; + top: auto !important; + vertical-align: baseline !important; + width: auto !important; + box-sizing: content-box !important; + font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; + font-weight: normal !important; + font-style: normal !important; + font-size: 1em !important; + min-height: inherit !important; + min-height: auto !important; +} + +.syntaxhighlighter { + width: 100% !important; + margin: 1em 0 1em 0 !important; + position: relative !important; + overflow: auto !important; + font-size: 1em !important; +} +.syntaxhighlighter.source { + overflow: hidden !important; +} +.syntaxhighlighter .bold { + font-weight: bold !important; +} +.syntaxhighlighter .italic { + font-style: italic !important; +} +.syntaxhighlighter .line { + white-space: pre !important; +} +.syntaxhighlighter table { + width: 100% !important; +} +.syntaxhighlighter table caption { + text-align: left !important; + padding: .5em 0 0.5em 1em !important; +} +.syntaxhighlighter table td.code { + width: 100% !important; +} +.syntaxhighlighter table td.code .container { + position: relative !important; +} +.syntaxhighlighter table td.code .container textarea { + box-sizing: border-box !important; + position: absolute !important; + left: 0 !important; + top: 0 !important; + width: 100% !important; + height: 100% !important; + border: none !important; + background: white !important; + padding-left: 1em !important; + overflow: hidden !important; + white-space: pre !important; +} +.syntaxhighlighter table td.gutter .line { + text-align: right !important; + padding: 0 0.5em 0 1em !important; +} +.syntaxhighlighter table td.code .line { + padding: 0 1em !important; +} +.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { + padding-left: 0em !important; +} +.syntaxhighlighter.show { + display: block !important; +} +.syntaxhighlighter.collapsed table { + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar { + padding: 0.1em 0.8em 0em 0.8em !important; + font-size: 1em !important; + position: static !important; + width: auto !important; + height: auto !important; +} +.syntaxhighlighter.collapsed .toolbar span { + display: inline !important; + margin-right: 1em !important; +} +.syntaxhighlighter.collapsed .toolbar span a { + padding: 0 !important; + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar span a.expandSource { + display: inline !important; +} +.syntaxhighlighter .toolbar { + position: absolute !important; + right: 1px !important; + top: 1px !important; + width: 11px !important; + height: 11px !important; + font-size: 10px !important; + z-index: 10 !important; +} +.syntaxhighlighter .toolbar span.title { + display: inline !important; +} +.syntaxhighlighter .toolbar a { + display: block !important; + text-align: center !important; + text-decoration: none !important; + padding-top: 1px !important; +} +.syntaxhighlighter .toolbar a.expandSource { + display: none !important; +} +.syntaxhighlighter.ie { + font-size: .9em !important; + padding: 1px 0 1px 0 !important; +} +.syntaxhighlighter.ie .toolbar { + line-height: 8px !important; +} +.syntaxhighlighter.ie .toolbar a { + padding-top: 0px !important; +} +.syntaxhighlighter.printing .line.alt1 .content, +.syntaxhighlighter.printing .line.alt2 .content, +.syntaxhighlighter.printing .line.highlighted .number, +.syntaxhighlighter.printing .line.highlighted.alt1 .content, +.syntaxhighlighter.printing .line.highlighted.alt2 .content { + background: none !important; +} +.syntaxhighlighter.printing .line .number { + color: #bbbbbb !important; +} +.syntaxhighlighter.printing .line .content { + color: black !important; +} +.syntaxhighlighter.printing .toolbar { + display: none !important; +} +.syntaxhighlighter.printing a { + text-decoration: none !important; +} +.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { + color: black !important; +} +.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { + color: #008200 !important; +} +.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { + color: blue !important; +} +.syntaxhighlighter.printing .keyword { + color: #006699 !important; + font-weight: bold !important; +} +.syntaxhighlighter.printing .preprocessor { + color: gray !important; +} +.syntaxhighlighter.printing .variable { + color: #aa7700 !important; +} +.syntaxhighlighter.printing .value { + color: #009900 !important; +} +.syntaxhighlighter.printing .functions { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .constants { + color: #0066cc !important; +} +.syntaxhighlighter.printing .script { + font-weight: bold !important; +} +.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { + color: gray !important; +} +.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { + color: red !important; +} +.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { + color: black !important; +} === added file 'lava_scheduler_app/static/css/shThemeDefault.css' --- lava_scheduler_app/static/css/shThemeDefault.css 1970-01-01 00:00:00 +0000 +++ lava_scheduler_app/static/css/shThemeDefault.css 2011-11-26 21:49:36 +0000 @@ -0,0 +1,117 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +.syntaxhighlighter { + background-color: white !important; +} +.syntaxhighlighter .line.alt1 { + background-color: white !important; +} +.syntaxhighlighter .line.alt2 { + background-color: white !important; +} +.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { + background-color: #e0e0e0 !important; +} +.syntaxhighlighter .line.highlighted.number { + color: black !important; +} +.syntaxhighlighter table caption { + color: black !important; +} +.syntaxhighlighter .gutter { + color: #afafaf !important; +} +.syntaxhighlighter .gutter .line { + border-right: 3px solid #6ce26c !important; +} +.syntaxhighlighter .gutter .line.highlighted { + background-color: #6ce26c !important; + color: white !important; +} +.syntaxhighlighter.printing .line .content { + border: none !important; +} +.syntaxhighlighter.collapsed { + overflow: visible !important; +} +.syntaxhighlighter.collapsed .toolbar { + color: blue !important; + background: white !important; + border: 1px solid #6ce26c !important; +} +.syntaxhighlighter.collapsed .toolbar a { + color: blue !important; +} +.syntaxhighlighter.collapsed .toolbar a:hover { + color: red !important; +} +.syntaxhighlighter .toolbar { + color: white !important; + background: #6ce26c !important; + border: none !important; +} +.syntaxhighlighter .toolbar a { + color: white !important; +} +.syntaxhighlighter .toolbar a:hover { + color: black !important; +} +.syntaxhighlighter .plain, .syntaxhighlighter .plain a { + color: black !important; +} +.syntaxhighlighter .comments, .syntaxhighlighter .comments a { + color: #008200 !important; +} +.syntaxhighlighter .string, .syntaxhighlighter .string a { + color: blue !important; +} +.syntaxhighlighter .keyword { + color: #006699 !important; +} +.syntaxhighlighter .preprocessor { + color: gray !important; +} +.syntaxhighlighter .variable { + color: #aa7700 !important; +} +.syntaxhighlighter .value { + color: #009900 !important; +} +.syntaxhighlighter .functions { + color: #ff1493 !important; +} +.syntaxhighlighter .constants { + color: #0066cc !important; +} +.syntaxhighlighter .script { + font-weight: bold !important; + color: #006699 !important; + background-color: none !important; +} +.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { + color: gray !important; +} +.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { + color: red !important; +} + +.syntaxhighlighter .keyword { + font-weight: bold !important; +} === added directory 'lava_scheduler_app/static/images' === added file 'lava_scheduler_app/static/images/ajax-progress.gif' Binary files lava_scheduler_app/static/images/ajax-progress.gif 1970-01-01 00:00:00 +0000 and lava_scheduler_app/static/images/ajax-progress.gif 2011-12-12 04:38:14 +0000 differ === added directory 'lava_scheduler_app/static/js' === added file 'lava_scheduler_app/static/js/jQuery.Rule.js' --- lava_scheduler_app/static/js/jQuery.Rule.js 1970-01-01 00:00:00 +0000 +++ lava_scheduler_app/static/js/jQuery.Rule.js 2011-12-09 04:45:32 +0000 @@ -0,0 +1,273 @@ +/*! + * jQuery.Rule - Css Rules manipulation, the jQuery way. + * Copyright (c) 2007-2011 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com + * Dual licensed under MIT and GPL. + * Date: 02/7/2011 + * Compatible with jQuery 1.2+ + * + * @author Ariel Flesler + * @version 1.0.2 + * + * @id jQuery.rule + * @param {Undefined|String|jQuery.Rule} The rules, can be a selector, or literal CSS rules. Many can be given, comma separated. + * @param {Undefined|String|DOMElement|jQuery) The context stylesheets, all of them by default. + * @return {jQuery.Rule} Returns a jQuery.Rule object. + * + * @example $.rule('p,div').filter(function(){ return this.style.display != 'block'; }).remove(); + * + * @example $.rule('div{ padding:20px;background:#CCC}, p{ border:1px red solid; }').appendTo('style'); + * + * @example $.rule('div{}').append('margin:40px').css('margin-left',0).appendTo('link:eq(1)'); + * + * @example $.rule().not('div, p.magic').fadeOut('slow'); + * + * @example var text = $.rule('#screen h2').add('h4').end().eq(4).text(); + */ +;(function( $ ){ + + /** + * Notes + * Some styles and animations might fail, please report it. + * The plugin needs a style node to stay in the DOM all along to temporarily hold rules. DON'T TOUCH IT. + * Opera requires this style to have alternate in the rel to allow disabling it. + * Rules in IE don't have .parentStylesheet. We need to find it each time(slow). + * Animations need close attention. Programatically knowing which rule has precedence, would require a LOT of work. + * This plugin adds $.rule and also 4 methods to $.fn: ownerNode, sheet, cssRules and cssText + * Note that rules are not directly inside nodes, you need to do: $('style').sheet().cssRules(). + */ + + var storageNode = $(' + {% endblock %} + {% block content %} -

Job {{ job.pk }}

- -{% if show_cancel %} -
- {% csrf_token %} - -
-{% endif %} - -
-
-
Submitted by:
-
{{ job.submitter }}
- - {% if job.requested_device %} -
Requested device:
-
{{ job.requested_device }}
- {% endif %} - - {% if job.requested_device_type %} -
Requested type:
-
{{ job.requested_device_type }}
- {% endif %} - - {% if job.description %} -
Description:
-
{{ job.description }}
- {% endif %} -
- -
-
Status:
-
{{ job.get_status_display }}
- - {% if job.actual_device %} -
On device:
-
{{ job.actual_device }}
- {% endif %} - - {% if job.results_link %} -

- - Results - -

- {% endif %} -
- -
-
Submitted at:
-
{{ job.submit_time }}
- -
Started at:
-
{{ job.start_time|default:"not started" }}
- -
Finished at:
-
{{ job.end_time|default:"not finished" }}
-
-
-
- -
- -
-
{{ job.definition }}
-
-{% if log_file_present %} -
-
- -
-
-{% endif %} -
- - +{% endblock %} -{% endblock %} === added file 'lava_scheduler_app/templates/lava_scheduler_app/job_definition.html' --- lava_scheduler_app/templates/lava_scheduler_app/job_definition.html 1970-01-01 00:00:00 +0000 +++ lava_scheduler_app/templates/lava_scheduler_app/job_definition.html 2011-12-09 03:55:33 +0000 @@ -0,0 +1,21 @@ +{% extends "lava_scheduler_app/job_sidebar.html" %} + +{% block extrahead %} +{{ block.super }} + + + + + +{% endblock %} + +{% block content %} +

Job defintion file - {{ job.id }}

+Download as text file +
{{ job.definition }}
+ + + +{% endblock %} === added file 'lava_scheduler_app/templates/lava_scheduler_app/job_log_file.html' --- lava_scheduler_app/templates/lava_scheduler_app/job_log_file.html 1970-01-01 00:00:00 +0000 +++ lava_scheduler_app/templates/lava_scheduler_app/job_log_file.html 2011-12-13 04:22:40 +0000 @@ -0,0 +1,64 @@ +{% extends "lava_scheduler_app/job_sidebar.html" %} + +{% block extrahead %} +{{ block.super }} + +{% endblock %} + +{% block content %} +

Dispatcher log file - {{ job.id }}

+Download as text file + +
+{% for section in sections %} + +{% if section.0 == 'console' and section.1 > 20 and not forloop.last %} +skip {{ section.1 }} lines to next log entry → +{% endif %} +
{{ section.2 }}
+{% endfor %} +{% if job.status == job.RUNNING %} + +{% endif %} +
+ +{% if job.status == job.RUNNING %} + +{% endif %} + +{% endblock %} === added file 'lava_scheduler_app/templates/lava_scheduler_app/job_sidebar.html' --- lava_scheduler_app/templates/lava_scheduler_app/job_sidebar.html 1970-01-01 00:00:00 +0000 +++ lava_scheduler_app/templates/lava_scheduler_app/job_sidebar.html 2011-12-09 03:55:33 +0000 @@ -0,0 +1,76 @@ +{% extends "layouts/content_with_sidebar.html" %} + + +{% block extrahead %} +{{ block.super }} + + + +{% endblock %} + + +{% block sidebar %} +

Job information

+
+
Submitted by:
+
{{ job.submitter }}
+ + {% if job.requested_device %} +
Requested device:
+
{{ job.requested_device }}
+ {% endif %} + + {% if job.requested_device_type %} +
Requested type:
+
{{ job.requested_device_type }}
+ {% endif %} + + {% if job.description %} +
Description:
+
{{ job.description }}
+ {% endif %} +
Status:
+
{{ job.get_status_display }}
+ + {% if job.actual_device %} +
On device:
+
{{ job.actual_device }}
+ {% endif %} +
Submitted at:
+
{{ job.submit_time }}
+ +
Started at:
+
{{ job.start_time|default:"not started" }}
+ +
Finished at:
+
{{ job.end_time|default:"not finished" }}
+
+

Views

+ +{% if show_cancel %} +

Actions

+
+ {% csrf_token %} + +
+{% endif %} + +{% endblock %} + === modified file 'lava_scheduler_app/urls.py' --- lava_scheduler_app/urls.py 2011-10-28 00:24:13 +0000 +++ lava_scheduler_app/urls.py 2011-12-13 03:58:12 +0000 @@ -20,6 +20,18 @@ url(r'^job/(?P[0-9]+)$', 'job_detail', name='lava.scheduler.job.detail'), + url(r'^job/(?P[0-9]+)/definition$', + 'job_definition', + name='lava.scheduler.job.definition'), + url(r'^job/(?P[0-9]+)/definition/plain$', + 'job_definition_plain', + name='lava.scheduler.job.definition.plain'), + url(r'^job/(?P[0-9]+)/log_file$', + 'job_log_file', + name='lava.scheduler.job.log_file'), + url(r'^job/(?P[0-9]+)/log_file/plain$', + 'job_log_file_plain', + name='lava.scheduler.job.log_file.plain'), url(r'^job/(?P[0-9]+)/cancel$', 'job_cancel', name='lava.scheduler.job.cancel'), @@ -28,4 +40,11 @@ name='lava.scheduler.job.json'), url(r'^job/(?P[0-9]+)/output$', 'job_output', - name='lava.scheduler.job.output')) + name='lava.scheduler.job.output'), + url(r'^job/(?P[0-9]+)/log_incremental$', + 'job_log_incremental', + name='lava.scheduler.job.log_incremental'), + url(r'^job/(?P[0-9]+)/full_log_incremental$', + 'job_full_log_incremental', + name='lava.scheduler.job.full_log_incremental'), + ) === modified file 'lava_scheduler_app/views.py' --- lava_scheduler_app/views.py 2011-10-28 00:24:13 +0000 +++ lava_scheduler_app/views.py 2011-12-13 03:58:12 +0000 @@ -1,5 +1,11 @@ -import json +from collections import defaultdict +import simplejson +import logging import os +import StringIO + +from logfile_helper import formatLogFile, getDispatcherErrors +from logfile_helper import getDispatcherLogMessages, getDispatcherLogSize from django.http import ( HttpResponse, @@ -60,15 +66,101 @@ @BreadCrumb("Job #{pk}", parent=index, needs=['pk']) def job_detail(request, pk): job = get_object_or_404(TestJob, pk=pk) + job_errors = getDispatcherErrors(job.log_file) + job_log_messages = getDispatcherLogMessages(job.log_file) + + levels = defaultdict(int) + for kl in ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']: + levels[kl] = 0 + for level, msg in job_log_messages: + levels[level] += 1 + levels = sorted(levels.items(), key=lambda (k,v):logging._levelNames.get(k)) + return render_to_response( "lava_scheduler_app/job.html", { - 'log_file_present': bool(job.log_file), 'job': TestJob.objects.get(pk=pk), 'show_cancel': job.status <= TestJob.RUNNING and job.can_cancel(request.user), 'bread_crumb_trail': BreadCrumbTrail.leading_to(job_detail, pk=pk), - }, - RequestContext(request)) + 'job_errors' : job_errors, + 'job_has_error' : len(job_errors) > 0, + 'job_log_messages' : job_log_messages, + 'levels': levels, + 'show_reload_page' : job.status <= TestJob.RUNNING, + 'job_file_size' : getDispatcherLogSize(job.log_file), + }, + RequestContext(request)) + + +def job_definition(request, pk): + job = get_object_or_404(TestJob, pk=pk) + return render_to_response( + "lava_scheduler_app/job_definition.html", + { + 'job': job, + }, + RequestContext(request)) + + +def job_definition_plain(request, pk): + job = get_object_or_404(TestJob, pk=pk) + response = HttpResponse(job.definition, mimetype='text/plain') + response['Content-Disposition'] = "attachment; filename=job_%d.json"%job.id + return response + + +@BreadCrumb("Complete log", parent=job_detail, needs=['pk']) +def job_log_file(request, pk): + job = get_object_or_404(TestJob, pk=pk) + content = formatLogFile(job.log_file) + return render_to_response( + "lava_scheduler_app/job_log_file.html", + { + 'job': TestJob.objects.get(pk=pk), + 'sections' : content, + 'job_file_size' : getDispatcherLogSize(job.log_file), + }, + RequestContext(request)) + + +def job_log_file_plain(request, pk): + job = get_object_or_404(TestJob, pk=pk) + response = HttpResponse(job.log_file, mimetype='text/plain') + response['Content-Disposition'] = "attachment; filename=job_%d.log"%job.id + return response + + +def job_log_incremental(request, pk): + start = int(request.GET.get('start', 0)) + job = get_object_or_404(TestJob, pk=pk) + log_file = job.log_file + log_file.seek(start) + new_content = log_file.read() + m = getDispatcherLogMessages(StringIO.StringIO(new_content)) + response = HttpResponse( + simplejson.dumps(m), content_type='application/json') + response['X-Current-Size'] = str(start + len(new_content)) + if job.status not in [TestJob.RUNNING, TestJob.CANCELING]: + response['X-Is-Finished'] = '1' + return response + + +def job_full_log_incremental(request, pk): + start = int(request.GET.get('start', 0)) + job = get_object_or_404(TestJob, pk=pk) + log_file = job.log_file + log_file.seek(start) + new_content = log_file.read() + nl_index = new_content.rfind('\n', -NEWLINE_SCAN_SIZE) + if nl_index >= 0: + new_content = new_content[:nl_index+1] + m = formatLogFile(StringIO.StringIO(new_content)) + response = HttpResponse( + simplejson.dumps(m), content_type='application/json') + response['X-Current-Size'] = str(start + len(new_content)) + if job.status not in [TestJob.RUNNING, TestJob.CANCELING]: + response['X-Is-Finished'] = '1' + return response LOG_CHUNK_SIZE = 512*1024 @@ -118,7 +210,7 @@ def job_json(request, pk): job = get_object_or_404(TestJob, pk=pk) - json_text = json.dumps({ + json_text = simplejson.dumps({ 'status': job.get_status_display(), 'results_link': job.results_link, })