diff --git a/src/rockstor/smart_manager/data_collector.py b/src/rockstor/smart_manager/data_collector.py
index 8d8d70108..3e4481294 100644
--- a/src/rockstor/smart_manager/data_collector.py
+++ b/src/rockstor/smart_manager/data_collector.py
@@ -419,6 +419,7 @@ def recv_disconnect(self):
def send_top_disks(self):
def disk_stats(prev_stats):
+ disks_stats = []
# invoke body of disk_stats with empty cur_stats
stats_file_path = '/proc/diskstats'
cur_stats = {}
@@ -455,23 +456,23 @@ def disk_stats(prev_stats):
else:
datum = (float(cur[i]) - float(prev[i]))/interval
data.append(datum)
- self.emit('diskWidget:top_disks', {
- 'key': 'diskWidget:top_disks', 'data': [{
- 'name': disk,
- 'reads_completed': data[0],
- 'reads_merged': data[1],
- 'sectors_read': data[2],
- 'ms_reading': data[3],
- 'writes_completed': data[4],
- 'writes_merged': data[5],
- 'sectors_written': data[6],
- 'ms_writing': data[7],
- 'ios_progress': data[8],
- 'ms_ios': data[9],
- 'weighted_ios': data[10],
- 'ts': str(datetime.utcnow().replace(tzinfo=utc).isoformat())
- }]
- })
+ disks_stats.append({
+ 'name': disk,
+ 'reads_completed': data[0],
+ 'reads_merged': data[1],
+ 'sectors_read': data[2],
+ 'ms_reading': data[3],
+ 'writes_completed': data[4],
+ 'writes_merged': data[5],
+ 'sectors_written': data[6],
+ 'ms_writing': data[7],
+ 'ios_progress': data[8],
+ 'ms_ios': data[9],
+ 'weighted_ios': data[10],
+ 'ts': str(datetime.utcnow().replace(tzinfo=utc).isoformat())
+ })
+
+ self.emit('diskWidget:top_disks',{ 'key': 'diskWidget:top_disks', 'data': disks_stats })
return cur_stats
def get_stats():
diff --git a/src/rockstor/storageadmin/static/storageadmin/js/templates/dashboard/widgets/disk_util_select.jst b/src/rockstor/storageadmin/static/storageadmin/js/templates/dashboard/widgets/disk_util_select.jst
index 9cdb1aa9a..afb58832d 100644
--- a/src/rockstor/storageadmin/static/storageadmin/js/templates/dashboard/widgets/disk_util_select.jst
+++ b/src/rockstor/storageadmin/static/storageadmin/js/templates/dashboard/widgets/disk_util_select.jst
@@ -1,12 +1,11 @@
-
- Disk activity for disk
-
-
-
-
-
+
+ Disk activity for disk
+
+
+
+
\ No newline at end of file
diff --git a/src/rockstor/storageadmin/static/storageadmin/js/templates/dashboard/widgets/disk_utilization.jst b/src/rockstor/storageadmin/static/storageadmin/js/templates/dashboard/widgets/disk_utilization.jst
index cd7924749..6b02e47cb 100644
--- a/src/rockstor/storageadmin/static/storageadmin/js/templates/dashboard/widgets/disk_utilization.jst
+++ b/src/rockstor/storageadmin/static/storageadmin/js/templates/dashboard/widgets/disk_utilization.jst
@@ -1,28 +1,45 @@
-
+
+
-
Top Disks
-
-
-
- Sort by:
- Reads
- Writes
-
-
- Total:
-
-
-
-
+
+
+
+
+ Top disks sort by:
+
+
+
+
diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/dashboard/disk_utilization.js b/src/rockstor/storageadmin/static/storageadmin/js/views/dashboard/disk_utilization.js
index 706473198..65a00dc34 100644
--- a/src/rockstor/storageadmin/static/storageadmin/js/views/dashboard/disk_utilization.js
+++ b/src/rockstor/storageadmin/static/storageadmin/js/views/dashboard/disk_utilization.js
@@ -3,7 +3,7 @@
* @licstart The following is the entire license notice for the
* JavaScript code in this page.
*
- * Copyright (c) 2012-2013 RockStor, Inc.
+ * Copyright (c) 2012-2016 RockStor, Inc.
* This file is part of RockStor.
*
* RockStor is free software; you can redistribute it and/or modify
@@ -27,405 +27,507 @@
DiskUtilizationWidget = RockStorWidgetView.extend({
- initialize: function() {
- RockStorSocket.diskWidget = io.connect('/disk-widget', {'secure': true,
- 'force new connection': true});
- var _this = this;
- this.constructor.__super__.initialize.apply(this, arguments);
- this.template = window.JST.dashboard_widgets_disk_utilization;
- this.diskUtilSelect = window.JST.dashboard_widgets_disk_util_select;
- this.dataLength = 300;
- this.topDiskColors = [];
- // calculate colors from dark to light for top disks
- var startColor = d3.rgb('#CC6104');
- for (var i=0; i<5; i++) {
- this.topDiskColors.push(startColor.toString());
- startColor = startColor.brighter(2);
- }
- this.colors = ["#4DAF4A", "#377EB8"];
- // disks data is a map of diskname to array of values of length
- // dataLength
- // each value is of the format of the data returned by the api
- // see genEmptyDiskData for an example of this format
- this.disksData = {};
- this.disks = new DiskCollection();
- this.disks.pageSize = RockStorGlobals.maxPageSize;
-
- this.topDisks = [];
- this.topDisksWidth = this.maximized ? 520 : 240;
- this.topDisksHeight = 50;
-
- this.selectedDisk = null;
-
- this.updateFreq = 1000;
- this.sortAttrs = ['reads_completed']; // attrs to sort by
- // maximum number of top disks to display
- this.numTop = this.maximized ? 5 : 3;
- this.partition = d3.layout.partition()
- .value(function(d) {
- return _.reduce(_this.sortAttrs, function(s, a) { return s + d[a]; }, 0);
- });
- this.graphOptions = {
- grid : {
- //hoverable : true,
- borderWidth: {
- top: 1,
- right: 1,
- bottom: 1,
- left: 1
- },
- borderColor: "#ddd"
- },
- xaxis: {
- min: 0,
- max: this.dataLength-1,
- tickFormatter: this.timeTickFormatter(this.dataLength),
- axisLabel: "Time (minutes)",
- axisLabelColour: "#000"
- },
- yaxis: {
- min: 0
- },
- series: {
- lines: {show: true, fill: false},
- shadowSize: 0 // Drawing is faster without shadows
- }
- };
- this.dataGraphOptions = {
- grid : {
- //hoverable : true,
- borderWidth: {
- top: 1,
- right: 1,
- bottom: 1,
- left: 1
- },
- borderColor: "#ddd"
- },
- xaxis: {
- min: 0,
- max: this.dataLength-1,
- tickFormatter: this.timeTickFormatter(this.dataLength),
- axisLabel: "Time (minutes)",
- axisLabelColour: "#000"
- },
- yaxis: {
- min: 0,
- tickFormatter: this.valueTickFormatter
- },
- series: {
- lines: {show: true, fill: false},
- shadowSize: 0 // Drawing is faster without shadows
- }
- };
- },
-
- render: function() {
- var _this = this;
- // call render of base
- this.constructor.__super__.render.apply(this, arguments);
- $(this.el).html(this.template({
- module_name: this.module_name,
- displayName: this.displayName,
- maximized: this.maximized
- }));
-
- this.$('.diskSortAttr').change(function(event) {
- var cbox = $(event.currentTarget);
- var v = cbox.val();
- if (cbox.is(':checked')) {
- if (_.indexOf(_this.sortAttrs, v) == -1 ) {
- _this.sortAttrs.push(v);
- }
- } else {
- if (_.indexOf(_this.sortAttrs, v) != -1 ) {
- if (_this.sortAttrs.length > 1) {
- _this.sortAttrs = _.without(_this.sortAttrs, v);
- } else {
- // dont allow the last attr to be unchecked
- cbox.prop('checked', true);
- }
+ initialize: function() {
+
+ RockStorSocket.diskWidget = io.connect('/disk-widget', {
+ 'secure': true,
+ 'force new connection': true
+ });
+ var _this = this;
+ this.constructor.__super__.initialize.apply(this, arguments);
+ this.template = window.JST.dashboard_widgets_disk_utilization;
+ this.diskUtilSelect = window.JST.dashboard_widgets_disk_util_select;
+
+ Chart.defaults.global.tooltips.enabled = false;
+ Chart.defaults.global.elements.line.tension = 0.2;
+ Chart.defaults.global.elements.line.borderCapStyle = 'butt';
+ Chart.defaults.global.elements.line.borderDash = [];
+ Chart.defaults.global.elements.line.borderDashOffset = 0.0;
+ Chart.defaults.global.elements.line.borderWidth = 1;
+ Chart.defaults.global.elements.line.borderJoinStyle = 'miter';
+ Chart.defaults.global.elements.line.fill = false;
+ Chart.defaults.global.elements.point.radius = 0;
+ Chart.defaults.global.elements.point.hoverRadius = 0;
+
+ this.numTop = this.maximized ? 5 : 3;
+ this.dataLength = 300;
+ this.Disksfields = ['ms_ios', 'sectors_written', 'writes_completed', 'ms_writing', 'ms_reading', 'reads_completed', 'sectors_read'];
+ this.Diskslabels = ['ms on I/Os', 'kB written', 'Writes', 'ms writing', 'ms reading', 'Reads', 'kB read'];
+ this.TopDiskscolors = ['242, 0, 0', '36, 229, 84', '41, 108, 232', '232, 200, 41', '146, 41, 232']
+ this.SingleDiskcolors = ['7, 233, 7', '21, 124, 217', '255, 184, 7', '255, 25, 7']
+
+ // disks data is a map of diskname to array of values of length
+ // dataLength
+ // each value is of the format of the data returned by the api
+ // see genEmptyDiskData for an example of this format
+ this.disksData = {};
+ this.disks = new DiskCollection();
+ this.disks.pageSize = RockStorGlobals.maxPageSize;
+
+ this.topDisks = [];
+ this.selectedDisk = null;
+
+ this.best_draftSort = ['reads_completed', 'writes_completed', 'sectors_read', 'sectors_written', 'ms_ios', 'ms_writing', 'ms_reading'];
+ this.selectedAttr = 'best_draft';
+
+ this.SingleDiskChart = null;
+ this.SingleDiskChartOptions = {
+ animation: false,
+ responsive: false,
+ title: {
+ display: true,
+ text: '',
+ padding: 5,
+ fontSize: 11
+ },
+ legend: {
+ display: true,
+ position: 'bottom',
+ labels: {
+ boxWidth: 10,
+ padding: 5,
+ fontSize: 10
+ }
+ },
+ scales: {
+ yAxes: [{
+ id: 'IOs',
+ position: 'left',
+ scaleLabel: {
+ display: false
+ },
+ ticks: {
+ fontSize: 9,
+ beginAtZero: true,
+ min: 0
+ },
+ gridLines: {
+ drawTicks: true
+ }
+ }, {
+ id: 'Data',
+ position: 'right',
+ scaleLabel: {
+ display: false
+ },
+ ticks: {
+ fontSize: 9,
+ beginAtZero: true,
+ min: 0,
+ callback: function(value) {
+ return humanize.filesize(value);
+ }
+ },
+ gridLines: {
+ drawTicks: false
+ }
+ }],
+ xAxes: [{
+ scaleLabel: {
+ display: true,
+ fontSize: 11,
+ labelString: 'Time'
+ },
+ gridLines: {
+ display: true,
+ drawTicks: false
+ },
+ ticks: {
+ fontSize: 9,
+ maxRotation: 0,
+ autoSkip: false,
+ callback: function(value) {
+ return (value.toString().length > 0 ? value : null);
+ }
+ }
+ }]
+ }
+ };
+ this.SingleDiskChartData = {
+ labels: [],
+ datasets: [{
+ label: this.Diskslabels[5],
+ yAxisID: 'IOs',
+ backgroundColor: 'rgba(' + this.SingleDiskcolors[0] + ', 0.4)',
+ borderColor: 'rgba(' + this.SingleDiskcolors[0] + ', 1)',
+ data: []
+ }, {
+ label: this.Diskslabels[2],
+ yAxisID: 'IOs',
+ backgroundColor: 'rgba(' + this.SingleDiskcolors[1] + ', 0.4)',
+ borderColor: 'rgba(' + this.SingleDiskcolors[1] + ', 1)',
+ data: []
+ }, {
+ label: this.Diskslabels[6],
+ yAxisID: 'Data',
+ backgroundColor: 'rgba(' + this.SingleDiskcolors[2] + ', 0.4)',
+ borderColor: 'rgba(' + this.SingleDiskcolors[2] + ', 1)',
+ data: []
+ }, {
+ label: this.Diskslabels[1],
+ yAxisID: 'Data',
+ backgroundColor: 'rgba(' + this.SingleDiskcolors[3] + ', 0.4)',
+ borderColor: 'rgba(' + this.SingleDiskcolors[3] + ', 1)',
+ data: []
+ }]
}
- }
- });
- this.$('#top-disks-ph').css('width', this.topDisksWidth);
- this.topDisksPh = d3.select(this.el).select('#top-disks-ph');
-
- this.topDisksVis = this.topDisksPh
- .append('svg:svg')
- .attr('id', 'top-disks-svg')
- .attr('height', 75)
- .attr('width', this.topDisksWidth);
-
- this.disks.fetch({
- success: function(collection, response, options) {
- _this.initializeDisksData();
- RockStorSocket.addListener(_this.getData, _this, 'diskWidget:top_disks');
- }
- });
- return this;
- },
-
- // initialize disksData with disk names and empty value arrays
- initializeDisksData: function() {
- var _this = this;
- this.disks.each(function(disk) {
- var name = disk.get('name');
- var temp_name = disk.get('temp_name');
- _this.disksData[name] = [];
- for (var i=0; i<_this.dataLength; i++) {
- _this.disksData[name].push(_this.genEmptyDiskData());
- }
- });
- if (this.maximized) {
- // initialize disk-select
- this.$('#disk-details-ph').html(this.diskUtilSelect({
- disks: this.disks.toJSON()
- }));
- if (this.selectedDisk) {
- this.$('#disk-select').val(this.selectedDisk);
- }
- this.$('#disk-select').change(function(event) {
- _this.selectedDisk = _this.$('#disk-select').val();
- });
- } else {
- this.$('#disk-details-ph').html("Expand for details");
- }
- },
-
- getData: function(data) {
- var _this = this;
- _this.startTime = new Date().getTime();
- _this.update(data);
- },
-
- update: function(data) {
- this.updateDisksData(data);
- this.updateTopDisks();
- this.renderTopDisks();
- if (this.maximized) this.renderDiskGraph();
- },
-
- updateDisksData: function(data) {
- var _this = this;
- _.each(data, function(d) {
- _this.disksData[d.name].push(d);
- });
- _.each(_.keys(_this.disksData), function(diskName) {
- var diskData = _this.disksData[diskName];
- if (diskData.length > _this.dataLength) {
- diskData.splice(0, diskData.length - _this.dataLength);
- }
- });
- },
-
- // sorts latest values in disksData by sortAttrs and returns top n
- updateTopDisks: function() {
- var _this = this;
- var tmp = _.map(_.keys(_this.disksData), function(k) {
- return _this.disksData[k][_this.dataLength - 1];
- });
- tmp = _.reject(tmp, function(d) {
- var x = _.reduce(_this.sortAttrs, function(s, a) { return s + d[a]; }, 0);
- return x == 0;
- });
- var sorted = _.sortBy(tmp, function(d) {
- return _.reduce(_this.sortAttrs, function(s, a) { return s + d[a]; }, 0);
- }).reverse();
- this.topDisks = sorted.slice(0,_this.numTop);
- },
-
- // render bars for top disks. the width of each bar is proportional
- // to the sort value. Use d3 partition layout to calculate coordinates.
- renderTopDisks: function() {
- var _this = this;
- var w = this.topDisksWidth;
- var h = this.topDisksHeight;
- // calculate total value of all sortAttrs over all disks
- var totalAttr = _.reduce(this.topDisks, function(total, disk) {
- return total + _.reduce(_this.sortAttrs, function(s, a) {
- return s + disk[a];
- }, 0);
- }, 0);
- this.$('#attr-total').html(totalAttr);
-
- if (this.topDisks.length == 0) {
- if (!this.noDisks) {
- this.$('#top-disks-svg').empty();
- this.topDisksVis.append('g')
- .append('svg:text')
- .attr("transform", function(d) {
- return 'translate(0,' + 32 + ')';
- })
- .text('No disk activity')
- .attr('fill-opacity', 1.0);
- this.noDisks = true;
- }
- } else {
- if (this.noDisks) {
- // clear no disk activity msg
- this.$('#top-disks-svg').empty();
- }
- this.noDisks = false;
- var root = {name: 'root',
- reads_completed: 0,
- writes_completed: 0,
- children: this.topDisks
- };
- var x = d3.scale.linear().range([0, w]);
- var y = d3.scale.linear().range([0, h]);
- var diskNodes = this.partition.nodes(root);
- var kx = w / root.dx, ky = h / 1;
- var duration = 200;
-
- var disk = this.topDisksVis.selectAll('g')
- .data(diskNodes, function(d, i) { return d.name; });
-
- // Create g elements - each g element is positioned at appropriate
- // x coordinate, and contains a rect with width acc to disk sort value,
- // and a text element with the disk name
- var diskEnter = disk
- .enter().append('svg:g');
-
- diskEnter.append('svg:rect')
- .attr('class', 'diskRect')
- .attr('height', function(d) {
- if (d.name == 'root') {
- return 0;
+
+ this.TopDisksChart = null;
+ this.TopDisksChartOptions = {
+ animation: {
+ duration: 1500,
+ easing: 'linear'
+ },
+ responsive: true,
+ legend: {
+ display: true,
+ position: 'bottom',
+ labels: {
+ boxWidth: 10,
+ padding: 5,
+ fontSize: 10
+ }
+ },
+ scale: {
+ ticks: {
+ display: false,
+ min: 0,
+ max: 100,
+ stepSize: 20
+ }
+ }
+ };
+ this.TopDisksChartData = {
+ labels: this.Diskslabels,
+ datasets: []
+ };
+
+ this.initHandlebarHelpers();
+ },
+
+ render: function() {
+
+ var _this = this;
+ // call render of base
+ this.constructor.__super__.render.apply(this, arguments);
+ $(this.el).html(this.template({
+ module_name: this.module_name,
+ displayName: this.displayName,
+ maximized: this.maximized
+ }));
+ if (this.maximized) this.$('#top-disks-container').css('width', '60%');
+
+ this.$('#attr-select').change(function(event) {
+ var cbox = $(event.currentTarget);
+ var v = cbox.val();
+ _this.selectedAttr = v;
+ });
+
+ this.disks.fetch({
+ success: function(collection, response, options) {
+ _this.initializeDisksData();
+ _this.initTopDisksData();
+ _this.initSingleDiskData();
+ RockStorSocket.addListener(_this.getData, _this, 'diskWidget:top_disks');
+ }
+ });
+
+ return this;
+ },
+
+ // initialize disksData with disk names and empty value arrays
+ initializeDisksData: function() {
+
+ var _this = this;
+ this.disks.each(function(disk) {
+ var name = disk.get('name');
+ _this.disksData[name] = [];
+ for (var i = 0; i < _this.dataLength; i++) {
+ _this.disksData[name].push(_this.genEmptyDiskData());
+ }
+ });
+ if (this.maximized) {
+ // initialize disk-select
+ this.$('#disk-details-ph').html(this.diskUtilSelect({
+ disks: this.disks.toJSON()
+ }));
+ if (this.selectedDisk) {
+ this.$('#disk-select').val(this.selectedDisk);
+ }
+ this.$('#disk-select').change(function(event) {
+ _this.selectedDisk = _this.$('#disk-select').val();
+ });
} else {
- return 25;
+ this.$('#disk-details-ph').html("Expand for details");
}
- })
- .attr('fill', function(d,i) { return _this.topDiskColors[i-1]; });
-
- diskEnter.append("svg:text")
- .attr('class', 'diskText')
- .attr("transform", function(d) {
- return 'translate(0,' + 32 + ')';
- })
- .text(function(d) {
- if (d.name == 'root') {
- return '';
- } else {
- return d.name.split('_').pop();
+
+ },
+
+ initTopDisksData: function() {
+
+ var _this = this;
+ var num_disks = Object.keys(_this.disksData).length < _this.numTop ? Object.keys(_this.disksData).length : _this.numTop;
+ for (var i = 0; i < num_disks; i++) {
+ var dataset = {
+ label: '',
+ borderWidth: 1,
+ fill: true,
+ borderColor: 'rgba(' + _this.TopDiskscolors[i] + ', 1)',
+ backgroundColor: 'rgba(' + _this.TopDiskscolors[i] + ', 0.1)',
+ pointBackgroundColor: 'rgba(' + _this.TopDiskscolors[i] + ', 1)',
+ pointBorderColor: '#fff',
+ pointHoverBackgroundColor: '#fff',
+ pointHoverBorderColor: 'rgba(' + _this.TopDiskscolors[i] + ', 1)',
+ data: [0, 0, 0, 0, 0, 0, 0]
+ };
+ _this.TopDisksChartData.datasets.push(dataset);
}
- })
- .attr('fill-opacity', 1.0);
+ },
- var diskUpdate = disk.transition()
- .duration(duration)
- .attr('transform', function(d) {
- return 'translate(' + x(d.x) + ',' + y(d.y) + ')';
- });
+ initSingleDiskData: function() {
- var diskRectUpdate = diskUpdate.select('rect.diskRect')
- .attr('width', function(d) { return (d.dx * w) - 1; })
- .attr('fill', function(d,i) { return _this.topDiskColors[i-1]; });
+ var _this = this;
+ for (var i = 0; i < _this.dataLength; i++) {
+ _.each(_this.SingleDiskChartData.datasets, function(dataset) {
+ dataset.data.push(null);
+ });
+ _this.SingleDiskChartData.labels.push('');
+ }
+ },
- var diskExit = disk.exit().remove();
- }
- },
-
- renderDiskGraph: function() {
- if (!this.selectedDisk) {
- if (this.topDisks.length > 0) {
- this.selectedDisk = this.topDisks[0].name;
- } else {
- this.selectedDisk = this.disks.at(0).get('name');
- }
- this.$('#disk-select').val(this.selectedDisk);
- }
+ getData: function(data) {
- var vals = this.disksData[this.selectedDisk];
- var tmpReads = [];
- for (var i=0; iExpand for details");
- }
- },
+ var _this = this;
+ _this.update(data);
+ },
- timeTickFormatter: function(dataLength) {
- return function(val, axis) {
- return ((dataLength/60) - (parseInt(val/60))).toString() + ' m';
- };
- },
+ update: function(data) {
- valueTickFormatter: function(val, axis) {
- return humanize.filesize(val, 1024, 2);
- },
+ var _this = this;
+ _this.updateDisksData(data);
+ _this.sortDisks();
- setSelectedDisk: function(event) {
- this.selectedDisk = this.$('#disk-select').val();
- },
+ if (!_this.TopDisksgraphRendered) {
+ _this.initTopDisksGraph();
+ _this.TopDisksgraphRendered = true;
+ }
+ _this.updateTopDisksChart();
+
+ if (_this.maximized) {
+ if (!_this.SingleDiskgraphRendered) {
+ _this.initSingleDiskGraph();
+ _this.SingleDiskgraphRendered = true;
+ }
+ _this.updateSingleDiskChart();
+ }
+ },
+
+ initTopDisksGraph: function() {
+
+ var _this = this;
+ _this.TopDisksChart = new Chart(this.$('#top-disks-chart'), {
+ type: 'radar',
+ data: _this.TopDisksChartData,
+ options: _this.TopDisksChartOptions
+ });
+ },
+
+ initSingleDiskGraph: function() {
+
+ var _this = this;
+ _this.SingleDiskChart = new Chart(this.$('#single-disk-chart'), {
+ type: 'line',
+ data: _this.SingleDiskChartData,
+ options: _this.SingleDiskChartOptions
+ });
+ },
+
+ updateTopDisksChart: function() {
+
+ var _this = this;
+ //If avail disks < numTop, use only avail disks
+ var num_disks = Object.keys(_this.disksData).length < _this.numTop ? Object.keys(_this.disksData).length : _this.numTop;
+ for (var i = 0; i < num_disks; i++) {
+ var data = [];
+ _.each(_this.Disksfields, function(field) {
+ data.push(_this.normalizeData(field, _this.topDisks[i][field]));
+ });
+ _this.TopDisksChartData.datasets[i].data = data;
+ _this.TopDisksChartData.datasets[i].label = _this.topDisks[i].name;
+ }
+ _this.TopDisksChart.update();
+ },
+
+ updateSingleDiskChart: function() {
+
+ var _this = this;
+ if (!_this.selectedDisk) {
+ if (_this.topDisks.length > 0) {
+ _this.selectedDisk = _this.topDisks[0].name;
+ } else {
+ _this.selectedDisk = _this.disks.at(0).get('name');
+ }
+ this.$('#disk-select').val(_this.selectedDisk);
+ }
+ var current_disk = _this.disksData[_this.selectedDisk];
+ if (current_disk) {
+ var singlediskdata = {
+ reads_completed: [],
+ writes_completed: [],
+ sectors_read: [],
+ sectors_written: [],
+ ms_ios: [],
+ ms_writing: [],
+ ms_reading: []
+ };
+ var singledisklabels = [];
+
+ for (var i = 0; i < _this.dataLength; i++) {
+ _.each(singlediskdata, function(dataval, datakey) {
+ var multiplier = datakey.indexOf('sectors') > -1 ? 512 : 1;
+ singlediskdata[datakey].push(current_disk[i][datakey] * multiplier);
+ });
+ var csecs = moment(current_disk[i].ts).format('s');
+ var label = '';
+ if (csecs % 60 === 0) {
+ label = moment(current_disk[i].ts).format('HH:mm');
+ }
+ singledisklabels.push(label);
+ }
+ var msios = _.reduce(singlediskdata.ms_ios, function(s, n){ return s + n; }, 0)/singlediskdata.ms_ios.length;
+ var msw = _.reduce(singlediskdata.ms_writing, function(s, n){ return s + n; }, 0)/singlediskdata.ms_writing.length;
+ var msr = _.reduce(singlediskdata.ms_reading, function(s, n){ return s + n; }, 0)/singlediskdata.ms_reading.length;
+ var title = ': Avg I/Os: ' + msios.toFixed(2) + 'ms - ';
+ title +='Avg writing: ' + msw.toFixed(2) + 'ms - ';
+ title +='Avg reading: ' + msr.toFixed(2) + 'ms :';
+ delete singlediskdata.ms_ios;
+ delete singlediskdata.ms_writing;
+ delete singlediskdata.ms_reading;
+ _.each(_.values(singlediskdata), function(val, index) {
+ _this.SingleDiskChartData.datasets[index].data = val;
+ });
+ _this.SingleDiskChart.options.title.text = title;
+ _this.SingleDiskChartData.labels = singledisklabels;
+ _this.SingleDiskChart.update();
+ }
+ },
+
+ //Chart.js radar chart don't have multiple scales
+ //so we have to normalize our data
+ //data normalization has new_x = (x - x_min) / (x_max -x_min) and returns x [0..1]
+ //we assume our x_min = 0, so new_x = x /x_max
+ normalizeData: function(field, val) {
+
+ var _this = this;
+ var val_max = _.max(_.pluck(_this.topDisks, field));
+ var new_val = val == 0 ? 0 : (val * 100 / val_max).toFixed(2); //we use a 0..100 range with 2 decimals
+ return new_val;
+ },
+
+ sortDisks: function() {
+
+ var _this = this;
+ var tmp = _.map(_.keys(_this.disksData), function(k) {
+ return _this.disksData[k][_this.dataLength - 1];
+ });
+
+ var sort_attr = _this.selectedAttr;
+ if (sort_attr == 'best_draft') {
+ var selected_top = [];
+ for (var i = 0; i < Object.keys(tmp).length; i++) {
+ _.each(_this.best_draftSort, function(d) {
+ var sorted = _.sortBy(tmp, function(k) {
+ return k[d];
+ }).reverse();
+ if (!_.contains(selected_top, sorted[i].name) && selected_top.length < _this.numTop) {
+ selected_top.push(sorted[i].name);
+ }
+ });
+ }
+ var local_topdisks = []
+ _.each(selected_top, function(disk) {
+ _.each(tmp, function(d) {
+ if (d.name == disk) local_topdisks.push(d);
+ });
+ });
+ _this.topDisks = local_topdisks;
+ } else {
+ _this.topDisks = _.sortBy(tmp, function(d) {
+ return d[sort_attr];
+ }).reverse();
+ }
+ },
+
+ updateDisksData: function(data) {
+
+ var _this = this;
+ _.each(data, function(d) {
+ _this.disksData[d.name].push(d);
+ _this.disksData[d.name].shift();
+ });
+ },
+
+ genEmptyDiskData: function() {
+ // empty disk data
+ return {
+ "reads_completed": 0,
+ "reads_merged": 0,
+ "sectors_read": 0,
+ "ms_reading": 0,
+ "writes_completed": 0,
+ "writes_merged": 0,
+ "sectors_written": 0,
+ "ms_writing": 0,
+ "ios_progress": 0,
+ "ms_ios": 0,
+ "weighted_ios": 0,
+ "ts": ''
+ };
+ },
+
+ resize: function(event) {
+
+ var _this = this;
+ this.constructor.__super__.resize.apply(this, arguments);
+ // maximum number of top disks to display
+ this.numTop = this.maximized ? 5 : 3;
+ if (this.maximized) {
+ this.$('#disk-details-ph').html(this.diskUtilSelect({
+ disks: this.disks.toJSON()
+ }));
+ if (this.selectedDisk) {
+ this.$('#disk-select').val(this.selectedDisk);
+ }
+ this.$('#disk-select').change(function(event) {
+ _this.selectedDisk = _this.$('#disk-select').val();
+ });
+ this.$('#top-disks-container').css('width', '60%');
+ } else {
+ this.$('#top-disks-container').css('width', '70%');
+ _this.SingleDiskgraphRendered = false;
+ this.$('#disk-details-ph').html("Expand for details");
+ }
+ _this.TopDisksChart.resize();
+ },
+
+ cleanup: function() {
+
+ RockStorSocket.removeOneListener('diskWidget');
+ },
+
+ initHandlebarHelpers: function() {
- cleanup: function() {
- RockStorSocket.removeOneListener('diskWidget');
- }
+ var _this = this;
+
+ Handlebars.registerHelper('genAttrSelect', function() {
+
+ var html = '';
+ _.each(_this.Disksfields, function(field, index) {
+ html += '';
+ });
+ return new Handlebars.SafeString(html);
+ });
+ }
});