mirror of https://github.com/rancher/ui.git
522 lines
12 KiB
JavaScript
522 lines
12 KiB
JavaScript
import Ember from 'ember';
|
|
import MultiStatsSocket from 'ui/utils/multi-stats';
|
|
import { formatPercent, formatMib, formatKbps } from 'ui/utils/util';
|
|
|
|
const MAX_POINTS = 60;
|
|
const TICK_COUNT = 6;
|
|
const COLORS = ["#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf"];
|
|
const ALT_COLORS = ["#ff7f0e", "#1f77b4", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf"];
|
|
|
|
export default Ember.Component.extend({
|
|
model: null,
|
|
linkName: 'containerStats',
|
|
single: true,
|
|
|
|
statsSocket: null,
|
|
available: Ember.computed.alias('statsSocket.available'),
|
|
active: Ember.computed.alias('statsSocket.active'),
|
|
loading: Ember.computed.alias('statsSocket.loading'),
|
|
|
|
cpuCanvas: '#cpuGraph',
|
|
cpuGraph: null,
|
|
cpuData: null,
|
|
setCpuScale: false,
|
|
|
|
memoryCanvas: '#memoryGraph',
|
|
memoryGraph: null,
|
|
memoryData: null,
|
|
useMemoryLimit: true,
|
|
setMemoryScale: false,
|
|
|
|
storageCanvas: '#storageGraph',
|
|
storageGraph: null,
|
|
storageData: null,
|
|
|
|
networkCanvas: '#networkGraph',
|
|
networkGraph: null,
|
|
networkData: null,
|
|
|
|
renderOk: false,
|
|
renderTimer: null,
|
|
|
|
|
|
didInsertElement: function() {
|
|
this._super();
|
|
|
|
Ember.run.next(() => {
|
|
var stats = MultiStatsSocket.create({
|
|
resource: this.get('model'),
|
|
linkName: this.get('linkName'),
|
|
});
|
|
|
|
this.set('statsSocket',stats);
|
|
stats.on('dataPoint', (data) => { this.onDataPoint(data); });
|
|
});
|
|
},
|
|
|
|
willDestroyElement: function() {
|
|
this._super();
|
|
this.tearDown();
|
|
this.get('statsSocket').close();
|
|
},
|
|
|
|
onActiveChanged: function() {
|
|
if ( this.get('active') )
|
|
{
|
|
this.setUp();
|
|
}
|
|
else
|
|
{
|
|
this.tearDown();
|
|
}
|
|
}.observes('active'),
|
|
|
|
setUp() {
|
|
this.set('renderOk', false);
|
|
this.set('setMemoryScale', false);
|
|
this.set('setCpuScale', false);
|
|
|
|
if ( this.get('cpuCanvas') )
|
|
{
|
|
this.initCpuGraph();
|
|
}
|
|
|
|
if ( this.get('memoryCanvas') )
|
|
{
|
|
this.initMemoryGraph();
|
|
}
|
|
|
|
if ( this.get('storageCanvas') )
|
|
{
|
|
this.initStorageGraph();
|
|
}
|
|
|
|
if ( this.get('networkCanvas') )
|
|
{
|
|
this.initNetworkGraph();
|
|
}
|
|
|
|
clearInterval(this.get('renderTimer'));
|
|
// Give it a second for some data to come in...
|
|
this.set('renderTimer', setInterval(this.renderGraphs.bind(this), 1000));
|
|
},
|
|
|
|
tearDown() {
|
|
['cpuGraph','memoryGraph','storageGraph','networkGraph'].forEach((key) => {
|
|
var obj = this.get(key);
|
|
if ( obj )
|
|
{
|
|
obj.destroy();
|
|
this.set(key,null);
|
|
}
|
|
});
|
|
},
|
|
|
|
onDataPoint(point) {
|
|
var didSetCpuScale = false;
|
|
var didSetMemoryScale = false;
|
|
|
|
// CPU
|
|
var row;
|
|
var graph = this.get('cpuGraph');
|
|
var data = this.get('cpuData');
|
|
if ( data && (typeof point.cpu_total !== 'undefined') )
|
|
{
|
|
if ( this.get('single') )
|
|
{
|
|
row = getOrCreateDataRow(graph, data, 'System');
|
|
row.push(point.cpu_system);
|
|
row = getOrCreateDataRow(graph, data, 'User');
|
|
row.push(point.cpu_user);
|
|
}
|
|
else
|
|
{
|
|
row = getOrCreateDataRow(graph, data, point.key);
|
|
row.push(point.cpu_total);
|
|
}
|
|
|
|
if ( point.cpu_count && this.get('renderOk') && !this.get('setCpuScale') )
|
|
{
|
|
graph.axis.max(point.cpu_count*100);
|
|
didSetCpuScale = true;
|
|
}
|
|
}
|
|
|
|
// Memory
|
|
graph = this.get('memoryGraph');
|
|
data = this.get('memoryData');
|
|
if ( data && (typeof point.mem_used_mb !== 'undefined') )
|
|
{
|
|
if ( this.get('single') )
|
|
{
|
|
row = getOrCreateDataRow(graph, data, 'Used');
|
|
}
|
|
else
|
|
{
|
|
row = getOrCreateDataRow(graph, data, point.key);
|
|
}
|
|
row.push(point.mem_used_mb);
|
|
|
|
var max = Math.ceil(point.mem_total_mb || this.get('model.info.memoryInfo.memTotal'));
|
|
if ( max && this.get('renderOk') && !this.get('setMemoryScale') )
|
|
{
|
|
graph.axis.max(max);
|
|
didSetMemoryScale = true;
|
|
}
|
|
}
|
|
|
|
// Network
|
|
graph = this.get('networkGraph');
|
|
data = this.get('networkData');
|
|
if ( data && (typeof point.net_rx_kb !== 'undefined') )
|
|
{
|
|
if ( this.get('single') )
|
|
{
|
|
row = getOrCreateDataRow(graph, data, 'Transmit');
|
|
row.push(point.net_tx_kb);
|
|
row = getOrCreateDataRow(graph, data, 'Receive');
|
|
row.push(point.net_rx_kb);
|
|
}
|
|
else
|
|
{
|
|
row = getOrCreateDataRow(graph, data, point.key);
|
|
row.push(point.net_rx_kb + point.net_tx_kb);
|
|
}
|
|
}
|
|
|
|
// Storage
|
|
graph = this.get('storageGraph');
|
|
data = this.get('storageData');
|
|
if ( data && (typeof point.disk_read_kb !== 'undefined') )
|
|
{
|
|
if ( this.get('single') )
|
|
{
|
|
row = getOrCreateDataRow(graph, data, 'Write');
|
|
row.push(point.disk_write_kb);
|
|
row = getOrCreateDataRow(graph, data, 'Read');
|
|
row.push(point.disk_read_kb);
|
|
}
|
|
else
|
|
{
|
|
row = getOrCreateDataRow(graph, data, point.key);
|
|
row.push(point.disk_read_kb + point.disk_write_kb);
|
|
}
|
|
}
|
|
|
|
if ( didSetMemoryScale )
|
|
{
|
|
this.set('setMemoryScale', true);
|
|
}
|
|
|
|
if ( didSetCpuScale )
|
|
{
|
|
this.set('setCpuScale', true);
|
|
}
|
|
|
|
this.set('renderOk', true);
|
|
},
|
|
|
|
initCpuGraph() {
|
|
var store = this.get('store');
|
|
var single = this.get('single');
|
|
|
|
//console.log('Init CPU');
|
|
var x = ['x'];
|
|
for ( var i = 0 ; i < MAX_POINTS ; i++ )
|
|
{
|
|
x.push(i);
|
|
}
|
|
this.set('cpuData', [x]);
|
|
|
|
var cpuGraph = c3.generate({
|
|
bindto: this.get('cpuCanvas'),
|
|
size: {
|
|
height: 110,
|
|
},
|
|
color: { pattern: ALT_COLORS.slice() },
|
|
data: {
|
|
type: 'area-step',
|
|
x: 'x',
|
|
columns: this.get('cpuData'),
|
|
groups: [[]], // Stacked graph, populated by getOrCreateDataRow...
|
|
order: null,
|
|
},
|
|
transition: { duration: 0 },
|
|
legend: { show: false },
|
|
tooltip: {
|
|
show: true,
|
|
format: {
|
|
title: formatSecondsAgo,
|
|
name: formatKey.bind(this,single,store),
|
|
value: formatPercent,
|
|
}
|
|
},
|
|
axis: {
|
|
x: {
|
|
show: false,
|
|
},
|
|
y: {
|
|
min: 0,
|
|
max: 100,
|
|
inner: true,
|
|
padding: {
|
|
top: 0,
|
|
left: 0,
|
|
bottom: 0,
|
|
right: 0
|
|
},
|
|
tick: {
|
|
count: TICK_COUNT,
|
|
format: formatPercent,
|
|
},
|
|
},
|
|
}
|
|
});
|
|
|
|
this.set('cpuGraph', cpuGraph);
|
|
},
|
|
|
|
initMemoryGraph() {
|
|
var store = this.get('store');
|
|
var single = this.get('single');
|
|
|
|
//console.log('Init Memory');
|
|
var x = ['x'];
|
|
for ( var i = 0 ; i < MAX_POINTS ; i++ )
|
|
{
|
|
x.push(i);
|
|
}
|
|
this.set('memoryData', [x]);
|
|
|
|
var memoryGraph = c3.generate({
|
|
bindto: this.get('memoryCanvas'),
|
|
size: {
|
|
height: 110,
|
|
},
|
|
color: { pattern: COLORS.slice() },
|
|
data: {
|
|
type: 'area-step',
|
|
x: 'x',
|
|
columns: this.get('memoryData'),
|
|
groups: [[]], // Stacked graph, populated by getOrCreateDataRow...
|
|
},
|
|
transition: { duration: 0 },
|
|
legend: { show: false },
|
|
tooltip: {
|
|
show: true,
|
|
format: {
|
|
title: formatSecondsAgo,
|
|
name: formatKey.bind(this,single,store),
|
|
value: formatMib,
|
|
}
|
|
},
|
|
axis: {
|
|
x: {
|
|
show: false,
|
|
},
|
|
y: {
|
|
min: 0,
|
|
inner: true,
|
|
padding: {
|
|
top: 0,
|
|
left: 0,
|
|
bottom: 0,
|
|
right: 0
|
|
},
|
|
tick: {
|
|
count: TICK_COUNT,
|
|
format: formatMib,
|
|
},
|
|
},
|
|
}
|
|
});
|
|
|
|
this.set('memoryGraph', memoryGraph);
|
|
},
|
|
|
|
initStorageGraph() {
|
|
var store = this.get('store');
|
|
var single = this.get('single');
|
|
|
|
//console.log('Init Storage');
|
|
var x = ['x'];
|
|
for ( var i = 0 ; i < MAX_POINTS ; i++ )
|
|
{
|
|
x.push(i);
|
|
}
|
|
this.set('storageData', [x]);
|
|
|
|
var storageGraph = c3.generate({
|
|
bindto: this.get('storageCanvas'),
|
|
size: {
|
|
height: 110,
|
|
},
|
|
color: { pattern: ALT_COLORS.slice() },
|
|
data: {
|
|
type: 'area-step',
|
|
x: 'x',
|
|
columns: this.get('storageData'),
|
|
groups: [[]], // Stacked graph, populated by getOrCreateDataRow...
|
|
order: null,
|
|
},
|
|
transition: { duration: 0 },
|
|
legend: { show: false },
|
|
tooltip: {
|
|
show: true,
|
|
format: {
|
|
title: formatSecondsAgo,
|
|
name: formatKey.bind(this,single,store),
|
|
value: formatKbps,
|
|
},
|
|
},
|
|
axis: {
|
|
x: {
|
|
show: false,
|
|
},
|
|
y: {
|
|
inner: true,
|
|
padding: {
|
|
top: 0,
|
|
left: 0,
|
|
bottom: 0,
|
|
right: 0
|
|
},
|
|
tick: {
|
|
count: TICK_COUNT,
|
|
format: formatKbps,
|
|
},
|
|
},
|
|
}
|
|
});
|
|
|
|
this.set('storageGraph', storageGraph);
|
|
},
|
|
|
|
initNetworkGraph() {
|
|
var store = this.get('store');
|
|
var single = this.get('single');
|
|
|
|
//console.log('Init Network');
|
|
var x = ['x'];
|
|
for ( var i = 0 ; i < MAX_POINTS ; i++ )
|
|
{
|
|
x.push(i);
|
|
}
|
|
this.set('networkData', [x]);
|
|
|
|
var networkGraph = c3.generate({
|
|
bindto: this.get('networkCanvas'),
|
|
size: {
|
|
height: 110,
|
|
},
|
|
color: { pattern: ALT_COLORS.slice() },
|
|
data: {
|
|
type: 'area-step',
|
|
x: 'x',
|
|
columns: this.get('networkData'),
|
|
groups: [[]], // Stacked graph, populated by getOrCreateDataRow...
|
|
order: null,
|
|
},
|
|
transition: { duration: 0 },
|
|
legend: { show: false },
|
|
tooltip: {
|
|
show: true,
|
|
format: {
|
|
title: formatSecondsAgo,
|
|
name: formatKey.bind(this,single,store),
|
|
value: formatKbps,
|
|
},
|
|
},
|
|
axis: {
|
|
x: {
|
|
show: false,
|
|
},
|
|
y: {
|
|
inner: true,
|
|
padding: {
|
|
top: 0,
|
|
left: 0,
|
|
bottom: 0,
|
|
right: 0
|
|
},
|
|
tick: {
|
|
count: TICK_COUNT,
|
|
format: formatKbps,
|
|
},
|
|
},
|
|
}
|
|
});
|
|
|
|
this.set('networkGraph', networkGraph);
|
|
},
|
|
|
|
renderGraphs() {
|
|
['cpu','memory','storage','network'].forEach((key) => {
|
|
var graph = this.get(key+'Graph');
|
|
var data = this.get(key+'Data');
|
|
if ( graph && data )
|
|
{
|
|
graph.load({columns: data});
|
|
|
|
// Remove the oldest point
|
|
for ( var i = 1 ; i < data.length ; i++ )
|
|
{
|
|
data[i].splice(1, Math.max(0, data[i].length - 1 - MAX_POINTS));
|
|
}
|
|
}
|
|
});
|
|
},
|
|
});
|
|
|
|
function getOrCreateDataRow(graph, data, key) {
|
|
var i;
|
|
for ( i = 0 ; i < data.length ; i++ )
|
|
{
|
|
if ( data[i][0] === key )
|
|
{
|
|
return data[i];
|
|
}
|
|
}
|
|
|
|
// Create a new row and backfill with 0's
|
|
var newRow = [key];
|
|
for ( i = 1 ; i < data[0].length ; i++ )
|
|
{
|
|
newRow.push(0);
|
|
}
|
|
data.push(newRow);
|
|
|
|
// Add the new key to the graph stack
|
|
var groups = graph.groups();
|
|
if ( groups.length )
|
|
{
|
|
groups[0].push(key);
|
|
graph.groups(groups);
|
|
}
|
|
|
|
return newRow;
|
|
}
|
|
|
|
function formatSecondsAgo(d) {
|
|
var ago = Math.max(0,MAX_POINTS - d);
|
|
return ago + ' second' + (ago === 1 ? '' : 's') + ' ago';
|
|
}
|
|
|
|
function formatKey(single, store, key /*, ratio, _id, index*/) {
|
|
if ( single )
|
|
{
|
|
return key;
|
|
}
|
|
|
|
var [type, id] = key.split('/');
|
|
var obj = store.getById(type, id);
|
|
if ( obj )
|
|
{
|
|
return obj.get('displayName');
|
|
}
|
|
else
|
|
{
|
|
return key;
|
|
}
|
|
}
|