mirror of
https://github.com/puppetlabs/vmpooler.git
synced 2026-01-26 10:08:40 -05:00
commit
ad4e760f56
11 changed files with 881 additions and 907 deletions
5
lib/vmpooler/public/bootstrap.min.css
vendored
Normal file
5
lib/vmpooler/public/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
7
lib/vmpooler/public/lib/bootstrap.min.js
vendored
Normal file
7
lib/vmpooler/public/lib/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
5
lib/vmpooler/public/lib/d3.min.js
vendored
Normal file
5
lib/vmpooler/public/lib/d3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
734
lib/vmpooler/public/lib/dashboard.js
Normal file
734
lib/vmpooler/public/lib/dashboard.js
Normal file
|
|
@ -0,0 +1,734 @@
|
||||||
|
var dashboard_data = {};
|
||||||
|
var dashboard_svg = {};
|
||||||
|
var date_from = new Date();
|
||||||
|
|
||||||
|
var running_data = {};
|
||||||
|
var weekly_data = {
|
||||||
|
clone_max: 0,
|
||||||
|
clone_platform_max: 0
|
||||||
|
};
|
||||||
|
var capacity_data = {};
|
||||||
|
|
||||||
|
var colorscale = d3.scale.category20();
|
||||||
|
var stack = d3.layout.stack().values(function(d) { return d.values; });
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Date.prototype.yyyymmdd = function() {
|
||||||
|
var yyyy = this.getFullYear().toString();
|
||||||
|
var mm = (this.getMonth()+1).toString();
|
||||||
|
var dd = this.getDate().toString();
|
||||||
|
return yyyy + '-' + (mm[1] ? mm : '0' + mm[0]) + '-' + (dd[1] ? dd : '0' + dd[0]);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var data_url = {
|
||||||
|
'capacity': '/dashboard/stats/vmpooler/pool',
|
||||||
|
'pools' : '/api/v1/vm',
|
||||||
|
'running' : '/dashboard/stats/vmpooler/running',
|
||||||
|
'status' : '/api/v1/status',
|
||||||
|
'summary' : '/api/v1/summary'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
// Everything below this line will be updated in-browser via tick();
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
(function tick() { setTimeout(function() { // <self-update>
|
||||||
|
|
||||||
|
// Update "today's" date
|
||||||
|
|
||||||
|
date_from.setDate(date_from.getDate() - 6);
|
||||||
|
|
||||||
|
// Gather up data from multiple endpoints
|
||||||
|
|
||||||
|
$.each([
|
||||||
|
'capacity',
|
||||||
|
'pools',
|
||||||
|
'running',
|
||||||
|
'status',
|
||||||
|
'summary'
|
||||||
|
], function(index, value) {
|
||||||
|
dashboard_data[value] = (function() {
|
||||||
|
var dashboard_data__live = null;
|
||||||
|
|
||||||
|
var url = data_url[value];
|
||||||
|
|
||||||
|
// Get history if this is the first tick() iteration
|
||||||
|
|
||||||
|
switch (value) {
|
||||||
|
case 'capacity': if (! dashboard_data[value]) { url += ('?history=1'); }; break;
|
||||||
|
case 'running' : if (! dashboard_data[value]) { url += ('?history=1'); }; break;
|
||||||
|
case 'summary' : if (! dashboard_data[value]) { url += ('?from=' + date_from.yyyymmdd()); }; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
'url': url,
|
||||||
|
'async': false,
|
||||||
|
'global': false,
|
||||||
|
'dataType': 'json',
|
||||||
|
'success': function(data) {
|
||||||
|
dashboard_data__live = data;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return dashboard_data__live;
|
||||||
|
})();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create an array of pool_maj
|
||||||
|
|
||||||
|
dashboard_data['tmp'] = {};
|
||||||
|
dashboard_data['pools_maj'] = [];
|
||||||
|
dashboard_data['pools'].sort().map(function(pool) {
|
||||||
|
var pool_maj = pool.split('-', 2)[0];
|
||||||
|
|
||||||
|
if (! dashboard_data['tmp'][pool_maj]) {
|
||||||
|
dashboard_data['pools_maj'].push(pool_maj);
|
||||||
|
dashboard_data['tmp'][pool_maj] = 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
delete dashboard_data['tmp'];
|
||||||
|
|
||||||
|
// Create a color swatch for each pool_maj
|
||||||
|
|
||||||
|
dashboard_data['color'] = {};
|
||||||
|
dashboard_data['tmp'] = 0;
|
||||||
|
dashboard_data['pools_maj'].sort().map(function(pool_maj) {
|
||||||
|
dashboard_data['color'][pool_maj] = colorscale(dashboard_data['tmp']);
|
||||||
|
dashboard_data['tmp']++;
|
||||||
|
});
|
||||||
|
delete dashboard_data['tmp'];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// #dashboard-numbers
|
||||||
|
// Numerical metrics (# cloning, running, ready, waiting, etc.)
|
||||||
|
|
||||||
|
$('#dashboard-numbers').empty();
|
||||||
|
|
||||||
|
var numbers_width = parseInt(d3.select('.col-md-2').style('width')) / 2;
|
||||||
|
var numbers_height = 75;
|
||||||
|
var numbers_data = {
|
||||||
|
label: {
|
||||||
|
'clone_total': 'cloned today',
|
||||||
|
'clone_average': 'clone time avg',
|
||||||
|
'capacity': 'capacity pct',
|
||||||
|
'total': 'total # of VMs',
|
||||||
|
'ready': 'ready & waiting',
|
||||||
|
'cloning': 'being cloned',
|
||||||
|
'booting': 'booting up',
|
||||||
|
'running': 'running tests',
|
||||||
|
'completed': 'waiting to die'
|
||||||
|
},
|
||||||
|
key: {
|
||||||
|
'clone_total': dashboard_data['status']['clone']['count']['total'],
|
||||||
|
'clone_average': dashboard_data['status']['clone']['duration']['average'] + 's',
|
||||||
|
'capacity': dashboard_data['status']['capacity']['percent'],
|
||||||
|
'total': dashboard_data['status']['queue']['total'],
|
||||||
|
'ready': dashboard_data['status']['queue']['ready'],
|
||||||
|
'cloning': dashboard_data['status']['queue']['cloning'],
|
||||||
|
'booting': dashboard_data['status']['queue']['booting'],
|
||||||
|
'running': dashboard_data['status']['queue']['running'],
|
||||||
|
'completed': dashboard_data['status']['queue']['completed']
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$.each([
|
||||||
|
'clone_total',
|
||||||
|
'clone_average',
|
||||||
|
'capacity',
|
||||||
|
'total',
|
||||||
|
'ready',
|
||||||
|
'cloning',
|
||||||
|
'booting',
|
||||||
|
'running',
|
||||||
|
'completed'
|
||||||
|
], function(index, value) {
|
||||||
|
dashboard_svg[value] = d3.select('#dashboard-numbers')
|
||||||
|
.append('svg')
|
||||||
|
.style('float', 'right')
|
||||||
|
.attr('class', 'col-md-1')
|
||||||
|
.attr('height', numbers_height);
|
||||||
|
|
||||||
|
dashboard_svg[value]
|
||||||
|
.append('text')
|
||||||
|
.text(
|
||||||
|
(numbers_data['label'][value])
|
||||||
|
)
|
||||||
|
.attr({
|
||||||
|
'text-anchor': 'end',
|
||||||
|
'x': numbers_width - 5,
|
||||||
|
'y': '50',
|
||||||
|
'font-face': '\'PT Sans\', sans-serif',
|
||||||
|
'font-size': '12px',
|
||||||
|
'font-weight': 'bold',
|
||||||
|
'fill': '#666'
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
dashboard_svg[value]
|
||||||
|
.append('text')
|
||||||
|
.text(
|
||||||
|
(numbers_data['key'][value])
|
||||||
|
)
|
||||||
|
.attr({
|
||||||
|
'text-anchor': 'end',
|
||||||
|
'x': numbers_width - 5,
|
||||||
|
'y': '36',
|
||||||
|
'font-face': '\'PT Sans\', sans-serif',
|
||||||
|
'font-weight': 'bold',
|
||||||
|
'font-size': '40px',
|
||||||
|
'letter-spacing': '-0.025em',
|
||||||
|
'fill': '#444'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
numbers_data = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// #dashboard-running
|
||||||
|
// By-platform graph of what's been running for the past hour; includes pool_maj legend
|
||||||
|
|
||||||
|
$('#dashboard-running').empty();
|
||||||
|
|
||||||
|
var running_width = parseInt(d3.select('.col-md-10').style('width'));
|
||||||
|
var running_height = 160;
|
||||||
|
|
||||||
|
if (! running_data['stack']) {
|
||||||
|
running_data['stack'] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process 'running' history
|
||||||
|
|
||||||
|
dashboard_data['pools_maj'].sort().map(function(pool_maj) {
|
||||||
|
if (dashboard_data['running'][pool_maj]['history']) {
|
||||||
|
for (var c = 0; c < dashboard_data['running'][pool_maj]['history'].length; c++) {
|
||||||
|
if (! running_data['stack'][c]) {
|
||||||
|
running_data['stack'][c] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
running_data['stack'][c][pool_maj] = dashboard_data['running'][pool_maj]['history'][c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (! running_data['graph']) {
|
||||||
|
running_data['tmp'] = [];
|
||||||
|
for (var metric in running_data['stack']) {
|
||||||
|
for (var c = 0; c < 8; c++) {
|
||||||
|
running_data['tmp'].push(running_data['stack'][metric]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
running_data['stack'] = running_data['tmp'];
|
||||||
|
delete running_data['tmp'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process 'running' newest values and add them to the stack
|
||||||
|
|
||||||
|
dashboard_data['tmp'] = {};
|
||||||
|
for (var key in dashboard_data['running']) {
|
||||||
|
dashboard_data['tmp'][key] = dashboard_data['running'][key]['running'];
|
||||||
|
}
|
||||||
|
|
||||||
|
running_data['stack'].push(dashboard_data['tmp']);
|
||||||
|
delete dashboard_data['tmp'];
|
||||||
|
|
||||||
|
// Calculate 'running' graph stack
|
||||||
|
|
||||||
|
running_data['graph'] = stack(
|
||||||
|
dashboard_data['pools_maj'].sort().map(function(pool_maj) {
|
||||||
|
return {
|
||||||
|
name: pool_maj,
|
||||||
|
values: running_data['stack'].map(function(d) {
|
||||||
|
return { y: d[pool_maj] };
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// Calculate 'running' graph shapes
|
||||||
|
|
||||||
|
running_data['total'] = d3.max(
|
||||||
|
running_data['graph'], function(layer) {
|
||||||
|
return d3.max(layer.values, function(d) {
|
||||||
|
return d.y0 + d.y;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
var running_x = d3.scale.linear().domain([0, 500]).range([5, running_width - 20]);
|
||||||
|
var running_y = d3.scale.linear().domain([0, running_data['total']]).range([running_height, 0]);
|
||||||
|
|
||||||
|
var running_area = d3.svg.area()
|
||||||
|
.x(function(d, i) { return running_x(i); })
|
||||||
|
.y0(function(d) { return running_y(d.y0); })
|
||||||
|
.y1(function(d) { return running_y(d.y0 + d.y); });
|
||||||
|
|
||||||
|
// The 'running' SVG
|
||||||
|
|
||||||
|
var running_graph = d3.select('#dashboard-running')
|
||||||
|
.append('svg')
|
||||||
|
.attr('height', running_height)
|
||||||
|
.attr('class', 'col-md-10')
|
||||||
|
.append('g');
|
||||||
|
|
||||||
|
dashboard_svg['running'] = running_graph.selectAll('#dashboard-running')
|
||||||
|
.data(running_data['graph'])
|
||||||
|
.enter()
|
||||||
|
.append('g');
|
||||||
|
|
||||||
|
// A texture
|
||||||
|
defs = dashboard_svg['running'].append('svg:defs');
|
||||||
|
|
||||||
|
defs.append('svg:pattern')
|
||||||
|
.attr('id', 'background')
|
||||||
|
.attr('patternUnits', 'userSpaceOnUse')
|
||||||
|
.attr('width', '500px')
|
||||||
|
.attr('height', '500px')
|
||||||
|
.append('svg:image')
|
||||||
|
.attr('xlink:href', '/img/textured_paper.png')
|
||||||
|
.attr('x', 0)
|
||||||
|
.attr('y', 0)
|
||||||
|
.attr('width', '500px')
|
||||||
|
.attr('height', '500px');
|
||||||
|
|
||||||
|
dashboard_svg['running']
|
||||||
|
.append('path')
|
||||||
|
.attr('class', 'area')
|
||||||
|
.attr('d', function(d) { return running_area(d.values); })
|
||||||
|
.attr('opacity', '0.75')
|
||||||
|
.style('fill', 'url(#background)');
|
||||||
|
|
||||||
|
dashboard_svg['running']
|
||||||
|
.append('path')
|
||||||
|
.attr('class', 'area')
|
||||||
|
.attr('d', function(d) { return running_area(d.values); })
|
||||||
|
.attr('opacity', '0.5')
|
||||||
|
.style('fill', function(d) { return dashboard_data['color'][d.name]; });
|
||||||
|
|
||||||
|
// Legend
|
||||||
|
|
||||||
|
dashboard_data['pools_maj'].sort().map(function(pool_maj) {
|
||||||
|
dashboard_svg['legend' + pool_maj] = d3.select('#dashboard-running')
|
||||||
|
.append('svg')
|
||||||
|
.attr('class', 'col-md-1')
|
||||||
|
.attr('height', '20px');
|
||||||
|
|
||||||
|
dashboard_svg['legend' + pool_maj]
|
||||||
|
.append('rect')
|
||||||
|
.attr({
|
||||||
|
'x': '5',
|
||||||
|
'y': '5',
|
||||||
|
'width': '10',
|
||||||
|
'height': '10',
|
||||||
|
'opacity': '0.75',
|
||||||
|
'fill': 'url(#background)'
|
||||||
|
});
|
||||||
|
|
||||||
|
dashboard_svg['legend' + pool_maj]
|
||||||
|
.append('rect')
|
||||||
|
.attr({
|
||||||
|
'x': '5',
|
||||||
|
'y': '5',
|
||||||
|
'width': '10',
|
||||||
|
'height': '10',
|
||||||
|
'opacity': '0.5',
|
||||||
|
'fill': function(d) { return dashboard_data['color'][pool_maj]; }
|
||||||
|
});
|
||||||
|
|
||||||
|
dashboard_svg['legend' + pool_maj]
|
||||||
|
.append('text')
|
||||||
|
.text(
|
||||||
|
(pool_maj)
|
||||||
|
)
|
||||||
|
.attr({
|
||||||
|
'x': '20',
|
||||||
|
'y': '15',
|
||||||
|
'font-face': '\'PT Sans\', sans-serif',
|
||||||
|
'font-size': '12px',
|
||||||
|
'font-weight': 'bold',
|
||||||
|
'fill': '#666'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (running_data['stack'].length > 500) {
|
||||||
|
running_data['stack'].shift();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// #dashboard-weekly
|
||||||
|
// Weekly graphs (daily clone count, clone/boot avgs, etc.)
|
||||||
|
|
||||||
|
$('#dashboard-weekly').empty();
|
||||||
|
|
||||||
|
var weekly_width = (parseInt(d3.select('.col-md-2').style('width')) * 2) - 10;
|
||||||
|
var weekly_height = 100;
|
||||||
|
|
||||||
|
// Update based on if it's a new day, first tick() iteration, or neither
|
||||||
|
|
||||||
|
if (dashboard_data['summary']['daily'].length == 1) {
|
||||||
|
weekly_data['clone_count'].pop();
|
||||||
|
weekly_data['clone_avg'].pop();
|
||||||
|
weekly_data['boot_avg'].pop();
|
||||||
|
}
|
||||||
|
else if (dashboard_data['summary']['daily'].length == 7) {
|
||||||
|
weekly_data['clone_count'] = [];
|
||||||
|
weekly_data['clone_avg'] = [];
|
||||||
|
weekly_data['boot_avg'] = [];
|
||||||
|
weekly_data['platform_count'] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
dashboard_data['summary']['daily'].sort().map(function(day) {
|
||||||
|
weekly_data['clone_count'].push(day['clone']['count']['total']);
|
||||||
|
weekly_data['clone_avg'].push(day['clone']['duration']['average']);
|
||||||
|
weekly_data['boot_avg'].push(day['boot']['duration']['average']);
|
||||||
|
|
||||||
|
if (day['clone']['count']['total'] > weekly_data['clone_max']) {
|
||||||
|
weekly_data['clone_max'] = day['clone']['count']['total'];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Consolidate clone totals into pool_maj groups
|
||||||
|
|
||||||
|
dashboard_data['pools'].sort().map(function(pool) {
|
||||||
|
var pool_maj = pool.split('-', 2)[0];
|
||||||
|
|
||||||
|
if (! weekly_data['platform_count'][pool_maj]) {
|
||||||
|
weekly_data['platform_count'][pool_maj] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dashboard_data['summary']['clone']['count']['pool'][pool]) {
|
||||||
|
weekly_data['platform_count'][pool_maj] += dashboard_data['summary']['clone']['count']['pool'][pool]['total'];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dashboard_data['pools_maj'].sort().map(function(pool_maj) {
|
||||||
|
if (weekly_data['platform_count'][pool_maj] > weekly_data['clone_platform_max']) {
|
||||||
|
weekly_data['clone_platform_max'] = weekly_data['platform_count'][pool_maj];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var weekly_x = d3.scale.linear().domain([0, 6]).range([0, weekly_width]);
|
||||||
|
var weekly_y_clone_count = d3.scale.linear().domain([0, weekly_data['clone_max']]).range([weekly_height, 0]);
|
||||||
|
var weekly_y_boot_avg = d3.scale.linear().domain([0, Math.max.apply(Math, weekly_data['boot_avg'])]).range([weekly_height, 0]);
|
||||||
|
var weekly_y_platform_count = d3.scale.linear().domain([0, weekly_data['clone_platform_max']]).range([weekly_height, 0]);
|
||||||
|
|
||||||
|
var area_clone_count = d3.svg.area()
|
||||||
|
.interpolate('linear')
|
||||||
|
.x(function(d, i) { return weekly_x(i); })
|
||||||
|
.y0(weekly_height)
|
||||||
|
.y1(function(d) { return weekly_y_clone_count(d); });
|
||||||
|
|
||||||
|
var area_boot_avg = d3.svg.area()
|
||||||
|
.interpolate('linear')
|
||||||
|
.x(function(d, i) { return weekly_x(i); })
|
||||||
|
.y0(weekly_height)
|
||||||
|
.y1(function(d) { return weekly_y_boot_avg(d); });
|
||||||
|
|
||||||
|
// Create some SVGs
|
||||||
|
|
||||||
|
for (graph in graphs = ['clone_count', 'clone_boot_avg']) {
|
||||||
|
dashboard_svg[graphs[graph]] = d3.select('#dashboard-weekly')
|
||||||
|
.append('svg')
|
||||||
|
.attr('class', 'col-md-4')
|
||||||
|
.attr('height', weekly_height);
|
||||||
|
|
||||||
|
dashboard_svg[graphs[graph]]
|
||||||
|
.append('g')
|
||||||
|
.attr('class', 'x tick')
|
||||||
|
.attr('transform', 'translate(0,' + (weekly_height) + ')')
|
||||||
|
.call(
|
||||||
|
d3.svg.axis()
|
||||||
|
.scale(weekly_x)
|
||||||
|
.ticks(7)
|
||||||
|
.tickSize(-weekly_height)
|
||||||
|
.outerTickSize(0)
|
||||||
|
.tickFormat('')
|
||||||
|
.tickSubdivide(true)
|
||||||
|
.orient('bottom')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
dashboard_svg['platform_count'] = d3.select('#dashboard-weekly')
|
||||||
|
.append('svg')
|
||||||
|
.attr('class', 'col-md-4')
|
||||||
|
.attr('height', weekly_height);
|
||||||
|
|
||||||
|
dashboard_svg['platform_count']
|
||||||
|
.append('g')
|
||||||
|
.attr('class', 'x tick')
|
||||||
|
.attr('transform', 'translate(0,' + (weekly_height) + ')')
|
||||||
|
.call(
|
||||||
|
d3.svg.axis()
|
||||||
|
.scale(weekly_x)
|
||||||
|
.ticks(0)
|
||||||
|
.tickSize(-weekly_height)
|
||||||
|
.orient('bottom')
|
||||||
|
);
|
||||||
|
|
||||||
|
// Area shapes for clone_count and clone/boot time avgs
|
||||||
|
|
||||||
|
var area_clone_count = d3.svg.area()
|
||||||
|
.interpolate('linear')
|
||||||
|
.x(function(d, i) { return weekly_x(i); })
|
||||||
|
.y0(weekly_height)
|
||||||
|
.y1(function(d) { return weekly_y_clone_count(d); });
|
||||||
|
|
||||||
|
var area_boot_avg = d3.svg.area()
|
||||||
|
.interpolate('linear')
|
||||||
|
.x(function(d, i) { return weekly_x(i); })
|
||||||
|
.y0(weekly_height)
|
||||||
|
.y1(function(d) { return weekly_y_boot_avg(d); });
|
||||||
|
|
||||||
|
dashboard_svg['clone_count']
|
||||||
|
.append('path')
|
||||||
|
.attr({
|
||||||
|
'class': 'area',
|
||||||
|
'fill': 'url(#background)',
|
||||||
|
'opacity': '0.75',
|
||||||
|
'd': area_clone_count(weekly_data['clone_count'])
|
||||||
|
});
|
||||||
|
|
||||||
|
dashboard_svg['clone_count']
|
||||||
|
.append('path')
|
||||||
|
.attr({
|
||||||
|
'class': 'area',
|
||||||
|
'fill': 'seagreen',
|
||||||
|
'opacity': '0.5',
|
||||||
|
'd': area_clone_count(weekly_data['clone_count'])
|
||||||
|
});
|
||||||
|
|
||||||
|
dashboard_svg['clone_boot_avg']
|
||||||
|
.append('path')
|
||||||
|
.attr({
|
||||||
|
'class': 'area',
|
||||||
|
'fill': 'url(#background)',
|
||||||
|
'opacity': '0.75',
|
||||||
|
'd': area_boot_avg(weekly_data['boot_avg'])
|
||||||
|
});
|
||||||
|
|
||||||
|
dashboard_svg['clone_boot_avg']
|
||||||
|
.append('path')
|
||||||
|
.attr({
|
||||||
|
'class': 'area',
|
||||||
|
'fill': 'crimson',
|
||||||
|
'opacity': '0.5',
|
||||||
|
'd': area_boot_avg(weekly_data['boot_avg'])
|
||||||
|
});
|
||||||
|
|
||||||
|
dashboard_svg['clone_boot_avg']
|
||||||
|
.append('path')
|
||||||
|
.attr({
|
||||||
|
'class': 'area',
|
||||||
|
'fill': 'gold',
|
||||||
|
'opacity': '0.75',
|
||||||
|
'd': area_boot_avg(weekly_data['clone_avg'])
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add a bar to the platform_count raph for each pool_maj
|
||||||
|
|
||||||
|
dashboard_data['tmp'] = 0;
|
||||||
|
dashboard_data['pools_maj'].sort().map(function(pool_maj) {
|
||||||
|
var x = dashboard_data['tmp'] * (weekly_width / dashboard_data['pools_maj'].length);
|
||||||
|
var y = weekly_y_platform_count(weekly_data['platform_count'][pool_maj]) - 1;
|
||||||
|
var width = weekly_width / dashboard_data['pools_maj'].length;
|
||||||
|
|
||||||
|
if (y == -1) { y = 0; }
|
||||||
|
|
||||||
|
dashboard_svg['platform_count']
|
||||||
|
.append('rect')
|
||||||
|
.attr({
|
||||||
|
'x': x,
|
||||||
|
'y': y,
|
||||||
|
'width': width,
|
||||||
|
'height': weekly_height,
|
||||||
|
'fill': 'url(#background)',
|
||||||
|
'opacity': '0.75'
|
||||||
|
});
|
||||||
|
|
||||||
|
dashboard_svg['platform_count']
|
||||||
|
.append('rect')
|
||||||
|
.attr({
|
||||||
|
'x': x,
|
||||||
|
'y': y,
|
||||||
|
'width': width,
|
||||||
|
'height': weekly_height,
|
||||||
|
'fill': function(d) { return dashboard_data['color'][pool_maj]; },
|
||||||
|
'opacity': '0.5'
|
||||||
|
});
|
||||||
|
|
||||||
|
dashboard_data['tmp']++;
|
||||||
|
});
|
||||||
|
delete dashboard_data['tmp'];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// #dashboard-pool
|
||||||
|
// Many little graphs showing individual pool capacities
|
||||||
|
|
||||||
|
$('#dashboard-pool').empty();
|
||||||
|
|
||||||
|
var capacity_col_class = 'col-md-2';
|
||||||
|
var capacity_width = parseInt(d3.select('.col-md-2').style('width'));
|
||||||
|
var capacity_height = 47;
|
||||||
|
|
||||||
|
if (capacity_width > 250) {
|
||||||
|
capacity_col_class = 'col-md-1';
|
||||||
|
capacity_width = parseInt(d3.select('.col-md-1').style('width'));
|
||||||
|
}
|
||||||
|
|
||||||
|
dashboard_data['pools'].sort().map(function(pool) {
|
||||||
|
var capacity_x = d3.scale.linear().domain([0, 500]).range([5, capacity_width - 5]);
|
||||||
|
var capacity_y = d3.scale.linear().domain([dashboard_data['capacity'][pool]['size'], 0]).range([0, capacity_height - 15]);
|
||||||
|
|
||||||
|
var capacity_area = d3.svg.area()
|
||||||
|
.interpolate('basis')
|
||||||
|
.x(function(d, i) { return capacity_x(i); })
|
||||||
|
.y0(capacity_height - 15)
|
||||||
|
.y1(function(d) { return capacity_y(d); });
|
||||||
|
|
||||||
|
var capacity_path = d3.svg.line()
|
||||||
|
.interpolate('basis')
|
||||||
|
.x(function(d, i) { return capacity_x(i); })
|
||||||
|
.y(function(d) { return capacity_y(d); });
|
||||||
|
|
||||||
|
if (! capacity_data[pool]) {
|
||||||
|
capacity_data[pool] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! capacity_data[pool]['r']) {
|
||||||
|
capacity_data[pool]['r'] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process 'capacity' history
|
||||||
|
|
||||||
|
if (dashboard_data['capacity'][pool]['history']) {
|
||||||
|
capacity_data[pool]['r'] = dashboard_data['capacity'][pool]['history'];
|
||||||
|
}
|
||||||
|
|
||||||
|
capacity_data[pool]['r'].push(dashboard_data['capacity'][pool]['ready']);
|
||||||
|
|
||||||
|
var capacity_current = capacity_data[pool]['r'].slice(-1)[0];
|
||||||
|
var capacity_size = dashboard_data['capacity'][pool]['size'];
|
||||||
|
var capacity_pct = Math.floor((capacity_current / capacity_size) * 100);
|
||||||
|
|
||||||
|
var statuscolor = '#78a830';
|
||||||
|
if (capacity_pct < 50) { statuscolor = '#f0a800'; }
|
||||||
|
if (capacity_pct < 25) { statuscolor = '#d84830'; }
|
||||||
|
|
||||||
|
// Define 'capacity' SVG
|
||||||
|
|
||||||
|
dashboard_svg['capacity' + pool] = d3.select('#dashboard-pool')
|
||||||
|
.append('svg')
|
||||||
|
.attr('class', capacity_col_class)
|
||||||
|
.attr('height', capacity_height);
|
||||||
|
|
||||||
|
dashboard_svg['capacity' + pool]
|
||||||
|
.append('g')
|
||||||
|
.attr('class', 'x tick')
|
||||||
|
.attr('transform', 'translate(0,' + (capacity_height - 15) + ')')
|
||||||
|
.call(
|
||||||
|
d3.svg.axis()
|
||||||
|
.scale(capacity_x)
|
||||||
|
.ticks(4)
|
||||||
|
.tickSize(-capacity_height)
|
||||||
|
.outerTickSize(0)
|
||||||
|
.tickFormat('')
|
||||||
|
.tickSubdivide(true)
|
||||||
|
.orient('bottom')
|
||||||
|
);
|
||||||
|
|
||||||
|
// Draw 'capacity' path
|
||||||
|
|
||||||
|
dashboard_svg['capacity' + pool]
|
||||||
|
.append('path')
|
||||||
|
.attr('class', 'area')
|
||||||
|
.attr('fill', 'url(#background)')
|
||||||
|
.attr('opacity', '0.75')
|
||||||
|
.attr('d', capacity_area(capacity_data[pool]['r']));
|
||||||
|
|
||||||
|
dashboard_svg['capacity' + pool]
|
||||||
|
.append('path')
|
||||||
|
.attr('class', 'area')
|
||||||
|
.attr('fill', statuscolor)
|
||||||
|
.attr('opacity', '0.5')
|
||||||
|
.attr('d', capacity_area(capacity_data[pool]['r']));
|
||||||
|
|
||||||
|
dashboard_svg['capacity' + pool]
|
||||||
|
.append('path')
|
||||||
|
.attr('class', 'line')
|
||||||
|
.attr('stroke', statuscolor)
|
||||||
|
.attr('stroke-width', '1')
|
||||||
|
.attr('d', capacity_path(capacity_data[pool]['r']));
|
||||||
|
|
||||||
|
// Add labels to 'capacity' graphs
|
||||||
|
|
||||||
|
dashboard_svg['capacity' + pool]
|
||||||
|
.append('text')
|
||||||
|
.text(
|
||||||
|
(pool)
|
||||||
|
)
|
||||||
|
.attr({
|
||||||
|
'x': '10',
|
||||||
|
'y': capacity_height - 33,
|
||||||
|
'font-face': '\'PT Sans\', sans-serif',
|
||||||
|
'font-weight': 'bold',
|
||||||
|
'font-size': '12px',
|
||||||
|
'fill': '#444'
|
||||||
|
});
|
||||||
|
|
||||||
|
dashboard_svg['capacity' + pool]
|
||||||
|
.append('text')
|
||||||
|
.text(
|
||||||
|
(capacity_pct + '%')
|
||||||
|
)
|
||||||
|
.attr({
|
||||||
|
'x': '10',
|
||||||
|
'y': capacity_height - 20,
|
||||||
|
'font-face': '\'PT Sans\', sans-serif',
|
||||||
|
'font-size': '12px',
|
||||||
|
'letter-spacing': '-0.05em',
|
||||||
|
'fill': '#444'
|
||||||
|
});
|
||||||
|
|
||||||
|
dashboard_svg['capacity' + pool]
|
||||||
|
.append('text')
|
||||||
|
.text(
|
||||||
|
('(') +
|
||||||
|
(capacity_current) +
|
||||||
|
('/') +
|
||||||
|
(capacity_size) +
|
||||||
|
(')')
|
||||||
|
)
|
||||||
|
.attr({
|
||||||
|
'x': 45,
|
||||||
|
'y': capacity_height - 20,
|
||||||
|
'font-face': '\'PT Sans\', sans-serif',
|
||||||
|
'font-size': '12px',
|
||||||
|
'letter-spacing': '-0.05em',
|
||||||
|
'fill': '#444'
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (capacity_data[pool]['r'].length > 500) {
|
||||||
|
capacity_data[pool]['r'].shift();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Hide the 'loading' screen
|
||||||
|
|
||||||
|
$('#loading').hide();
|
||||||
|
|
||||||
|
// Refresh!
|
||||||
|
|
||||||
|
tick(); }, 5000); })(); // </self-update>
|
||||||
4
lib/vmpooler/public/lib/jquery.min.js
vendored
Normal file
4
lib/vmpooler/public/lib/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -1,400 +0,0 @@
|
||||||
var numbers_url = '/status';
|
|
||||||
var numbers_width = 110;
|
|
||||||
var numbers_height = 50;
|
|
||||||
|
|
||||||
var stats_vmpooler_numbers__data = {};
|
|
||||||
var stats_vmpooler_numbers__svg = {};
|
|
||||||
|
|
||||||
d3.json( numbers_url,
|
|
||||||
|
|
||||||
function( stats_vmpooler_numbers__data ) {
|
|
||||||
|
|
||||||
( function tick() {
|
|
||||||
setTimeout( function() {
|
|
||||||
var stats_vmpooler_numbers__data__live = ( function() {
|
|
||||||
var stats_vmpooler_numbers__data__live = null;
|
|
||||||
|
|
||||||
$.ajax( {
|
|
||||||
'url': numbers_url,
|
|
||||||
'async': false,
|
|
||||||
'global': false,
|
|
||||||
'dataType': 'json',
|
|
||||||
'success': function( data ) {
|
|
||||||
stats_vmpooler_numbers__data__live = data;
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
return stats_vmpooler_numbers__data__live;
|
|
||||||
} )();
|
|
||||||
|
|
||||||
$( '#stats-vmpooler-numbers' ).empty();
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'clone_total' ] = d3.select( '#stats-vmpooler-numbers' )
|
|
||||||
.append( 'svg' )
|
|
||||||
.style( 'margin', '15px 0px 0px 0px' )
|
|
||||||
.style( 'padding', '0px 10px 20px 10px' )
|
|
||||||
.style( 'float', 'right' )
|
|
||||||
.attr( 'class', 'extra' )
|
|
||||||
.attr( 'width', numbers_width + 'px' )
|
|
||||||
.attr( 'height', numbers_height + 'px' );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'clone_total' ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( 'cloned today' )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'text-anchor': 'end',
|
|
||||||
'x': numbers_width,
|
|
||||||
'y': numbers_height,
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-size': '12px',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'fill': '#888'
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'clone_total' ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( stats_vmpooler_numbers__data__live[ 'clone' ][ 'count' ][ 'total' ] )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'text-anchor': 'end',
|
|
||||||
'x': numbers_width,
|
|
||||||
'y': '36',
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'font-size': '50px',
|
|
||||||
'letter-spacing': '-0.05em',
|
|
||||||
'fill': '#444'
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'clone_average' ] = d3.select( '#stats-vmpooler-numbers' )
|
|
||||||
.append( 'svg' )
|
|
||||||
.style( 'margin', '15px 0px 0px 0px' )
|
|
||||||
.style( 'padding', '0px 10px 20px 10px' )
|
|
||||||
.style( 'float', 'right' )
|
|
||||||
.attr( 'class', 'extra' )
|
|
||||||
.attr( 'width', numbers_width + 'px' )
|
|
||||||
.attr( 'height', numbers_height + 'px' );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'clone_average' ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( 'clone time average' )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'text-anchor': 'end',
|
|
||||||
'x': numbers_width,
|
|
||||||
'y': numbers_height,
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-size': '12px',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'fill': '#888'
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'clone_average' ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( stats_vmpooler_numbers__data__live[ 'clone' ][ 'duration' ][ 'average' ] + 's' )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'text-anchor': 'end',
|
|
||||||
'x': numbers_width,
|
|
||||||
'y': '36',
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'font-size': '50px',
|
|
||||||
'letter-spacing': '-0.05em',
|
|
||||||
'fill': '#444'
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'capacity' ] = d3.select( '#stats-vmpooler-numbers' )
|
|
||||||
.append( 'svg' )
|
|
||||||
.style( 'margin', '15px 0px 0px 0px' )
|
|
||||||
.style( 'padding', '0px 10px 20px 10px' )
|
|
||||||
.style( 'float', 'right' )
|
|
||||||
.attr( 'class', 'extra' )
|
|
||||||
.attr( 'width', numbers_width + 'px' )
|
|
||||||
.attr( 'height', numbers_height + 'px' );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'capacity' ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( 'capacity percent' )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'text-anchor': 'end',
|
|
||||||
'x': numbers_width,
|
|
||||||
'y': numbers_height,
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-size': '12px',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'fill': '#888'
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'capacity' ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( stats_vmpooler_numbers__data__live[ 'capacity' ][ 'percent' ] )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'text-anchor': 'end',
|
|
||||||
'x': numbers_width,
|
|
||||||
'y': '36',
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'font-size': '50px',
|
|
||||||
'letter-spacing': '-0.05em',
|
|
||||||
'fill': '#444'
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'total' ] = d3.select( '#stats-vmpooler-numbers' )
|
|
||||||
.append( 'svg' )
|
|
||||||
.style( 'margin', '15px 0px 0px 0px' )
|
|
||||||
.style( 'padding', '0px 10px 20px 10px' )
|
|
||||||
.style( 'float', 'right' )
|
|
||||||
.attr( 'width', numbers_width + 'px' )
|
|
||||||
.attr( 'height', numbers_height + 'px' );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'total' ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( 'total # of VMs' )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'text-anchor': 'end',
|
|
||||||
'x': numbers_width,
|
|
||||||
'y': numbers_height,
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-size': '12px',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'fill': '#888'
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'total' ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( stats_vmpooler_numbers__data__live[ 'queue' ][ 'total' ] )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'text-anchor': 'end',
|
|
||||||
'x': numbers_width,
|
|
||||||
'y': '36',
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'font-size': '50px',
|
|
||||||
'letter-spacing': '-0.05em',
|
|
||||||
'fill': '#444'
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'ready' ] = d3.select( '#stats-vmpooler-numbers' )
|
|
||||||
.append( 'svg' )
|
|
||||||
.style( 'margin', '15px 0px 0px 0px' )
|
|
||||||
.style( 'padding', '0px 10px 20px 10px' )
|
|
||||||
.style( 'float', 'right' )
|
|
||||||
.attr( 'width', numbers_width + 'px' )
|
|
||||||
.attr( 'height', numbers_height + 'px' );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'ready' ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( 'ready and waiting' )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'text-anchor': 'end',
|
|
||||||
'x': numbers_width,
|
|
||||||
'y': numbers_height,
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-size': '12px',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'fill': '#888'
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'ready' ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( stats_vmpooler_numbers__data__live[ 'queue' ][ 'ready' ] )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'text-anchor': 'end',
|
|
||||||
'x': numbers_width,
|
|
||||||
'y': '36',
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'font-size': '50px',
|
|
||||||
'letter-spacing': '-0.05em',
|
|
||||||
'fill': '#444'
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'cloning' ] = d3.select( '#stats-vmpooler-numbers' )
|
|
||||||
.append( 'svg' )
|
|
||||||
.style( 'margin', '15px 0px 0px 0px' )
|
|
||||||
.style( 'padding', '0px 10px 20px 10px' )
|
|
||||||
.style( 'float', 'right' )
|
|
||||||
.attr( 'width', numbers_width + 'px' )
|
|
||||||
.attr( 'height', numbers_height + 'px' );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'cloning' ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( 'being cloned' )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'text-anchor': 'end',
|
|
||||||
'x': numbers_width,
|
|
||||||
'y': numbers_height,
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-size': '12px',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'fill': '#888'
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'cloning' ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( stats_vmpooler_numbers__data__live[ 'queue' ][ 'cloning' ] )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'text-anchor': 'end',
|
|
||||||
'x': numbers_width,
|
|
||||||
'y': '36',
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'font-size': '50px',
|
|
||||||
'letter-spacing': '-0.05em',
|
|
||||||
'fill': '#444'
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'booting' ] = d3.select( '#stats-vmpooler-numbers' )
|
|
||||||
.append( 'svg' )
|
|
||||||
.style( 'margin', '15px 0px 0px 0px' )
|
|
||||||
.style( 'padding', '0px 10px 20px 10px' )
|
|
||||||
.style( 'float', 'right' )
|
|
||||||
.attr( 'width', numbers_width + 'px' )
|
|
||||||
.attr( 'height', numbers_height + 'px' );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'booting' ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( 'booting up' )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'text-anchor': 'end',
|
|
||||||
'x': numbers_width,
|
|
||||||
'y': numbers_height,
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-size': '12px',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'fill': '#888'
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'booting' ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( stats_vmpooler_numbers__data__live[ 'queue' ][ 'booting' ] )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'text-anchor': 'end',
|
|
||||||
'x': numbers_width,
|
|
||||||
'y': '36',
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'font-size': '50px',
|
|
||||||
'letter-spacing': '-0.05em',
|
|
||||||
'fill': '#444'
|
|
||||||
} );
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'running' ] = d3.select( '#stats-vmpooler-numbers' )
|
|
||||||
.append( 'svg' )
|
|
||||||
.style( 'margin', '15px 0px 0px 0px' )
|
|
||||||
.style( 'padding', '0px 10px 20px 10px' )
|
|
||||||
.style( 'float', 'right' )
|
|
||||||
.attr( 'width', numbers_width + 'px' )
|
|
||||||
.attr( 'height', numbers_height + 'px' );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'running' ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( 'running tests' )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'text-anchor': 'end',
|
|
||||||
'x': numbers_width,
|
|
||||||
'y': numbers_height,
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-size': '12px',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'fill': '#888'
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'running' ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( stats_vmpooler_numbers__data__live[ 'queue' ][ 'running' ] )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'text-anchor': 'end',
|
|
||||||
'x': numbers_width,
|
|
||||||
'y': '36',
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'font-size': '50px',
|
|
||||||
'letter-spacing': '-0.05em',
|
|
||||||
'fill': '#444'
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'completed' ] = d3.select( '#stats-vmpooler-numbers' )
|
|
||||||
.append( 'svg' )
|
|
||||||
.style( 'margin', '15px 0px 0px 0px' )
|
|
||||||
.style( 'padding', '0px 10px 20px 10px' )
|
|
||||||
.style( 'float', 'right' )
|
|
||||||
.style( 'text-align', 'right' )
|
|
||||||
.attr( 'width', numbers_width + 'px' )
|
|
||||||
.attr( 'height', numbers_height + 'px' );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'completed' ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( 'waiting to die' )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'text-anchor': 'end',
|
|
||||||
'x': numbers_width,
|
|
||||||
'y': numbers_height,
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-size': '12px',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'fill': '#888'
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_numbers__svg[ 'completed' ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( stats_vmpooler_numbers__data__live[ 'queue' ][ 'completed' ] )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'text-anchor': 'end',
|
|
||||||
'x': numbers_width,
|
|
||||||
'y': '36',
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'font-size': '50px',
|
|
||||||
'letter-spacing': '-0.05em',
|
|
||||||
'fill': '#444'
|
|
||||||
} );
|
|
||||||
|
|
||||||
tick();
|
|
||||||
}, 5000 );
|
|
||||||
} )();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
@ -1,187 +0,0 @@
|
||||||
var pool_url = '/dashboard/stats/vmpooler/pool';
|
|
||||||
var pool_width = 130;
|
|
||||||
var pool_height = 55;
|
|
||||||
|
|
||||||
var stats_vmpooler_pool__data = {};
|
|
||||||
var stats_vmpooler_pool__svg = {};
|
|
||||||
|
|
||||||
d3.json( pool_url+'?history=1',
|
|
||||||
|
|
||||||
function( stats_vmpooler_pool__data ) {
|
|
||||||
|
|
||||||
var stats_vmpooler_pool__data__keys = [];
|
|
||||||
|
|
||||||
for ( var key in stats_vmpooler_pool__data ) {
|
|
||||||
stats_vmpooler_pool__data__keys.push( key );
|
|
||||||
}
|
|
||||||
|
|
||||||
stats_vmpooler_pool__data__keys.sort().map(
|
|
||||||
function( pool ) {
|
|
||||||
stats_vmpooler_pool__data[ pool ][ 'r' ] = stats_vmpooler_pool__data[ pool ][ 'history' ];
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
( function tick() {
|
|
||||||
setTimeout( function() {
|
|
||||||
var stats_vmpooler_pool__data__live = ( function() {
|
|
||||||
var stats_vmpooler_pool__data__live = null;
|
|
||||||
|
|
||||||
$.ajax( {
|
|
||||||
'url': pool_url,
|
|
||||||
'async': false,
|
|
||||||
'global': false,
|
|
||||||
'dataType': 'json',
|
|
||||||
'success': function( data ) {
|
|
||||||
stats_vmpooler_pool__data__live = data;
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
return stats_vmpooler_pool__data__live;
|
|
||||||
} )();
|
|
||||||
|
|
||||||
$( '#stats-vmpooler-pool' ).empty();
|
|
||||||
|
|
||||||
stats_vmpooler_pool__data__keys.sort().map(
|
|
||||||
function( pool ) {
|
|
||||||
var x = d3.scale.linear().domain( [ 0, 500 ] ).range( [ 0, pool_width ] );
|
|
||||||
var y = d3.scale.linear().domain( [ parseInt( stats_vmpooler_pool__data__live[ pool ][ 'size' ] ), 0 ] ).range( [ 0, pool_height - 15 ] );
|
|
||||||
|
|
||||||
var area = d3.svg.area()
|
|
||||||
.interpolate( 'basis' )
|
|
||||||
.x( function( d, i ) { return x( i ); } )
|
|
||||||
.y0( pool_height - 15 )
|
|
||||||
.y1( function( d ) { return y( d ); } );
|
|
||||||
|
|
||||||
var path = d3.svg.line()
|
|
||||||
.interpolate( 'basis' )
|
|
||||||
.x( function( d, i ) { return x( i ); } )
|
|
||||||
.y( function( d ) { return y( d ); } );
|
|
||||||
|
|
||||||
stats_vmpooler_pool__data[ pool ][ 'r' ].push( parseInt( stats_vmpooler_pool__data__live[ pool ][ 'ready' ] ) );
|
|
||||||
|
|
||||||
var pool_current = stats_vmpooler_pool__data[ pool ][ 'r' ].slice( -1 )[ 0 ];
|
|
||||||
var pool_size = stats_vmpooler_pool__data[ pool ][ 'size' ]
|
|
||||||
var pool_pct = Math.floor( ( pool_current / pool_size ) * 100 );
|
|
||||||
|
|
||||||
var statuscolor = '#78a830';
|
|
||||||
if ( pool_pct < 50 ) { statuscolor = '#f0a800'; }
|
|
||||||
if ( pool_pct < 25 ) { statuscolor = '#d84830'; }
|
|
||||||
|
|
||||||
stats_vmpooler_pool__svg[ pool ] = d3.select( '#stats-vmpooler-pool' )
|
|
||||||
.append( 'svg' )
|
|
||||||
.style( 'margin', '15px 0px 0px 0px' )
|
|
||||||
.style( 'padding', '0px 10px 0px 10px' )
|
|
||||||
.attr( 'width', pool_width )
|
|
||||||
.attr( 'height', pool_height );
|
|
||||||
|
|
||||||
defs = stats_vmpooler_pool__svg[ pool ].append( 'svg:defs' );
|
|
||||||
|
|
||||||
defs.append( 'svg:pattern' )
|
|
||||||
.attr( 'id', 'background' )
|
|
||||||
.attr( 'patternUnits', 'userSpaceOnUse' )
|
|
||||||
.attr( 'width', '500px' )
|
|
||||||
.attr( 'height', '500px' )
|
|
||||||
.append( 'svg:image' )
|
|
||||||
.attr( 'xlink:href', '/img/textured_paper.png' )
|
|
||||||
.attr( 'x', 0 )
|
|
||||||
.attr( 'y', 0 )
|
|
||||||
.attr( 'width', '500px' )
|
|
||||||
.attr( 'height', '500px' );
|
|
||||||
|
|
||||||
stats_vmpooler_pool__svg[ pool ]
|
|
||||||
.append( 'path' )
|
|
||||||
.attr( 'class', 'area' )
|
|
||||||
.attr( 'fill', 'url( #background )' )
|
|
||||||
.attr( 'opacity', '0.50' )
|
|
||||||
.attr( 'd', area( stats_vmpooler_pool__data[ pool ][ 'r' ] ) );
|
|
||||||
|
|
||||||
stats_vmpooler_pool__svg[ pool ]
|
|
||||||
.append( 'g' )
|
|
||||||
.attr( 'class', 'x tick' )
|
|
||||||
.attr( 'transform', 'translate( 0,' + ( pool_height - 15 ) + ')' )
|
|
||||||
.call(
|
|
||||||
d3.svg.axis()
|
|
||||||
.scale( x )
|
|
||||||
.ticks( 4 )
|
|
||||||
.tickSize( -pool_height )
|
|
||||||
.outerTickSize( 0 )
|
|
||||||
.tickFormat( '' )
|
|
||||||
.tickSubdivide( true )
|
|
||||||
.orient( 'bottom' )
|
|
||||||
);
|
|
||||||
|
|
||||||
stats_vmpooler_pool__svg[ pool ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( pool )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'x': '5',
|
|
||||||
'y': pool_height - 2,
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'font-size': '12px',
|
|
||||||
'fill': '#888'
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_pool__svg[ pool ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( pool_pct + '%' )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'x': '5',
|
|
||||||
'y': pool_height - 20,
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'font-size': '12px',
|
|
||||||
'letter-spacing': '-0.05em',
|
|
||||||
'fill': '#888'
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_pool__svg[ pool ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( '( ' ) +
|
|
||||||
( pool_current ) +
|
|
||||||
( '/' ) +
|
|
||||||
( pool_size ) +
|
|
||||||
( ' )' )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'x': 40,
|
|
||||||
'y': pool_height - 20,
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-size': '12px',
|
|
||||||
'letter-spacing': '-0.05em',
|
|
||||||
'fill': '#888'
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_pool__svg[ pool ]
|
|
||||||
.append( 'path' )
|
|
||||||
.attr( 'class', 'area' )
|
|
||||||
.attr( 'fill', statuscolor )
|
|
||||||
.attr( 'opacity', '0.35' )
|
|
||||||
.attr( 'd', area( stats_vmpooler_pool__data[ pool ][ 'r' ] ) );
|
|
||||||
|
|
||||||
stats_vmpooler_pool__svg[ pool ]
|
|
||||||
.append( 'path' )
|
|
||||||
.attr( 'class', 'line' )
|
|
||||||
.attr( 'stroke', statuscolor )
|
|
||||||
.attr( 'stroke-width', '1' )
|
|
||||||
.attr( 'd', path( stats_vmpooler_pool__data[ pool ][ 'r' ] ) );
|
|
||||||
|
|
||||||
if ( stats_vmpooler_pool__data[ pool ][ 'r' ].length > 500 ) {
|
|
||||||
stats_vmpooler_pool__data[ pool ][ 'r' ].shift();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
tick();
|
|
||||||
}, 5000 );
|
|
||||||
} )();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
@ -1,210 +0,0 @@
|
||||||
var running_url = '/dashboard/stats/vmpooler/running';
|
|
||||||
var running_height = 160;
|
|
||||||
|
|
||||||
var colorscale = d3.scale.category20();
|
|
||||||
var color = {};
|
|
||||||
|
|
||||||
var stats_vmpooler_running__data = {};
|
|
||||||
var stats_vmpooler_running__svg = {};
|
|
||||||
|
|
||||||
var stats_vmpooler_running__data__total = 0;
|
|
||||||
|
|
||||||
d3.json( running_url+'?history=1',
|
|
||||||
|
|
||||||
function( stats_vmpooler_running__data ) {
|
|
||||||
|
|
||||||
if ( typeof stats_vmpooler_running__data[ 'stack' ] === 'undefined' ) {
|
|
||||||
stats_vmpooler_running__data[ 'stack' ] = [];
|
|
||||||
stats_vmpooler_running__data[ 'stack_t' ] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( var key in stats_vmpooler_running__data ) {
|
|
||||||
if ( stats_vmpooler_running__data[ key ][ 'history' ] ) {
|
|
||||||
for ( var c = 0; c < stats_vmpooler_running__data[ key ][ 'history' ].length; c++ ) {
|
|
||||||
if ( typeof stats_vmpooler_running__data[ 'stack' ][ c ] === 'undefined' ) {
|
|
||||||
stats_vmpooler_running__data[ 'stack' ][ c ] = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
stats_vmpooler_running__data[ 'stack' ][ c ][ key ] = stats_vmpooler_running__data[ key ][ 'history' ][ c ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( var c in stats_vmpooler_running__data[ 'stack' ] ) {
|
|
||||||
for ( var n = 0; n < 8; n++ ) {
|
|
||||||
stats_vmpooler_running__data[ 'stack_t' ].push( stats_vmpooler_running__data[ 'stack' ][ c ] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stats_vmpooler_running__data[ 'stack' ] = stats_vmpooler_running__data[ 'stack_t' ];
|
|
||||||
delete stats_vmpooler_running__data[ 'stack_t' ];
|
|
||||||
|
|
||||||
( function tick() {
|
|
||||||
setTimeout( function() {
|
|
||||||
|
|
||||||
var stats_vmpooler_running__data__live = ( function() {
|
|
||||||
var stats_vmpooler_running__data__live = null;
|
|
||||||
|
|
||||||
$.ajax( {
|
|
||||||
'url': running_url,
|
|
||||||
'async': false,
|
|
||||||
'global': false,
|
|
||||||
'dataType': 'json',
|
|
||||||
'success': function( data ) {
|
|
||||||
stats_vmpooler_running__data__live = data;
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
return stats_vmpooler_running__data__live;
|
|
||||||
} )();
|
|
||||||
|
|
||||||
var stats_vmpooler_running__data__keys = [];
|
|
||||||
|
|
||||||
for ( var key in stats_vmpooler_running__data__live ) {
|
|
||||||
stats_vmpooler_running__data__keys.push( key );
|
|
||||||
for ( var c = 0; c < Object.keys(stats_vmpooler_running__data__keys).length; c++ ) { color[key] = colorscale( c ); }
|
|
||||||
}
|
|
||||||
|
|
||||||
$( '#stats-vmpooler-running' ).empty();
|
|
||||||
|
|
||||||
var x = d3.scale.linear().domain( [ 0, 500 ] ).range( [ 0, document.getElementById( 'stats-vmpooler-running' ).offsetWidth ] );
|
|
||||||
var y = d3.scale.linear().domain( [ 0, stats_vmpooler_running__data__total ] ).range( [ running_height, 0 ] );
|
|
||||||
|
|
||||||
var area = d3.svg.area()
|
|
||||||
.x( function( d, i ) { return x( i ); } )
|
|
||||||
.y0( function( d ) { return y( d.y0 ); } )
|
|
||||||
.y1( function( d ) { return y( d.y0 + d.y ); } );
|
|
||||||
|
|
||||||
var path = d3.svg.line()
|
|
||||||
.x( function( d, i ) { return x( i ); } )
|
|
||||||
.y( function( d ) { return y( d.y0 + d.y ); } );
|
|
||||||
|
|
||||||
var stack = d3.layout.stack()
|
|
||||||
.values( function( d ) { return d.values; } );
|
|
||||||
|
|
||||||
if ( typeof stats_vmpooler_running__data[ 'stack' ] === 'undefined' ) {
|
|
||||||
stats_vmpooler_running__data[ 'stack' ] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
stats_vmpooler_running__data[ 'tmp' ] = {};
|
|
||||||
|
|
||||||
for ( var key in stats_vmpooler_running__data__live ) {
|
|
||||||
stats_vmpooler_running__data[ 'tmp' ][ key ] = stats_vmpooler_running__data__live[ key ][ 'running' ];
|
|
||||||
}
|
|
||||||
|
|
||||||
stats_vmpooler_running__data[ 'stack' ].push( stats_vmpooler_running__data[ 'tmp' ] );
|
|
||||||
|
|
||||||
var stats_vmpooler_running__data__graph = stack(
|
|
||||||
stats_vmpooler_running__data__keys.sort().map(
|
|
||||||
function( name ) {
|
|
||||||
return {
|
|
||||||
name: name,
|
|
||||||
values: stats_vmpooler_running__data[ 'stack' ].map( function( d ) {
|
|
||||||
return { y: d[ name ] };
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
stats_vmpooler_running__data__total = d3.max(
|
|
||||||
stats_vmpooler_running__data__graph, function( layer ) {
|
|
||||||
return d3.max( layer.values, function( d ) {
|
|
||||||
return d.y0 + d.y;
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
var svg = d3.select( '#stats-vmpooler-running' )
|
|
||||||
.append( 'svg' )
|
|
||||||
.attr( 'height', running_height )
|
|
||||||
.attr( 'width', ( document.getElementById( 'stats-vmpooler-running' ).offsetWidth - 35 ) )
|
|
||||||
.style( 'margin', '-40px 0px 0px 0px' )
|
|
||||||
.style( 'padding', '0px 10px 10px 10px' )
|
|
||||||
.append( 'g' );
|
|
||||||
|
|
||||||
var mysvg = svg.selectAll( '#stats-vmpooler-running' )
|
|
||||||
.data( stats_vmpooler_running__data__graph )
|
|
||||||
.enter()
|
|
||||||
.append( 'g' );
|
|
||||||
|
|
||||||
defs = mysvg.append( 'svg:defs' );
|
|
||||||
|
|
||||||
defs.append( 'svg:pattern' )
|
|
||||||
.attr( 'id', 'background' )
|
|
||||||
.attr( 'patternUnits', 'userSpaceOnUse' )
|
|
||||||
.attr( 'width', '500px' )
|
|
||||||
.attr( 'height', '500px' )
|
|
||||||
.append( 'svg:image' )
|
|
||||||
.attr( 'xlink:href', '/img/textured_paper.png' )
|
|
||||||
.attr( 'x', 0 )
|
|
||||||
.attr( 'y', 0 )
|
|
||||||
.attr( 'width', '500px' )
|
|
||||||
.attr( 'height', '500px' );
|
|
||||||
|
|
||||||
mysvg
|
|
||||||
.append( 'path' )
|
|
||||||
.attr( 'class', 'area' )
|
|
||||||
.attr( 'fill', 'url( #background )' )
|
|
||||||
.attr( 'opacity', '0.50' )
|
|
||||||
.attr( 'd', function( d ) { return area( d.values ); } );
|
|
||||||
|
|
||||||
mysvg.append( 'path' )
|
|
||||||
.attr( 'd', function( d ) { return area( d.values ); } )
|
|
||||||
.attr( 'class', 'area' )
|
|
||||||
.attr( 'opacity', '0.25' )
|
|
||||||
.style( 'fill', function( d ) { return color[ d.name ]; } );
|
|
||||||
|
|
||||||
mysvg.append( 'path' )
|
|
||||||
.attr( 'd', function( d ) { return path( d.values ); } )
|
|
||||||
.attr( 'class', 'line' )
|
|
||||||
.attr( 'stroke', function( d ) { return '#888'; } )
|
|
||||||
.attr( 'stroke-width', '1' );
|
|
||||||
|
|
||||||
stats_vmpooler_running__data__keys.sort().map(
|
|
||||||
function( key ) {
|
|
||||||
stats_vmpooler_running__svg[ key ] = d3.select( '#stats-vmpooler-running' )
|
|
||||||
.append( 'svg' )
|
|
||||||
.style( 'margin', '0px 0px 0px 0px' )
|
|
||||||
.style( 'padding', '0px 10px 10px 10px' )
|
|
||||||
.attr( 'width', '130px' )
|
|
||||||
.attr( 'height', '12px' );
|
|
||||||
|
|
||||||
stats_vmpooler_running__svg[ key ]
|
|
||||||
.append( 'rect' )
|
|
||||||
.attr( {
|
|
||||||
'x': '5',
|
|
||||||
'y': '3',
|
|
||||||
'width': '10',
|
|
||||||
'height': '10',
|
|
||||||
'opacity': '0.25',
|
|
||||||
'fill': function( d ) { return color[ key ]; }
|
|
||||||
} );
|
|
||||||
|
|
||||||
stats_vmpooler_running__svg[ key ]
|
|
||||||
.append( 'text' )
|
|
||||||
.text(
|
|
||||||
( key )
|
|
||||||
)
|
|
||||||
.attr( {
|
|
||||||
'x': '20',
|
|
||||||
'y': '12',
|
|
||||||
'font-face': '\'PT Sans\', sans-serif',
|
|
||||||
'font-size': '12px',
|
|
||||||
'font-weight': 'bold',
|
|
||||||
'fill': '#888'
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( stats_vmpooler_running__data[ 'stack' ].length > 500 ) {
|
|
||||||
stats_vmpooler_running__data[ 'stack' ].shift();
|
|
||||||
}
|
|
||||||
|
|
||||||
tick();
|
|
||||||
}, 5000 );
|
|
||||||
} )();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
@ -1,75 +1,66 @@
|
||||||
@media screen and (max-width:1500px) {
|
body {
|
||||||
#stats-vmpooler-numbers .extra {
|
margin: 1%;
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body,
|
#site-name {
|
||||||
#content {
|
text-align: right;
|
||||||
background: #fff;
|
|
||||||
margin-top: 0px;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#wrap {
|
|
||||||
margin-left: 1%;
|
|
||||||
margin-right: 1%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#header {
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#header .logo,
|
|
||||||
#header .text {
|
|
||||||
margin-left: 30px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
#header .text {
|
|
||||||
float: right;
|
|
||||||
position: relative;
|
|
||||||
right: 30px;
|
|
||||||
top: 25px;
|
|
||||||
font: 55px 'PT Sans', sans-serif;
|
font: 55px 'PT Sans', sans-serif;
|
||||||
letter-spacing: -0.05em;
|
letter-spacing: -0.05em;
|
||||||
line-height: 50px;
|
padding-top: 15px;
|
||||||
color: #444;
|
padding-right: 5px;
|
||||||
padding-left: 20px;
|
|
||||||
padding-right: 20px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#stats-vmpooler-numbers {
|
#dashboard-running .col-md-10 {
|
||||||
position: relative;
|
margin-bottom: 5px;
|
||||||
top: -80px;
|
|
||||||
right: 15px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#stats-vmpooler-running {
|
.col-md-1,
|
||||||
margin-bottom: -15px;
|
.col-md-2,
|
||||||
|
.col-md-3,
|
||||||
|
.col-md-4,
|
||||||
|
.col-md-6,
|
||||||
|
.col-md-10,
|
||||||
|
.col-md-12 {
|
||||||
|
padding-left: 0px;
|
||||||
|
padding-right: 0px;
|
||||||
|
margin-left: 0px;
|
||||||
|
margin-right: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.section_label {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
text-transform: uppercase;
|
margin-bottom: 10px;
|
||||||
text-indent: 25px;
|
|
||||||
font: 12px 'PT Sans', sans-serif;
|
font: 12px 'PT Sans', sans-serif;
|
||||||
font-weight: bold;
|
text-indent: 10px;
|
||||||
line-height: 20px;
|
|
||||||
color: #888;
|
|
||||||
border-bottom: solid 1px #888;
|
border-bottom: solid 1px #888;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.line {
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.area {
|
||||||
|
stroke-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.axis path,
|
||||||
|
.axis line {
|
||||||
|
fill: none;
|
||||||
|
stroke: #fff;
|
||||||
|
shape-rendering: crispEdges;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tick {
|
||||||
|
fill: none;
|
||||||
|
stroke: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
.spinner {
|
.spinner {
|
||||||
background-image: url( '/img/spinner.svg' );
|
background-image: url( '/img/spinner.svg' );
|
||||||
width: 15px;
|
width: 25px;
|
||||||
height: 15px;
|
height: 25px;
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
opacity: .7;
|
opacity: .7;
|
||||||
float: left;
|
|
||||||
margin-right: 5px;
|
|
||||||
-webkit-animation:rotate 1.5s infinite steps( 12 );
|
-webkit-animation:rotate 1.5s infinite steps( 12 );
|
||||||
-moz-animation:rotate 1.5s infinite steps( 12 );
|
-moz-animation:rotate 1.5s infinite steps( 12 );
|
||||||
-ms-animation:rotate 1.5s infinite steps( 12 );
|
-ms-animation:rotate 1.5s infinite steps( 12 );
|
||||||
|
|
@ -132,32 +123,3 @@ body,
|
||||||
transform: rotate( 360deg );
|
transform: rotate( 360deg );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.module {
|
|
||||||
margin-top: 5px;
|
|
||||||
margin-left: 25px;
|
|
||||||
margin-right: 25px;
|
|
||||||
font: 13px 'PT Sans', sans-serif;
|
|
||||||
line-height: 20px;
|
|
||||||
color: #888;
|
|
||||||
}
|
|
||||||
|
|
||||||
.line {
|
|
||||||
fill: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.area {
|
|
||||||
stroke-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.axis path,
|
|
||||||
.axis line {
|
|
||||||
fill: none;
|
|
||||||
stroke: #fff;
|
|
||||||
shape-rendering: crispEdges;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tick {
|
|
||||||
fill: none;
|
|
||||||
stroke: #ddd;
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +1,63 @@
|
||||||
<!-- stats-vmpooler-running -->
|
<!-- header -->
|
||||||
|
|
||||||
<div class='label'>VMs running tests</div>
|
<div id='header'>
|
||||||
|
<div class='row'>
|
||||||
|
<div id='logo' class='col-md-2'><embed src='/img/logo.gif' style='max-width: 100%; max-height: 100%' /></div>
|
||||||
|
<div id='site-name' class='col-md-10'><%= site_name %></div>
|
||||||
|
|
||||||
<div id='stats-vmpooler-running' class='module'>
|
<!-- dashboard-numbers -->
|
||||||
<div class='spinner'></div> Loading data...
|
|
||||||
|
<div id='dashboard-numbers'></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src='/lib/stats-vmpooler-running.js'></script>
|
<!-- dashboard-running -->
|
||||||
|
|
||||||
|
<div class='row'>
|
||||||
|
<div class='col-md-10' style='padding-right: 10px'>
|
||||||
|
<div class='section_label'><b>VMS RUNNING TESTS</b> ( past hour )</div>
|
||||||
|
</div>
|
||||||
|
<div class='col-md-2'>
|
||||||
|
<div class='section_label'><b>LEGEND</b></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='row'>
|
||||||
|
<div id='dashboard-running'></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<!-- stats-vmpooler-pool -->
|
<!-- dashboard-weekly -->
|
||||||
|
|
||||||
<div class='label'>individual pool capacity / fullness status</div>
|
<div class='row'>
|
||||||
|
<div class='col-md-4' style='padding-right: 10px'>
|
||||||
<div id='stats-vmpooler-pool' class='module'>
|
<div class='section_label'><b>VMS CLONED</b> ( by day, past week )</div>
|
||||||
<div class='spinner'></div> Loading data...
|
</div>
|
||||||
|
<div class='col-md-4' style='padding-right: 10px'>
|
||||||
|
<div class='section_label'><b>AVG CLONE / BOOT TIME</b> ( by day, past week )</div>
|
||||||
|
</div>
|
||||||
|
<div class='col-md-4'>
|
||||||
|
<div class='section_label'><b>PLATFORM USAGE COUNT</b> ( past week )</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src='/lib/stats-vmpooler-pool.js'></script>
|
<div class='row'>
|
||||||
|
<div id='dashboard-weekly' style='padding-left: 5px'></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<!-- dashboard-pool -->
|
||||||
|
|
||||||
|
<div class='row'>
|
||||||
|
<div class='col-md-12'>
|
||||||
|
<div class='section_label'><b>INDIVIDUAL POOL CAPACITY</b> ( "fullness" status, past hour )</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='row'>
|
||||||
|
<div id='dashboard-pool'></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src='/lib/dashboard.js'></script>
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,46 @@
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
|
||||||
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en'>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset='utf-8'>
|
<meta charset='utf-8'>
|
||||||
|
|
||||||
<link rel='stylesheet' type='text/css' href='/dashboard.css' />
|
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
|
||||||
|
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
||||||
|
|
||||||
<script type='text/javascript' src='http://code.jquery.com/jquery-latest.min.js'></script>
|
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
||||||
<script type='text/javascript' src='http://d3js.org/d3.v3.min.js'></script>
|
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src='https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js'></script>
|
||||||
|
<script src='https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js'></script>
|
||||||
|
<![endif]-->
|
||||||
|
|
||||||
|
<link rel='stylesheet' href='/bootstrap.min.css'>
|
||||||
|
<link rel='stylesheet' href='/vmpooler.css'>
|
||||||
|
|
||||||
|
<script type='text/javascript' src='/lib/jquery.min.js'></script>
|
||||||
|
<script type='text/javascript' src='/lib/bootstrap.min.js'></script>
|
||||||
|
<script type='text/javascript' src='/lib/d3.min.js'></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div id='wrap'>
|
<div id='loading' style='position: absolute; top: 0px; height: 100%; width: 100%; background-color: #fff; z-index: 1;'>
|
||||||
<div id='content'>
|
<div id='logo' style='position: relative; top: 50%; transform: translateY(-50%);'>
|
||||||
|
<center>
|
||||||
|
<img src='/img/logo.gif' />
|
||||||
|
|
||||||
<div id='header'>
|
<br />
|
||||||
<embed src='/img/logo.gif' width='200px' height='150px' class='logo' />
|
|
||||||
|
|
||||||
<div class='text'><%= site_name %></div>
|
<div class='spinner'></div>
|
||||||
|
</center>
|
||||||
<div id='stats-vmpooler-numbers' class='module'></div>
|
|
||||||
|
|
||||||
<script src='/lib/stats-vmpooler-numbers.js'></script>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='container-fluid'>
|
||||||
|
|
||||||
<%= yield %>
|
<%= yield %>
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue