Visualize Zuul's NNFI scheduler

Adds a subway map to the status page that reflects the current
proposed merge state according to Zuul's NNFI scheduler.

Makes the screen wider (1024 instead of 950 px) to accomodate
the additional width of the subway map.

Widen the graphs as well to match (also, evenly space them).

Change-Id: I11689c24c5d4aa58bb2dac3c595068e24af7e1d5
This commit is contained in:
James E. Blair 2013-09-13 11:42:46 -07:00
parent f6b08577c5
commit dd1786701f
7 changed files with 184 additions and 85 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 B

View File

@ -2,14 +2,81 @@
xmlns:py="http://genshi.edgewall.org/" xmlns:py="http://genshi.edgewall.org/"
lang="en"> lang="en">
<HEAD> <HEAD>
<TITLE>Zuul Status</TITLE>
<script type="text/javascript"
src="http://status.openstack.org/jquery.min.js"></script>
<script type="text/javascript"
src="http://status.openstack.org/jquery-visibility.min.js"></script>
<script type="text/javascript"
src="http://status.openstack.org/jquery-graphite.js"></script>
<script type="text/javascript"
src="http://status.openstack.org/common.js"></script>
<script type="text/javascript"
src="status.js"></script>
<!-- Google Fonts -->
<link href='http://fonts.googleapis.com/css?family=PT+Sans&amp;subset=latin' rel='stylesheet' type='text/css'/>
<!-- Framework CSS -->
<link rel="stylesheet" href="http://www.openstack.org/themes/openstack/css/blueprint/screen.css" type="text/css" media="screen, projection"/>
<link rel="stylesheet" href="http://www.openstack.org/themes/openstack/css/blueprint/print.css" type="text/css" media="print"/>
<!-- IE CSS -->
<!--[if lt IE 8]><link rel="stylesheet" href="http://www.openstack.org/blueprint/ie.css" type="text/css" media="screen, projection"><![endif]-->
<!-- OpenStack Specific CSS -->
<link rel="stylesheet" href="http://www.openstack.org/themes/openstack/css/dropdown.css" type="text/css" media="screen, projection, print"/>
<!-- Page Specific CSS -->
<link rel="stylesheet" href="http://www.openstack.org/themes/openstack/css/home.css" type="text/css" media="screen, projection, print"/>
<link rel="stylesheet" type="text/css" href="http://www.openstack.org/themes/openstack/css/main.css" />
<style type="text/css"> <style type="text/css">
.container {
width: 1024px;
}
#pipeline-container { #pipeline-container {
max-width: 950px;
margin: 0 auto; margin: 0 auto;
} }
.line {
background-image: url('line.png');
background-repeat: repeat-y;
}
.pipeline {
float: left;
padding: 4px;
}
.pipeline > .header {
background: #0000cc;
color: white;
}
.pipeline > .subhead > .count {
float: right;
margin-right: 1em;
color: #535353;
font-size: 11pt;
}
.pipeline table {
margin: 0 0 2px 0;
}
.pipeline table td {
margin: 0;
padding: 0 0 10px 0;
}
td.graph {
width: 16px;
height: 100%;
vertical-align: top;
}
.pipeline table td.change-container {
padding-left: 4px;
}
.change { .change {
border: 1px solid #95c7db; border: 1px solid #95c7db;
margin-top: 10px;
padding: 2px; padding: 2px;
} }
.change > .header { .change > .header {
@ -24,28 +91,9 @@
.change > .header > .time { .change > .header > .time {
float: right; float: right;
} }
.pipeline > .subhead > .count {
float: right;
margin-right: 1em;
color: #535353;
font-size: 11pt;
}
.job { .job {
display: block; display: block;
} line-height: 1.5;
.pipeline {
float: left;
width: 25em;
padding: 4px;
}
.pipeline > .header {
background: #0000cc;
color: white;
}
.arrow {
text-align: center;
font-size: 16pt;
line-height: 1.0;
} }
.result { .result {
float: right; float: right;
@ -59,6 +107,12 @@
.result_unstable { .result_unstable {
color: #e39f00; color: #e39f00;
} }
#graph-container img {
margin-left: 10px;
}
#graph-container img:first-of-type {
margin-left: 0px;
}
a:link { a:link {
color: #204A87; color: #204A87;
} }
@ -143,37 +197,6 @@ progress[aria-valuenow]:before {
</style> </style>
<TITLE>Zuul Status</TITLE>
<script type="text/javascript"
src="http://status.openstack.org/jquery.min.js"></script>
<script type="text/javascript"
src="http://status.openstack.org/jquery-visibility.min.js"></script>
<script type="text/javascript"
src="http://status.openstack.org/jquery-graphite.js"></script>
<script type="text/javascript"
src="http://status.openstack.org/common.js"></script>
<script type="text/javascript"
src="status.js"></script>
<!-- Google Fonts -->
<link href='http://fonts.googleapis.com/css?family=PT+Sans&amp;subset=latin' rel='stylesheet' type='text/css'/>
<!-- Framework CSS -->
<link rel="stylesheet" href="http://www.openstack.org/themes/openstack/css/blueprint/screen.css" type="text/css" media="screen, projection"/>
<link rel="stylesheet" href="http://www.openstack.org/themes/openstack/css/blueprint/print.css" type="text/css" media="print"/>
<!-- IE CSS -->
<!--[if lt IE 8]><link rel="stylesheet" href="http://www.openstack.org/blueprint/ie.css" type="text/css" media="screen, projection"><![endif]-->
<!-- OpenStack Specific CSS -->
<link rel="stylesheet" href="http://www.openstack.org/themes/openstack/css/dropdown.css" type="text/css" media="screen, projection, print"/>
<!-- Page Specific CSS -->
<link rel="stylesheet" href="http://www.openstack.org/themes/openstack/css/home.css" type="text/css" media="screen, projection, print"/>
<link rel="stylesheet" type="text/css" href="http://www.openstack.org/themes/openstack/css/main.css" />
</HEAD> </HEAD>
<BODY> <BODY>
@ -211,8 +234,8 @@ $.fn.graphite.defaults.url = "http://graphite.openstack.org/render/";
$("#graph-container").append($(new Image()).addClass('graph').graphite({ $("#graph-container").append($(new Image()).addClass('graph').graphite({
from: "-24hours", from: "-24hours",
width: 310, width: 334,
height: 170, height: 180,
bgcolor: 'ffffff', bgcolor: 'ffffff',
fgcolor: '000000', fgcolor: '000000',
areaMode: 'stacked', areaMode: 'stacked',
@ -227,8 +250,8 @@ $("#graph-container").append($(new Image()).addClass('graph').graphite({
$("#graph-container").append($(new Image()).addClass('graph').graphite({ $("#graph-container").append($(new Image()).addClass('graph').graphite({
from: "-24hours", from: "-24hours",
width: 310, width: 334,
height: 170, height: 180,
bgcolor: 'ffffff', bgcolor: 'ffffff',
fgcolor: '000000', fgcolor: '000000',
target: [ target: [
@ -239,8 +262,8 @@ $("#graph-container").append($(new Image()).addClass('graph').graphite({
$("#graph-container").append($(new Image()).addClass('graph').graphite({ $("#graph-container").append($(new Image()).addClass('graph').graphite({
from: "-24hours", from: "-24hours",
width: 310, width: 334,
height: 170, height: 180,
bgcolor: 'ffffff', bgcolor: 'ffffff',
fgcolor: '000000', fgcolor: '000000',
target: [ target: [

View File

@ -68,38 +68,86 @@ function is_hide_project(project) {
return hide; return hide;
} }
function count_changes(pipeline) { function remove(l, idx) {
l[idx] = null;
while (l[l.length-1] === null) {
l.pop();
}
}
function create_graph(pipeline) {
var count = 0; var count = 0;
var pipeline_max_graph_columns = 1;
$.each(pipeline['change_queues'], function(change_queue_i, change_queue) { $.each(pipeline['change_queues'], function(change_queue_i, change_queue) {
var graph = [];
var max_graph_columns = 1;
var changes = [];
var last_graph_length = 0;
$.each(change_queue['heads'], function(head_i, head) { $.each(change_queue['heads'], function(head_i, head) {
count += head.length; $.each(head, function(change_i, change) {
changes[change['id']] = change;
change['_graph_position'] = change_i;
});
}); });
$.each(change_queue['heads'], function(head_i, head) {
$.each(head, function(change_i, change) {
count += 1;
var idx = graph.indexOf(change['id']);
if (idx > -1) {
change['_graph_index'] = idx;
remove(graph, idx);
} else {
change['_graph_index'] = 0;
}
change['_graph_branches'] = [];
change['_graph'] = [];
change['items_behind'].sort(function(a, b) {
return changes[b]['_graph_position'] - changes[a]['_graph_position'];
});
$.each(change['items_behind'], function(i, id) {
graph.push(id);
if (last_graph_length>0 && graph.length>last_graph_length)
change['_graph_branches'].push(graph.length-1);
});
if (graph.length > max_graph_columns) {
max_graph_columns = graph.length;
}
if (graph.length > pipeline_max_graph_columns) {
pipeline_max_graph_columns = graph.length;
}
change['_graph'] = graph.slice(0); // make a copy
last_graph_length = graph.length;
});
});
change_queue['_graph_columns'] = max_graph_columns;
}); });
pipeline['_graph_columns'] = pipeline_max_graph_columns;
return count; return count;
} }
function get_sparkline_url(pipeline_name) { function get_sparkline_url(pipeline_name) {
if (!(pipeline_name in window.zuul_sparkline_urls)) { if (!(pipeline_name in window.zuul_sparkline_urls)) {
window.zuul_sparkline_urls[pipeline_name] = $.fn.graphite.geturl({ window.zuul_sparkline_urls[pipeline_name] = $.fn.graphite.geturl({
url: "http://graphite.openstack.org/render/", url: "http://graphite.openstack.org/render/",
from: "-8hours", from: "-8hours",
width: 100, width: 100,
height: 16, height: 16,
margin: 0, margin: 0,
hideLegend: true, hideLegend: true,
hideAxes: true, hideAxes: true,
hideGrid: true, hideGrid: true,
target: [ target: [
"color(stats.gauges.zuul.pipeline."+pipeline_name+".current_changes, '6b8182')", "color(stats.gauges.zuul.pipeline."+pipeline_name+".current_changes, '6b8182')",
], ],
}); });
} }
return window.zuul_sparkline_urls[pipeline_name]; return window.zuul_sparkline_urls[pipeline_name];
} }
function format_pipeline(data) { function format_pipeline(data) {
var count = count_changes(data); var count = create_graph(data);
var html = '<div class="pipeline"><h3 class="subhead">'+ var width = (16 * data['_graph_columns']) + 300;
var html = '<div class="pipeline" style="width:'+width+'"><h3 class="subhead">'+
data['name']; data['name'];
html += '<span class="count"><img src="' + get_sparkline_url(data['name']); html += '<span class="count"><img src="' + get_sparkline_url(data['name']);
@ -134,13 +182,11 @@ function format_pipeline(data) {
} }
html += name + '</a></div>'; html += name + '</a></div>';
} }
html += '<table>'
$.each(head, function(change_i, change) { $.each(head, function(change_i, change) {
if (change_i > 0) { html += format_change(change, change_queue);
html += '<div class="arrow">&uarr;</div>';
}
html += format_change(change);
}); });
html += '</div>' html += '</table></div>'
}); });
}); });
@ -148,8 +194,38 @@ function format_pipeline(data) {
return html; return html;
} }
function format_change(change) { function safe_id(id) {
var html = '<div class="change"><div class="header">'; return id.replace(',', '_');
}
function format_change(change, change_queue) {
var html = '<tr>';
for (var i=0; i<change_queue['_graph_columns']; i++) {
var cls = 'graph';
if (i < change['_graph'].length && change['_graph'][i] !== null) {
cls += ' line';
}
html += '<td class="'+cls+'">';
if (i == change['_graph_index']) {
if (change['failing_reasons'] && change['failing_reasons'].length > 0) {
html += '<img src="red.png" title="Failing because '+
change['failing_reasons'].join(', ')+'"/>';
} else {
html += '<img src="green.png" title="Succeeding"/>';
}
}
if (change['_graph_branches'].indexOf(i) != -1) {
if (change['_graph_branches'].indexOf(i) == change['_graph_branches'].length-1)
html += '<img src="line-angle.png"/>';
else
html += '<img src="line-t.png"/>';
}
html += '</td>';
}
html += '<td class="change-container">';
html += '<div class="change" id="'+safe_id(change['id'])+'"><div class="header">';
html += '<span class="project">'+change['project']+'</span>'; html += '<span class="project">'+change['project']+'</span>';
var id = change['id']; var id = change['id'];
@ -209,7 +285,7 @@ function format_change(change) {
html += '</span>'; html += '</span>';
}); });
html += '</div></div>'; html += '</div></div></td></tr>';
return html; return html;
} }
@ -275,7 +351,7 @@ function update_graphs() {
var parts = url.split('#'); var parts = url.split('#');
newimg.src = parts[0] + '#' + new Date().getTime(); newimg.src = parts[0] + '#' + new Date().getTime();
$(newimg).load(function (x) { $(newimg).load(function (x) {
window.zuul_sparkline_urls[name] = newimg.src; window.zuul_sparkline_urls[name] = newimg.src;
}); });
}); });
} }