[pve-devel] [PATCH manager 6/7] add new ceph dashboard
Dominik Csapak
d.csapak at proxmox.com
Tue Nov 22 12:32:14 CET 2016
this patch changes the ceph dashboard
now we show the information in a more graphical way, namely:
the overall status is displayed by a big icon (+health)
the warnings/errors are in a list (with severity)
we show more detailed information about monitors, osds, and pgs
we show the usage of the cluster as a gauge graph, and
the reads, writes and iops as running charts (the last 5 minutes)
Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
www/manager6/Utils.js | 8 ++
www/manager6/ceph/Status.js | 338 +++++++++++++++++++++++++++++---------------
2 files changed, 231 insertions(+), 115 deletions(-)
diff --git a/www/manager6/Utils.js b/www/manager6/Utils.js
index a32697a..7f261a2 100644
--- a/www/manager6/Utils.js
+++ b/www/manager6/Utils.js
@@ -893,6 +893,14 @@ Ext.define('PVE.Utils', { utilities: {
return PVE.Utils.format_size(value);
},
+ render_bandwidth: function(value) {
+ if (!Ext.isNumeric(value)) {
+ return '';
+ }
+
+ return PVE.Utils.format_size(value) + '/s';
+ },
+
render_timestamp: function(value, metaData, record, rowIndex, colIndex, store) {
var servertime = new Date(value * 1000);
return Ext.Date.format(servertime, 'Y-m-d H:i:s');
diff --git a/www/manager6/ceph/Status.js b/www/manager6/ceph/Status.js
index ab97a9f..f04fca0 100644
--- a/www/manager6/ceph/Status.js
+++ b/www/manager6/ceph/Status.js
@@ -1,128 +1,236 @@
Ext.define('PVE.node.CephStatus', {
- extend: 'PVE.grid.ObjectGrid',
- alias: ['widget.pveNodeCephStatus'],
+ extend: 'Ext.panel.Panel',
+ alias: 'widget.pveNodeCephStatus',
+
onlineHelp: 'chapter_pveceph',
- cwidth1: 150,
- interval: 3000,
+
+ scrollable: true,
+
+ bodyPadding: '10 0 0 0',
+
+ defaults: {
+ width: 762,
+ userCls: 'inline-block',
+ padding: '0 0 10 10'
+ },
+
+ items: [
+ {
+ xtype: 'panel',
+ title: gettext('Health'),
+ bodyPadding: '0 10 10 10',
+ minHeight: 210,
+ layout: {
+ type: 'hbox',
+ align: 'top'
+ },
+ items: [
+ {
+ flex: 1,
+ itemId: 'overallhealth',
+ xtype: 'pveHealthWidget',
+ title: gettext('Status')
+ },
+ {
+ flex: 2,
+ itemId: 'warnings',
+ stateful: true,
+ stateId: 'ceph-status-warnings',
+ padding: '15 0 0 0',
+ xtype: 'grid',
+ minHeight: 100,
+ // since we load the store manually,
+ // to show the emptytext, we have to
+ // specify an empty store
+ store: { data:[] },
+ emptyText: gettext('No Warnings/Errors'),
+ columns: [
+ {
+ dataIndex: 'severity',
+ header: gettext('Severity'),
+ align: 'center',
+ width: 70,
+ renderer: function(value) {
+ var health = PVE.Utils.map_ceph_health[value];
+ var classes = PVE.Utils.get_health_icon(health);
+
+ return '<i class="fa fa-fw ' + classes + '"></i>';
+ },
+ sorter: {
+ sorterFn: function(a,b) {
+ var healthArr = ['HEALTH_ERR', 'HEALTH_WARN', 'HEALTH_OK'];
+ return healthArr.indexOf(b.data.severity) - healthArr.indexOf(a.data.severity);
+ }
+ }
+ },
+ {
+ dataIndex: 'summary',
+ header: gettext('Summary'),
+ flex: 1
+ }
+ ]
+ }
+ ]
+ },
+ {
+ xtype: 'pveCephStatusDetail',
+ itemId: 'statusdetail',
+ title: gettext('Status')
+ },
+ {
+ xtype: 'panel',
+ title: gettext('Performance'),
+ bodyPadding: '0 10 10 10',
+ layout: {
+ type: 'hbox',
+ align: 'center'
+ },
+ items: [
+ {
+ flex: 1,
+ xtype: 'pveGauge',
+ itemId: 'space',
+ title: gettext('Usage')
+ },
+ {
+ flex: 2,
+ xtype: 'container',
+ defaults: {
+ padding: '0 0 0 30',
+ height: 100
+ },
+ items: [
+ {
+ itemId: 'reads',
+ xtype: 'pveRunningChart',
+ title: gettext('Reads'),
+ renderer: PVE.Utils.render_bandwidth
+ },
+ {
+ itemId: 'writes',
+ xtype: 'pveRunningChart',
+ title: gettext('Writes'),
+ renderer: PVE.Utils.render_bandwidth
+ },
+ {
+ itemId: 'iops',
+ xtype: 'pveRunningChart',
+ hidden: true,
+ title: gettext('IOPS'),
+ renderer: Ext.util.Format.numberRenderer('0,000')
+ },
+ {
+ itemId: 'readiops',
+ xtype: 'pveRunningChart',
+ hidden: true,
+ title: gettext('Read IOPS'),
+ renderer: Ext.util.Format.numberRenderer('0,000')
+ },
+ {
+ itemId: 'writeiops',
+ xtype: 'pveRunningChart',
+ hidden: true,
+ title: gettext('Write IOPS'),
+ renderer: Ext.util.Format.numberRenderer('0,000')
+ }
+ ]
+ }
+ ]
+ }
+ ],
+
+ updateAll: function(store, records, success) {
+ if (!success || records.length === 0) {
+ return;
+ }
+
+ var me = this;
+ var rec = records[0];
+
+ // add health panel
+ me.down('#overallhealth').updateHealth(PVE.Utils.render_ceph_health(rec));
+ // add errors to gridstore
+ me.down('#warnings').getStore().loadRawData(rec.data.health.summary, false);
+
+ // update detailstatus panel
+ me.getComponent('statusdetail').updateAll(rec);
+
+ // add performance data
+ var used = rec.data.pgmap.bytes_used;
+ var total = rec.data.pgmap.bytes_total;
+
+ var text = Ext.String.format(gettext('{0} of {1}'),
+ PVE.Utils.render_size(used),
+ PVE.Utils.render_size(total)
+ );
+
+ // update the usage widget
+ me.down('#space').updateValue(used/total, text);
+
+ // TODO: logic for jewel (iops splitted in read/write)
+
+ var iops = rec.data.pgmap.op_per_sec;
+ var readiops = rec.data.pgmap.read_op_per_sec;
+ var writeiops = rec.data.pgmap.write_op_per_sec0;
+ var reads = rec.data.pgmap.read_bytes_sec || 0;
+ var writes = rec.data.pgmap.write_bytes_sec || 0;
+
+ if (iops !== undefined && me.version !== 'hammer') {
+ me.change_version('hammer');
+ } else if((readiops !== undefined || writeiops !== undefined) && me.version !== 'jewel') {
+ me.change_version('jewel');
+ }
+ // update the graphs
+ me.reads.addDataPoint(reads);
+ me.writes.addDataPoint(writes);
+ me.iops.addDataPoint(iops);
+ me.readiops.addDataPoint(readiops);
+ me.writeiops.addDataPoint(writeiops);
+ },
+
+ change_version: function(version) {
+ var me = this;
+ me.version = version;
+ me.sp.set('ceph-version', version);
+ me.iops.setVisible(version === 'hammer');
+ me.readiops.setVisible(version === 'jewel');
+ me.writeiops.setVisible(version === 'jewel');
+ },
+
initComponent: function() {
- /*jslint confusion: true */
- var me = this;
+ var me = this;
var nodename = me.pveSelNode.data.node;
if (!nodename) {
throw "no node name specified";
}
- var renderquorum = function(value) {
- if (!value || value.length < 0) {
- return 'No';
- }
-
- return 'Yes {' + value.join(' ') + '}';
- };
-
- var rendermonmap = function(d) {
- if (!d) {
- return '';
- }
-
- var txt = 'e' + d.epoch + ': ' + d.mons.length + " mons at ";
-
- Ext.Array.each(d.mons, function(d) {
- txt += d.name + '=' + d.addr + ',';
- });
-
- return txt;
- };
-
- var renderosdmap = function(value) {
- if (!value || !value.osdmap) {
- return '';
- }
-
- var d = value.osdmap;
-
- var txt = 'e' + d.epoch + ': ';
-
- txt += d.num_osds + ' osds: ' + d.num_up_osds + ' up, ' +
- d.num_in_osds + " in";
-
- return txt;
- };
-
- var renderhealth = function(value) {
- if (!value || !value.overall_status) {
- return '';
- }
-
- var txt = value.overall_status;
-
- Ext.Array.each(value.summary, function(d) {
- txt += " " + d.summary + ';';
- });
-
- return txt;
- };
-
- var renderpgmap = function(d) {
- if (!d) {
- return '';
- }
-
- var txt = 'v' + d.version + ': ';
-
- txt += d.num_pgs + " pgs:";
-
- Ext.Array.each(d.pgs_by_state, function(s) {
- txt += " " + s.count + " " + s.state_name;
- });
- txt += '; ';
-
- txt += PVE.Utils.format_size(d.data_bytes) + " data, ";
- txt += PVE.Utils.format_size(d.bytes_used) + " used, ";
- txt += PVE.Utils.format_size(d.bytes_avail) + " avail";
-
- return txt;
- };
-
- Ext.applyIf(me, {
- url: "/api2/json/nodes/" + nodename + "/ceph/status",
- rows: {
- health: {
- header: 'health',
- renderer: renderhealth,
- required: true
- },
- quorum_names: {
- header: 'quorum',
- renderer: renderquorum,
- required: true
- },
- fsid: {
- header: 'cluster',
- required: true
- },
- monmap: {
- header: 'monmap',
- renderer: rendermonmap,
- required: true
- },
- osdmap: {
- header: 'osdmap',
- renderer: renderosdmap,
- required: true
- },
- pgmap: {
- header: 'pgmap',
- renderer: renderpgmap,
- required: true
- }
- }
- });
-
me.callParent();
+ me.store = Ext.create('PVE.data.UpdateStore', {
+ storeid: 'ceph-status-' + nodename,
+ interval: 5000,
+ proxy: {
+ type: 'pve',
+ url: '/api2/json/nodes/' + nodename + '/ceph/status'
+ }
+ });
- me.on('activate', me.rstore.startUpdate);
- me.on('destroy', me.rstore.stopUpdate);
+ // save references for the updatefunction
+ me.iops = me.down('#iops');
+ me.readiops = me.down('#readiops');
+ me.writeiops = me.down('#writeiops');
+ me.reads = me.down('#reads');
+ me.writes = me.down('#writes');
+
+ // get ceph version
+ me.sp = Ext.state.Manager.getProvider();
+ me.version = me.sp.get('ceph-version');
+ me.change_version(me.version);
+
+ PVE.Utils.monStoreErrors(me,me.store);
+ me.mon(me.store, 'load', me.updateAll, me);
+ me.on('destroy', me.store.stopUpdate);
+ me.store.startUpdate();
}
+
});
--
2.1.4
More information about the pve-devel
mailing list