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:
parent
f6b08577c5
commit
dd1786701f
BIN
modules/openstack_project/files/zuul/green.png
Normal file
BIN
modules/openstack_project/files/zuul/green.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 409 B |
BIN
modules/openstack_project/files/zuul/line-angle.png
Normal file
BIN
modules/openstack_project/files/zuul/line-angle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 281 B |
BIN
modules/openstack_project/files/zuul/line-t.png
Normal file
BIN
modules/openstack_project/files/zuul/line-t.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 216 B |
BIN
modules/openstack_project/files/zuul/line.png
Normal file
BIN
modules/openstack_project/files/zuul/line.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 192 B |
BIN
modules/openstack_project/files/zuul/red.png
Normal file
BIN
modules/openstack_project/files/zuul/red.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 409 B |
@ -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&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&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: [
|
||||||
|
@ -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">↑</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;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user