mirror of https://github.com/rancher/ui.git
443 lines
9.6 KiB
JavaScript
443 lines
9.6 KiB
JavaScript
import Ember from "ember";
|
|
import Socket from "ui/utils/socket";
|
|
|
|
/*
|
|
Usage:
|
|
|
|
import StatsSocket from "./stats"
|
|
var sock = StatsSocket.create({resource: a_host_or_instance});
|
|
sock.on('dataPoint', function(point) {
|
|
// Do something with data
|
|
});
|
|
|
|
// When done
|
|
sock.disconnect();
|
|
*/
|
|
export var StatsSocket = Ember.Object.extend(Ember.Evented, {
|
|
resource: null,
|
|
url: null,
|
|
connected: false,
|
|
prev: null,
|
|
|
|
init: function() {
|
|
this._super();
|
|
this.connect();
|
|
},
|
|
|
|
connect: function() {
|
|
var self = this;
|
|
|
|
self.get('resource').followLink('stats').then(function(response) {
|
|
//console.log(response);
|
|
var url = response.get('url') + '?token=' + encodeURIComponent(response.get('token'));
|
|
//console.log('url',url);
|
|
|
|
var socket = Socket.create({
|
|
url: url
|
|
});
|
|
|
|
socket.on('message', function(event) {
|
|
if ( self.get('connected') )
|
|
{
|
|
self.process(JSON.parse(event.data));
|
|
}
|
|
});
|
|
|
|
socket.on('connected', function(/*tries, after*/) {
|
|
//console.log('StatsSocket connected');
|
|
self.set('connected',true);
|
|
self.trigger('connected');
|
|
});
|
|
|
|
socket.on('disconnected', function(/*tries*/) {
|
|
//console.log('StatsSocket disconnected');
|
|
self.set('connected',false);
|
|
self.trigger('disconnected');
|
|
});
|
|
|
|
self.set('socket', socket);
|
|
socket.connect();
|
|
});
|
|
},
|
|
|
|
disconnect: function() {
|
|
//console.log('StatsSocket disconnect');
|
|
var socket = this.get('socket');
|
|
if ( socket )
|
|
{
|
|
socket.disconnect();
|
|
}
|
|
},
|
|
|
|
process: function(data) {
|
|
//console.log('StatsSocket message',data);
|
|
var prev = this.get('prev');
|
|
var date = new Date(data.timestamp);
|
|
|
|
var out = {
|
|
date: date
|
|
};
|
|
|
|
if ( prev )
|
|
{
|
|
var prev_date = new Date(prev.timestamp);
|
|
var time_diff_ns = (date.getTime() - prev_date.getTime())*1e6;
|
|
|
|
// There counters are per-core, so multiply by number of cores
|
|
if ( data.cpu.usage.per_cpu_usage )
|
|
{
|
|
time_diff_ns *= data.cpu.usage.per_cpu_usage.length;
|
|
}
|
|
|
|
if ( time_diff_ns > 1000 )
|
|
{
|
|
out.cpu_user = toPercent((data.cpu.usage.user - prev.cpu.usage.user )/time_diff_ns);
|
|
out.cpu_system = toPercent((data.cpu.usage.system - prev.cpu.usage.system )/time_diff_ns);
|
|
out.cpu_total = toPercent((data.cpu.usage.total - prev.cpu.usage.total )/time_diff_ns);
|
|
}
|
|
}
|
|
|
|
if ( data.memory.usage )
|
|
{
|
|
out.mem_used_mb = Math.round(data.memory.usage/1048576);
|
|
}
|
|
else
|
|
{
|
|
out.mem_used_mb = 0;
|
|
}
|
|
|
|
if ( data.memory.limit )
|
|
{
|
|
out.mem_total_mb = Math.round(data.memory.limit/1048576);
|
|
}
|
|
|
|
if ( data.filesystem )
|
|
{
|
|
out.filesystem = [];
|
|
data.filesystem.forEach(function(disk) {
|
|
out.filesystem.push({
|
|
device: disk.device,
|
|
used_gb: Math.round(disk.usage/(1024*1024*1024)*10)/10,
|
|
size_gb: Math.round(disk.capacity/(1024*1024*1024)*10)/10,
|
|
used_percent: toPercent(disk.usage/disk.capacity),
|
|
});
|
|
});
|
|
|
|
out.filesystem.sort(function(ia, ib) {
|
|
var a = ia.device;
|
|
var b = ib.device;
|
|
return (a < b ? -1 : (a > b ? 1 : 0));
|
|
});
|
|
}
|
|
|
|
this.set('prev', data);
|
|
this.trigger('dataPoint', out);
|
|
|
|
function toPercent(decimal) {
|
|
var percent = Math.round(decimal*10000)/100;
|
|
return Math.max(0, Math.min(percent, 100));
|
|
}
|
|
},
|
|
});
|
|
|
|
/*
|
|
Usage:
|
|
|
|
import Stats from './stats';
|
|
var graphs = Stats.create({
|
|
resource: a_host_or_instance,
|
|
cpuCanvas: $('#cpuGraph')[0].getContext("2d"),
|
|
memoryCanvas: $('#memoryGraph')[0].getContext("2d")
|
|
});
|
|
|
|
// Filesystem info
|
|
stats.get('filesystem').forEach(fs) {
|
|
console.log('Filesystem:',fs);
|
|
});
|
|
|
|
// When done
|
|
sock.disconnect();
|
|
*/
|
|
var Stats = Ember.Object.extend({
|
|
resource: null,
|
|
|
|
statsSocket: null,
|
|
filesystem: null,
|
|
|
|
cpuCanvas: null,
|
|
cpuGraph: null,
|
|
cpuData: null,
|
|
|
|
memoryCanvas: null,
|
|
memoryGraph: null,
|
|
memoryData: null,
|
|
useMemoryLimit: true,
|
|
|
|
maxPoints: 60,
|
|
renderDelay: 1000,
|
|
renderOk: false,
|
|
firstPoint: true,
|
|
|
|
init: function() {
|
|
this._super();
|
|
this.onAvailableChanged();
|
|
},
|
|
|
|
available: function() {
|
|
return ['running','updating-running','active','updating-active','unhealthy'].indexOf(this.get('resource.state')) >= 0;
|
|
}.property('resource.state'),
|
|
|
|
active: Ember.computed.and('available', 'statsSocket.connected','renderOk'),
|
|
|
|
loading: function() {
|
|
return this.get('available') && !this.get('active');
|
|
}.property('available','active'),
|
|
|
|
onAvailableChanged: function() {
|
|
//console.log('Available changed', this.get('available'));
|
|
if ( this.get('available') )
|
|
{
|
|
if ( !this.get('statsSocket') )
|
|
{
|
|
this.setUp();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this.disconnect();
|
|
}
|
|
}.observes('available'),
|
|
|
|
setUp: function() {
|
|
//console.log('Stats Setup');
|
|
if ( this.get('cpuCanvas') )
|
|
{
|
|
this.initCpuGraph();
|
|
}
|
|
|
|
if ( this.get('memoryCanvas') )
|
|
{
|
|
this.initMemoryGraph();
|
|
}
|
|
|
|
if ( !this.get('statsSocket') )
|
|
{
|
|
var stats = StatsSocket.create({resource: this.get('resource')});
|
|
this.set('statsSocket',stats);
|
|
stats.on('dataPoint', this.onDataPoint.bind(this));
|
|
}
|
|
},
|
|
|
|
onDataPoint: function(data) {
|
|
var self = this;
|
|
|
|
// Don't load/render any data for a bit of time, so the initial points can load in
|
|
if ( this.get('firstPoint') )
|
|
{
|
|
this.set('firstPoint',false);
|
|
setTimeout(function() {
|
|
self.set('renderOk',true);
|
|
}, this.get('renderDelay'));
|
|
}
|
|
|
|
//console.log('DataPoint', data);
|
|
var rows;
|
|
|
|
// Filesytem
|
|
var fs = this.get('filesystem');
|
|
if ( !fs )
|
|
{
|
|
fs = [];
|
|
this.set('filesystem',fs);
|
|
}
|
|
|
|
if ( data.filesystem && JSON.stringify(fs) !== JSON.stringify(data.filesystem) )
|
|
{
|
|
fs.length = 0;
|
|
data.filesystem.forEach(function(entry) {
|
|
fs.push(entry);
|
|
});
|
|
}
|
|
|
|
// CPU
|
|
var cpuGraph = this.get('cpuGraph');
|
|
if ( cpuGraph && (typeof data.cpu_user !== 'undefined') )
|
|
{
|
|
rows = this.get('cpuData');
|
|
rows.push([data.date, data.cpu_user, data.cpu_system]);
|
|
|
|
if ( rows.length > this.get('maxPoints') )
|
|
{
|
|
rows.splice(1,1);
|
|
}
|
|
|
|
if ( this.get('renderOk') )
|
|
{
|
|
cpuGraph.load({
|
|
rows: rows
|
|
});
|
|
}
|
|
}
|
|
|
|
// Memory
|
|
var memoryGraph = this.get('memoryGraph');
|
|
if ( memoryGraph )
|
|
{
|
|
rows = this.get('memoryData');
|
|
rows.push([data.date, data.mem_used_mb]);
|
|
|
|
if ( rows.length > this.get('maxPoints') )
|
|
{
|
|
rows.splice(1,1);
|
|
}
|
|
|
|
if ( this.get('renderOk') )
|
|
{
|
|
if ( this.get('useMemoryLimit') && data.mem_total_mb )
|
|
{
|
|
memoryGraph.axis.max(Math.ceil(data.mem_total_mb/1000)*1000);
|
|
}
|
|
|
|
memoryGraph.load({
|
|
rows: rows
|
|
});
|
|
}
|
|
}
|
|
},
|
|
|
|
initCpuGraph: function() {
|
|
//console.log('Init CPU');
|
|
this.set('cpuData', [['x','User','System'],[new Date(), 0,0]]);
|
|
|
|
var cpuGraph = c3.generate({
|
|
bindto: this.get('cpuCanvas'),
|
|
size: {
|
|
height: 210,
|
|
},
|
|
data: {
|
|
type: 'area-step',
|
|
x: 'x',
|
|
rows: this.get('cpuData'),
|
|
groups: [['User','System']],
|
|
colors: {
|
|
User: '#61d4bf',
|
|
System: '#00ff00',
|
|
},
|
|
},
|
|
transition: { duration: 0 },
|
|
tooltip: { show: false },
|
|
legend: {
|
|
position: 'inset',
|
|
},
|
|
padding: {
|
|
left: 40,
|
|
right: 0,
|
|
top: 2,
|
|
bottom: -20,
|
|
},
|
|
axis: {
|
|
x: {
|
|
type: 'timeseries',
|
|
},
|
|
y: {
|
|
min: 0,
|
|
max: 100,
|
|
padding: {
|
|
top: 0,
|
|
bottom: 0
|
|
},
|
|
tick: {
|
|
format: function(label) { return label + '%'; }
|
|
}
|
|
},
|
|
}
|
|
});
|
|
|
|
this.set('cpuGraph', cpuGraph);
|
|
},
|
|
|
|
initMemoryGraph: function() {
|
|
//console.log('Init Memory');
|
|
this.set('memoryData', [['x','Used'],[new Date(), 0]]);
|
|
|
|
var memoryGraph = c3.generate({
|
|
bindto: this.get('memoryCanvas'),
|
|
size: {
|
|
height: 210,
|
|
},
|
|
data: {
|
|
type: 'area-step',
|
|
x: 'x',
|
|
rows: this.get('memoryData'),
|
|
colors: {
|
|
Used: '#c6b2e7',
|
|
},
|
|
},
|
|
legend: {
|
|
position: 'inset',
|
|
},
|
|
padding: {
|
|
right: 0,
|
|
top: 2,
|
|
bottom: -20,
|
|
},
|
|
transition: { duration: 0 },
|
|
tooltip: { show: false },
|
|
axis: {
|
|
x: {
|
|
type: 'timeseries',
|
|
},
|
|
y: {
|
|
padding: {
|
|
top: 0,
|
|
bottom: 0
|
|
},
|
|
tick: {
|
|
format: function(label) {
|
|
if ( label> 10240 )
|
|
{
|
|
return Math.round(label/1024) + 'GiB';
|
|
}
|
|
else
|
|
{
|
|
return Math.ceil(label/102.4)/10 + 'GiB';
|
|
}
|
|
}
|
|
}
|
|
},
|
|
}
|
|
});
|
|
|
|
this.set('memoryGraph', memoryGraph);
|
|
},
|
|
|
|
disconnect: function() {
|
|
//console.log('Stats disconnect');
|
|
this.set('renderOk',false);
|
|
this.set('firstPoint',true);
|
|
|
|
var socket = this.get('statsSocket');
|
|
if ( socket )
|
|
{
|
|
socket.disconnect();
|
|
this.set('statsSocket', null);
|
|
}
|
|
|
|
var cpuGraph = this.get('cpuGraph');
|
|
if ( cpuGraph )
|
|
{
|
|
cpuGraph.destroy();
|
|
this.set('cpuGraph',null);
|
|
}
|
|
|
|
var memoryGraph = this.get('memoryGraph');
|
|
if ( memoryGraph )
|
|
{
|
|
memoryGraph.destroy();
|
|
this.set('memoryGraph',null);
|
|
}
|
|
}
|
|
});
|
|
|
|
export default Stats;
|